From 90d0c76d59be45091a8ea123208ba6a8b86fcf44 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 29 Jan 2016 22:43:55 +0000 Subject: [PATCH] Initial Commit of Source --- .gitattributes | 17 + .gitignore | 61 + QVR.iml | 19 + app/app.iml | 92 + app/build.gradle | 25 + app/jni/Android.mk | 117 + app/jni/Application.mk | 22 + app/jni/COPYING | 340 + app/jni/QVR.c | 449 + app/jni/SDLMain.h | 11 + app/jni/bih.c | 216 + app/jni/bih.h | 91 + app/jni/bspfile.h | 321 + app/jni/build.bat | 19 + app/jni/builddate.c | 12 + app/jni/cap_avi.c | 720 + app/jni/cap_avi.h | 1 + app/jni/cap_ogg.c | 1121 ++ app/jni/cap_ogg.h | 4 + app/jni/cd_null.c | 91 + app/jni/cd_shared.c | 783 + app/jni/cdaudio.h | 66 + app/jni/cflags.mk | 30 + app/jni/cl_collision.c | 1079 ++ app/jni/cl_collision.h | 19 + app/jni/cl_demo.c | 617 + app/jni/cl_dyntexture.c | 93 + app/jni/cl_dyntexture.h | 20 + app/jni/cl_input.c | 2297 +++ app/jni/cl_main.c | 2499 +++ app/jni/cl_parse.c | 4278 ++++++ app/jni/cl_particles.c | 3101 ++++ app/jni/cl_screen.c | 2788 ++++ app/jni/cl_screen.h | 30 + app/jni/cl_video.c | 743 + app/jni/cl_video.h | 97 + app/jni/cl_video_libavw.c | 386 + app/jni/client.h | 2052 +++ app/jni/clprogdefs.h | 98 + app/jni/clvm_cmds.c | 5007 ++++++ app/jni/clvm_cmds.h | 27 + app/jni/cmd.c | 2233 +++ app/jni/cmd.h | 173 + app/jni/collision.c | 1988 +++ app/jni/collision.h | 191 + app/jni/common.c | 2276 +++ app/jni/common.h | 380 + app/jni/conproc.c | 365 + app/jni/conproc.h | 42 + app/jni/console.c | 3014 ++++ app/jni/console.h | 151 + app/jni/crypto.c | 2588 ++++ app/jni/crypto.h | 158 + app/jni/csprogs.c | 1252 ++ app/jni/csprogs.h | 121 + app/jni/curves.c | 440 + app/jni/curves.h | 39 + app/jni/cvar.c | 1027 ++ app/jni/cvar.h | 245 + app/jni/dpsoftrast.c | 5690 +++++++ app/jni/dpsoftrast.h | 327 + app/jni/dpvsimpledecode.c | 656 + app/jni/dpvsimpledecode.h | 49 + app/jni/draw.h | 207 + app/jni/filematch.c | 204 + app/jni/fractalnoise.c | 226 + app/jni/fs.c | 3995 +++++ app/jni/fs.h | 144 + app/jni/ft2.c | 1593 ++ app/jni/ft2.h | 81 + app/jni/ft2_defs.h | 500 + app/jni/ft2_fontdefs.h | 64 + app/jni/gl_backend.c | 4867 ++++++ app/jni/gl_backend.h | 127 + app/jni/gl_draw.c | 2268 +++ app/jni/gl_rmain.c | 12691 ++++++++++++++++ app/jni/gl_rsurf.c | 1645 ++ app/jni/gl_textures.c | 2983 ++++ app/jni/glquake.h | 1347 ++ app/jni/hmac.c | 61 + app/jni/hmac.h | 15 + app/jni/host.c | 1460 ++ app/jni/host_cmd.c | 3051 ++++ app/jni/image.c | 1588 ++ app/jni/image.h | 62 + app/jni/image_png.c | 559 + app/jni/image_png.h | 33 + app/jni/input.h | 53 + app/jni/intoverflow.h | 22 + app/jni/jpeg.c | 1108 ++ app/jni/jpeg.h | 39 + app/jni/keys.c | 2003 +++ app/jni/keys.h | 392 + app/jni/lhfont.h | 106 + app/jni/lhnet.c | 1419 ++ app/jni/lhnet.h | 52 + app/jni/libcurl.c | 1828 +++ app/jni/libcurl.h | 44 + app/jni/mathlib.c | 805 + app/jni/mathlib.h | 305 + app/jni/matrixlib.c | 1825 +++ app/jni/matrixlib.h | 172 + app/jni/mdfour.c | 229 + app/jni/mdfour.h | 54 + app/jni/menu.c | 6055 ++++++++ app/jni/menu.h | 99 + app/jni/meshqueue.c | 151 + app/jni/meshqueue.h | 12 + .../mod_skeletal_animatevertices_generic.c | 136 + .../mod_skeletal_animatevertices_generic.h | 8 + app/jni/mod_skeletal_animatevertices_sse.c | 446 + app/jni/mod_skeletal_animatevertices_sse.h | 10 + app/jni/model_alias.c | 4044 +++++ app/jni/model_alias.h | 252 + app/jni/model_brush.c | 8071 ++++++++++ app/jni/model_brush.h | 716 + app/jni/model_dpmodel.h | 123 + app/jni/model_iqm.h | 127 + app/jni/model_psk.h | 117 + app/jni/model_shared.c | 4474 ++++++ app/jni/model_shared.h | 1241 ++ app/jni/model_sprite.c | 482 + app/jni/model_sprite.h | 41 + app/jni/model_zymotic.h | 68 + app/jni/modelgen.h | 137 + app/jni/mprogdefs.h | 22 + app/jni/mvm_cmds.c | 1577 ++ app/jni/netconn.c | 3766 +++++ app/jni/netconn.h | 469 + app/jni/palette.c | 336 + app/jni/palette.h | 39 + app/jni/polygon.c | 310 + app/jni/polygon.h | 16 + app/jni/portals.c | 480 + app/jni/portals.h | 10 + app/jni/pr_comp.h | 225 + app/jni/progdefs.h | 170 + app/jni/progs.h | 151 + app/jni/progsvm.h | 886 ++ app/jni/protocol.c | 3387 +++++ app/jni/protocol.h | 1024 ++ app/jni/prvm_cmds.c | 7334 +++++++++ app/jni/prvm_cmds.h | 487 + app/jni/prvm_edict.c | 3381 ++++ app/jni/prvm_exec.c | 983 ++ app/jni/prvm_execprogram.h | 744 + app/jni/prvm_offsets.h | 850 ++ app/jni/qtypes.h | 65 + app/jni/quakedef.h | 550 + app/jni/r_explosion.c | 285 + app/jni/r_lerpanim.c | 0 app/jni/r_lerpanim.h | 0 app/jni/r_lightning.c | 327 + app/jni/r_modules.c | 134 + app/jni/r_modules.h | 15 + app/jni/r_shadow.c | 6919 +++++++++ app/jni/r_shadow.h | 110 + app/jni/r_sky.c | 461 + app/jni/r_sprites.c | 429 + app/jni/r_textures.h | 222 + app/jni/render.h | 646 + app/jni/resource.h | 16 + app/jni/sbar.c | 2238 +++ app/jni/sbar.h | 39 + app/jni/screen.h | 87 + app/jni/server.h | 615 + app/jni/shader_glsl.h | 1699 +++ app/jni/shader_hlsl.h | 1561 ++ app/jni/snd_android.c | 185 + app/jni/snd_main.c | 2342 +++ app/jni/snd_main.h | 213 + app/jni/snd_mem.c | 388 + app/jni/snd_mix.c | 532 + app/jni/snd_modplug.c | 432 + app/jni/snd_modplug.h | 33 + app/jni/snd_ogg.c | 718 + app/jni/snd_ogg.h | 33 + app/jni/snd_wav.c | 348 + app/jni/snd_wav.h | 34 + app/jni/snprintf.c | 1025 ++ app/jni/snprintf.h | 26 + app/jni/sound.h | 120 + app/jni/spritegn.h | 131 + app/jni/sv_demo.c | 99 + app/jni/sv_demo.h | 9 + app/jni/sv_main.c | 4033 +++++ app/jni/sv_move.c | 448 + app/jni/sv_phys.c | 3227 ++++ app/jni/sv_user.c | 965 ++ app/jni/svbsp.c | 453 + app/jni/svbsp.h | 75 + app/jni/svvm_cmds.c | 3847 +++++ app/jni/sys.h | 119 + app/jni/sys_linux.c | 200 + app/jni/sys_shared.c | 645 + app/jni/thread.h | 42 + app/jni/thread_pthread.c | 226 + app/jni/timing.h | 58 + app/jni/utf8lib.c | 3055 ++++ app/jni/utf8lib.h | 67 + app/jni/vid.h | 296 + app/jni/vid_android.c | 592 + app/jni/vid_shared.c | 2125 +++ app/jni/view.c | 1148 ++ app/jni/wad.c | 312 + app/jni/wad.h | 77 + app/jni/world.c | 3123 ++++ app/jni/world.h | 146 + app/jni/zone.c | 984 ++ app/jni/zone.h | 144 + app/libs/cardboard.jar | Bin 0 -> 620744 bytes app/proguard-rules.pro | 17 + app/src/main/AndroidManifest.xml | 32 + app/src/main/assets/commandline.txt | 0 app/src/main/assets/config.cfg | 58 + app/src/main/assets/source/GPL.txt | 340 + app/src/main/assets/source/QVRSource.zip | Bin 0 -> 4200763 bytes app/src/main/assets/splash.jpg | Bin 0 -> 55971 bytes .../java/com/drbeef/qvr/AudioCallback.java | 108 + .../java/com/drbeef/qvr/DownloadTask.java | 299 + .../java/com/drbeef/qvr/MainActivity.java | 1195 ++ .../main/java/com/drbeef/qvr/QVRCallback.java | 10 + app/src/main/java/com/drbeef/qvr/QVRFBO.java | 20 + .../main/java/com/drbeef/qvr/QVRJNILib.java | 26 + app/src/main/res/layout/activity_main.xml | 16 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 8993 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 4643 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 14745 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 30312 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 49342 bytes app/src/main/res/raw/m010912339 | Bin 0 -> 2379942 bytes app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 5 + build.gradle | 19 + gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 + gradlew.bat | 90 + local.properties | 11 + settings.gradle | 1 + 242 files changed, 208887 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 QVR.iml create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/jni/Android.mk create mode 100644 app/jni/Application.mk create mode 100644 app/jni/COPYING create mode 100644 app/jni/QVR.c create mode 100644 app/jni/SDLMain.h create mode 100644 app/jni/bih.c create mode 100644 app/jni/bih.h create mode 100644 app/jni/bspfile.h create mode 100644 app/jni/build.bat create mode 100644 app/jni/builddate.c create mode 100644 app/jni/cap_avi.c create mode 100644 app/jni/cap_avi.h create mode 100644 app/jni/cap_ogg.c create mode 100644 app/jni/cap_ogg.h create mode 100644 app/jni/cd_null.c create mode 100644 app/jni/cd_shared.c create mode 100644 app/jni/cdaudio.h create mode 100644 app/jni/cflags.mk create mode 100644 app/jni/cl_collision.c create mode 100644 app/jni/cl_collision.h create mode 100644 app/jni/cl_demo.c create mode 100644 app/jni/cl_dyntexture.c create mode 100644 app/jni/cl_dyntexture.h create mode 100644 app/jni/cl_input.c create mode 100644 app/jni/cl_main.c create mode 100644 app/jni/cl_parse.c create mode 100644 app/jni/cl_particles.c create mode 100644 app/jni/cl_screen.c create mode 100644 app/jni/cl_screen.h create mode 100644 app/jni/cl_video.c create mode 100644 app/jni/cl_video.h create mode 100644 app/jni/cl_video_libavw.c create mode 100644 app/jni/client.h create mode 100644 app/jni/clprogdefs.h create mode 100644 app/jni/clvm_cmds.c create mode 100644 app/jni/clvm_cmds.h create mode 100644 app/jni/cmd.c create mode 100644 app/jni/cmd.h create mode 100644 app/jni/collision.c create mode 100644 app/jni/collision.h create mode 100644 app/jni/common.c create mode 100644 app/jni/common.h create mode 100644 app/jni/conproc.c create mode 100644 app/jni/conproc.h create mode 100644 app/jni/console.c create mode 100644 app/jni/console.h create mode 100644 app/jni/crypto.c create mode 100644 app/jni/crypto.h create mode 100644 app/jni/csprogs.c create mode 100644 app/jni/csprogs.h create mode 100644 app/jni/curves.c create mode 100644 app/jni/curves.h create mode 100644 app/jni/cvar.c create mode 100644 app/jni/cvar.h create mode 100644 app/jni/dpsoftrast.c create mode 100644 app/jni/dpsoftrast.h create mode 100644 app/jni/dpvsimpledecode.c create mode 100644 app/jni/dpvsimpledecode.h create mode 100644 app/jni/draw.h create mode 100644 app/jni/filematch.c create mode 100644 app/jni/fractalnoise.c create mode 100644 app/jni/fs.c create mode 100644 app/jni/fs.h create mode 100644 app/jni/ft2.c create mode 100644 app/jni/ft2.h create mode 100644 app/jni/ft2_defs.h create mode 100644 app/jni/ft2_fontdefs.h create mode 100644 app/jni/gl_backend.c create mode 100644 app/jni/gl_backend.h create mode 100644 app/jni/gl_draw.c create mode 100644 app/jni/gl_rmain.c create mode 100644 app/jni/gl_rsurf.c create mode 100644 app/jni/gl_textures.c create mode 100644 app/jni/glquake.h create mode 100644 app/jni/hmac.c create mode 100644 app/jni/hmac.h create mode 100644 app/jni/host.c create mode 100644 app/jni/host_cmd.c create mode 100644 app/jni/image.c create mode 100644 app/jni/image.h create mode 100644 app/jni/image_png.c create mode 100644 app/jni/image_png.h create mode 100644 app/jni/input.h create mode 100644 app/jni/intoverflow.h create mode 100644 app/jni/jpeg.c create mode 100644 app/jni/jpeg.h create mode 100644 app/jni/keys.c create mode 100644 app/jni/keys.h create mode 100644 app/jni/lhfont.h create mode 100644 app/jni/lhnet.c create mode 100644 app/jni/lhnet.h create mode 100644 app/jni/libcurl.c create mode 100644 app/jni/libcurl.h create mode 100644 app/jni/mathlib.c create mode 100644 app/jni/mathlib.h create mode 100644 app/jni/matrixlib.c create mode 100644 app/jni/matrixlib.h create mode 100644 app/jni/mdfour.c create mode 100644 app/jni/mdfour.h create mode 100644 app/jni/menu.c create mode 100644 app/jni/menu.h create mode 100644 app/jni/meshqueue.c create mode 100644 app/jni/meshqueue.h create mode 100644 app/jni/mod_skeletal_animatevertices_generic.c create mode 100644 app/jni/mod_skeletal_animatevertices_generic.h create mode 100644 app/jni/mod_skeletal_animatevertices_sse.c create mode 100644 app/jni/mod_skeletal_animatevertices_sse.h create mode 100644 app/jni/model_alias.c create mode 100644 app/jni/model_alias.h create mode 100644 app/jni/model_brush.c create mode 100644 app/jni/model_brush.h create mode 100644 app/jni/model_dpmodel.h create mode 100644 app/jni/model_iqm.h create mode 100644 app/jni/model_psk.h create mode 100644 app/jni/model_shared.c create mode 100644 app/jni/model_shared.h create mode 100644 app/jni/model_sprite.c create mode 100644 app/jni/model_sprite.h create mode 100644 app/jni/model_zymotic.h create mode 100644 app/jni/modelgen.h create mode 100644 app/jni/mprogdefs.h create mode 100644 app/jni/mvm_cmds.c create mode 100644 app/jni/netconn.c create mode 100644 app/jni/netconn.h create mode 100644 app/jni/palette.c create mode 100644 app/jni/palette.h create mode 100644 app/jni/polygon.c create mode 100644 app/jni/polygon.h create mode 100644 app/jni/portals.c create mode 100644 app/jni/portals.h create mode 100644 app/jni/pr_comp.h create mode 100644 app/jni/progdefs.h create mode 100644 app/jni/progs.h create mode 100644 app/jni/progsvm.h create mode 100644 app/jni/protocol.c create mode 100644 app/jni/protocol.h create mode 100644 app/jni/prvm_cmds.c create mode 100644 app/jni/prvm_cmds.h create mode 100644 app/jni/prvm_edict.c create mode 100644 app/jni/prvm_exec.c create mode 100644 app/jni/prvm_execprogram.h create mode 100644 app/jni/prvm_offsets.h create mode 100644 app/jni/qtypes.h create mode 100644 app/jni/quakedef.h create mode 100644 app/jni/r_explosion.c create mode 100644 app/jni/r_lerpanim.c create mode 100644 app/jni/r_lerpanim.h create mode 100644 app/jni/r_lightning.c create mode 100644 app/jni/r_modules.c create mode 100644 app/jni/r_modules.h create mode 100644 app/jni/r_shadow.c create mode 100644 app/jni/r_shadow.h create mode 100644 app/jni/r_sky.c create mode 100644 app/jni/r_sprites.c create mode 100644 app/jni/r_textures.h create mode 100644 app/jni/render.h create mode 100644 app/jni/resource.h create mode 100644 app/jni/sbar.c create mode 100644 app/jni/sbar.h create mode 100644 app/jni/screen.h create mode 100644 app/jni/server.h create mode 100644 app/jni/shader_glsl.h create mode 100644 app/jni/shader_hlsl.h create mode 100644 app/jni/snd_android.c create mode 100644 app/jni/snd_main.c create mode 100644 app/jni/snd_main.h create mode 100644 app/jni/snd_mem.c create mode 100644 app/jni/snd_mix.c create mode 100644 app/jni/snd_modplug.c create mode 100644 app/jni/snd_modplug.h create mode 100644 app/jni/snd_ogg.c create mode 100644 app/jni/snd_ogg.h create mode 100644 app/jni/snd_wav.c create mode 100644 app/jni/snd_wav.h create mode 100644 app/jni/snprintf.c create mode 100644 app/jni/snprintf.h create mode 100644 app/jni/sound.h create mode 100644 app/jni/spritegn.h create mode 100644 app/jni/sv_demo.c create mode 100644 app/jni/sv_demo.h create mode 100644 app/jni/sv_main.c create mode 100644 app/jni/sv_move.c create mode 100644 app/jni/sv_phys.c create mode 100644 app/jni/sv_user.c create mode 100644 app/jni/svbsp.c create mode 100644 app/jni/svbsp.h create mode 100644 app/jni/svvm_cmds.c create mode 100644 app/jni/sys.h create mode 100644 app/jni/sys_linux.c create mode 100644 app/jni/sys_shared.c create mode 100644 app/jni/thread.h create mode 100644 app/jni/thread_pthread.c create mode 100644 app/jni/timing.h create mode 100644 app/jni/utf8lib.c create mode 100644 app/jni/utf8lib.h create mode 100644 app/jni/vid.h create mode 100644 app/jni/vid_android.c create mode 100644 app/jni/vid_shared.c create mode 100644 app/jni/view.c create mode 100644 app/jni/wad.c create mode 100644 app/jni/wad.h create mode 100644 app/jni/world.c create mode 100644 app/jni/world.h create mode 100644 app/jni/zone.c create mode 100644 app/jni/zone.h create mode 100644 app/libs/cardboard.jar create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/commandline.txt create mode 100644 app/src/main/assets/config.cfg create mode 100644 app/src/main/assets/source/GPL.txt create mode 100644 app/src/main/assets/source/QVRSource.zip create mode 100644 app/src/main/assets/splash.jpg create mode 100644 app/src/main/java/com/drbeef/qvr/AudioCallback.java create mode 100644 app/src/main/java/com/drbeef/qvr/DownloadTask.java create mode 100644 app/src/main/java/com/drbeef/qvr/MainActivity.java create mode 100644 app/src/main/java/com/drbeef/qvr/QVRCallback.java create mode 100644 app/src/main/java/com/drbeef/qvr/QVRFBO.java create mode 100644 app/src/main/java/com/drbeef/qvr/QVRJNILib.java create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/raw/m010912339 create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 local.properties create mode 100644 settings.gradle diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fa5f59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +# build files +*.o +*.d + +#binaries +*.so + +#files created by build +*.apk +*.ap_ +*.class +*.log +bin/* +gen/* +.idea/* +.gradle/* diff --git a/QVR.iml b/QVR.iml new file mode 100644 index 0000000..225b52a --- /dev/null +++ b/QVR.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..540250c --- /dev/null +++ b/app/app.iml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..09a43aa --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 16 + buildToolsVersion '19.1.0' + defaultConfig { + applicationId "com.drbeef.qvr" + minSdkVersion 16 + targetSdkVersion 19 + versionCode 1 + versionName '1.0.0' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + productFlavors { + } + } + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') +} diff --git a/app/jni/Android.mk b/app/jni/Android.mk new file mode 100644 index 0000000..9f1c01b --- /dev/null +++ b/app/jni/Android.mk @@ -0,0 +1,117 @@ + +LOCAL_PATH:= $(call my-dir) + +#-------------------------------------------------------- +# libquakecardboard.so +#-------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := qvr +LOCAL_CFLAGS := -std=c99 +LOCAL_SRC_FILES := QVR.c +LOCAL_LDLIBS := -llog -landroid -lGLESv2 -lEGL # include default libraries + +# CD objects +SRC_NOCD=cd_null.c + +SRC_SND_COMMON=snd_main.c snd_mem.c snd_mix.c snd_ogg.c snd_wav.c snd_modplug.c + + + +###### Common objects and flags ##### + +# Common objects +SRC_COMMON= \ + bih.c \ + cap_avi.c \ + cap_ogg.c \ + cd_shared.c \ + crypto.c \ + cl_collision.c \ + cl_demo.c \ + cl_dyntexture.c \ + cl_input.c \ + cl_main.c \ + cl_parse.c \ + cl_particles.c \ + cl_screen.c \ + cl_video.c \ + clvm_cmds.c \ + cmd.c \ + collision.c \ + common.c \ + console.c \ + csprogs.c \ + curves.c \ + cvar.c \ + dpsoftrast.c \ + dpvsimpledecode.c \ + filematch.c \ + fractalnoise.c \ + fs.c \ + ft2.c \ + utf8lib.c \ + gl_backend.c \ + gl_draw.c \ + gl_rmain.c \ + gl_rsurf.c \ + gl_textures.c \ + hmac.c \ + host.c \ + host_cmd.c \ + image.c \ + image_png.c \ + jpeg.c \ + keys.c \ + lhnet.c \ + libcurl.c \ + mathlib.c \ + matrixlib.c \ + mdfour.c \ + menu.c \ + meshqueue.c \ + mod_skeletal_animatevertices_sse.c \ + mod_skeletal_animatevertices_generic.c \ + model_alias.c \ + model_brush.c \ + model_shared.c \ + model_sprite.c \ + mvm_cmds.c \ + netconn.c \ + palette.c \ + polygon.c \ + portals.c \ + protocol.c \ + prvm_cmds.c \ + prvm_edict.c \ + prvm_exec.c \ + r_explosion.c \ + r_lerpanim.c \ + r_lightning.c \ + r_modules.c \ + r_shadow.c \ + r_sky.c \ + r_sprites.c \ + sbar.c \ + snprintf.c \ + sv_demo.c \ + sv_main.c \ + sv_move.c \ + sv_phys.c \ + sv_user.c \ + svbsp.c \ + svvm_cmds.c \ + sys_shared.c \ + vid_shared.c \ + view.c \ + wad.c \ + world.c \ + zone.c + + +SRC_ANDROID= builddate.c sys_linux.c vid_android.c thread_pthread.c snd_android.c $(SRC_SND_COMMON) $(SRC_NOCD) $(SRC_COMMON) + +LOCAL_SRC_FILES += $(SRC_ANDROID) + +include $(BUILD_SHARED_LIBRARY) + diff --git a/app/jni/Application.mk b/app/jni/Application.mk new file mode 100644 index 0000000..129f439 --- /dev/null +++ b/app/jni/Application.mk @@ -0,0 +1,22 @@ +# Common build settings for all VR apps + +# This needs to be defined to get the right header directories for egl / etc +APP_PLATFORM := android-16 + +APP_ABI := armeabi-v7a + +# Statically link the GNU STL. This may not be safe for multi-so libraries but +# we don't know of any problems yet. +APP_STL := gnustl_static + +# Make sure every shared lib includes a .note.gnu.build-id header, for crash reporting +APP_LDFLAGS := -Wl,--build-id + +# Explicitly use GCC 4.8 as our toolchain. This is the 32-bit default as of +# r10d but versions as far back as r9d have 4.8. The previous default, 4.6, is +# deprecated as of r10c. +NDK_TOOLCHAIN_VERSION := 4.8 + +# Define the directories for $(import-module, ...) to look in +ROOT_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +NDK_MODULE_PATH := diff --git a/app/jni/COPYING b/app/jni/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/app/jni/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/app/jni/QVR.c b/app/jni/QVR.c new file mode 100644 index 0000000..29557d0 --- /dev/null +++ b/app/jni/QVR.c @@ -0,0 +1,449 @@ +#include +#include +#include +#include +#include +#include +#include // for native window JNI +#include + +#include +#include +#include +#include + +//All the functionality we link to in the DarkPlaces Engine implementation +extern void QC_BeginFrame(); +extern void QC_DrawFrame(int eye, int x, int y); +extern void QC_EndFrame(); +extern void QC_GetAudio(); +extern void QC_KeyEvent(int state,int key,int character); +extern void QC_MoveEvent(float yaw, float pitch, float roll); +extern void QC_SetCallbacks(void *init_audio, void *write_audio); +extern void QC_SetResolution(int width, int height); +extern void QC_Analog(int enable,float x,float y); +extern void QC_MotionEvent(float delta, float dx, float dy); +extern int main (int argc, char **argv); + +extern qboolean vrMode; +extern int bigScreen; +extern int gameAssetsDownloadStatus; + +extern cvar_t cl_autocentreoffset; +extern cvar_t v_eyebufferresolution; + +static JavaVM *jVM; +static jobject audioBuffer=0; +static jobject audioCallbackObj=0; + +jmethodID android_initAudio; +jmethodID android_writeAudio; +jmethodID android_pauseAudio; +jmethodID android_resumeAudio; +jmethodID android_terminateAudio; + +static jobject quakeCallbackObj=0; +jmethodID android_BigScreenMode; +jmethodID android_SwitchVRMode; +jmethodID android_SwitchStereoMode; +jmethodID android_Exit; + +void jni_initAudio(void *buffer, int size) +{ + JNIEnv *env; + jobject tmp; + (*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4); + tmp = (*env)->NewDirectByteBuffer(env, buffer, size); + audioBuffer = (jobject)(*env)->NewGlobalRef(env, tmp); + return (*env)->CallVoidMethod(env, audioCallbackObj, android_initAudio, size); +} + +void jni_writeAudio(int offset, int length) +{ + if (audioBuffer==0) return; + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, audioCallbackObj, android_writeAudio, audioBuffer, offset, length); +} + +void jni_pauseAudio() +{ + if (audioBuffer==0) return; + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, audioCallbackObj, android_pauseAudio); +} + +void jni_resumeAudio() +{ + if (audioBuffer==0) return; + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, audioCallbackObj, android_resumeAudio); +} + +void jni_terminateAudio() +{ + if (audioBuffer==0) return; + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, audioCallbackObj, android_terminateAudio); +} + + +void jni_BigScreenMode(int mode) +{ + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, quakeCallbackObj, android_BigScreenMode, mode); +} + + +void jni_SwitchStereoMode(int mode) +{ + JNIEnv *env; + if (((*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4))<0) + { + (*jVM)->AttachCurrentThread(jVM,&env, NULL); + } + (*env)->CallVoidMethod(env, quakeCallbackObj, android_SwitchStereoMode, mode); +} + +void jni_SwitchVRMode(int mode) +{ + //Force headtracking on / off depending on whether we are using VR mode + //user must then change to their preference + headtracking = vrMode > 0; + + JNIEnv *env; + jobject tmp; + (*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4); + (*env)->CallVoidMethod(env, quakeCallbackObj, android_SwitchVRMode, mode); +} + +void jni_Exit() +{ + JNIEnv *env; + jobject tmp; + (*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4); + (*env)->CallVoidMethod(env, quakeCallbackObj, android_Exit); +} + +//Retain the folder we are using +char *strGameFolder = NULL; + +//Timing stuff for joypad control +static long oldtime=0; +long delta=0; +float last_joystick_x=0; +float last_joystick_y=0; + +int curtime; +int Sys_Milliseconds (void) +{ + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000; + } + + curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; + + return curtime; +} + +int returnvalue = -1; +void QC_exit(int exitCode) +{ + returnvalue = exitCode; + Host_Shutdown(); + jni_Exit(); +} + +vec3_t hmdorientation; + +int JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv *env; + jVM = vm; + if((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) + { + return -1; + } + + return JNI_VERSION_1_4; +} + +static void UnEscapeQuotes( char *arg ) +{ + char *last = NULL; + while( *arg ) { + if( *arg == '"' && *last == '\\' ) { + char *c_curr = arg; + char *c_last = last; + while( *c_curr ) { + *c_last = *c_curr; + c_last = c_curr; + c_curr++; + } + *c_last = '\0'; + } + last = arg; + arg++; + } +} + +static int ParseCommandLine(char *cmdline, char **argv) +{ + char *bufp; + char *lastp = NULL; + int argc, last_argc; + argc = last_argc = 0; + for ( bufp = cmdline; *bufp; ) { + while ( isspace(*bufp) ) { + ++bufp; + } + if ( *bufp == '"' ) { + ++bufp; + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) { + lastp = bufp; + ++bufp; + } + } else { + if ( *bufp ) { + if ( argv ) { + argv[argc] = bufp; + } + ++argc; + } + while ( *bufp && ! isspace(*bufp) ) { + ++bufp; + } + } + if ( *bufp ) { + if ( argv ) { + *bufp = '\0'; + } + ++bufp; + } + if( argv && last_argc != argc ) { + UnEscapeQuotes( argv[last_argc] ); + } + last_argc = argc; + } + if ( argv ) { + argv[argc] = NULL; + } + return(argc); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_setResolution( JNIEnv * env, jobject obj, int width, int height ) +{ + QC_SetResolution(width, height); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_initialise( JNIEnv * env, jobject obj, jstring gameFolder, jstring commandLineParams ) +{ + static qboolean quake_initialised = false; + if (!quake_initialised) + { + jboolean iscopy; + const char * folder = (*env)->GetStringUTFChars(env, gameFolder, &iscopy); + chdir(folder); + strGameFolder = strdup(folder); + (*env)->ReleaseStringUTFChars(env, gameFolder, folder); + + const char *arg = (*env)->GetStringUTFChars(env, commandLineParams, &iscopy); + + char *cmdLine = NULL; + if (arg && strlen(arg)) + { + cmdLine = strdup(arg); + } + + (*env)->ReleaseStringUTFChars(env, commandLineParams, arg); + + if (cmdLine) + { + char **argv; + int argc=0; + argv = malloc(sizeof(char*) * 255); + argc = ParseCommandLine(strdup(cmdLine), argv); + main(argc, argv); + } + else + { + int argc =1; char *argv[] = { "quake" }; + main(argc, argv); + } + + //Start game with credits active + MR_ToggleMenu(1); + quake_initialised = true; + } +} + +#define YAW 1 +#define PITCH 0 +#define ROLL 2 + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onNewFrame( JNIEnv * env, jobject obj, float pitch, float yaw, float roll ) +{ + long t=Sys_Milliseconds(); + delta=t-oldtime; + oldtime=t; + if (delta>1000) + delta=1000; + + QC_MotionEvent(delta, last_joystick_x, last_joystick_y); + + //Save orientation + if (headtracking) + { + hmdorientation[YAW] = yaw; + hmdorientation[PITCH] = pitch; + hmdorientation[ROLL] = roll; + } + else + { + hmdorientation[YAW] = 0; + hmdorientation[PITCH] = 0; + hmdorientation[ROLL] = 0; + + } + + //Set move information + QC_MoveEvent(hmdorientation[YAW], hmdorientation[PITCH], hmdorientation[ROLL]); + + //Set everything up + QC_BeginFrame(); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onDrawEye( JNIEnv * env, jobject obj, int eye, int x, int y ) +{ + QC_DrawFrame(eye, x, y); + + //const GLenum depthAttachment[1] = { GL_DEPTH_ATTACHMENT }; + //glInvalidateFramebuffer( GL_FRAMEBUFFER, 1, depthAttachment ); + //glFlush(); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onFinishFrame( JNIEnv * env, jobject obj ) +{ + QC_EndFrame(); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onSwitchVRMode( JNIEnv * env, jobject obj, int mode ) +{ + vrMode = mode; +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onBigScreenMode( JNIEnv * env, jobject obj, int mode ) +{ + bigScreen = mode; +} + +JNIEXPORT int JNICALL Java_com_drbeef_qvr_QVRJNILib_getCentreOffset( JNIEnv * env, jobject obj ) +{ + return cl_autocentreoffset.integer; +} + +JNIEXPORT int JNICALL Java_com_drbeef_qvr_QVRJNILib_getEyeBufferResolution( JNIEnv * env, jobject obj ) +{ + return v_eyebufferresolution.integer; +} + + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_setCentreOffset( JNIEnv * env, jobject obj, int offset ) +{ + //This is called only by the calculator, so only set it if it is not already set (i.e. by user or a previous run) + if (cl_autocentreoffset.integer == 0) + Cvar_SetValueQuick (&cl_autocentreoffset, offset); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onKeyEvent( JNIEnv * env, jobject obj, int keyCode, int action, int character ) +{ + //Dispatch to quake + QC_KeyEvent(action == AKEY_EVENT_ACTION_DOWN ? 1 : 0, keyCode, character); +} + +#define SOURCE_GAMEPAD 0x00000401 +#define SOURCE_JOYSTICK 0x01000010 +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onTouchEvent( JNIEnv * env, jobject obj, int source, int action, float x, float y ) +{ + if (source == SOURCE_JOYSTICK || source == SOURCE_GAMEPAD) + QC_Analog(true, x, y); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_onMotionEvent( JNIEnv * env, jobject obj, int source, int action, float x, float y ) +{ + if (source == SOURCE_JOYSTICK || source == SOURCE_GAMEPAD) + { + last_joystick_x=x; + last_joystick_y=y; + } +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_setCallbackObjects(JNIEnv *env, jclass c, jobject obj1, jobject obj2) +{ + jclass audioCallbackClass; + + (*jVM)->GetEnv(jVM, (void**) &env, JNI_VERSION_1_4); + + audioCallbackObj = (jobject)(*env)->NewGlobalRef(env, obj1); + audioCallbackClass = (*env)->GetObjectClass(env, audioCallbackObj); + + android_initAudio = (*env)->GetMethodID(env,audioCallbackClass,"initAudio","(I)V"); + android_writeAudio = (*env)->GetMethodID(env,audioCallbackClass,"writeAudio","(Ljava/nio/ByteBuffer;II)V"); + android_pauseAudio = (*env)->GetMethodID(env,audioCallbackClass,"pauseAudio","()V"); + android_resumeAudio = (*env)->GetMethodID(env,audioCallbackClass,"resumeAudio","()V"); + android_terminateAudio = (*env)->GetMethodID(env,audioCallbackClass,"terminateAudio","()V"); + + + jclass quakeCallbackClass; + + quakeCallbackObj = (jobject)(*env)->NewGlobalRef(env, obj2); + quakeCallbackClass = (*env)->GetObjectClass(env, quakeCallbackObj); + + android_BigScreenMode = (*env)->GetMethodID(env,quakeCallbackClass,"BigScreenMode","(I)V"); + android_SwitchVRMode = (*env)->GetMethodID(env,quakeCallbackClass,"SwitchVRMode","(I)V"); + android_SwitchStereoMode = (*env)->GetMethodID(env,quakeCallbackClass,"SwitchStereoMode","(I)V"); + android_Exit = (*env)->GetMethodID(env,quakeCallbackClass,"Exit","()V"); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_requestAudioData(JNIEnv *env, jclass c, jlong handle) +{ + QC_GetAudio(); +} + +JNIEXPORT void JNICALL Java_com_drbeef_qvr_QVRJNILib_setDownloadStatus( JNIEnv * env, jobject obj, int status ) +{ + gameAssetsDownloadStatus = status; +} \ No newline at end of file diff --git a/app/jni/SDLMain.h b/app/jni/SDLMain.h new file mode 100644 index 0000000..4683df5 --- /dev/null +++ b/app/jni/SDLMain.h @@ -0,0 +1,11 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import + +@interface SDLMain : NSObject +@end diff --git a/app/jni/bih.c b/app/jni/bih.c new file mode 100644 index 0000000..7a25c66 --- /dev/null +++ b/app/jni/bih.c @@ -0,0 +1,216 @@ + +// This code written in 2010 by Forest Hale (lordhavoc ghdigital com), and placed into public domain. + +#include +#include +#include "bih.h" + +static int BIH_BuildNode(bih_t *bih, int numchildren, int *leaflist, float *totalmins, float *totalmaxs) +{ + int i; + int j; + int longestaxis; + int axis = 0; + int nodenum; + int front = 0; + int back = 0; + bih_node_t *node; + bih_leaf_t *child; + float splitdist; + float d; + float mins[3]; + float maxs[3]; + float size[3]; + float frontmins[3]; + float frontmaxs[3]; + float backmins[3]; + float backmaxs[3]; + // calculate bounds of children + child = bih->leafs + leaflist[0]; + mins[0] = child->mins[0]; + mins[1] = child->mins[1]; + mins[2] = child->mins[2]; + maxs[0] = child->maxs[0]; + maxs[1] = child->maxs[1]; + maxs[2] = child->maxs[2]; + for (i = 1;i < numchildren;i++) + { + child = bih->leafs + leaflist[i]; + if (mins[0] > child->mins[0]) mins[0] = child->mins[0]; + if (mins[1] > child->mins[1]) mins[1] = child->mins[1]; + if (mins[2] > child->mins[2]) mins[2] = child->mins[2]; + if (maxs[0] < child->maxs[0]) maxs[0] = child->maxs[0]; + if (maxs[1] < child->maxs[1]) maxs[1] = child->maxs[1]; + if (maxs[2] < child->maxs[2]) maxs[2] = child->maxs[2]; + } + size[0] = maxs[0] - mins[0]; + size[1] = maxs[1] - mins[1]; + size[2] = maxs[2] - mins[2]; + // provide bounds to caller + totalmins[0] = mins[0]; + totalmins[1] = mins[1]; + totalmins[2] = mins[2]; + totalmaxs[0] = maxs[0]; + totalmaxs[1] = maxs[1]; + totalmaxs[2] = maxs[2]; + // if we run out of nodes it's the caller's fault, but don't crash + if (bih->numnodes == bih->maxnodes) + { + if (!bih->error) + bih->error = BIHERROR_OUT_OF_NODES; + return 0; + } + nodenum = bih->numnodes++; + node = bih->nodes + nodenum; + // store bounds for node + node->mins[0] = mins[0]; + node->mins[1] = mins[1]; + node->mins[2] = mins[2]; + node->maxs[0] = maxs[0]; + node->maxs[1] = maxs[1]; + node->maxs[2] = maxs[2]; + node->front = 0; + node->back = 0; + node->frontmin = 0; + node->backmax = 0; + memset(node->children, -1, sizeof(node->children)); + // check if there are few enough children to store an unordered node + if (numchildren <= BIH_MAXUNORDEREDCHILDREN) + { + node->type = BIH_UNORDERED; + for (j = 0;j < numchildren;j++) + node->children[j] = leaflist[j]; + return nodenum; + } + // pick longest axis + longestaxis = 0; + if (size[0] < size[1]) longestaxis = 1; + if (size[longestaxis] < size[2]) longestaxis = 2; + // iterate possible split axis choices, starting with the longest axis, if + // all fail it means all children have the same bounds and we simply split + // the list in half because each node can only have two children. + for (j = 0;j < 3;j++) + { + // pick an axis + axis = (longestaxis + j) % 3; + // sort children into front and back lists + splitdist = (node->mins[axis] + node->maxs[axis]) * 0.5f; + front = 0; + back = 0; + for (i = 0;i < numchildren;i++) + { + child = bih->leafs + leaflist[i]; + d = (child->mins[axis] + child->maxs[axis]) * 0.5f; + if (d < splitdist) + bih->leafsortscratch[back++] = leaflist[i]; + else + leaflist[front++] = leaflist[i]; + } + // now copy the back ones into the space made in the leaflist for them + if (back) + memcpy(leaflist + front, bih->leafsortscratch, back*sizeof(leaflist[0])); + // if both sides have some children, it's good enough for us. + if (front && back) + break; + } + if (j == 3) + { + // somewhat common case: no good choice, divide children arbitrarily + axis = 0; + back = numchildren >> 1; + front = numchildren - back; + } + + // we now have front and back children divided in leaflist... + node->type = (bih_nodetype_t)((int)BIH_SPLITX + axis); + node->front = BIH_BuildNode(bih, front, leaflist, frontmins, frontmaxs); + node->frontmin = frontmins[axis]; + node->back = BIH_BuildNode(bih, back, leaflist + front, backmins, backmaxs); + node->backmax = backmaxs[axis]; + return nodenum; +} + +int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_node_t *nodes, int *temp_leafsort, int *temp_leafsortscratch) +{ + int i; + + memset(bih, 0, sizeof(*bih)); + bih->numleafs = numleafs; + bih->leafs = leafs; + bih->leafsort = temp_leafsort; + bih->leafsortscratch = temp_leafsortscratch; + bih->numnodes = 0; + bih->maxnodes = maxnodes; + bih->nodes = nodes; + + // clear things we intend to rebuild + memset(bih->nodes, 0, sizeof(bih->nodes[0]) * bih->maxnodes); + for (i = 0;i < bih->numleafs;i++) + bih->leafsort[i] = i; + + bih->rootnode = BIH_BuildNode(bih, bih->numleafs, bih->leafsort, bih->mins, bih->maxs); + return bih->error; +} + +static void BIH_GetTriangleListForBox_Node(const bih_t *bih, int nodenum, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, int *numtrianglespointer, const float *mins, const float *maxs) +{ + int axis; + bih_node_t *node; + bih_leaf_t *leaf; + for(;;) + { + node = bih->nodes + nodenum; + // check if this is an unordered node (which holds an array of leaf numbers) + if (node->type == BIH_UNORDERED) + { + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = bih->leafs + node->children[axis]; + if (mins[0] > leaf->maxs[0] || maxs[0] < leaf->mins[0] + || mins[1] > leaf->maxs[1] || maxs[1] < leaf->mins[1] + || mins[2] > leaf->maxs[2] || maxs[2] < leaf->mins[2]) + continue; + switch(leaf->type) + { + case BIH_RENDERTRIANGLE: + if (*numtrianglespointer >= maxtriangles) + { + ++*numtrianglespointer; // so the caller can detect overflow + break; + } + if(trianglelist_surf) + trianglelist_surf[*numtrianglespointer] = leaf->surfaceindex; + trianglelist_idx[*numtrianglespointer] = leaf->itemindex; + ++*numtrianglespointer; + break; + default: + break; + } + } + return; + } + // splitting node + axis = node->type - BIH_SPLITX; + if (mins[axis] < node->backmax) + { + if (maxs[axis] > node->frontmin) + BIH_GetTriangleListForBox_Node(bih, node->front, maxtriangles, trianglelist_idx, trianglelist_surf, numtrianglespointer, mins, maxs); + nodenum = node->back; + continue; + } + if (maxs[axis] > node->frontmin) + { + nodenum = node->front; + continue; + } + // fell between the child groups, nothing here + return; + } +} + +int BIH_GetTriangleListForBox(const bih_t *bih, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, const float *mins, const float *maxs) +{ + int numtriangles = 0; + BIH_GetTriangleListForBox_Node(bih, bih->rootnode, maxtriangles, trianglelist_idx, trianglelist_surf, &numtriangles, mins, maxs); + return numtriangles; +} diff --git a/app/jni/bih.h b/app/jni/bih.h new file mode 100644 index 0000000..43b659e --- /dev/null +++ b/app/jni/bih.h @@ -0,0 +1,91 @@ + +// This code written in 2010 by Forest Hale (lordhavoc ghdigital com), and placed into public domain. + +// Based on information in http://zach.in.tu-clausthal.de/papers/vrst02.html (in particular vrst02_boxtree.pdf) + +#ifndef BIH_H +#define BIH_H + +#define BIH_MAXUNORDEREDCHILDREN 8 + +typedef enum biherror_e +{ + BIHERROR_OK, // no error, be happy + BIHERROR_OUT_OF_NODES // could not produce complete hierarchy, maxnodes too low (should be roughly half of numleafs) +} +biherror_t; + +typedef enum bih_nodetype_e +{ + BIH_SPLITX = 0, + BIH_SPLITY = 1, + BIH_SPLITZ = 2, + BIH_UNORDERED = 3, +} +bih_nodetype_t; + +typedef enum bih_leaftype_e +{ + BIH_BRUSH = 4, + BIH_COLLISIONTRIANGLE = 5, + BIH_RENDERTRIANGLE = 6 +} +bih_leaftype_t; + +typedef struct bih_node_s +{ + bih_nodetype_t type; // = BIH_SPLITX and similar values + // TODO: store just one float for distance, and have BIH_SPLITMINX and BIH_SPLITMAXX distinctions, to reduce memory footprint and traversal time, as described in the paper (vrst02_boxtree.pdf) + // TODO: move bounds data to parent node and remove it from leafs? + float mins[3]; + float maxs[3]; + // node indexes of children (always > this node's index) + int front; + int back; + // interval of children + float frontmin; // children[0] + float backmax; // children[1] + // BIH_UNORDERED uses this for a list of leafindex (all >= 0), -1 = end of list + int children[BIH_MAXUNORDEREDCHILDREN]; +} +bih_node_t; + +typedef struct bih_leaf_s +{ + bih_leaftype_t type; // = BIH_BRUSH And similar values + float mins[3]; + float maxs[3]; + // data past this point is generic and entirely up to the caller... + int textureindex; + int surfaceindex; + int itemindex; // triangle or brush index +} +bih_leaf_t; + +typedef struct bih_s +{ + // permanent fields + // leafs are constructed by caller before calling BIH_Build + int numleafs; + bih_leaf_t *leafs; + // nodes are constructed by BIH_Build + int numnodes; + bih_node_t *nodes; + int rootnode; // 0 if numnodes > 0, -1 otherwise + // bounds calculated by BIH_Build + float mins[3]; + float maxs[3]; + + // fields used only during BIH_Build: + int maxnodes; + int error; // set to a value if an error occurs in building (such as numnodes == maxnodes) + int *leafsort; + int *leafsortscratch; +} +bih_t; + +int BIH_Build(bih_t *bih, int numleafs, bih_leaf_t *leafs, int maxnodes, bih_node_t *nodes, int *temp_leafsort, int *temp_leafsortscratch); + +int BIH_GetTriangleListForBox(const bih_t *bih, int maxtriangles, int *trianglelist_idx, int *trianglelist_surf, const float *mins, const float *maxs); + +#endif diff --git a/app/jni/bspfile.h b/app/jni/bspfile.h new file mode 100644 index 0000000..e29a9f3 --- /dev/null +++ b/app/jni/bspfile.h @@ -0,0 +1,321 @@ +/* +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. + +*/ + + +#define MAX_MAP_HULLS 16 // Q1BSP has 4, Hexen2 Q1BSP has 8, MCBSP has 16 + +//============================================================================= + + +#define BSPVERSION 29 + +typedef struct lump_s +{ + 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 hullinfo_s +{ + int filehulls; + float hullsizes[MAX_MAP_HULLS][2][3]; +} hullinfo_t; + +typedef struct mmodel_s +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} mmodel_t; + +/* +// WARNING: this struct does NOT match q1bsp's disk format because MAX_MAP_HULLS has been changed by Sajt's MCBSP code, this struct is only being used in memory as a result +typedef struct dmodel_s +{ + 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 dheader_s +{ + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct dmiptexlump_s +{ + 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 dvertex_s +{ + 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 dplane_s +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; +*/ + + +// contents values in Q1 maps +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +// these were #ifdef QUAKE2 in the quake source +#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 + +//contents flags in Q2 maps +#define CONTENTSQ2_SOLID 0x00000001 // an eye is never valid in a solid +#define CONTENTSQ2_WINDOW 0x00000002 // translucent, but not watery +#define CONTENTSQ2_AUX 0x00000004 +#define CONTENTSQ2_LAVA 0x00000008 +#define CONTENTSQ2_SLIME 0x00000010 +#define CONTENTSQ2_WATER 0x00000020 +#define CONTENTSQ2_MIST 0x00000040 +#define CONTENTSQ2_AREAPORTAL 0x00008000 +#define CONTENTSQ2_PLAYERCLIP 0x00010000 +#define CONTENTSQ2_MONSTERCLIP 0x00020000 +#define CONTENTSQ2_CURRENT_0 0x00040000 +#define CONTENTSQ2_CURRENT_90 0x00080000 +#define CONTENTSQ2_CURRENT_180 0x00100000 +#define CONTENTSQ2_CURRENT_270 0x00200000 +#define CONTENTSQ2_CURRENT_UP 0x00400000 +#define CONTENTSQ2_CURRENT_DOWN 0x00800000 +#define CONTENTSQ2_ORIGIN 0x01000000 // removed before bsping an entity +#define CONTENTSQ2_MONSTER 0x02000000 // should never be on a brush, only in game +#define CONTENTSQ2_DEADMONSTER 0x04000000 +#define CONTENTSQ2_DETAIL 0x08000000 // brushes to be added after vis leafs +#define CONTENTSQ2_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTSQ2_LADDER 0x20000000 + +//contents flags in Q3 maps +#define CONTENTSQ3_SOLID 0x00000001 // solid (opaque and transparent) +#define CONTENTSQ3_LAVA 0x00000008 // lava +#define CONTENTSQ3_SLIME 0x00000010 // slime +#define CONTENTSQ3_WATER 0x00000020 // water +#define CONTENTSQ3_FOG 0x00000040 // unused? +#define CONTENTSQ3_AREAPORTAL 0x00008000 // areaportal (separates areas) +#define CONTENTSQ3_PLAYERCLIP 0x00010000 // block players +#define CONTENTSQ3_MONSTERCLIP 0x00020000 // block monsters +#define CONTENTSQ3_TELEPORTER 0x00040000 // hint for Q3's bots +#define CONTENTSQ3_JUMPPAD 0x00080000 // hint for Q3's bots +#define CONTENTSQ3_CLUSTERPORTAL 0x00100000 // hint for Q3's bots +#define CONTENTSQ3_DONOTENTER 0x00200000 // hint for Q3's bots +#define CONTENTSQ3_BOTCLIP 0x00400000 // hint for Q3's bots +#define CONTENTSQ3_ORIGIN 0x01000000 // used by origin brushes to indicate origin of bmodel (removed by map compiler) +#define CONTENTSQ3_BODY 0x02000000 // used by bbox entities (should never be on a brush) +#define CONTENTSQ3_CORPSE 0x04000000 // used by dead bodies (SOLID_CORPSE in darkplaces) +#define CONTENTSQ3_DETAIL 0x08000000 // brushes that do not split the bsp tree (decorations) +#define CONTENTSQ3_STRUCTURAL 0x10000000 // brushes that split the bsp tree +#define CONTENTSQ3_TRANSLUCENT 0x20000000 // leaves surfaces that are inside for rendering +#define CONTENTSQ3_TRIGGER 0x40000000 // used by trigger entities +#define CONTENTSQ3_NODROP 0x80000000 // remove items that fall into this brush + +#define SUPERCONTENTS_SOLID 0x00000001 +#define SUPERCONTENTS_WATER 0x00000002 +#define SUPERCONTENTS_SLIME 0x00000004 +#define SUPERCONTENTS_LAVA 0x00000008 +#define SUPERCONTENTS_SKY 0x00000010 +#define SUPERCONTENTS_BODY 0x00000020 +#define SUPERCONTENTS_CORPSE 0x00000040 +#define SUPERCONTENTS_NODROP 0x00000080 +#define SUPERCONTENTS_PLAYERCLIP 0x00000100 +#define SUPERCONTENTS_MONSTERCLIP 0x00000200 +#define SUPERCONTENTS_DONOTENTER 0x00000400 +#define SUPERCONTENTS_BOTCLIP 0x00000800 +#define SUPERCONTENTS_OPAQUE 0x00001000 +// TODO: is there any reason to define: +// fog? +// areaportal? +// teleporter? +// jumppad? +// clusterportal? +// detail? (div0) no, game code should not be allowed to differentiate between structural and detail +// structural? (div0) no, game code should not be allowed to differentiate between structural and detail +// trigger? (div0) no, as these are always solid anyway, and that's all that matters for trigger brushes +#define SUPERCONTENTS_LIQUIDSMASK (SUPERCONTENTS_LAVA | SUPERCONTENTS_SLIME | SUPERCONTENTS_WATER) +#define SUPERCONTENTS_VISBLOCKERMASK SUPERCONTENTS_OPAQUE + +/* +#define SUPERCONTENTS_DEADMONSTER 0x00000000 +#define SUPERCONTENTS_CURRENT_0 0x00000000 +#define SUPERCONTENTS_CURRENT_90 0x00000000 +#define SUPERCONTENTS_CURRENT_180 0x00000000 +#define SUPERCONTENTS_CURRENT_270 0x00000000 +#define SUPERCONTENTS_CURRENT_DOWN 0x00000000 +#define SUPERCONTENTS_CURRENT_UP 0x00000000 +#define SUPERCONTENTS_AREAPORTAL 0x00000000 +#define SUPERCONTENTS_AUX 0x00000000 +#define SUPERCONTENTS_CLUSTERPORTAL 0x00000000 +#define SUPERCONTENTS_DETAIL 0x00000000 +#define SUPERCONTENTS_STRUCTURAL 0x00000000 +#define SUPERCONTENTS_DONOTENTER 0x00000000 +#define SUPERCONTENTS_JUMPPAD 0x00000000 +#define SUPERCONTENTS_LADDER 0x00000000 +#define SUPERCONTENTS_MONSTER 0x00000000 +#define SUPERCONTENTS_MONSTERCLIP 0x00000000 +#define SUPERCONTENTS_PLAYERCLIP 0x00000000 +#define SUPERCONTENTS_TELEPORTER 0x00000000 +#define SUPERCONTENTS_TRANSLUCENT 0x00000000 +#define SUPERCONTENTS_TRIGGER 0x00000000 +#define SUPERCONTENTS_WINDOW 0x00000000 +*/ + +/* +typedef struct dnode_s +{ + 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 dclipnode_s +{ + 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 dedge_s +{ + unsigned short v[2]; // vertex numbers +} dedge_t; +*/ + +#define MAXLIGHTMAPS 4 +/* +typedef struct dface_s +{ + // LordHavoc: changed from short to unsigned short for q2 support + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + unsigned char 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 dleaf_s +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + + unsigned char ambient_level[NUM_AMBIENTS]; +} dleaf_t; +*/ + diff --git a/app/jni/build.bat b/app/jni/build.bat new file mode 100644 index 0000000..51a72b8 --- /dev/null +++ b/app/jni/build.bat @@ -0,0 +1,19 @@ +call ndk-build V=0 -j10 NDK_DEBUG=0 %1 + +cd ..\libs + +del libs.jar +mkdir lib +mkdir lib\armeabi-v7a +copy .\armeabi-v7a\ lib\armeabi-v7a\* +7z a -x!*.jar libs.zip .\lib* +rename libs.zip libs.jar + +REM Create an archive of the source +cd ..\src\main\assets\source +del QVRSource.zip +REM exclude unnecessary files from build +7z a -r -x!.git* -x!*.o -x!*.d -x!obj -x!*.bin -x!app\build -x!app\libs -x!*.jar -x!*.so -x!*.log -x!*.jks -x!*.apk QVRSource.zip ..\..\..\..\..\* + + +cd ..\..\..\..\jni diff --git a/app/jni/builddate.c b/app/jni/builddate.c new file mode 100644 index 0000000..061173e --- /dev/null +++ b/app/jni/builddate.c @@ -0,0 +1,12 @@ +#define STRINGIFY2(arg) #arg +#define STRINGIFY(arg) STRINGIFY2(arg) + +extern const char *buildstring; +const char *buildstring = __TIME__ " " __DATE__ +#ifdef SVNREVISION +" " STRINGIFY(SVNREVISION) +#endif +#ifdef BUILDTYPE +" " STRINGIFY(BUILDTYPE) +#endif +; diff --git a/app/jni/cap_avi.c b/app/jni/cap_avi.c new file mode 100644 index 0000000..9a238e8 --- /dev/null +++ b/app/jni/cap_avi.c @@ -0,0 +1,720 @@ +#include "quakedef.h" +#include "cap_avi.h" + +#define AVI_MASTER_INDEX_SIZE 640 // GB ought to be enough for anyone + +typedef struct capturevideostate_avi_formatspecific_s +{ + // AVI stuff + fs_offset_t videofile_firstchunkframes_offset; + fs_offset_t videofile_totalframes_offset1; + fs_offset_t videofile_totalframes_offset2; + fs_offset_t videofile_totalsampleframes_offset; + int videofile_ix_master_audio_inuse; + fs_offset_t videofile_ix_master_audio_inuse_offset; + fs_offset_t videofile_ix_master_audio_start_offset; + int videofile_ix_master_video_inuse; + fs_offset_t videofile_ix_master_video_inuse_offset; + fs_offset_t videofile_ix_master_video_start_offset; + fs_offset_t videofile_ix_movistart; + fs_offset_t position; + qboolean canseek; + sizebuf_t riffbuffer; + unsigned char riffbufferdata[128]; + sizebuf_t riffindexbuffer; + int riffstacklevel; + fs_offset_t riffstackstartoffset[4]; + fs_offset_t riffstacksizehint[4]; + const char *riffstackfourcc[4]; +} +capturevideostate_avi_formatspecific_t; +#define LOAD_FORMATSPECIFIC_AVI() capturevideostate_avi_formatspecific_t *format = (capturevideostate_avi_formatspecific_t *) cls.capturevideo.formatspecific + +static void SCR_CaptureVideo_RIFF_Start(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + memset(&format->riffbuffer, 0, sizeof(sizebuf_t)); + format->riffbuffer.maxsize = sizeof(format->riffbufferdata); + format->riffbuffer.data = format->riffbufferdata; + format->position = 0; +} + +static void SCR_CaptureVideo_RIFF_Flush(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize > 0) + { + if (!FS_Write(cls.capturevideo.videofile, format->riffbuffer.data, format->riffbuffer.cursize)) + cls.capturevideo.error = true; + format->position += format->riffbuffer.cursize; + format->riffbuffer.cursize = 0; + format->riffbuffer.overflowed = false; + } +} + +static void SCR_CaptureVideo_RIFF_FlushNoIncrease(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize > 0) + { + if (!FS_Write(cls.capturevideo.videofile, format->riffbuffer.data, format->riffbuffer.cursize)) + cls.capturevideo.error = true; + format->riffbuffer.cursize = 0; + format->riffbuffer.overflowed = false; + } +} + +static void SCR_CaptureVideo_RIFF_WriteBytes(const unsigned char *data, size_t size) +{ + LOAD_FORMATSPECIFIC_AVI(); + SCR_CaptureVideo_RIFF_Flush(); + if (!FS_Write(cls.capturevideo.videofile, data, size)) + cls.capturevideo.error = true; + format->position += size; +} + +static void SCR_CaptureVideo_RIFF_Write32(int n) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize + 4 > format->riffbuffer.maxsize) + SCR_CaptureVideo_RIFF_Flush(); + MSG_WriteLong(&format->riffbuffer, n); +} + +static void SCR_CaptureVideo_RIFF_Write16(int n) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize + 2 > format->riffbuffer.maxsize) + SCR_CaptureVideo_RIFF_Flush(); + MSG_WriteShort(&format->riffbuffer, n); +} + +static void SCR_CaptureVideo_RIFF_WriteFourCC(const char *chunkfourcc) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize + (int)strlen(chunkfourcc) > format->riffbuffer.maxsize) + SCR_CaptureVideo_RIFF_Flush(); + MSG_WriteUnterminatedString(&format->riffbuffer, chunkfourcc); +} + +static void SCR_CaptureVideo_RIFF_WriteTerminatedString(const char *string) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize + (int)strlen(string) > format->riffbuffer.maxsize) + SCR_CaptureVideo_RIFF_Flush(); + MSG_WriteString(&format->riffbuffer, string); +} + +static fs_offset_t SCR_CaptureVideo_RIFF_GetPosition(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + SCR_CaptureVideo_RIFF_Flush(); + //return FS_Tell(cls.capturevideo.videofile); + return format->position; +} + +static void SCR_CaptureVideo_RIFF_Push(const char *chunkfourcc, const char *listtypefourcc, fs_offset_t sizeHint) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (listtypefourcc && sizeHint >= 0) + sizeHint += 4; // size hint is for INNER size + SCR_CaptureVideo_RIFF_WriteFourCC(chunkfourcc); + SCR_CaptureVideo_RIFF_Write32(sizeHint); + SCR_CaptureVideo_RIFF_Flush(); + format->riffstacksizehint[format->riffstacklevel] = sizeHint; + format->riffstackstartoffset[format->riffstacklevel] = SCR_CaptureVideo_RIFF_GetPosition(); + format->riffstackfourcc[format->riffstacklevel] = chunkfourcc; + ++format->riffstacklevel; + if (listtypefourcc) + SCR_CaptureVideo_RIFF_WriteFourCC(listtypefourcc); +} + +static void SCR_CaptureVideo_RIFF_Pop(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + fs_offset_t offset, sizehint; + int x; + unsigned char sizebytes[4]; + // write out the chunk size and then return to the current file position + format->riffstacklevel--; + offset = SCR_CaptureVideo_RIFF_GetPosition(); + + sizehint = format->riffstacksizehint[format->riffstacklevel]; + x = (int)(offset - (format->riffstackstartoffset[format->riffstacklevel])); + + if(x != sizehint) + { + if(sizehint != -1) + { + int i; + Con_Printf("WARNING: invalid size hint %d when writing video data (actual size: %d)\n", (int) sizehint, x); + for(i = 0; i <= format->riffstacklevel; ++i) + { + Con_Printf(" RIFF level %d = %s\n", i, format->riffstackfourcc[i]); + } + } + sizebytes[0] = (x) & 0xff;sizebytes[1] = (x >> 8) & 0xff;sizebytes[2] = (x >> 16) & 0xff;sizebytes[3] = (x >> 24) & 0xff; + if(FS_Seek(cls.capturevideo.videofile, -(x + 4), SEEK_END) >= 0) + { + FS_Write(cls.capturevideo.videofile, sizebytes, 4); + } + FS_Seek(cls.capturevideo.videofile, 0, SEEK_END); + } + + if (offset & 1) + { + SCR_CaptureVideo_RIFF_WriteBytes((unsigned char *) "\0", 1); + } +} + +static void GrowBuf(sizebuf_t *buf, int extralen) +{ + if(buf->cursize + extralen > buf->maxsize) + { + int oldsize = buf->maxsize; + unsigned char *olddata; + olddata = buf->data; + buf->maxsize = max(buf->maxsize * 2, 4096); + buf->data = (unsigned char *) Mem_Alloc(tempmempool, buf->maxsize); + if(olddata) + { + memcpy(buf->data, olddata, oldsize); + Mem_Free(olddata); + } + } +} + +static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunksize, int flags) +{ + LOAD_FORMATSPECIFIC_AVI(); + if(!format->canseek) + Sys_Error("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI"); + + if (format->riffstacklevel != 2) + Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", format->riffstacklevel); + GrowBuf(&format->riffindexbuffer, 16); + SCR_CaptureVideo_RIFF_Flush(); + MSG_WriteUnterminatedString(&format->riffindexbuffer, chunkfourcc); + MSG_WriteLong(&format->riffindexbuffer, flags); + MSG_WriteLong(&format->riffindexbuffer, (int)FS_Tell(cls.capturevideo.videofile) - format->riffstackstartoffset[1]); + MSG_WriteLong(&format->riffindexbuffer, chunksize); +} + +static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChunkId, fs_offset_t masteridx_counter, int *masteridx_count, fs_offset_t masteridx_start) +{ + LOAD_FORMATSPECIFIC_AVI(); + int nMatching; + int i; + fs_offset_t ix = SCR_CaptureVideo_RIFF_GetPosition(); + fs_offset_t pos, sz; + + if(!format->canseek) + Sys_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI"); + + if(*masteridx_count >= AVI_MASTER_INDEX_SIZE) + return; + + nMatching = 0; // go through index and enumerate them + for(i = 0; i < format->riffindexbuffer.cursize; i += 16) + if(!memcmp(format->riffindexbuffer.data + i, dwChunkId, 4)) + ++nMatching; + + sz = 2+2+4+4+4+4+4; + for(i = 0; i < format->riffindexbuffer.cursize; i += 16) + if(!memcmp(format->riffindexbuffer.data + i, dwChunkId, 4)) + sz += 8; + + SCR_CaptureVideo_RIFF_Push(fcc, NULL, sz); + SCR_CaptureVideo_RIFF_Write16(2); // wLongsPerEntry + SCR_CaptureVideo_RIFF_Write16(0x0100); // bIndexType=1, bIndexSubType=0 + SCR_CaptureVideo_RIFF_Write32(nMatching); // nEntriesInUse + SCR_CaptureVideo_RIFF_WriteFourCC(dwChunkId); // dwChunkId + SCR_CaptureVideo_RIFF_Write32(format->videofile_ix_movistart & (fs_offset_t) 0xFFFFFFFFu); + SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) format->videofile_ix_movistart) >> 32); + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved + + for(i = 0; i < format->riffindexbuffer.cursize; i += 16) + if(!memcmp(format->riffindexbuffer.data + i, dwChunkId, 4)) + { + unsigned int *p = (unsigned int *) (format->riffindexbuffer.data + i); + unsigned int flags = p[1]; + unsigned int rpos = p[2]; + unsigned int size = p[3]; + size &= ~0x80000000; + if(!(flags & 0x10)) // no keyframe? + size |= 0x80000000; + SCR_CaptureVideo_RIFF_Write32(rpos + 8); + SCR_CaptureVideo_RIFF_Write32(size); + } + + SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_Pop(); + pos = SCR_CaptureVideo_RIFF_GetPosition(); + + if(FS_Seek(cls.capturevideo.videofile, masteridx_start + 16 * *masteridx_count, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(ix & (fs_offset_t) 0xFFFFFFFFu); + SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) ix) >> 32); + SCR_CaptureVideo_RIFF_Write32(pos - ix); + SCR_CaptureVideo_RIFF_Write32(nMatching); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + + if(FS_Seek(cls.capturevideo.videofile, masteridx_counter, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(++*masteridx_count); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + + FS_Seek(cls.capturevideo.videofile, 0, SEEK_END); // return value doesn't matter here +} + +static void SCR_CaptureVideo_RIFF_Finish(qboolean final) +{ + LOAD_FORMATSPECIFIC_AVI(); + // close the "movi" list + SCR_CaptureVideo_RIFF_Pop(); + if(format->videofile_ix_master_video_inuse_offset) + SCR_CaptureVideo_RIFF_MakeIxChunk("ix00", "00dc", format->videofile_ix_master_video_inuse_offset, &format->videofile_ix_master_video_inuse, format->videofile_ix_master_video_start_offset); + if(format->videofile_ix_master_audio_inuse_offset) + SCR_CaptureVideo_RIFF_MakeIxChunk("ix01", "01wb", format->videofile_ix_master_audio_inuse_offset, &format->videofile_ix_master_audio_inuse, format->videofile_ix_master_audio_start_offset); + // write the idx1 chunk that we've been building while saving the frames (for old style players) + if(final && format->videofile_firstchunkframes_offset) + // TODO replace index creating by OpenDML ix##/##ix/indx chunk so it works for more than one AVI part too + { + SCR_CaptureVideo_RIFF_Push("idx1", NULL, format->riffindexbuffer.cursize); + SCR_CaptureVideo_RIFF_WriteBytes(format->riffindexbuffer.data, format->riffindexbuffer.cursize); + SCR_CaptureVideo_RIFF_Pop(); + } + format->riffindexbuffer.cursize = 0; + // pop the RIFF chunk itself + while (format->riffstacklevel > 0) + SCR_CaptureVideo_RIFF_Pop(); + SCR_CaptureVideo_RIFF_Flush(); + if(format->videofile_firstchunkframes_offset) + { + Con_DPrintf("Finishing first chunk (%d frames)\n", cls.capturevideo.frame); + if(FS_Seek(cls.capturevideo.videofile, format->videofile_firstchunkframes_offset, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + FS_Seek(cls.capturevideo.videofile, 0, SEEK_END); + format->videofile_firstchunkframes_offset = 0; + } + else + Con_DPrintf("Finishing another chunk (%d frames)\n", cls.capturevideo.frame); +} + +static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize) +{ + LOAD_FORMATSPECIFIC_AVI(); + fs_offset_t cursize; + //fs_offset_t curfilesize; + if (format->riffstacklevel != 2) + Sys_Error("SCR_CaptureVideo_RIFF_OverflowCheck: chunk stack leakage!\n"); + + if(!format->canseek) + return; + + // check where we are in the file + SCR_CaptureVideo_RIFF_Flush(); + cursize = SCR_CaptureVideo_RIFF_GetPosition() - format->riffstackstartoffset[0]; + //curfilesize = SCR_CaptureVideo_RIFF_GetPosition(); + + // if this would overflow the windows limit of 1GB per RIFF chunk, we need + // to close the current RIFF chunk and open another for future frames + if (8 + cursize + framesize + format->riffindexbuffer.cursize + 8 + format->riffindexbuffer.cursize + 64 > 1<<30) // note that the Ix buffer takes less space... I just don't dare to / 2 here now... sorry, maybe later + { + SCR_CaptureVideo_RIFF_Finish(false); + // begin a new 1GB extended section of the AVI + SCR_CaptureVideo_RIFF_Push("RIFF", "AVIX", -1); + SCR_CaptureVideo_RIFF_Push("LIST", "movi", -1); + format->videofile_ix_movistart = format->riffstackstartoffset[1]; + } +} + +// converts from BGRA32 to I420 colorspace (identical to YV12 except chroma plane order is reversed), this colorspace is handled by the Intel(r) 4:2:0 codec on Windows +static void SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(int width, int height, unsigned char *instart, unsigned char *outstart) +{ + int x, y; + int blockr, blockg, blockb; + int outoffset = (width/2)*(height/2); + unsigned char *b, *out; + // process one line at a time, and CbCr every other line at 2 pixel intervals + for (y = 0;y < height;y++) + { + // 1x1 Y + for (b = instart + (height-1-y)*width*4, out = outstart + y*width, x = 0;x < width;x++, b += 4, out++) + { + blockr = b[2]; + blockg = b[1]; + blockb = b[0]; + *out = cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]]; + } + if ((y & 1) == 0 && y/2 < height/2) // if h is odd, this skips the last row + { + // 2x2 Cr and Cb planes + int inpitch = width*4; + for (b = instart + (height-2-y)*width*4, out = outstart + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 8, out++) + { + blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2; + blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2; + blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2; + // Cr + out[0 ] = cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128]; + // Cb + out[outoffset] = cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128]; + } + } + } +} + +static void SCR_CaptureVideo_Avi_VideoFrames(int num) +{ + LOAD_FORMATSPECIFIC_AVI(); + int x = 0, width = cls.capturevideo.width, height = cls.capturevideo.height; + unsigned char *in, *out; + // FIXME: width/height must be multiple of 2, enforce this? + in = cls.capturevideo.outbuffer; + out = cls.capturevideo.outbuffer + width*height*4; + SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(width, height, in, out); + x = width*height+(width/2)*(height/2)*2; + while(num-- > 0) + { + if(format->canseek) + { + SCR_CaptureVideo_RIFF_OverflowCheck(8 + x); + SCR_CaptureVideo_RIFF_IndexEntry("00dc", x, 0x10); // AVIIF_KEYFRAME + } + + if(!format->canseek) + { + SCR_CaptureVideo_RIFF_Push("RIFF", "AVIX", 12+8+x); + SCR_CaptureVideo_RIFF_Push("LIST", "movi", 8+x); + } + SCR_CaptureVideo_RIFF_Push("00dc", NULL, x); + SCR_CaptureVideo_RIFF_WriteBytes(out, x); + SCR_CaptureVideo_RIFF_Pop(); + if(!format->canseek) + { + SCR_CaptureVideo_RIFF_Pop(); + SCR_CaptureVideo_RIFF_Pop(); + } + } +} + +static void SCR_CaptureVideo_Avi_EndVideo(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + + if(format->canseek) + { + // close any open chunks + SCR_CaptureVideo_RIFF_Finish(true); + + // go back and fix the video frames and audio samples fields + if(format->videofile_totalframes_offset1) + if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalframes_offset1, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + if(format->videofile_totalframes_offset2) + if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalframes_offset2, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + if (cls.capturevideo.soundrate) + { + if(format->videofile_totalsampleframes_offset) + if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalsampleframes_offset, SEEK_SET) >= 0) + { + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundsampleframe); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); + } + } + } + + if (format->riffindexbuffer.data) + { + Mem_Free(format->riffindexbuffer.data); + format->riffindexbuffer.data = NULL; + } + + FS_Close(cls.capturevideo.videofile); + cls.capturevideo.videofile = NULL; + + Mem_Free(format); +} + +static void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) +{ + LOAD_FORMATSPECIFIC_AVI(); + int x; + unsigned char bufstereo16le[PAINTBUFFER_SIZE * 4]; + unsigned char* out_ptr; + size_t i; + + // write the sound buffer as little endian 16bit interleaved stereo + for(i = 0, out_ptr = bufstereo16le; i < length; i++, out_ptr += 4) + { + int n0, n1; + + n0 = paintbuffer[i].sample[0] * 32768.0f; + n0 = bound(-32768, n0, 32767); + out_ptr[0] = (unsigned char)n0; + out_ptr[1] = (unsigned char)(n0 >> 8); + + n1 = paintbuffer[i].sample[1] * 32768.0f; + n1 = bound(-32768, n1, 32767); + out_ptr[2] = (unsigned char)n1; + out_ptr[3] = (unsigned char)(n1 >> 8); + } + + x = length*4; + if(format->canseek) + { + SCR_CaptureVideo_RIFF_OverflowCheck(8 + x); + SCR_CaptureVideo_RIFF_IndexEntry("01wb", x, 0x10); // AVIIF_KEYFRAME + } + + if(!format->canseek) + { + SCR_CaptureVideo_RIFF_Push("RIFF", "AVIX", 12+8+x); + SCR_CaptureVideo_RIFF_Push("LIST", "movi", 8+x); + } + SCR_CaptureVideo_RIFF_Push("01wb", NULL, x); + SCR_CaptureVideo_RIFF_WriteBytes(bufstereo16le, x); + SCR_CaptureVideo_RIFF_Pop(); + if(!format->canseek) + { + SCR_CaptureVideo_RIFF_Pop(); + SCR_CaptureVideo_RIFF_Pop(); + } +} + +void SCR_CaptureVideo_Avi_BeginVideo(void) +{ + int width = cls.capturevideo.width; + int height = cls.capturevideo.height; + int n, d; + unsigned int i; + double aspect; + char vabuf[1024]; + + aspect = vid.width / (vid.height * vid_pixelheight.value); + + cls.capturevideo.format = CAPTUREVIDEOFORMAT_AVI_I420; + cls.capturevideo.formatextension = "avi"; + cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false); + cls.capturevideo.endvideo = SCR_CaptureVideo_Avi_EndVideo; + cls.capturevideo.videoframes = SCR_CaptureVideo_Avi_VideoFrames; + cls.capturevideo.soundframe = SCR_CaptureVideo_Avi_SoundFrame; + cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_avi_formatspecific_t)); + { + LOAD_FORMATSPECIFIC_AVI(); + format->canseek = (FS_Seek(cls.capturevideo.videofile, 0, SEEK_SET) == 0); + SCR_CaptureVideo_RIFF_Start(); + // enclosing RIFF chunk (there can be multiple of these in >1GB files, the later ones are "AVIX" instead of "AVI " and have no header/stream info) + SCR_CaptureVideo_RIFF_Push("RIFF", "AVI ", format->canseek ? -1 : 12+(8+56+12+(12+52+8+40+8+68)+(cls.capturevideo.soundrate?(12+12+52+8+18):0)+12+(8+4))+12+(8+(((int) strlen(engineversion) | 1) + 1))+12); + // AVI main header + SCR_CaptureVideo_RIFF_Push("LIST", "hdrl", format->canseek ? -1 : 8+56+12+(12+52+8+40+8+68)+(cls.capturevideo.soundrate?(12+12+52+8+18):0)+12+(8+4)); + SCR_CaptureVideo_RIFF_Push("avih", NULL, 56); + SCR_CaptureVideo_RIFF_Write32((int)(1000000.0 / (cls.capturevideo.framerate / cls.capturevideo.framestep))); // microseconds per frame + SCR_CaptureVideo_RIFF_Write32(0); // max bytes per second + SCR_CaptureVideo_RIFF_Write32(0); // padding granularity + SCR_CaptureVideo_RIFF_Write32(0x910); // flags (AVIF_HASINDEX | AVIF_ISINTERLEAVED | AVIF_TRUSTCKTYPE) + format->videofile_firstchunkframes_offset = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0); // total frames + SCR_CaptureVideo_RIFF_Write32(0); // initial frames + if (cls.capturevideo.soundrate) + SCR_CaptureVideo_RIFF_Write32(2); // number of streams + else + SCR_CaptureVideo_RIFF_Write32(1); // number of streams + SCR_CaptureVideo_RIFF_Write32(0); // suggested buffer size + SCR_CaptureVideo_RIFF_Write32(width); // width + SCR_CaptureVideo_RIFF_Write32(height); // height + SCR_CaptureVideo_RIFF_Write32(0); // reserved[0] + SCR_CaptureVideo_RIFF_Write32(0); // reserved[1] + SCR_CaptureVideo_RIFF_Write32(0); // reserved[2] + SCR_CaptureVideo_RIFF_Write32(0); // reserved[3] + SCR_CaptureVideo_RIFF_Pop(); + // video stream info + SCR_CaptureVideo_RIFF_Push("LIST", "strl", format->canseek ? -1 : 12+52+8+40+8+68); + SCR_CaptureVideo_RIFF_Push("strh", "vids", 52); + SCR_CaptureVideo_RIFF_WriteFourCC("I420"); // stream fourcc (I420 colorspace, uncompressed) + SCR_CaptureVideo_RIFF_Write32(0); // flags + SCR_CaptureVideo_RIFF_Write16(0); // priority + SCR_CaptureVideo_RIFF_Write16(0); // language + SCR_CaptureVideo_RIFF_Write32(0); // initial frames + // find an ideal divisor for the framerate + FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &n, &d, 1000); + SCR_CaptureVideo_RIFF_Write32(d); // samples/second divisor + SCR_CaptureVideo_RIFF_Write32(n); // samples/second multiplied by divisor + SCR_CaptureVideo_RIFF_Write32(0); // start + format->videofile_totalframes_offset1 = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0xFFFFFFFF); // length + SCR_CaptureVideo_RIFF_Write32(width*height+(width/2)*(height/2)*2); // suggested buffer size + SCR_CaptureVideo_RIFF_Write32(0); // quality + SCR_CaptureVideo_RIFF_Write32(0); // sample size + SCR_CaptureVideo_RIFF_Write16(0); // frame left + SCR_CaptureVideo_RIFF_Write16(0); // frame top + SCR_CaptureVideo_RIFF_Write16(width); // frame right + SCR_CaptureVideo_RIFF_Write16(height); // frame bottom + SCR_CaptureVideo_RIFF_Pop(); + // video stream format + SCR_CaptureVideo_RIFF_Push("strf", NULL, 40); + SCR_CaptureVideo_RIFF_Write32(40); // BITMAPINFO struct size + SCR_CaptureVideo_RIFF_Write32(width); // width + SCR_CaptureVideo_RIFF_Write32(height); // height + SCR_CaptureVideo_RIFF_Write16(3); // planes + SCR_CaptureVideo_RIFF_Write16(12); // bitcount + SCR_CaptureVideo_RIFF_WriteFourCC("I420"); // compression + SCR_CaptureVideo_RIFF_Write32(width*height+(width/2)*(height/2)*2); // size of image + SCR_CaptureVideo_RIFF_Write32(0); // x pixels per meter + SCR_CaptureVideo_RIFF_Write32(0); // y pixels per meter + SCR_CaptureVideo_RIFF_Write32(0); // color used + SCR_CaptureVideo_RIFF_Write32(0); // color important + SCR_CaptureVideo_RIFF_Pop(); + // master index + if(format->canseek) + { + SCR_CaptureVideo_RIFF_Push("indx", NULL, -1); + SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry + SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0 + format->videofile_ix_master_video_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse + SCR_CaptureVideo_RIFF_WriteFourCC("00dc"); // dwChunkId + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1 + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2 + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3 + format->videofile_ix_master_video_start_offset = SCR_CaptureVideo_RIFF_GetPosition(); + for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i) + SCR_CaptureVideo_RIFF_Write32(0); // fill up later + SCR_CaptureVideo_RIFF_Pop(); + } + // extended format (aspect!) + SCR_CaptureVideo_RIFF_Push("vprp", NULL, 68); + SCR_CaptureVideo_RIFF_Write32(0); // VideoFormatToken + SCR_CaptureVideo_RIFF_Write32(0); // VideoStandard + SCR_CaptureVideo_RIFF_Write32((int)(cls.capturevideo.framerate / cls.capturevideo.framestep)); // dwVerticalRefreshRate (bogus) + SCR_CaptureVideo_RIFF_Write32(width); // dwHTotalInT + SCR_CaptureVideo_RIFF_Write32(height); // dwVTotalInLines + FindFraction(aspect, &n, &d, 1000); + SCR_CaptureVideo_RIFF_Write32((n << 16) | d); // dwFrameAspectRatio // TODO a word + SCR_CaptureVideo_RIFF_Write32(width); // dwFrameWidthInPixels + SCR_CaptureVideo_RIFF_Write32(height); // dwFrameHeightInLines + SCR_CaptureVideo_RIFF_Write32(1); // nFieldPerFrame + SCR_CaptureVideo_RIFF_Write32(width); // CompressedBMWidth + SCR_CaptureVideo_RIFF_Write32(height); // CompressedBMHeight + SCR_CaptureVideo_RIFF_Write32(width); // ValidBMHeight + SCR_CaptureVideo_RIFF_Write32(height); // ValidBMWidth + SCR_CaptureVideo_RIFF_Write32(0); // ValidBMXOffset + SCR_CaptureVideo_RIFF_Write32(0); // ValidBMYOffset + SCR_CaptureVideo_RIFF_Write32(0); // ValidBMXOffsetInT + SCR_CaptureVideo_RIFF_Write32(0); // ValidBMYValidStartLine + SCR_CaptureVideo_RIFF_Pop(); + SCR_CaptureVideo_RIFF_Pop(); + if (cls.capturevideo.soundrate) + { + // audio stream info + SCR_CaptureVideo_RIFF_Push("LIST", "strl", format->canseek ? -1 : 12+52+8+18); + SCR_CaptureVideo_RIFF_Push("strh", "auds", 52); + SCR_CaptureVideo_RIFF_Write32(1); // stream fourcc (PCM audio, uncompressed) + SCR_CaptureVideo_RIFF_Write32(0); // flags + SCR_CaptureVideo_RIFF_Write16(0); // priority + SCR_CaptureVideo_RIFF_Write16(0); // language + SCR_CaptureVideo_RIFF_Write32(0); // initial frames + SCR_CaptureVideo_RIFF_Write32(1); // samples/second divisor + SCR_CaptureVideo_RIFF_Write32((int)(cls.capturevideo.soundrate)); // samples/second multiplied by divisor + SCR_CaptureVideo_RIFF_Write32(0); // start + format->videofile_totalsampleframes_offset = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0xFFFFFFFF); // length + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate * 2); // suggested buffer size (this is a half second) + SCR_CaptureVideo_RIFF_Write32(0); // quality + SCR_CaptureVideo_RIFF_Write32(4); // sample size + SCR_CaptureVideo_RIFF_Write16(0); // frame left + SCR_CaptureVideo_RIFF_Write16(0); // frame top + SCR_CaptureVideo_RIFF_Write16(0); // frame right + SCR_CaptureVideo_RIFF_Write16(0); // frame bottom + SCR_CaptureVideo_RIFF_Pop(); + // audio stream format + SCR_CaptureVideo_RIFF_Push("strf", NULL, 18); + SCR_CaptureVideo_RIFF_Write16(1); // format (uncompressed PCM?) + SCR_CaptureVideo_RIFF_Write16(2); // channels (stereo) + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate); // sampleframes per second + SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate * 4); // average bytes per second + SCR_CaptureVideo_RIFF_Write16(4); // block align + SCR_CaptureVideo_RIFF_Write16(16); // bits per sample + SCR_CaptureVideo_RIFF_Write16(0); // size + SCR_CaptureVideo_RIFF_Pop(); + // master index + if(format->canseek) + { + SCR_CaptureVideo_RIFF_Push("indx", NULL, -1); + SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry + SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0 + format->videofile_ix_master_audio_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse + SCR_CaptureVideo_RIFF_WriteFourCC("01wb"); // dwChunkId + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1 + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2 + SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3 + format->videofile_ix_master_audio_start_offset = SCR_CaptureVideo_RIFF_GetPosition(); + for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i) + SCR_CaptureVideo_RIFF_Write32(0); // fill up later + SCR_CaptureVideo_RIFF_Pop(); + } + SCR_CaptureVideo_RIFF_Pop(); + } + + format->videofile_ix_master_audio_inuse = format->videofile_ix_master_video_inuse = 0; + + // extended header (for total #frames) + SCR_CaptureVideo_RIFF_Push("LIST", "odml", 8+4); + SCR_CaptureVideo_RIFF_Push("dmlh", NULL, 4); + format->videofile_totalframes_offset2 = SCR_CaptureVideo_RIFF_GetPosition(); + SCR_CaptureVideo_RIFF_Write32(0xFFFFFFFF); + SCR_CaptureVideo_RIFF_Pop(); + SCR_CaptureVideo_RIFF_Pop(); + + // close the AVI header list + SCR_CaptureVideo_RIFF_Pop(); + // software that produced this AVI video file + SCR_CaptureVideo_RIFF_Push("LIST", "INFO", 8+((strlen(engineversion) | 1) + 1)); + SCR_CaptureVideo_RIFF_Push("ISFT", NULL, strlen(engineversion) + 1); + SCR_CaptureVideo_RIFF_WriteTerminatedString(engineversion); + SCR_CaptureVideo_RIFF_Pop(); + // enable this junk filler if you like the LIST movi to always begin at 4KB in the file (why?) +#if 0 + SCR_CaptureVideo_RIFF_Push("JUNK", NULL); + x = 4096 - SCR_CaptureVideo_RIFF_GetPosition(); + while (x > 0) + { + const char *junkfiller = "[ DarkPlaces junk data ]"; + int i = min(x, (int)strlen(junkfiller)); + SCR_CaptureVideo_RIFF_WriteBytes((const unsigned char *)junkfiller, i); + x -= i; + } + SCR_CaptureVideo_RIFF_Pop(); +#endif + SCR_CaptureVideo_RIFF_Pop(); + // begin the actual video section now + SCR_CaptureVideo_RIFF_Push("LIST", "movi", format->canseek ? -1 : 0); + format->videofile_ix_movistart = format->riffstackstartoffset[1]; + // we're done with the headers now... + SCR_CaptureVideo_RIFF_Flush(); + if (format->riffstacklevel != 2) + Sys_Error("SCR_CaptureVideo_BeginVideo: broken AVI writing code (stack level is %i (should be 2) at end of headers)\n", format->riffstacklevel); + + if(!format->canseek) + { + // close the movi immediately + SCR_CaptureVideo_RIFF_Pop(); + // close the AVI immediately (we'll put all frames into AVIX) + SCR_CaptureVideo_RIFF_Pop(); + } + } +} diff --git a/app/jni/cap_avi.h b/app/jni/cap_avi.h new file mode 100644 index 0000000..2cf15d6 --- /dev/null +++ b/app/jni/cap_avi.h @@ -0,0 +1 @@ +void SCR_CaptureVideo_Avi_BeginVideo(void); diff --git a/app/jni/cap_ogg.c b/app/jni/cap_ogg.c new file mode 100644 index 0000000..a4913ae --- /dev/null +++ b/app/jni/cap_ogg.c @@ -0,0 +1,1121 @@ +#ifndef _MSC_VER +#include +#endif +#include + +#include "quakedef.h" +#include "client.h" +#include "cap_ogg.h" + +// video capture cvars +static cvar_t cl_capturevideo_ogg_theora_vp3compat = {CVAR_SAVE, "cl_capturevideo_ogg_theora_vp3compat", "1", "make VP3 compatible theora streams"}; +static cvar_t cl_capturevideo_ogg_theora_quality = {CVAR_SAVE, "cl_capturevideo_ogg_theora_quality", "48", "video quality factor (0 to 63), or -1 to use bitrate only; higher is better; setting both to -1 achieves unlimited quality"}; +static cvar_t cl_capturevideo_ogg_theora_bitrate = {CVAR_SAVE, "cl_capturevideo_ogg_theora_bitrate", "-1", "video bitrate (45 to 2000 kbps), or -1 to use quality only; higher is better; setting both to -1 achieves unlimited quality"}; +static cvar_t cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier", "1.5", "how much more bit rate to use for keyframes, specified as a factor of at least 1"}; +static cvar_t cl_capturevideo_ogg_theora_keyframe_maxinterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_maxinterval", "64", "maximum keyframe interval (1 to 1000)"}; +static cvar_t cl_capturevideo_ogg_theora_keyframe_mininterval = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_mininterval", "8", "minimum keyframe interval (1 to 1000)"}; +static cvar_t cl_capturevideo_ogg_theora_keyframe_auto_threshold = {CVAR_SAVE, "cl_capturevideo_ogg_theora_keyframe_auto_threshold", "80", "threshold for key frame decision (0 to 100)"}; +static cvar_t cl_capturevideo_ogg_theora_noise_sensitivity = {CVAR_SAVE, "cl_capturevideo_ogg_theora_noise_sensitivity", "1", "video noise sensitivity (0 to 6); lower is better"}; +static cvar_t cl_capturevideo_ogg_theora_sharpness = {CVAR_SAVE, "cl_capturevideo_ogg_theora_sharpness", "0", "sharpness (0 to 2); lower is sharper"}; +static cvar_t cl_capturevideo_ogg_vorbis_quality = {CVAR_SAVE, "cl_capturevideo_ogg_vorbis_quality", "3", "audio quality (-1 to 10); higher is better"}; + +// ogg.h stuff +#ifdef _MSC_VER +typedef __int16 ogg_int16_t; +typedef unsigned __int16 ogg_uint16_t; +typedef __int32 ogg_int32_t; +typedef unsigned __int32 ogg_uint32_t; +typedef __int64 ogg_int64_t; +#else +typedef int16_t ogg_int16_t; +typedef uint16_t ogg_uint16_t; +typedef int32_t ogg_int32_t; +typedef uint32_t ogg_uint32_t; +typedef int64_t ogg_int64_t; +#endif + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +static int (*qogg_stream_packetin) (ogg_stream_state *os, ogg_packet *op); +static int (*qogg_stream_pageout) (ogg_stream_state *os, ogg_page *og); +static int (*qogg_stream_flush) (ogg_stream_state *os, ogg_page *og); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +static int (*qogg_stream_init) (ogg_stream_state *os,int serialno); +static int (*qogg_stream_clear) (ogg_stream_state *os); +static ogg_int64_t (*qogg_page_granulepos) (ogg_page *og); + +// end of ogg.h stuff + +// vorbis/codec.h stuff +typedef struct vorbis_info{ + int version; + int channels; + long rate; + + /* The below bitrate declarations are *hints*. + Combinations of the three values carry the following implications: + + all three set to the same value: + implies a fixed rate bitstream + only nominal set: + implies a VBR stream that averages the nominal bitrate. No hard + upper/lower limit + upper and or lower set: + implies a VBR bitstream that obeys the bitrate limits. nominal + may also be set to give a nominal rate. + none set: + the coder does not care to speculate. + */ + + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + long bitrate_window; + + void *codec_setup; +} vorbis_info; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +typedef struct vorbis_dsp_state{ + int analysisp; + vorbis_info *vi; + + float **pcm; + float **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + + int preextrapolate; + int eofflag; + + long lW; + long W; + long nW; + long centerW; + + ogg_int64_t granulepos; + ogg_int64_t sequence; + + ogg_int64_t glue_bits; + ogg_int64_t time_bits; + ogg_int64_t floor_bits; + ogg_int64_t res_bits; + + void *backend_state; +} vorbis_dsp_state; + +typedef struct vorbis_block{ + /* necessary stream state for linking to the framing abstraction */ + float **pcm; /* this is a pointer into local storage */ + oggpack_buffer opb; + + long lW; + long W; + long nW; + int pcmend; + int mode; + + int eofflag; + ogg_int64_t granulepos; + ogg_int64_t sequence; + vorbis_dsp_state *vd; /* For read-only access of configuration */ + + /* local storage to avoid remallocing; it's up to the mapping to + structure it */ + void *localstore; + long localtop; + long localalloc; + long totaluse; + struct alloc_chain *reap; + + /* bitmetrics for the frame */ + long glue_bits; + long time_bits; + long floor_bits; + long res_bits; + + void *internal; + +} vorbis_block; + +/* vorbis_block is a single block of data to be processed as part of +the analysis/synthesis stream; it belongs to a specific logical +bitstream, but is independant from other vorbis_blocks belonging to +that logical bitstream. *************************************************/ + +struct alloc_chain{ + void *ptr; + struct alloc_chain *next; +}; + +/* vorbis_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). vorbis_info and substructures are in backends.h. +*********************************************************************/ + +/* the comments are not part of vorbis_info so that vorbis_info can be + static storage */ +typedef struct vorbis_comment{ + /* unlimited user comment fields. libvorbis writes 'libvorbis' + whatever vendor is set to in encode */ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} vorbis_comment; + + +/* libvorbis encodes in two abstraction layers; first we perform DSP + and produce a packet (see docs/analysis.txt). The packet is then + coded into a framed OggSquish bitstream by the second layer (see + docs/framing.txt). Decode is the reverse process; we sync/frame + the bitstream and extract individual packets, then decode the + packet back into PCM audio. + + The extra framing/packetizing is used in streaming formats, such as + files. Over the net (such as with UDP), the framing and + packetization aren't necessary as they're provided by the transport + and the streaming layer is not used */ + +/* Vorbis PRIMITIVES: general ***************************************/ + +static void (*qvorbis_info_init) (vorbis_info *vi); +static void (*qvorbis_info_clear) (vorbis_info *vi); +static void (*qvorbis_comment_init) (vorbis_comment *vc); +static void (*qvorbis_comment_clear) (vorbis_comment *vc); + +static int (*qvorbis_block_init) (vorbis_dsp_state *v, vorbis_block *vb); +static int (*qvorbis_block_clear) (vorbis_block *vb); +static void (*qvorbis_dsp_clear) (vorbis_dsp_state *v); +static double (*qvorbis_granule_time) (vorbis_dsp_state *v, + ogg_int64_t granulepos); + +/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ + +static int (*qvorbis_analysis_init) (vorbis_dsp_state *v,vorbis_info *vi); +static int (*qvorbis_commentheader_out) (vorbis_comment *vc, ogg_packet *op); +static int (*qvorbis_analysis_headerout) (vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code); +static float ** (*qvorbis_analysis_buffer) (vorbis_dsp_state *v,int vals); +static int (*qvorbis_analysis_wrote) (vorbis_dsp_state *v,int vals); +static int (*qvorbis_analysis_blockout) (vorbis_dsp_state *v,vorbis_block *vb); +static int (*qvorbis_analysis) (vorbis_block *vb,ogg_packet *op); + +static int (*qvorbis_bitrate_addblock) (vorbis_block *vb); +static int (*qvorbis_bitrate_flushpacket) (vorbis_dsp_state *vd, + ogg_packet *op); + +// end of vorbis/codec.h stuff + +// vorbisenc.h stuff +static int (*qvorbis_encode_init_vbr) (vorbis_info *vi, + long channels, + long rate, + + float base_quality /* quality level from 0. (lo) to 1. (hi) */ + ); +// end of vorbisenc.h stuff + +// theora.h stuff + +#define TH_ENCCTL_SET_VP3_COMPATIBLE (10) + +typedef struct { + int y_width; /**< Width of the Y' luminance plane */ + int y_height; /**< Height of the luminance plane */ + int y_stride; /**< Offset in bytes between successive rows */ + + int uv_width; /**< Width of the Cb and Cr chroma planes */ + int uv_height; /**< Height of the chroma planes */ + int uv_stride; /**< Offset between successive chroma rows */ + unsigned char *y; /**< Pointer to start of luminance data */ + unsigned char *u; /**< Pointer to start of Cb data */ + unsigned char *v; /**< Pointer to start of Cr data */ + +} yuv_buffer; + +/** + * A Colorspace. + */ +typedef enum { + OC_CS_UNSPECIFIED, /**< The colorspace is unknown or unspecified */ + OC_CS_ITU_REC_470M, /**< This is the best option for 'NTSC' content */ + OC_CS_ITU_REC_470BG, /**< This is the best option for 'PAL' content */ + OC_CS_NSPACES /**< This marks the end of the defined colorspaces */ +} theora_colorspace; + +/** + * A Chroma subsampling + * + * These enumerate the available chroma subsampling options supported + * by the theora format. See Section 4.4 of the specification for + * exact definitions. + */ +typedef enum { + OC_PF_420, /**< Chroma subsampling by 2 in each direction (4:2:0) */ + OC_PF_RSVD, /**< Reserved value */ + OC_PF_422, /**< Horizonatal chroma subsampling by 2 (4:2:2) */ + OC_PF_444 /**< No chroma subsampling at all (4:4:4) */ +} theora_pixelformat; +/** + * Theora bitstream info. + * Contains the basic playback parameters for a stream, + * corresponding to the initial 'info' header packet. + * + * Encoded theora frames must be a multiple of 16 in width and height. + * To handle other frame sizes, a crop rectangle is specified in + * frame_height and frame_width, offset_x and * offset_y. The offset + * and size should still be a multiple of 2 to avoid chroma sampling + * shifts. Offset values in this structure are measured from the + * upper left of the image. + * + * Frame rate, in frames per second, is stored as a rational + * fraction. Aspect ratio is also stored as a rational fraction, and + * refers to the aspect ratio of the frame pixels, not of the + * overall frame itself. + * + * See + * examples/encoder_example.c for usage examples of the + * other paramters and good default settings for the encoder parameters. + */ +typedef struct { + ogg_uint32_t width; /**< encoded frame width */ + ogg_uint32_t height; /**< encoded frame height */ + ogg_uint32_t frame_width; /**< display frame width */ + ogg_uint32_t frame_height; /**< display frame height */ + ogg_uint32_t offset_x; /**< horizontal offset of the displayed frame */ + ogg_uint32_t offset_y; /**< vertical offset of the displayed frame */ + ogg_uint32_t fps_numerator; /**< frame rate numerator **/ + ogg_uint32_t fps_denominator; /**< frame rate denominator **/ + ogg_uint32_t aspect_numerator; /**< pixel aspect ratio numerator */ + ogg_uint32_t aspect_denominator; /**< pixel aspect ratio denominator */ + theora_colorspace colorspace; /**< colorspace */ + int target_bitrate; /**< nominal bitrate in bits per second */ + int quality; /**< Nominal quality setting, 0-63 */ + int quick_p; /**< Quick encode/decode */ + + /* decode only */ + unsigned char version_major; + unsigned char version_minor; + unsigned char version_subminor; + + void *codec_setup; + + /* encode only */ + int dropframes_p; + int keyframe_auto_p; + ogg_uint32_t keyframe_frequency; + ogg_uint32_t keyframe_frequency_force; /* also used for decode init to + get granpos shift correct */ + ogg_uint32_t keyframe_data_target_bitrate; + ogg_int32_t keyframe_auto_threshold; + ogg_uint32_t keyframe_mindistance; + ogg_int32_t noise_sensitivity; + ogg_int32_t sharpness; + + theora_pixelformat pixelformat; /**< chroma subsampling mode to expect */ + +} theora_info; + +/** Codec internal state and context. + */ +typedef struct{ + theora_info *i; + ogg_int64_t granulepos; + + void *internal_encode; + void *internal_decode; + +} theora_state; + +/** + * Comment header metadata. + * + * This structure holds the in-stream metadata corresponding to + * the 'comment' header packet. + * + * Meta data is stored as a series of (tag, value) pairs, in + * length-encoded string vectors. The first occurence of the + * '=' character delimits the tag and value. A particular tag + * may occur more than once. The character set encoding for + * the strings is always UTF-8, but the tag names are limited + * to case-insensitive ASCII. See the spec for details. + * + * In filling in this structure, qtheora_decode_header() will + * null-terminate the user_comment strings for safety. However, + * the bitstream format itself treats them as 8-bit clean, + * and so the length array should be treated as authoritative + * for their length. + */ +typedef struct theora_comment{ + char **user_comments; /**< An array of comment string vectors */ + int *comment_lengths; /**< An array of corresponding string vector lengths in bytes */ + int comments; /**< The total number of comment string vectors */ + char *vendor; /**< The vendor string identifying the encoder, null terminated */ + +} theora_comment; +static int (*qtheora_encode_init) (theora_state *th, theora_info *ti); +static int (*qtheora_encode_YUVin) (theora_state *t, yuv_buffer *yuv); +static int (*qtheora_encode_packetout) ( theora_state *t, int last_p, + ogg_packet *op); +static int (*qtheora_encode_header) (theora_state *t, ogg_packet *op); +static int (*qtheora_encode_comment) (theora_comment *tc, ogg_packet *op); +static int (*qtheora_encode_tables) (theora_state *t, ogg_packet *op); +static void (*qtheora_info_init) (theora_info *c); +static void (*qtheora_info_clear) (theora_info *c); +static void (*qtheora_clear) (theora_state *t); +static void (*qtheora_comment_init) (theora_comment *tc); +static void (*qtheora_comment_clear) (theora_comment *tc); +static double (*qtheora_granule_time) (theora_state *th,ogg_int64_t granulepos); +static int (*qtheora_control) (theora_state *th,int req,void *buf,size_t buf_sz); +// end of theora.h stuff + +static dllfunction_t oggfuncs[] = +{ + {"ogg_stream_packetin", (void **) &qogg_stream_packetin}, + {"ogg_stream_pageout", (void **) &qogg_stream_pageout}, + {"ogg_stream_flush", (void **) &qogg_stream_flush}, + {"ogg_stream_init", (void **) &qogg_stream_init}, + {"ogg_stream_clear", (void **) &qogg_stream_clear}, + {"ogg_page_granulepos", (void **) &qogg_page_granulepos}, + {NULL, NULL} +}; + +static dllfunction_t vorbisencfuncs[] = +{ + {"vorbis_encode_init_vbr", (void **) &qvorbis_encode_init_vbr}, + {NULL, NULL} +}; + +static dllfunction_t vorbisfuncs[] = +{ + {"vorbis_info_init", (void **) &qvorbis_info_init}, + {"vorbis_info_clear", (void **) &qvorbis_info_clear}, + {"vorbis_comment_init", (void **) &qvorbis_comment_init}, + {"vorbis_comment_clear", (void **) &qvorbis_comment_clear}, + {"vorbis_block_init", (void **) &qvorbis_block_init}, + {"vorbis_block_clear", (void **) &qvorbis_block_clear}, + {"vorbis_dsp_clear", (void **) &qvorbis_dsp_clear}, + {"vorbis_analysis_init", (void **) &qvorbis_analysis_init}, + {"vorbis_commentheader_out", (void **) &qvorbis_commentheader_out}, + {"vorbis_analysis_headerout", (void **) &qvorbis_analysis_headerout}, + {"vorbis_analysis_buffer", (void **) &qvorbis_analysis_buffer}, + {"vorbis_analysis_wrote", (void **) &qvorbis_analysis_wrote}, + {"vorbis_analysis_blockout", (void **) &qvorbis_analysis_blockout}, + {"vorbis_analysis", (void **) &qvorbis_analysis}, + {"vorbis_bitrate_addblock", (void **) &qvorbis_bitrate_addblock}, + {"vorbis_bitrate_flushpacket", (void **) &qvorbis_bitrate_flushpacket}, + {"vorbis_granule_time", (void **) &qvorbis_granule_time}, + {NULL, NULL} +}; + +static dllfunction_t theorafuncs[] = +{ + {"theora_info_init", (void **) &qtheora_info_init}, + {"theora_info_clear", (void **) &qtheora_info_clear}, + {"theora_comment_init", (void **) &qtheora_comment_init}, + {"theora_comment_clear", (void **) &qtheora_comment_clear}, + {"theora_encode_init", (void **) &qtheora_encode_init}, + {"theora_encode_YUVin", (void **) &qtheora_encode_YUVin}, + {"theora_encode_packetout", (void **) &qtheora_encode_packetout}, + {"theora_encode_header", (void **) &qtheora_encode_header}, + {"theora_encode_comment", (void **) &qtheora_encode_comment}, + {"theora_encode_tables", (void **) &qtheora_encode_tables}, + {"theora_clear", (void **) &qtheora_clear}, + {"theora_granule_time", (void **) &qtheora_granule_time}, + {"theora_control", (void **) &qtheora_control}, + {NULL, NULL} +}; + +static dllhandle_t og_dll = NULL, vo_dll = NULL, ve_dll = NULL, th_dll = NULL; + +static qboolean SCR_CaptureVideo_Ogg_OpenLibrary(void) +{ + const char* dllnames_og [] = + { +#if defined(WIN32) + "libogg-0.dll", + "libogg.dll", + "ogg.dll", +#elif defined(MACOSX) + "libogg.dylib", +#else + "libogg.so.0", + "libogg.so", +#endif + NULL + }; + const char* dllnames_vo [] = + { +#if defined(WIN32) + "libvorbis-0.dll", + "libvorbis.dll", + "vorbis.dll", +#elif defined(MACOSX) + "libvorbis.dylib", +#else + "libvorbis.so.0", + "libvorbis.so", +#endif + NULL + }; + const char* dllnames_ve [] = + { +#if defined(WIN32) + "libvorbisenc-2.dll", + "libvorbisenc.dll", + "vorbisenc.dll", +#elif defined(MACOSX) + "libvorbisenc.dylib", +#else + "libvorbisenc.so.2", + "libvorbisenc.so", +#endif + NULL + }; + const char* dllnames_th [] = + { +#if defined(WIN32) + "libtheora-0.dll", + "libtheora.dll", + "theora.dll", +#elif defined(MACOSX) + "libtheora.dylib", +#else + "libtheora.so.0", + "libtheora.so", +#endif + NULL + }; + + return + Sys_LoadLibrary (dllnames_og, &og_dll, oggfuncs) + && + Sys_LoadLibrary (dllnames_th, &th_dll, theorafuncs) + && + Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs) + && + Sys_LoadLibrary (dllnames_ve, &ve_dll, vorbisencfuncs); +} + +void SCR_CaptureVideo_Ogg_Init(void) +{ + SCR_CaptureVideo_Ogg_OpenLibrary(); + + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_vp3compat); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_quality); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_bitrate); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_maxinterval); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_mininterval); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_keyframe_auto_threshold); + Cvar_RegisterVariable(&cl_capturevideo_ogg_theora_noise_sensitivity); + Cvar_RegisterVariable(&cl_capturevideo_ogg_vorbis_quality); +} + +qboolean SCR_CaptureVideo_Ogg_Available(void) +{ + return og_dll && th_dll && vo_dll && ve_dll; +} + +void SCR_CaptureVideo_Ogg_CloseDLL(void) +{ + Sys_UnloadLibrary (&ve_dll); + Sys_UnloadLibrary (&vo_dll); + Sys_UnloadLibrary (&th_dll); + Sys_UnloadLibrary (&og_dll); +} + +// this struct should not be needed +// however, libogg appears to pull the ogg_page's data element away from our +// feet before we get to write the data due to interleaving +// so this struct is used to keep the page data around until it actually gets +// written +typedef struct allocatedoggpage_s +{ + size_t len; + double time; + unsigned char data[65307]; + // this number is from RFC 3533. In case libogg writes more, we'll have to increase this + // but we'll get a Host_Error in this case so we can track it down +} +allocatedoggpage_t; + +typedef struct capturevideostate_ogg_formatspecific_s +{ + ogg_stream_state to, vo; + int serial1, serial2; + theora_state ts; + vorbis_dsp_state vd; + vorbis_block vb; + vorbis_info vi; + yuv_buffer yuv[2]; + int yuvi; + int lastnum; + int channels; + + allocatedoggpage_t videopage, audiopage; +} +capturevideostate_ogg_formatspecific_t; +#define LOAD_FORMATSPECIFIC_OGG() capturevideostate_ogg_formatspecific_t *format = (capturevideostate_ogg_formatspecific_t *) cls.capturevideo.formatspecific + +static void SCR_CaptureVideo_Ogg_Interleave(void) +{ + LOAD_FORMATSPECIFIC_OGG(); + ogg_page pg; + + if(!cls.capturevideo.soundrate) + { + while(qogg_stream_pageout(&format->to, &pg) > 0) + { + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + return; + } + + for(;;) + { + // first: make sure we have a page of both types + if(!format->videopage.len) + if(qogg_stream_pageout(&format->to, &pg) > 0) + { + format->videopage.len = pg.header_len + pg.body_len; + format->videopage.time = qtheora_granule_time(&format->ts, qogg_page_granulepos(&pg)); + if(format->videopage.len > sizeof(format->videopage.data)) + Sys_Error("video page too long"); + memcpy(format->videopage.data, pg.header, pg.header_len); + memcpy(format->videopage.data + pg.header_len, pg.body, pg.body_len); + } + if(!format->audiopage.len) + if(qogg_stream_pageout(&format->vo, &pg) > 0) + { + format->audiopage.len = pg.header_len + pg.body_len; + format->audiopage.time = qvorbis_granule_time(&format->vd, qogg_page_granulepos(&pg)); + if(format->audiopage.len > sizeof(format->audiopage.data)) + Sys_Error("audio page too long"); + memcpy(format->audiopage.data, pg.header, pg.header_len); + memcpy(format->audiopage.data + pg.header_len, pg.body, pg.body_len); + } + + if(format->videopage.len && format->audiopage.len) + { + // output the page that ends first + if(format->videopage.time < format->audiopage.time) + { + FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len); + format->videopage.len = 0; + } + else + { + FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len); + format->audiopage.len = 0; + } + } + else + break; + } +} + +static void SCR_CaptureVideo_Ogg_FlushInterleaving(void) +{ + LOAD_FORMATSPECIFIC_OGG(); + + if(cls.capturevideo.soundrate) + if(format->audiopage.len) + { + FS_Write(cls.capturevideo.videofile, format->audiopage.data, format->audiopage.len); + format->audiopage.len = 0; + } + + if(format->videopage.len) + { + FS_Write(cls.capturevideo.videofile, format->videopage.data, format->videopage.len); + format->videopage.len = 0; + } +} + +static void SCR_CaptureVideo_Ogg_EndVideo(void) +{ + LOAD_FORMATSPECIFIC_OGG(); + ogg_page pg; + ogg_packet pt; + + if(format->yuvi >= 0) + { + // send the previous (and last) frame + while(format->lastnum-- > 0) + { + qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]); + + while(qtheora_encode_packetout(&format->ts, !format->lastnum, &pt)) + qogg_stream_packetin(&format->to, &pt); + + SCR_CaptureVideo_Ogg_Interleave(); + } + } + + if(cls.capturevideo.soundrate) + { + qvorbis_analysis_wrote(&format->vd, 0); + while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1) + { + qvorbis_analysis(&format->vb, NULL); + qvorbis_bitrate_addblock(&format->vb); + while(qvorbis_bitrate_flushpacket(&format->vd, &pt)) + qogg_stream_packetin(&format->vo, &pt); + SCR_CaptureVideo_Ogg_Interleave(); + } + } + + SCR_CaptureVideo_Ogg_FlushInterleaving(); + + while(qogg_stream_pageout(&format->to, &pg) > 0) + { + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + + if(cls.capturevideo.soundrate) + { + while(qogg_stream_pageout(&format->vo, &pg) > 0) + { + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + } + + while (1) { + int result = qogg_stream_flush (&format->to, &pg); + if (result < 0) + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + if (result <= 0) + break; + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + + if(cls.capturevideo.soundrate) + { + while (1) { + int result = qogg_stream_flush (&format->vo, &pg); + if (result < 0) + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + if (result <= 0) + break; + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + + qogg_stream_clear(&format->vo); + qvorbis_block_clear(&format->vb); + qvorbis_dsp_clear(&format->vd); + } + + qogg_stream_clear(&format->to); + qtheora_clear(&format->ts); + qvorbis_info_clear(&format->vi); + + Mem_Free(format->yuv[0].y); + Mem_Free(format->yuv[0].u); + Mem_Free(format->yuv[0].v); + Mem_Free(format->yuv[1].y); + Mem_Free(format->yuv[1].u); + Mem_Free(format->yuv[1].v); + Mem_Free(format); + + FS_Close(cls.capturevideo.videofile); + cls.capturevideo.videofile = NULL; +} + +static void SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(void) +{ + LOAD_FORMATSPECIFIC_OGG(); + yuv_buffer *yuv; + int x, y; + int blockr, blockg, blockb; + unsigned char *b; + int w = cls.capturevideo.width; + int h = cls.capturevideo.height; + int inpitch = w*4; + + yuv = &format->yuv[format->yuvi]; + + for(y = 0; y < h; ++y) + { + for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x) + { + blockr = b[2]; + blockg = b[1]; + blockb = b[0]; + yuv->y[x + yuv->y_stride * y] = + cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]]; + b += 4; + } + + if ((y & 1) == 0 && y/2 < h/2) // if h is odd, this skips the last row + { + for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < w/2; ++x) + { + blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2; + blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2; + blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2; + yuv->u[x + yuv->uv_stride * (y/2)] = + cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128]; + yuv->v[x + yuv->uv_stride * (y/2)] = + cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128]; + b += 8; + } + } + } +} + +static void SCR_CaptureVideo_Ogg_VideoFrames(int num) +{ + LOAD_FORMATSPECIFIC_OGG(); + ogg_packet pt; + + // data is in cls.capturevideo.outbuffer as BGRA and has size width*height + + if(format->yuvi >= 0) + { + // send the previous frame + while(format->lastnum-- > 0) + { + qtheora_encode_YUVin(&format->ts, &format->yuv[format->yuvi]); + + while(qtheora_encode_packetout(&format->ts, false, &pt)) + qogg_stream_packetin(&format->to, &pt); + + SCR_CaptureVideo_Ogg_Interleave(); + } + } + + format->yuvi = (format->yuvi + 1) % 2; + SCR_CaptureVideo_Ogg_ConvertFrame_BGRA_to_YUV(); + format->lastnum = num; + + // TODO maybe send num-1 frames from here already +} + +typedef int channelmapping_t[8]; +channelmapping_t mapping[8] = +{ + { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono + { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo + { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R + { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40 + { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR + { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51 + { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec) + { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec) +}; + +static void SCR_CaptureVideo_Ogg_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) +{ + LOAD_FORMATSPECIFIC_OGG(); + float **vorbis_buffer; + size_t i; + int j; + ogg_packet pt; + int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1]; + + vorbis_buffer = qvorbis_analysis_buffer(&format->vd, length); + for(j = 0; j < cls.capturevideo.soundchannels; ++j) + { + float *b = vorbis_buffer[map[j]]; + for(i = 0; i < length; ++i) + b[i] = paintbuffer[i].sample[j]; + } + qvorbis_analysis_wrote(&format->vd, length); + + while(qvorbis_analysis_blockout(&format->vd, &format->vb) == 1) + { + qvorbis_analysis(&format->vb, NULL); + qvorbis_bitrate_addblock(&format->vb); + + while(qvorbis_bitrate_flushpacket(&format->vd, &pt)) + qogg_stream_packetin(&format->vo, &pt); + } + + SCR_CaptureVideo_Ogg_Interleave(); +} + +void SCR_CaptureVideo_Ogg_BeginVideo(void) +{ + char vabuf[1024]; + cls.capturevideo.format = CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA; + cls.capturevideo.formatextension = "ogv"; + cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false); + cls.capturevideo.endvideo = SCR_CaptureVideo_Ogg_EndVideo; + cls.capturevideo.videoframes = SCR_CaptureVideo_Ogg_VideoFrames; + cls.capturevideo.soundframe = SCR_CaptureVideo_Ogg_SoundFrame; + cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_ogg_formatspecific_t)); + { + LOAD_FORMATSPECIFIC_OGG(); + int num, denom, i; + ogg_page pg; + ogg_packet pt, pt2, pt3; + theora_comment tc; + vorbis_comment vc; + theora_info ti; + int vp3compat; + + format->serial1 = rand(); + qogg_stream_init(&format->to, format->serial1); + + if(cls.capturevideo.soundrate) + { + do + { + format->serial2 = rand(); + } + while(format->serial1 == format->serial2); + qogg_stream_init(&format->vo, format->serial2); + } + + format->videopage.len = format->audiopage.len = 0; + + qtheora_info_init(&ti); + ti.frame_width = cls.capturevideo.width; + ti.frame_height = cls.capturevideo.height; + ti.width = (ti.frame_width + 15) & ~15; + ti.height = (ti.frame_height + 15) & ~15; + //ti.offset_x = ((ti.width - ti.frame_width) / 2) & ~1; + //ti.offset_y = ((ti.height - ti.frame_height) / 2) & ~1; + + for(i = 0; i < 2; ++i) + { + format->yuv[i].y_width = ti.width; + format->yuv[i].y_height = ti.height; + format->yuv[i].y_stride = ti.width; + format->yuv[i].uv_width = ti.width / 2; + format->yuv[i].uv_height = ti.height / 2; + format->yuv[i].uv_stride = ti.width / 2; + format->yuv[i].y = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].y_stride * format->yuv[i].y_height); + format->yuv[i].u = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height); + format->yuv[i].v = (unsigned char *) Mem_Alloc(tempmempool, format->yuv[i].uv_stride * format->yuv[i].uv_height); + } + format->yuvi = -1; // -1: no frame valid yet, write into 0 + + FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001); + ti.fps_numerator = num; + ti.fps_denominator = denom; + + FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000); + ti.aspect_numerator = num; + ti.aspect_denominator = denom; + + ti.colorspace = OC_CS_UNSPECIFIED; + ti.pixelformat = OC_PF_420; + + ti.quick_p = true; // http://mlblog.osdir.com/multimedia.ogg.theora.general/2004-07/index.shtml + ti.dropframes_p = false; + + ti.target_bitrate = cl_capturevideo_ogg_theora_bitrate.integer * 1000; + ti.quality = cl_capturevideo_ogg_theora_quality.integer; + + if(ti.target_bitrate <= 0) + { + ti.target_bitrate = -1; + ti.keyframe_data_target_bitrate = (unsigned int)-1; + } + else + { + ti.keyframe_data_target_bitrate = (int) (ti.target_bitrate * max(1, cl_capturevideo_ogg_theora_keyframe_bitrate_multiplier.value)); + + if(ti.target_bitrate < 45000 || ti.target_bitrate > 2000000) + Con_DPrintf("WARNING: requesting an odd bitrate for theora (sensible values range from 45 to 2000 kbps)\n"); + } + + if(ti.quality < 0 || ti.quality > 63) + { + ti.quality = 63; + if(ti.target_bitrate <= 0) + { + ti.target_bitrate = 0x7FFFFFFF; + ti.keyframe_data_target_bitrate = 0x7FFFFFFF; + } + } + + // this -1 magic is because ti.keyframe_frequency and ti.keyframe_mindistance use different metrics + ti.keyframe_frequency = bound(1, cl_capturevideo_ogg_theora_keyframe_maxinterval.integer, 1000); + ti.keyframe_mindistance = bound(1, cl_capturevideo_ogg_theora_keyframe_mininterval.integer, (int) ti.keyframe_frequency) - 1; + ti.noise_sensitivity = bound(0, cl_capturevideo_ogg_theora_noise_sensitivity.integer, 6); + ti.sharpness = bound(0, cl_capturevideo_ogg_theora_sharpness.integer, 2); + ti.keyframe_auto_threshold = bound(0, cl_capturevideo_ogg_theora_keyframe_auto_threshold.integer, 100); + + ti.keyframe_frequency_force = ti.keyframe_frequency; + ti.keyframe_auto_p = (ti.keyframe_frequency != ti.keyframe_mindistance + 1); + + qtheora_encode_init(&format->ts, &ti); + qtheora_info_clear(&ti); + + if(cl_capturevideo_ogg_theora_vp3compat.integer) + { + vp3compat = 1; + qtheora_control(&format->ts, TH_ENCCTL_SET_VP3_COMPATIBLE, &vp3compat, sizeof(vp3compat)); + if(!vp3compat) + Con_DPrintf("Warning: theora stream is not fully VP3 compatible\n"); + } + + // vorbis? + if(cls.capturevideo.soundrate) + { + qvorbis_info_init(&format->vi); + qvorbis_encode_init_vbr(&format->vi, cls.capturevideo.soundchannels, cls.capturevideo.soundrate, bound(-1, cl_capturevideo_ogg_vorbis_quality.value, 10) * 0.099); + qvorbis_comment_init(&vc); + qvorbis_analysis_init(&format->vd, &format->vi); + qvorbis_block_init(&format->vd, &format->vb); + } + + qtheora_comment_init(&tc); + + /* create the remaining theora headers */ + qtheora_encode_header(&format->ts, &pt); + qogg_stream_packetin(&format->to, &pt); + if (qogg_stream_pageout (&format->to, &pg) != 1) + fprintf (stderr, "Internal Ogg library error.\n"); + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + + qtheora_encode_comment(&tc, &pt); + qogg_stream_packetin(&format->to, &pt); + qtheora_encode_tables(&format->ts, &pt); + qogg_stream_packetin (&format->to, &pt); + + qtheora_comment_clear(&tc); + + if(cls.capturevideo.soundrate) + { + qvorbis_analysis_headerout(&format->vd, &vc, &pt, &pt2, &pt3); + qogg_stream_packetin(&format->vo, &pt); + if (qogg_stream_pageout (&format->vo, &pg) != 1) + fprintf (stderr, "Internal Ogg library error.\n"); + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + + qogg_stream_packetin(&format->vo, &pt2); + qogg_stream_packetin(&format->vo, &pt3); + + qvorbis_comment_clear(&vc); + } + + for(;;) + { + int result = qogg_stream_flush (&format->to, &pg); + if (result < 0) + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + if (result <= 0) + break; + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + + if(cls.capturevideo.soundrate) + for(;;) + { + int result = qogg_stream_flush (&format->vo, &pg); + if (result < 0) + fprintf (stderr, "Internal Ogg library error.\n"); // TODO Sys_Error + if (result <= 0) + break; + FS_Write(cls.capturevideo.videofile, pg.header, pg.header_len); + FS_Write(cls.capturevideo.videofile, pg.body, pg.body_len); + } + } +} diff --git a/app/jni/cap_ogg.h b/app/jni/cap_ogg.h new file mode 100644 index 0000000..81718f2 --- /dev/null +++ b/app/jni/cap_ogg.h @@ -0,0 +1,4 @@ +void SCR_CaptureVideo_Ogg_Init(void); +qboolean SCR_CaptureVideo_Ogg_Available(void); +void SCR_CaptureVideo_Ogg_BeginVideo(void); +void SCR_CaptureVideo_Ogg_CloseDLL(void); diff --git a/app/jni/cd_null.c b/app/jni/cd_null.c new file mode 100644 index 0000000..13826f0 --- /dev/null +++ b/app/jni/cd_null.c @@ -0,0 +1,91 @@ +/* +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 "cdaudio.h" + + +void CDAudio_SysEject (void) +{ +} + + +void CDAudio_SysCloseDoor (void) +{ +} + + +int CDAudio_SysGetAudioDiskInfo (void) +{ + return -1; +} + + +float CDAudio_SysGetVolume (void) +{ + return -1.0f; +} + + +void CDAudio_SysSetVolume (float volume) +{ +} + + +int CDAudio_SysPlay (int track) +{ + return -1; +} + + +int CDAudio_SysStop (void) +{ + return -1; +} + + +int CDAudio_SysPause (void) +{ + return -1; +} + +int CDAudio_SysResume (void) +{ + return -1; +} + +int CDAudio_SysUpdate (void) +{ + return -1; +} + + +void CDAudio_SysInit (void) +{ +} + +int CDAudio_SysStartup (void) +{ + return -1; +} + +void CDAudio_SysShutdown (void) +{ +} diff --git a/app/jni/cd_shared.c b/app/jni/cd_shared.c new file mode 100644 index 0000000..43b4a7f --- /dev/null +++ b/app/jni/cd_shared.c @@ -0,0 +1,783 @@ +/* +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. + +*/ +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. + +#include "quakedef.h" +#include "cdaudio.h" +#include "sound.h" + +// used by menu to ghost CD audio slider +cvar_t cdaudioinitialized = {CVAR_READONLY,"cdaudioinitialized","0","indicates if CD Audio system is active"}; +cvar_t cdaudio = {CVAR_SAVE,"cdaudio","1","CD playing mode (0 = never access CD drive, 1 = play CD tracks if no replacement available, 2 = play fake tracks if no CD track available, 3 = play only real CD tracks, 4 = play real CD tracks even instead of named fake tracks)"}; + +#define MAX_PLAYLISTS 10 +int music_playlist_active = -1; +int music_playlist_playing = 0; // 0 = not playing, 1 = playing, -1 = tried and failed + +cvar_t music_playlist_index = {0, "music_playlist_index", "-1", "selects which of the music_playlist_ variables is the active one, -1 disables playlists"}; +cvar_t music_playlist_list[MAX_PLAYLISTS] = +{ + {0, "music_playlist_list0", "", "list of tracks to play"}, + {0, "music_playlist_list1", "", "list of tracks to play"}, + {0, "music_playlist_list2", "", "list of tracks to play"}, + {0, "music_playlist_list3", "", "list of tracks to play"}, + {0, "music_playlist_list4", "", "list of tracks to play"}, + {0, "music_playlist_list5", "", "list of tracks to play"}, + {0, "music_playlist_list6", "", "list of tracks to play"}, + {0, "music_playlist_list7", "", "list of tracks to play"}, + {0, "music_playlist_list8", "", "list of tracks to play"}, + {0, "music_playlist_list9", "", "list of tracks to play"} +}; +cvar_t music_playlist_current[MAX_PLAYLISTS] = +{ + {0, "music_playlist_current0", "0", "current track index to play in list"}, + {0, "music_playlist_current1", "0", "current track index to play in list"}, + {0, "music_playlist_current2", "0", "current track index to play in list"}, + {0, "music_playlist_current3", "0", "current track index to play in list"}, + {0, "music_playlist_current4", "0", "current track index to play in list"}, + {0, "music_playlist_current5", "0", "current track index to play in list"}, + {0, "music_playlist_current6", "0", "current track index to play in list"}, + {0, "music_playlist_current7", "0", "current track index to play in list"}, + {0, "music_playlist_current8", "0", "current track index to play in list"}, + {0, "music_playlist_current9", "0", "current track index to play in list"}, +}; +cvar_t music_playlist_random[MAX_PLAYLISTS] = +{ + {0, "music_playlist_random0", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random1", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random2", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random3", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random4", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random5", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random6", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random7", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random8", "0", "enables random play order if 1, 0 is sequential play"}, + {0, "music_playlist_random9", "0", "enables random play order if 1, 0 is sequential play"}, +}; +cvar_t music_playlist_sampleposition[MAX_PLAYLISTS] = +{ + {0, "music_playlist_sampleposition0", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition1", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition2", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition3", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition4", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition5", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition6", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition7", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition8", "-1", "resume position for track, -1 restarts every time"}, + {0, "music_playlist_sampleposition9", "-1", "resume position for track, -1 restarts every time"}, +}; + +static qboolean wasPlaying = false; +static qboolean initialized = false; +static qboolean enabled = false; +static float cdvolume; +typedef char filename_t[MAX_QPATH]; +#ifdef MAXTRACKS +static filename_t remap[MAXTRACKS]; +#endif +static unsigned char maxTrack; +static int faketrack = -1; + +static float saved_vol = 1.0f; + +// exported variables +qboolean cdValid = false; +qboolean cdPlaying = false; +qboolean cdPlayLooping = false; +unsigned char cdPlayTrack; + +cl_cdstate_t cd; + +static void CDAudio_Eject (void) +{ + if (!enabled) + return; + + if(cdaudio.integer == 0) + return; + + CDAudio_SysEject(); +} + + +static void CDAudio_CloseDoor (void) +{ + if (!enabled) + return; + + if(cdaudio.integer == 0) + return; + + CDAudio_SysCloseDoor(); +} + +static int CDAudio_GetAudioDiskInfo (void) +{ + int ret; + + cdValid = false; + + if(cdaudio.integer == 0) + return -1; + + ret = CDAudio_SysGetAudioDiskInfo(); + if (ret < 1) + return -1; + + cdValid = true; + maxTrack = ret; + + return 0; +} + +static qboolean CDAudio_Play_real (int track, qboolean looping, qboolean complain) +{ + if(track < 1) + { + if(complain) + Con_Print("Could not load BGM track.\n"); + return false; + } + + if (!cdValid) + { + CDAudio_GetAudioDiskInfo(); + if (!cdValid) + { + if(complain) + Con_DPrint ("No CD in player.\n"); + return false; + } + } + + if (track > maxTrack) + { + if(complain) + Con_DPrintf("CDAudio: Bad track number %u.\n", track); + return false; + } + + if (CDAudio_SysPlay(track) == -1) + return false; + + if(cdaudio.integer != 3) + Con_DPrintf ("CD track %u playing...\n", track); + + return true; +} + +void CDAudio_Play_byName (const char *trackname, qboolean looping, qboolean tryreal, float startposition) +{ + unsigned int track; + sfx_t* sfx; + char filename[MAX_QPATH]; + + Host_StartVideo(); + + if (!enabled) + return; + + if(tryreal && strspn(trackname, "0123456789") == strlen(trackname)) + { + track = (unsigned char) atoi(trackname); +#ifdef MAXTRACKS + if(track > 0 && track < MAXTRACKS) + if(*remap[track]) + { + if(strspn(remap[track], "0123456789") == strlen(remap[track])) + { + trackname = remap[track]; + } + else + { + // ignore remappings to fake tracks if we're going to play a real track + switch(cdaudio.integer) + { + case 0: // we never access CD + case 1: // we have a replacement + trackname = remap[track]; + break; + case 2: // we only use fake track replacement if CD track is invalid + CDAudio_GetAudioDiskInfo(); + if(!cdValid || track > maxTrack) + trackname = remap[track]; + break; + case 3: // we always play from CD - ignore this remapping then + case 4: // we randomize anyway + break; + } + } + } +#endif + } + + if(tryreal && strspn(trackname, "0123456789") == strlen(trackname)) + { + track = (unsigned char) atoi(trackname); + if (track < 1) + { + Con_DPrintf("CDAudio: Bad track number %u.\n", track); + return; + } + } + else + track = 0; + + // div0: I assume this code was intentionally there. Maybe turn it into a cvar? + if (cdPlaying && cdPlayTrack == track && faketrack == -1) + return; + CDAudio_Stop (); + + if(track >= 1) + { + if(cdaudio.integer == 3) // only play real CD tracks at all + { + if(CDAudio_Play_real(track, looping, true)) + goto success; + return; + } + + if(cdaudio.integer == 2) // prefer real CD track over fake + { + if(CDAudio_Play_real(track, looping, false)) + goto success; + } + } + + if(cdaudio.integer == 4) // only play real CD tracks, EVEN instead of fake tracks! + { + if(CDAudio_Play_real(track, looping, false)) + goto success; + + if(cdValid && maxTrack > 0) + { + track = 1 + (rand() % maxTrack); + if(CDAudio_Play_real(track, looping, true)) + goto success; + } + else + { + Con_DPrint ("No CD in player.\n"); + } + return; + } + + // Try playing a fake track (sound file) first + if(track >= 1) + { + dpsnprintf(filename, sizeof(filename), "sound/cdtracks/track%03u.wav", track); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/track%03u.ogg", track); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/track%03u.ogg", track);// added by motorsep + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/cdtracks/track%03u.ogg", track);// added by motorsep + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/track%02u.wav", track); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/track%02u.ogg", track); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/track%02u.ogg", track);// added by motorsep + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/cdtracks/track%02u.ogg", track);// added by motorsep + } + else + { + dpsnprintf(filename, sizeof(filename), "%s", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "%s.wav", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "%s.ogg", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/%s", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/%s.wav", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/%s.ogg", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/%s", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/%s.wav", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "sound/cdtracks/%s.ogg", trackname); + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/%s.ogg", trackname); // added by motorsep + if (!FS_FileExists(filename)) dpsnprintf(filename, sizeof(filename), "music/cdtracks/%s.ogg", trackname); // added by motorsep + } + if (FS_FileExists(filename) && (sfx = S_PrecacheSound (filename, false, false))) + { + faketrack = S_StartSound_StartPosition_Flags (-1, 0, sfx, vec3_origin, cdvolume, 0, startposition, (looping ? CHANNELFLAG_FORCELOOP : 0) | CHANNELFLAG_FULLVOLUME | CHANNELFLAG_LOCALSOUND, 1.0f); + if (faketrack != -1) + { + if(track >= 1) + { + if(cdaudio.integer != 0) // we don't need these messages if only fake tracks can be played anyway + Con_DPrintf ("Fake CD track %u playing...\n", track); + } + else + Con_DPrintf ("BGM track %s playing...\n", trackname); + } + } + + // If we can't play a fake CD track, try the real one + if (faketrack == -1) + { + if(cdaudio.integer == 0 || track < 1) + { + Con_Print("Could not load BGM track.\n"); + return; + } + else + { + if(!CDAudio_Play_real(track, looping, true)) + return; + } + } + +success: + cdPlayLooping = looping; + cdPlayTrack = track; + cdPlaying = true; + + if (cdvolume == 0.0 || bgmvolume.value == 0) + CDAudio_Pause (); +} + +void CDAudio_Play (int track, qboolean looping) +{ + char buf[20]; + if (music_playlist_index.integer >= 0) + return; + dpsnprintf(buf, sizeof(buf), "%d", (int) track); + CDAudio_Play_byName(buf, looping, true, 0); +} + +float CDAudio_GetPosition (void) +{ + if(faketrack != -1) + return S_GetChannelPosition(faketrack); + return -1; +} + +static void CDAudio_StopPlaylistTrack(void); + +void CDAudio_Stop (void) +{ + if (!enabled) + return; + + // save the playlist position + CDAudio_StopPlaylistTrack(); + + if (faketrack != -1) + { + S_StopChannel (faketrack, true, true); + faketrack = -1; + } + else if (cdPlaying && (CDAudio_SysStop() == -1)) + return; + else if(wasPlaying) + { + CDAudio_Resume(); // needed by SDL - can't stop while paused there (causing pause/stop to fail after play, pause, stop, play otherwise) + if (cdPlaying && (CDAudio_SysStop() == -1)) + return; + } + + wasPlaying = false; + cdPlaying = false; +} + +void CDAudio_Pause (void) +{ + if (!enabled || !cdPlaying) + return; + + if (faketrack != -1) + S_SetChannelFlag (faketrack, CHANNELFLAG_PAUSED, true); + else if (CDAudio_SysPause() == -1) + return; + + wasPlaying = cdPlaying; + cdPlaying = false; +} + + +void CDAudio_Resume (void) +{ + if (!enabled || cdPlaying || !wasPlaying) + return; + + if (faketrack != -1) + S_SetChannelFlag (faketrack, CHANNELFLAG_PAUSED, false); + else if (CDAudio_SysResume() == -1) + return; + cdPlaying = true; +} + +static void CD_f (void) +{ + const char *command; +#ifdef MAXTRACKS + int ret; + int n; +#endif + + command = Cmd_Argv (1); + + if (strcasecmp(command, "remap") != 0) + Host_StartVideo(); + + if (strcasecmp(command, "on") == 0) + { + enabled = true; + return; + } + + if (strcasecmp(command, "off") == 0) + { + CDAudio_Stop(); + enabled = false; + return; + } + + if (strcasecmp(command, "reset") == 0) + { + enabled = true; + CDAudio_Stop(); +#ifdef MAXTRACKS + for (n = 0; n < MAXTRACKS; n++) + *remap[n] = 0; // empty string, that is, unremapped +#endif + CDAudio_GetAudioDiskInfo(); + return; + } + + if (strcasecmp(command, "rescan") == 0) + { + CDAudio_Shutdown(); + CDAudio_Startup(); + return; + } + + if (strcasecmp(command, "remap") == 0) + { +#ifdef MAXTRACKS + ret = Cmd_Argc() - 2; + if (ret <= 0) + { + for (n = 1; n < MAXTRACKS; n++) + if (*remap[n]) + Con_Printf(" %u -> %s\n", n, remap[n]); + return; + } + for (n = 1; n <= ret; n++) + strlcpy(remap[n], Cmd_Argv (n+1), sizeof(*remap)); +#endif + return; + } + + if (strcasecmp(command, "close") == 0) + { + CDAudio_CloseDoor(); + return; + } + + if (strcasecmp(command, "play") == 0) + { + if (music_playlist_index.integer >= 0) + return; + CDAudio_Play_byName(Cmd_Argv (2), false, true, (Cmd_Argc() > 3) ? atof( Cmd_Argv(3) ) : 0); + return; + } + + if (strcasecmp(command, "loop") == 0) + { + if (music_playlist_index.integer >= 0) + return; + CDAudio_Play_byName(Cmd_Argv (2), true, true, (Cmd_Argc() > 3) ? atof( Cmd_Argv(3) ) : 0); + return; + } + + if (strcasecmp(command, "stop") == 0) + { + if (music_playlist_index.integer >= 0) + return; + CDAudio_Stop(); + return; + } + + if (strcasecmp(command, "pause") == 0) + { + if (music_playlist_index.integer >= 0) + return; + CDAudio_Pause(); + return; + } + + if (strcasecmp(command, "resume") == 0) + { + if (music_playlist_index.integer >= 0) + return; + CDAudio_Resume(); + return; + } + + if (strcasecmp(command, "eject") == 0) + { + if (faketrack == -1) + CDAudio_Stop(); + CDAudio_Eject(); + cdValid = false; + return; + } + + if (strcasecmp(command, "info") == 0) + { + CDAudio_GetAudioDiskInfo (); + if (cdValid) + Con_Printf("%u tracks on CD.\n", maxTrack); + else + Con_Print ("No CD in player.\n"); + if (cdPlaying) + Con_Printf("Currently %s track %u\n", cdPlayLooping ? "looping" : "playing", cdPlayTrack); + else if (wasPlaying) + Con_Printf("Paused %s track %u\n", cdPlayLooping ? "looping" : "playing", cdPlayTrack); + if (cdvolume >= 0) + Con_Printf("Volume is %f\n", cdvolume); + else + Con_Printf("Can't get CD volume\n"); + return; + } + + Con_Printf("CD commands:\n"); + Con_Printf("cd on - enables CD audio system\n"); + Con_Printf("cd off - stops and disables CD audio system\n"); + Con_Printf("cd reset - resets CD audio system (clears track remapping and re-reads disc information)\n"); + Con_Printf("cd rescan - rescans disks in drives (to use another disc)\n"); + Con_Printf("cd remap [remap2] [remap3] [...] - chooses (possibly emulated) CD tracks to play when a map asks for a particular track, this has many uses\n"); + Con_Printf("cd close - closes CD tray\n"); + Con_Printf("cd eject - stops playing music and opens CD tray to allow you to change disc\n"); + Con_Printf("cd play - plays selected track in remapping table\n"); + Con_Printf("cd loop - plays and repeats selected track in remapping table\n"); + Con_Printf("cd stop - stops playing current CD track\n"); + Con_Printf("cd pause - pauses CD playback\n"); + Con_Printf("cd resume - unpauses CD playback\n"); + Con_Printf("cd info - prints basic disc information (number of tracks, currently playing track, volume level)\n"); +} + +static void CDAudio_SetVolume (float newvol) +{ + // If the volume hasn't changed + if (newvol == cdvolume) + return; + + // If the CD has been muted + if (newvol == 0.0f) + CDAudio_Pause (); + else + { + // If the CD has been unmuted + if (cdvolume == 0.0f) + CDAudio_Resume (); + + if (faketrack != -1) + S_SetChannelVolume (faketrack, newvol); + else + CDAudio_SysSetVolume (newvol * mastervolume.value); + } + + cdvolume = newvol; +} + +static void CDAudio_StopPlaylistTrack(void) +{ + if (music_playlist_active >= 0 && music_playlist_active < MAX_PLAYLISTS && music_playlist_sampleposition[music_playlist_active].value >= 0) + { + // save position for resume + float position = CDAudio_GetPosition(); + Cvar_SetValueQuick(&music_playlist_sampleposition[music_playlist_active], position >= 0 ? position : 0); + } + music_playlist_active = -1; + music_playlist_playing = 0; // not playing +} + +void CDAudio_StartPlaylist(qboolean resume) +{ + const char *list; + const char *t; + int index; + int current; + int randomplay; + int count; + int listindex; + float position; + char trackname[MAX_QPATH]; + CDAudio_Stop(); + index = music_playlist_index.integer; + if (index >= 0 && index < MAX_PLAYLISTS && bgmvolume.value > 0) + { + list = music_playlist_list[index].string; + current = music_playlist_current[index].integer; + randomplay = music_playlist_random[index].integer; + position = music_playlist_sampleposition[index].value; + count = 0; + trackname[0] = 0; + if (list && list[0]) + { + for (t = list;;count++) + { + if (!COM_ParseToken_Console(&t)) + break; + // if we don't find the desired track, use the first one + if (count == 0) + strlcpy(trackname, com_token, sizeof(trackname)); + } + } + if (count > 0) + { + // position < 0 means never resume track + if (position < 0) + position = 0; + // advance to next track in playlist if the last one ended + if (!resume) + { + position = 0; + current++; + if (randomplay) + current = (int)lhrandom(0, count); + } + // wrap playlist position if needed + if (current >= count) + current = 0; + // set current + Cvar_SetValueQuick(&music_playlist_current[index], current); + // get the Nth trackname + if (current >= 0 && current < count) + { + for (listindex = 0, t = list;;listindex++) + { + if (!COM_ParseToken_Console(&t)) + break; + if (listindex == current) + { + strlcpy(trackname, com_token, sizeof(trackname)); + break; + } + } + } + if (trackname[0]) + { + CDAudio_Play_byName(trackname, false, false, position); + if (faketrack != -1) + music_playlist_active = index; + } + } + } + music_playlist_playing = music_playlist_active >= 0 ? 1 : -1; +} + +void CDAudio_Update (void) +{ + static int lastplaylist = -1; + if (!enabled) + return; + + CDAudio_SetVolume (bgmvolume.value); + if (music_playlist_playing > 0 && CDAudio_GetPosition() < 0) + { + // this track ended, start a new track from the beginning + CDAudio_StartPlaylist(false); + lastplaylist = music_playlist_index.integer; + } + else if (lastplaylist != music_playlist_index.integer + || (bgmvolume.value > 0 && !music_playlist_playing && music_playlist_index.integer >= 0)) + { + // active playlist changed, save position and switch track + CDAudio_StartPlaylist(true); + lastplaylist = music_playlist_index.integer; + } + + if (faketrack == -1 && cdaudio.integer != 0 && bgmvolume.value != 0) + CDAudio_SysUpdate(); +} + +int CDAudio_Init (void) +{ + int i; + + if (cls.state == ca_dedicated) + return -1; + +// COMMANDLINEOPTION: Sound: -nocdaudio disables CD audio support + if (COM_CheckParm("-nocdaudio")) + return -1; + + CDAudio_SysInit(); + +#ifdef MAXTRACKS + for (i = 0; i < MAXTRACKS; i++) + *remap[i] = 0; +#endif + + Cvar_RegisterVariable(&cdaudio); + Cvar_RegisterVariable(&cdaudioinitialized); + Cvar_SetValueQuick(&cdaudioinitialized, true); + enabled = true; + + Cvar_RegisterVariable(&music_playlist_index); + for (i = 0;i < MAX_PLAYLISTS;i++) + { + Cvar_RegisterVariable(&music_playlist_list[i]); + Cvar_RegisterVariable(&music_playlist_current[i]); + Cvar_RegisterVariable(&music_playlist_random[i]); + Cvar_RegisterVariable(&music_playlist_sampleposition[i]); + } + + Cmd_AddCommand("cd", CD_f, "execute a CD drive command (cd on/off/reset/remap/close/play/loop/stop/pause/resume/eject/info) - use cd by itself for usage"); + + return 0; +} + +int CDAudio_Startup (void) +{ + if (COM_CheckParm("-nocdaudio")) + return -1; + + CDAudio_SysStartup (); + + if (CDAudio_GetAudioDiskInfo()) + { + Con_Print("CDAudio_Init: No CD in player.\n"); + cdValid = false; + } + + saved_vol = CDAudio_SysGetVolume (); + if (saved_vol < 0.0f) + { + Con_Print ("Can't get initial CD volume\n"); + saved_vol = 1.0f; + } + else + Con_Printf ("Initial CD volume: %g\n", saved_vol); + + initialized = true; + + Con_Print("CD Audio Initialized\n"); + + return 0; +} + +void CDAudio_Shutdown (void) +{ + if (!initialized) + return; + + CDAudio_SysSetVolume (saved_vol); + + CDAudio_Stop(); + CDAudio_SysShutdown(); + initialized = false; +} diff --git a/app/jni/cdaudio.h b/app/jni/cdaudio.h new file mode 100644 index 0000000..5eac430 --- /dev/null +++ b/app/jni/cdaudio.h @@ -0,0 +1,66 @@ +/* +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. + +*/ + +typedef struct cl_cdstate_s +{ + qboolean Valid; + qboolean Playing; + qboolean PlayLooping; + unsigned char PlayTrack; +} +cl_cdstate_t; + +//extern cl_cdstate_t cd; + +extern qboolean cdValid; +extern qboolean cdPlaying; +extern qboolean cdPlayLooping; +extern unsigned char cdPlayTrack; + +extern cvar_t cdaudioinitialized; + +int CDAudio_Init(void); +void CDAudio_Open(void); +void CDAudio_Close(void); +void CDAudio_Play(int track, qboolean looping); +void CDAudio_Play_byName (const char *trackname, qboolean looping, qboolean tryreal, float startposition); +void CDAudio_Stop(void); +void CDAudio_Pause(void); +void CDAudio_Resume(void); +int CDAudio_Startup(void); +void CDAudio_Shutdown(void); +void CDAudio_Update(void); +float CDAudio_GetPosition(void); +void CDAudio_StartPlaylist(qboolean resume); + +// Prototypes of the system dependent functions +void CDAudio_SysEject (void); +void CDAudio_SysCloseDoor (void); +int CDAudio_SysGetAudioDiskInfo (void); +float CDAudio_SysGetVolume (void); +void CDAudio_SysSetVolume (float volume); +int CDAudio_SysPlay (int track); +int CDAudio_SysStop (void); +int CDAudio_SysPause (void); +int CDAudio_SysResume (void); +int CDAudio_SysUpdate (void); +void CDAudio_SysInit (void); +int CDAudio_SysStartup (void); +void CDAudio_SysShutdown (void); diff --git a/app/jni/cflags.mk b/app/jni/cflags.mk new file mode 100644 index 0000000..2ea077b --- /dev/null +++ b/app/jni/cflags.mk @@ -0,0 +1,30 @@ +# This file is included in all .mk files to ensure their compilation flags are in sync +# across debug and release builds. + +# NOTE: this is not part of import_vrlib.mk because VRLib itself needs to have these flags +# set, but VRLib's make file cannot include import_vrlib.mk or it would be importing itself. + +LOCAL_CFLAGS := -DANDROID_NDK +LOCAL_CFLAGS += -Werror # error on warnings +LOCAL_CFLAGS += -Wall +LOCAL_CFLAGS += -Wextra +#LOCAL_CFLAGS += -Wlogical-op # not part of -Wall or -Wextra +#LOCAL_CFLAGS += -Weffc++ # too many issues to fix for now +LOCAL_CFLAGS += -Wno-strict-aliasing # TODO: need to rewrite some code +LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-missing-field-initializers # warns on this: SwipeAction ret = {} +LOCAL_CFLAGS += -Wno-multichar # used in internal Android headers: DISPLAY_EVENT_VSYNC = 'vsyn', +LOCAL_CPPFLAGS := -Wno-type-limits +LOCAL_CPPFLAGS += -Wno-invalid-offsetof + +# disable deprecation errors, but keep the warnings +LOCAL_CFLAGS += -Wno-error=deprecated-declarations + +ifeq ($(OVR_DEBUG),1) + LOCAL_CFLAGS += -DOVR_BUILD_DEBUG=1 -O0 -g +else + LOCAL_CFLAGS += -O3 +endif + +# Explicitly compile for the ARM and not the Thumb instruction set. +LOCAL_ARM_MODE := arm diff --git a/app/jni/cl_collision.c b/app/jni/cl_collision.c new file mode 100644 index 0000000..f0e0f7d --- /dev/null +++ b/app/jni/cl_collision.c @@ -0,0 +1,1079 @@ + +#include "quakedef.h" +#include "cl_collision.h" + +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +float CL_SelectTraceLine(const vec3_t start, const vec3_t pEnd, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent) +#else +float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent) +#endif +{ + float maxfrac, maxrealfrac; + int n; + entity_render_t *ent; + vec_t tracemins[3], tracemaxs[3]; + trace_t trace; + vec_t tempnormal[3], starttransformed[3], endtransformed[3]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#endif + + memset (&trace, 0 , sizeof(trace_t)); + trace.fraction = 1; + trace.realfraction = 1; + VectorCopy (end, trace.endpos); + + if (hitent) + *hitent = 0; + if (cl.worldmodel && cl.worldmodel->TraceLine) + cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID); + + if (normal) + VectorCopy(trace.plane.normal, normal); + maxfrac = trace.fraction; + maxrealfrac = trace.realfraction; + + tracemins[0] = min(start[0], end[0]); + tracemaxs[0] = max(start[0], end[0]); + tracemins[1] = min(start[1], end[1]); + tracemaxs[1] = max(start[1], end[1]); + tracemins[2] = min(start[2], end[2]); + tracemaxs[2] = max(start[2], end[2]); + + // look for embedded bmodels + for (n = 0;n < cl.num_entities;n++) + { + if (!cl.entities_active[n]) + continue; + ent = &cl.entities[n].render; + if (!BoxesOverlap(ent->mins, ent->maxs, tracemins, tracemaxs)) + continue; + if (!ent->model || !ent->model->TraceLine) + continue; + if ((ent->flags & RENDER_EXTERIORMODEL) && !chase_active.integer) + continue; + // if transparent and not selectable, skip entity + if (!(cl.entities[n].state_current.effects & EF_SELECTABLE) && (ent->alpha < 1 || (ent->effects & (EF_ADDITIVE | EF_NODEPTHTEST)))) + continue; + if (ent == ignoreent) + continue; + Matrix4x4_Transform(&ent->inversematrix, start, starttransformed); + Matrix4x4_Transform(&ent->inversematrix, end, endtransformed); + Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL); +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&trace, len / (len + collision_endposnudge.value), pEnd); +#endif + if (maxrealfrac < trace.realfraction) + continue; + + ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID); + + if (maxrealfrac > trace.realfraction) + { + if (hitent) + *hitent = n; + maxfrac = trace.fraction; + maxrealfrac = trace.realfraction; + if (normal) + { + VectorCopy(trace.plane.normal, tempnormal); + Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal); + } + } + } + maxfrac = bound(0, maxfrac, 1); + //maxrealfrac = bound(0, maxrealfrac, 1); + //if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__); + if (impact) + VectorLerp(start, maxfrac, end, impact); + return maxfrac; +} + +void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius) +{ + // FIXME: check multiple brush models + if (cl.worldmodel && cl.worldmodel->brush.FindNonSolidLocation) + cl.worldmodel->brush.FindNonSolidLocation(cl.worldmodel, in, out, radius); +} + +dp_model_t *CL_GetModelByIndex(int modelindex) +{ + if(!modelindex) + return NULL; + if (modelindex < 0) + { + modelindex = -(modelindex+1); + if (modelindex < MAX_MODELS) + return cl.csqc_model_precache[modelindex]; + } + else + { + if(modelindex < MAX_MODELS) + return cl.model_precache[modelindex]; + } + return NULL; +} + +dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed) +{ + prvm_prog_t *prog = CLVM_prog; + if (!ed || ed->priv.server->free) + return NULL; + return CL_GetModelByIndex((int)PRVM_clientedictfloat(ed, modelindex)); +} + +void CL_LinkEdict(prvm_edict_t *ent) +{ + prvm_prog_t *prog = CLVM_prog; + vec3_t mins, maxs; + + if (ent == prog->edicts) + return; // don't add the world + + if (ent->priv.server->free) + return; + + // set the abs box + + if (PRVM_clientedictfloat(ent, solid) == SOLID_BSP) + { + dp_model_t *model = CL_GetModelByIndex( (int)PRVM_clientedictfloat(ent, modelindex) ); + if (model == NULL) + { + Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent)); + + model = CL_GetModelByIndex( 0 ); + } + + if( model != NULL ) + { + if (!model->TraceBox) + Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); + + if (PRVM_clientedictvector(ent, angles)[0] || PRVM_clientedictvector(ent, angles)[2] || PRVM_clientedictvector(ent, avelocity)[0] || PRVM_clientedictvector(ent, avelocity)[2]) + { + VectorAdd(PRVM_clientedictvector(ent, origin), model->rotatedmins, mins); + VectorAdd(PRVM_clientedictvector(ent, origin), model->rotatedmaxs, maxs); + } + else if (PRVM_clientedictvector(ent, angles)[1] || PRVM_clientedictvector(ent, avelocity)[1]) + { + VectorAdd(PRVM_clientedictvector(ent, origin), model->yawmins, mins); + VectorAdd(PRVM_clientedictvector(ent, origin), model->yawmaxs, maxs); + } + else + { + VectorAdd(PRVM_clientedictvector(ent, origin), model->normalmins, mins); + VectorAdd(PRVM_clientedictvector(ent, origin), model->normalmaxs, maxs); + } + } + else + { + // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily + VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins); + VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs); + } + } + else + { + VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins); + VectorAdd(PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs); + } + + VectorCopy(mins, PRVM_clientedictvector(ent, absmin)); + VectorCopy(maxs, PRVM_clientedictvector(ent, absmax)); + + World_LinkEdict(&cl.world, ent, mins, maxs); +} + +int CL_GenericHitSuperContentsMask(const prvm_edict_t *passedict) +{ + prvm_prog_t *prog = CLVM_prog; + if (passedict) + { + int dphitcontentsmask = (int)PRVM_clientedictfloat(passedict, dphitcontentsmask); + if (dphitcontentsmask) + return dphitcontentsmask; + else if (PRVM_clientedictfloat(passedict, solid) == SOLID_SLIDEBOX) + { + if ((int)PRVM_clientedictfloat(passedict, flags) & FL_MONSTER) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP; + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP; + } + else if (PRVM_clientedictfloat(passedict, solid) == SOLID_CORPSE) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; + else if (PRVM_clientedictfloat(passedict, solid) == SOLID_TRIGGER) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; + } + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; +} + +/* +================== +CL_Move +================== +*/ +trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities) +{ + prvm_prog_t *prog = CLVM_prog; + int i, bodysupercontents; + int passedictprog; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may need conversion + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + + if (hitnetworkentity) + *hitnetworkentity = 0; + + VectorCopy(start, clipstart); + VectorClear(clipmins2); + VectorClear(clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]); +#endif + + // clip to world + Collision_ClipPointToWorld(&cliptrace, cl.worldmodel, clipstart, hitsupercontentsmask); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog ? prog->edicts : NULL; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = clipstart[i] - 1; + clipboxmaxs[i] = clipstart[i] + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + // this checks prog because this function is often called without a CSQC + // VM context + if (prog == NULL || passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0; + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL; + + // collide against network entities + if (hitnetworkbrushmodels) + { + for (i = 0;i < cl.num_brushmodel_entities;i++) + { + entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render; + if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs)) + continue; + Collision_ClipPointToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, hitsupercontentsmask); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = cl.brushmodel_entities[i]; + Collision_CombineTraces(&cliptrace, &trace, NULL, true); + } + } + + // collide against player entities + if (hitnetworkplayers) + { + vec3_t origin, entmins, entmaxs; + matrix4x4_t entmatrix, entinversematrix; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit network players, if we are a nonsolid player + if(cl.scores[cl.playerentity-1].frags == -666 || cl.scores[cl.playerentity-1].frags == -616) + goto skipnetworkplayers; + } + + for (i = 1;i <= cl.maxclients;i++) + { + entity_render_t *ent = &cl.entities[i].render; + + // don't hit ourselves + if (i == cl.playerentity) + continue; + + // don't hit players that don't exist + if (!cl.scores[i-1].name[0]) + continue; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit spectators or nonsolid players + if(cl.scores[i-1].frags == -666 || cl.scores[i-1].frags == -616) + continue; + } + + Matrix4x4_OriginFromMatrix(&ent->matrix, origin); + VectorAdd(origin, cl.playerstandmins, entmins); + VectorAdd(origin, cl.playerstandmaxs, entmaxs); + if (!BoxesOverlap(clipboxmins, clipboxmaxs, entmins, entmaxs)) + continue; + Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]); + Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]); + Collision_ClipPointToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, hitsupercontentsmask); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = i; + Collision_CombineTraces(&cliptrace, &trace, NULL, false); + } + +skipnetworkplayers: + ; + } + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + // note: if prog is NULL then there won't be any linked entities + numtouchedicts = 0; + if (hitcsqcentities && prog != NULL) + { + numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_clientedictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + model = CL_GetModelFromEdict(touch); + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VectorCopy(PRVM_clientedictvector(touch, mins), touchmins); + VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs); + if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask); + else + Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask); + + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = 0; + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP); + } + +finished: + return cliptrace; +} + +/* +================== +CL_TraceLine +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +trace_t CL_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces) +#else +trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces) +#endif +{ + prvm_prog_t *prog = CLVM_prog; + int i, bodysupercontents; + int passedictprog; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may need conversion + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if (VectorCompare(start, pEnd)) + return CL_TracePoint(start, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities); + + if(collision_endposnudge.value > 0) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#else + if (VectorCompare(start, end)) + return CL_TracePoint(start, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities); +#endif + + if (hitnetworkentity) + *hitnetworkentity = 0; + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); + VectorClear(clipmins2); + VectorClear(clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, hitsurfaces); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog ? prog->edicts : NULL; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + // this checks prog because this function is often called without a CSQC + // VM context + if (prog == NULL || passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0; + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL; + + // collide against network entities + if (hitnetworkbrushmodels) + { + for (i = 0;i < cl.num_brushmodel_entities;i++) + { + entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render; + if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs)) + continue; + Collision_ClipLineToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask, hitsurfaces); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = cl.brushmodel_entities[i]; + Collision_CombineTraces(&cliptrace, &trace, NULL, true); + } + } + + // collide against player entities + if (hitnetworkplayers) + { + vec3_t origin, entmins, entmaxs; + matrix4x4_t entmatrix, entinversematrix; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit network players, if we are a nonsolid player + if(cl.scores[cl.playerentity-1].frags == -666 || cl.scores[cl.playerentity-1].frags == -616) + goto skipnetworkplayers; + } + + for (i = 1;i <= cl.maxclients;i++) + { + entity_render_t *ent = &cl.entities[i].render; + + // don't hit ourselves + if (i == cl.playerentity) + continue; + + // don't hit players that don't exist + if (!cl.scores[i-1].name[0]) + continue; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit spectators or nonsolid players + if(cl.scores[i-1].frags == -666 || cl.scores[i-1].frags == -616) + continue; + } + + Matrix4x4_OriginFromMatrix(&ent->matrix, origin); + VectorAdd(origin, cl.playerstandmins, entmins); + VectorAdd(origin, cl.playerstandmaxs, entmaxs); + if (!BoxesOverlap(clipboxmins, clipboxmaxs, entmins, entmaxs)) + continue; + Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]); + Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]); + Collision_ClipLineToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, end, hitsupercontentsmask, hitsurfaces); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = i; + Collision_CombineTraces(&cliptrace, &trace, NULL, false); + } + +skipnetworkplayers: + ; + } + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + // note: if prog is NULL then there won't be any linked entities + numtouchedicts = 0; + if (hitcsqcentities && prog != NULL) + { + numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_clientedictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + model = CL_GetModelFromEdict(touch); + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VectorCopy(PRVM_clientedictvector(touch, mins), touchmins); + VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs); + if (type == MOVE_MISSILE && (int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask); + else + Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, hitsurfaces); + + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = 0; + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + +/* +================== +CL_Move +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities) +#else +trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities) +#endif +{ + prvm_prog_t *prog = CLVM_prog; + vec3_t hullmins, hullmaxs; + int i, bodysupercontents; + int passedictprog; + qboolean pointtrace; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may need conversion + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size of the moving object + vec3_t clipmins, clipmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if (VectorCompare(mins, maxs)) + { + vec3_t shiftstart, shiftend; + VectorAdd(start, mins, shiftstart); + VectorAdd(pEnd, mins, shiftend); + if (VectorCompare(start, pEnd)) + trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities); + else + trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false); + VectorSubtract(trace.endpos, mins, trace.endpos); + return trace; + } + + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#else + if (VectorCompare(mins, maxs)) + { + vec3_t shiftstart, shiftend; + VectorAdd(start, mins, shiftstart); + VectorAdd(end, mins, shiftend); + if (VectorCompare(start, end)) + trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities); + else + trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false); + VectorSubtract(trace.endpos, mins, trace.endpos); + return trace; + } +#endif + + if (hitnetworkentity) + *hitnetworkentity = 0; + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); + VectorCopy(mins, clipmins); + VectorCopy(maxs, clipmaxs); + VectorCopy(mins, clipmins2); + VectorCopy(maxs, clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_ClipToWorld(&cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog ? prog->edicts : NULL; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp + if (cl.worldmodel && cl.worldmodel->brush.RoundUpToHullSize) + cl.worldmodel->brush.RoundUpToHullSize(cl.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs); + else + { + VectorCopy(clipmins, hullmins); + VectorCopy(clipmaxs, hullmaxs); + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + // this checks prog because this function is often called without a CSQC + // VM context + if (prog == NULL || passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0; + // figure out whether this is a point trace for comparisons + pointtrace = VectorCompare(clipmins, clipmaxs); + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL; + + // collide against network entities + if (hitnetworkbrushmodels) + { + for (i = 0;i < cl.num_brushmodel_entities;i++) + { + entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render; + if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs)) + continue; + Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = cl.brushmodel_entities[i]; + Collision_CombineTraces(&cliptrace, &trace, NULL, true); + } + } + + // collide against player entities + if (hitnetworkplayers) + { + vec3_t origin, entmins, entmaxs; + matrix4x4_t entmatrix, entinversematrix; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit network players, if we are a nonsolid player + if(cl.scores[cl.playerentity-1].frags == -666 || cl.scores[cl.playerentity-1].frags == -616) + goto skipnetworkplayers; + } + + for (i = 1;i <= cl.maxclients;i++) + { + entity_render_t *ent = &cl.entities[i].render; + + // don't hit ourselves + if (i == cl.playerentity) + continue; + + // don't hit players that don't exist + if (!cl.scores[i-1].name[0]) + continue; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // don't hit spectators or nonsolid players + if(cl.scores[i-1].frags == -666 || cl.scores[i-1].frags == -616) + continue; + } + + Matrix4x4_OriginFromMatrix(&ent->matrix, origin); + VectorAdd(origin, cl.playerstandmins, entmins); + VectorAdd(origin, cl.playerstandmaxs, entmaxs); + if (!BoxesOverlap(clipboxmins, clipboxmaxs, entmins, entmaxs)) + continue; + Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]); + Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]); + Collision_ClipToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, mins, maxs, end, hitsupercontentsmask); + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = i; + Collision_CombineTraces(&cliptrace, &trace, NULL, false); + } + +skipnetworkplayers: + ; + } + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + // note: if prog is NULL then there won't be any linked entities + numtouchedicts = 0; + if (hitcsqcentities && prog != NULL) + { + numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_clientedictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_clientedictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (pointtrace && VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_clientedictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_clientedictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + model = CL_GetModelFromEdict(touch); + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VectorCopy(PRVM_clientedictvector(touch, mins), touchmins); + VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs); + if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask); + else + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask); + + if (cliptrace.realfraction > trace.realfraction && hitnetworkentity) + *hitnetworkentity = 0; + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + +/* +================== +CL_Cache_TraceLine +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t pEnd, int type, int hitsupercontentsmask) +#else +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask) +#endif +{ + prvm_prog_t *prog = CLVM_prog; + int i; + prvm_edict_t *touch; + trace_t trace; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if(collision_endposnudge.value > 0 && !VectorCompare(start, pEnd)) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#endif + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_Cache_ClipLineToWorldSurfaces(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog ? prog->edicts : NULL; + if (type == MOVE_WORLDONLY) + goto finished; + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + 1; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + // this checks prog because this function is often called without a CSQC + // VM context + + // collide against network entities + for (i = 0;i < cl.num_brushmodel_entities;i++) + { + entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render; + if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs)) + continue; + Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, ent->model, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask); + Collision_CombineTraces(&cliptrace, &trace, NULL, true); + } + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + // note: if prog is NULL then there won't be any linked entities + numtouchedicts = 0; + if (prog != NULL) + { + numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + // might interact, so do an exact clip + // only hit entity models, not collision shapes + model = CL_GetModelFromEdict(touch); + if (!model) + continue; + // animated models are too slow to collide against and can't be cached + if (touch->priv.server->frameblend || touch->priv.server->skeleton.relativetransforms) + continue; + if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP) + continue; + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, model, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask); + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + diff --git a/app/jni/cl_collision.h b/app/jni/cl_collision.h new file mode 100644 index 0000000..851502c --- /dev/null +++ b/app/jni/cl_collision.h @@ -0,0 +1,19 @@ + +#ifndef CL_COLLISION_H +#define CL_COLLISION_H + +float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent); +void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius); + +dp_model_t *CL_GetModelByIndex(int modelindex); +dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed); + +void CL_LinkEdict(prvm_edict_t *ent); +int CL_GenericHitSuperContentsMask(const prvm_edict_t *edict); +trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities); +trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces); +trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities); +trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask); +#define CL_PointSuperContents(point) (CL_TracePoint((point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL, 0, true, false, NULL, false).startsupercontents) + +#endif diff --git a/app/jni/cl_demo.c b/app/jni/cl_demo.c new file mode 100644 index 0000000..f30eff8 --- /dev/null +++ b/app/jni/cl_demo.c @@ -0,0 +1,617 @@ +/* +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 cl_capturevideo; +extern cvar_t cl_capturevideo_demo_stop; +int old_vsync = 0; + +static void CL_FinishTimeDemo (void); + +/* +============================================================================== + +DEMO CODE + +When a demo is playing back, all outgoing network messages are skipped, and +incoming messages are read from the demo file. + +Whenever cl.time gets past the last received message, another message is +read from the demo file. +============================================================================== +*/ + +/* +===================== +CL_NextDemo + +Called to play the next demo in the demo loop +===================== +*/ +void CL_NextDemo (void) +{ + char str[MAX_INPUTLINE]; + + if (cls.demonum == -1) + return; // don't play demos + + if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) + { + cls.demonum = 0; + if (!cls.demos[cls.demonum][0]) + { + Con_Print("No demos listed with startdemos\n"); + cls.demonum = -1; + return; + } + } + + dpsnprintf (str, sizeof(str), "playdemo %s\n", cls.demos[cls.demonum]); + Cbuf_InsertText (str); + cls.demonum++; +} + +/* +============== +CL_StopPlayback + +Called when a demo file runs out, or the user starts a game +============== +*/ +// LordHavoc: now called only by CL_Disconnect +void CL_StopPlayback (void) +{ + if (cl_capturevideo_demo_stop.integer) + Cvar_Set("cl_capturevideo", "0"); + + if (!cls.demoplayback) + return; + + FS_Close (cls.demofile); + cls.demoplayback = false; + cls.demofile = NULL; + + if (cls.timedemo) + CL_FinishTimeDemo (); + + if (!cls.demostarting) // only quit if not starting another demo + if (COM_CheckParm("-demo") || COM_CheckParm("-capturedemo")) + Host_Quit_f(); + +} + +/* +==================== +CL_WriteDemoMessage + +Dumps the current net message, prefixed by the length and view angles +#==================== +*/ +void CL_WriteDemoMessage (sizebuf_t *message) +{ + int len; + int i; + float f; + + if (cls.demopaused) // LordHavoc: pausedemo + return; + + len = LittleLong (message->cursize); + FS_Write (cls.demofile, &len, 4); + for (i=0 ; i<3 ; i++) + { + f = LittleFloat (cl.viewangles[i]); + FS_Write (cls.demofile, &f, 4); + } + FS_Write (cls.demofile, message->data, message->cursize); +} + +/* +==================== +CL_CutDemo + +Dumps the current demo to a buffer, and resets the demo to its starting point. +Used to insert csprogs.dat files as a download to the beginning of a demo file. +==================== +*/ +void CL_CutDemo (unsigned char **buf, fs_offset_t *filesize) +{ + *buf = NULL; + *filesize = 0; + + FS_Close(cls.demofile); + *buf = FS_LoadFile(cls.demoname, tempmempool, false, filesize); + + // restart the demo recording + cls.demofile = FS_OpenRealFile(cls.demoname, "wb", false); + if(!cls.demofile) + Sys_Error("failed to reopen the demo file"); + FS_Printf(cls.demofile, "%i\n", cls.forcetrack); +} + +/* +==================== +CL_PasteDemo + +Adds the cut stuff back to the demo. Also frees the buffer. +Used to insert csprogs.dat files as a download to the beginning of a demo file. +==================== +*/ +void CL_PasteDemo (unsigned char **buf, fs_offset_t *filesize) +{ + fs_offset_t startoffset = 0; + + if(!*buf) + return; + + // skip cdtrack + while(startoffset < *filesize && ((char *)(*buf))[startoffset] != '\n') + ++startoffset; + if(startoffset < *filesize) + ++startoffset; + + FS_Write(cls.demofile, *buf + startoffset, *filesize - startoffset); + + Mem_Free(*buf); + *buf = NULL; + *filesize = 0; +} + +/* +==================== +CL_ReadDemoMessage + +Handles playback of demos +==================== +*/ +void CL_ReadDemoMessage(void) +{ + int i; + float f; + + if (!cls.demoplayback) + return; + + // LordHavoc: pausedemo + if (cls.demopaused) + return; + + for (;;) + { + // decide if it is time to grab the next message + // always grab until fully connected + if (cls.signon == SIGNONS) + { + if (cls.timedemo) + { + cls.td_frames++; + cls.td_onesecondframes++; + // if this is the first official frame we can now grab the real + // td_starttime so the bogus time on the first frame doesn't + // count against the final report + if (cls.td_frames == 0) + { + cls.td_starttime = realtime; + cls.td_onesecondnexttime = cl.time + 1; + cls.td_onesecondrealtime = realtime; + cls.td_onesecondframes = 0; + cls.td_onesecondminfps = 0; + cls.td_onesecondmaxfps = 0; + cls.td_onesecondavgfps = 0; + cls.td_onesecondavgcount = 0; + } + if (cl.time >= cls.td_onesecondnexttime) + { + double fps = cls.td_onesecondframes / (realtime - cls.td_onesecondrealtime); + if (cls.td_onesecondavgcount == 0) + { + cls.td_onesecondminfps = fps; + cls.td_onesecondmaxfps = fps; + } + cls.td_onesecondrealtime = realtime; + cls.td_onesecondminfps = min(cls.td_onesecondminfps, fps); + cls.td_onesecondmaxfps = max(cls.td_onesecondmaxfps, fps); + cls.td_onesecondavgfps += fps; + cls.td_onesecondavgcount++; + cls.td_onesecondframes = 0; + cls.td_onesecondnexttime++; + } + } + else if (cl.time <= cl.mtime[0]) + { + // don't need another message yet + return; + } + } + + // get the next message + FS_Read(cls.demofile, &cl_message.cursize, 4); + cl_message.cursize = LittleLong(cl_message.cursize); + if(cl_message.cursize & DEMOMSG_CLIENT_TO_SERVER) // This is a client->server message! Ignore for now! + { + // skip over demo packet + FS_Seek(cls.demofile, 12 + (cl_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR); + continue; + } + if (cl_message.cursize > cl_message.maxsize) + { + Con_Printf("Demo message (%i) > cl_message.maxsize (%i)", cl_message.cursize, cl_message.maxsize); + cl_message.cursize = 0; + CL_Disconnect(); + return; + } + VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); + for (i = 0;i < 3;i++) + { + FS_Read(cls.demofile, &f, 4); + cl.mviewangles[0][i] = LittleFloat(f); + } + + if (FS_Read(cls.demofile, cl_message.data, cl_message.cursize) == cl_message.cursize) + { + MSG_BeginReading(&cl_message); + CL_ParseServerMessage(); + + if (cls.signon != SIGNONS) + Cbuf_Execute(); // immediately execute svc_stufftext if in the demo before connect! + + // In case the demo contains a "svc_disconnect" message + if (!cls.demoplayback) + return; + + if (cls.timedemo) + return; + } + else + { + CL_Disconnect(); + return; + } + } +} + + +/* +==================== +CL_Stop_f + +stop recording a demo +==================== +*/ +void CL_Stop_f (void) +{ + sizebuf_t buf; + unsigned char bufdata[64]; + + if (!cls.demorecording) + { + Con_Print("Not recording a demo.\n"); + return; + } + +// write a disconnect message to the demo file + // LordHavoc: don't replace the cl_message when doing this + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + SZ_Clear(&buf); + MSG_WriteByte(&buf, svc_disconnect); + CL_WriteDemoMessage(&buf); + +// finish up + if(cl_autodemo.integer && (cl_autodemo_delete.integer & 1)) + { + FS_RemoveOnClose(cls.demofile); + Con_Print("Completed and deleted demo\n"); + } + else + Con_Print("Completed demo\n"); + FS_Close (cls.demofile); + cls.demofile = NULL; + cls.demorecording = false; +} + +/* +==================== +CL_Record_f + +record [cd track] +==================== +*/ +void CL_Record_f (void) +{ + int c, track; + char name[MAX_OSPATH]; + char vabuf[1024]; + + c = Cmd_Argc(); + if (c != 2 && c != 3 && c != 4) + { + Con_Print("record [ [cd track]]\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Print("Relative pathnames are not allowed.\n"); + return; + } + + if (c == 2 && cls.state == ca_connected) + { + Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); + return; + } + + if (cls.state == ca_connected) + CL_Disconnect(); + + // 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; + + // get the demo name + strlcpy (name, Cmd_Argv(1), sizeof (name)); + FS_DefaultExtension (name, ".dem", sizeof (name)); + + // start the map up + if (c > 2) + Cmd_ExecuteString ( va(vabuf, sizeof(vabuf), "map %s", Cmd_Argv(2)), src_command, false); + + // open the demo file + Con_Printf("recording to %s.\n", name); + cls.demofile = FS_OpenRealFile(name, "wb", false); + if (!cls.demofile) + { + Con_Print("ERROR: couldn't open.\n"); + return; + } + strlcpy(cls.demoname, name, sizeof(cls.demoname)); + + cls.forcetrack = track; + FS_Printf(cls.demofile, "%i\n", cls.forcetrack); + + cls.demorecording = true; + cls.demo_lastcsprogssize = -1; + cls.demo_lastcsprogscrc = -1; +} + + +/* +==================== +CL_PlayDemo_f + +play [demoname] +==================== +*/ +void CL_PlayDemo_f (void) +{ + char name[MAX_QPATH]; + int c; + qboolean neg = false; + qfile_t *f; + + if (Cmd_Argc() != 2) + { + Con_Print("play : plays a demo\n"); + return; + } + + // open the demo file + strlcpy (name, Cmd_Argv(1), sizeof (name)); + FS_DefaultExtension (name, ".dem", sizeof (name)); + f = FS_OpenVirtualFile(name, false); + if (!f) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + cls.demonum = -1; // stop demo loop + return; + } + + cls.demostarting = true; + + // disconnect from server + CL_Disconnect (); + Host_ShutdownServer (); + + // update networking ports (this is mainly just needed at startup) + NetConn_UpdateSockets(); + + cls.protocol = PROTOCOL_QUAKE; + + Con_Printf("Playing demo %s.\n", name); + cls.demofile = f; + strlcpy(cls.demoname, name, sizeof(cls.demoname)); + + cls.demoplayback = true; + cls.state = ca_connected; + cls.forcetrack = 0; + + while ((c = FS_Getc (cls.demofile)) != '\n') + if (c == '-') + neg = true; + else + cls.forcetrack = cls.forcetrack * 10 + (c - '0'); + + if (neg) + cls.forcetrack = -cls.forcetrack; + + cls.demostarting = false; +} + +typedef struct +{ + int frames; + double time, totalfpsavg; + double fpsmin, fpsavg, fpsmax; +} +benchmarkhistory_t; +static size_t doublecmp_offset; +static int doublecmp_withoffset(const void *a_, const void *b_) +{ + const double *a = (const double *) ((const char *) a_ + doublecmp_offset); + const double *b = (const double *) ((const char *) b_ + doublecmp_offset); + if(*a > *b) + return +1; + if(*a < *b) + return -1; + return 0; +} + +/* +==================== +CL_FinishTimeDemo + +==================== +*/ +static void CL_FinishTimeDemo (void) +{ + int frames; + int i; + double time, totalfpsavg; + double fpsmin, fpsavg, fpsmax; // report min/avg/max fps + static int benchmark_runs = 0; + char vabuf[1024]; + + cls.timedemo = false; + + frames = cls.td_frames; + time = realtime - cls.td_starttime; + totalfpsavg = time > 0 ? frames / time : 0; + fpsmin = cls.td_onesecondminfps; + fpsavg = cls.td_onesecondavgcount ? cls.td_onesecondavgfps / cls.td_onesecondavgcount : 0; + fpsmax = cls.td_onesecondmaxfps; + // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max + Con_Printf("%i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); + Log_Printf("benchmark.log", "date %s | enginedate %s | demo %s | commandline %s | run %d | result %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", Sys_TimeString("%Y-%m-%d %H:%M:%S"), buildstring, cls.demoname, cmdline.string, benchmark_runs + 1, frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); + if (COM_CheckParm("-benchmark")) + { + ++benchmark_runs; + i = COM_CheckParm("-benchmarkruns"); + if(i && i + 1 < com_argc) + { + static benchmarkhistory_t *history = NULL; + if(!history) + history = (benchmarkhistory_t *)Z_Malloc(sizeof(*history) * atoi(com_argv[i + 1])); + + history[benchmark_runs - 1].frames = frames; + history[benchmark_runs - 1].time = time; + history[benchmark_runs - 1].totalfpsavg = totalfpsavg; + history[benchmark_runs - 1].fpsmin = fpsmin; + history[benchmark_runs - 1].fpsavg = fpsavg; + history[benchmark_runs - 1].fpsmax = fpsmax; + + if(atoi(com_argv[i + 1]) > benchmark_runs) + { + // restart the benchmark + Cbuf_AddText(va(vabuf, sizeof(vabuf), "timedemo %s\n", cls.demoname)); + // cannot execute here + } + else + { + // print statistics + int first = COM_CheckParm("-benchmarkruns_skipfirst") ? 1 : 0; + if(benchmark_runs > first) + { +#define DO_MIN(f) \ + for(i = first; i < benchmark_runs; ++i) if((i == first) || (history[i].f < f)) f = history[i].f + +#define DO_MAX(f) \ + for(i = first; i < benchmark_runs; ++i) if((i == first) || (history[i].f > f)) f = history[i].f + +#define DO_MED(f) \ + doublecmp_offset = (char *)&history->f - (char *)history; \ + qsort(history + first, benchmark_runs - first, sizeof(*history), doublecmp_withoffset); \ + if((first + benchmark_runs) & 1) \ + f = history[(first + benchmark_runs - 1) / 2].f; \ + else \ + f = (history[(first + benchmark_runs - 2) / 2].f + history[(first + benchmark_runs) / 2].f) / 2 + + DO_MIN(frames); + DO_MAX(time); + DO_MIN(totalfpsavg); + DO_MIN(fpsmin); + DO_MIN(fpsavg); + DO_MIN(fpsmax); + Con_Printf("MIN: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); + + DO_MED(frames); + DO_MED(time); + DO_MED(totalfpsavg); + DO_MED(fpsmin); + DO_MED(fpsavg); + DO_MED(fpsmax); + Con_Printf("MED: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); + + DO_MAX(frames); + DO_MIN(time); + DO_MAX(totalfpsavg); + DO_MAX(fpsmin); + DO_MAX(fpsavg); + DO_MAX(fpsmax); + Con_Printf("MAX: %i frames %5.7f seconds %5.7f fps, one-second fps min/avg/max: %.0f %.0f %.0f (%i seconds)\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax, cls.td_onesecondavgcount); + } + Z_Free(history); + history = NULL; + Host_Quit_f(); + } + } + else + Host_Quit_f(); + } +} + +/* +==================== +CL_TimeDemo_f + +timedemo [demoname] +==================== +*/ +void CL_TimeDemo_f (void) +{ + if (Cmd_Argc() != 2) + { + Con_Print("timedemo : gets demo speeds\n"); + return; + } + + srand(0); // predictable random sequence for benchmarking + + 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 + + // instantly hide console and deactivate it + key_dest = key_game; + key_consoleactive = 0; + scr_con_current = 0; + + cls.timedemo = true; + cls.td_frames = -2; // skip the first frame + cls.demonum = -1; // stop demo loop +} + diff --git a/app/jni/cl_dyntexture.c b/app/jni/cl_dyntexture.c new file mode 100644 index 0000000..fb378de --- /dev/null +++ b/app/jni/cl_dyntexture.c @@ -0,0 +1,93 @@ +// Andreas Kirsch 07 + +#include "quakedef.h" +#include "cl_dyntexture.h" + +typedef struct dyntexture_s { + // everything after DYNAMIC_TEXTURE_PATH_PREFIX + char name[ MAX_QPATH + 32 ]; + // texture pointer (points to r_texture_white at first) + rtexture_t *texture; +} dyntexture_t; + +static dyntexture_t dyntextures[ MAX_DYNAMIC_TEXTURE_COUNT ]; +static unsigned dyntexturecount; + +#define DEFAULT_DYNTEXTURE r_texture_grey128 + +static dyntexture_t * cl_finddyntexture( const char *name, qboolean warnonfailure ) { + unsigned i; + dyntexture_t *dyntexture = NULL; + + // sanity checks - make sure its actually a dynamic texture path + if( !name || !*name || strncmp( name, CLDYNTEXTUREPREFIX, sizeof( CLDYNTEXTUREPREFIX ) - 1 ) != 0 ) { + // TODO: print a warning or something + if (warnonfailure) + Con_Printf( "cl_finddyntexture: Bad dynamic texture name '%s'\n", name ); + return NULL; + } + + for( i = 0 ; i < dyntexturecount ; i++ ) { + dyntexture = &dyntextures[ i ]; + if( dyntexture->name && strcmp( dyntexture->name, name ) == 0 ) { + return dyntexture; + } + } + + if( dyntexturecount == MAX_DYNAMIC_TEXTURE_COUNT ) { + // TODO: warn or expand the array, etc. + return NULL; + } + dyntexture = &dyntextures[ dyntexturecount++ ]; + strlcpy( dyntexture->name, name, sizeof( dyntexture->name ) ); + dyntexture->texture = DEFAULT_DYNTEXTURE; + return dyntexture; +} + +rtexture_t * CL_GetDynTexture( const char *name ) { + dyntexture_t *dyntexture = cl_finddyntexture( name, false ); + if( dyntexture ) { + return dyntexture->texture; + } else { + return NULL; + } +} + +void CL_LinkDynTexture( const char *name, rtexture_t *texture ) { + dyntexture_t *dyntexture; + cachepic_t *cachepic; + skinframe_t *skinframe; + + dyntexture = cl_finddyntexture( name, true ); + if( !dyntexture ) { + Con_Printf( "CL_LinkDynTexture: internal error in cl_finddyntexture!\n" ); + return; + } + // TODO: assert dyntexture != NULL! + if( dyntexture->texture != texture ) { + dyntexture->texture = texture; + + cachepic = Draw_CachePic_Flags( name, CACHEPICFLAG_NOTPERSISTENT ); + // TODO: assert cachepic and skinframe should be valid pointers... + // TODO: assert cachepic->tex = dyntexture->texture + cachepic->tex = texture; + // update cachepic's size, too + cachepic->width = R_TextureWidth( texture ); + cachepic->height = R_TextureHeight( texture ); + + // update skinframes + skinframe = NULL; + while( (skinframe = R_SkinFrame_FindNextByName( skinframe, name )) != NULL ) { + skinframe->base = texture; + // simply reset the compare* attributes of skinframe + skinframe->comparecrc = 0; + skinframe->comparewidth = skinframe->compareheight = 0; + // this is kind of hacky + } + } +} + +void CL_UnlinkDynTexture( const char *name ) { + CL_LinkDynTexture( name, DEFAULT_DYNTEXTURE ); +} + diff --git a/app/jni/cl_dyntexture.h b/app/jni/cl_dyntexture.h new file mode 100644 index 0000000..130dc16 --- /dev/null +++ b/app/jni/cl_dyntexture.h @@ -0,0 +1,20 @@ +// Andreas 'Black' Kirsch 07 +#ifndef CL_DYNTEXTURE_H +#define CL_DYNTEXTURE_H + +#define CLDYNTEXTUREPREFIX "_dynamic/" + +// always path fully specified names to the dynamic texture functions! (ie. with the _dynamic/ prefix, etc.!) + +// return a valid texture handle for a dynamic texture (might be filler texture if it hasnt been initialized yet) +// or NULL if its not a valid dynamic texture name +rtexture_t * CL_GetDynTexture( const char *name ); + +// link a texture handle as dynamic texture and update texture handles in the renderer and draw_* accordingly +void CL_LinkDynTexture( const char *name, rtexture_t *texture ); + +// unlink a texture handle from its name +void CL_UnlinkDynTexture( const char *name ); + +#endif + diff --git a/app/jni/cl_input.c b/app/jni/cl_input.c new file mode 100644 index 0000000..1c87f43 --- /dev/null +++ b/app/jni/cl_input.c @@ -0,0 +1,2297 @@ +/* +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" +#include "csprogs.h" +#include "thread.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_jump, in_attack, in_use; +kbutton_t in_up, in_down; +// LordHavoc: added 6 new buttons +kbutton_t in_button3, in_button4, in_button5, in_button6, in_button7, in_button8; +//even more +kbutton_t in_button9, in_button10, in_button11, in_button12, in_button13, in_button14, in_button15, in_button16; + +int in_impulse; + + + +static void KeyDown (kbutton_t *b) +{ + int k; + const 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_Print("Three keys down for a button!\n"); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +static void KeyUp (kbutton_t *b) +{ + int k; + const 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 +} + +static void IN_KLookDown (void) {KeyDown(&in_klook);} +static void IN_KLookUp (void) {KeyUp(&in_klook);} +static void IN_MLookDown (void) {KeyDown(&in_mlook);} +static void IN_MLookUp (void) +{ + KeyUp(&in_mlook); + if ( !(in_mlook.state&1) && lookspring.value) + V_StartPitchDrift(); +} +static void IN_UpDown(void) {KeyDown(&in_up);} +static void IN_UpUp(void) {KeyUp(&in_up);} +static void IN_DownDown(void) {KeyDown(&in_down);} +static void IN_DownUp(void) {KeyUp(&in_down);} +static void IN_LeftDown(void) {KeyDown(&in_left);} +static void IN_LeftUp(void) {KeyUp(&in_left);} +static void IN_RightDown(void) {KeyDown(&in_right);} +static void IN_RightUp(void) {KeyUp(&in_right);} +static void IN_ForwardDown(void) {KeyDown(&in_forward);} +static void IN_ForwardUp(void) {KeyUp(&in_forward);} +static void IN_BackDown(void) {KeyDown(&in_back);} +static void IN_BackUp(void) {KeyUp(&in_back);} +static void IN_LookupDown(void) {KeyDown(&in_lookup);} +static void IN_LookupUp(void) {KeyUp(&in_lookup);} +static void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +static void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +static void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} +static void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} +static void IN_MoverightDown(void) {KeyDown(&in_moveright);} +static void IN_MoverightUp(void) {KeyUp(&in_moveright);} + +static void IN_SpeedDown(void) {KeyDown(&in_speed);} +static void IN_SpeedUp(void) {KeyUp(&in_speed);} +static void IN_StrafeDown(void) {KeyDown(&in_strafe);} +static void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +static void IN_AttackDown(void) {KeyDown(&in_attack);} +static void IN_AttackUp(void) {KeyUp(&in_attack);} + +static void IN_UseDown(void) {KeyDown(&in_use);} +static void IN_UseUp(void) {KeyUp(&in_use);} + +// LordHavoc: added 6 new buttons +static void IN_Button3Down(void) {KeyDown(&in_button3);} +static void IN_Button3Up(void) {KeyUp(&in_button3);} +static void IN_Button4Down(void) {KeyDown(&in_button4);} +static void IN_Button4Up(void) {KeyUp(&in_button4);} +static void IN_Button5Down(void) {KeyDown(&in_button5);} +static void IN_Button5Up(void) {KeyUp(&in_button5);} +static void IN_Button6Down(void) {KeyDown(&in_button6);} +static void IN_Button6Up(void) {KeyUp(&in_button6);} +static void IN_Button7Down(void) {KeyDown(&in_button7);} +static void IN_Button7Up(void) {KeyUp(&in_button7);} +static void IN_Button8Down(void) {KeyDown(&in_button8);} +static void IN_Button8Up(void) {KeyUp(&in_button8);} + +static void IN_Button9Down(void) {KeyDown(&in_button9);} +static void IN_Button9Up(void) {KeyUp(&in_button9);} +static void IN_Button10Down(void) {KeyDown(&in_button10);} +static void IN_Button10Up(void) {KeyUp(&in_button10);} +static void IN_Button11Down(void) {KeyDown(&in_button11);} +static void IN_Button11Up(void) {KeyUp(&in_button11);} +static void IN_Button12Down(void) {KeyDown(&in_button12);} +static void IN_Button12Up(void) {KeyUp(&in_button12);} +static void IN_Button13Down(void) {KeyDown(&in_button13);} +static void IN_Button13Up(void) {KeyUp(&in_button13);} +static void IN_Button14Down(void) {KeyDown(&in_button14);} +static void IN_Button14Up(void) {KeyUp(&in_button14);} +static void IN_Button15Down(void) {KeyDown(&in_button15);} +static void IN_Button15Up(void) {KeyUp(&in_button15);} +static void IN_Button16Down(void) {KeyDown(&in_button16);} +static void IN_Button16Up(void) {KeyUp(&in_button16);} + +static void IN_JumpDown (void) {KeyDown(&in_jump);} +static void IN_JumpUp (void) {KeyUp(&in_jump);} + +static void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));} + +in_bestweapon_info_t in_bestweapon_info[IN_BESTWEAPON_MAX]; + +static void IN_BestWeapon_Register(const char *name, int impulse, int weaponbit, int activeweaponcode, int ammostat, int ammomin) +{ + int i; + for(i = 0; i < IN_BESTWEAPON_MAX && in_bestweapon_info[i].impulse; ++i) + if(in_bestweapon_info[i].impulse == impulse) + break; + if(i >= IN_BESTWEAPON_MAX) + { + Con_Printf("no slot left for weapon definition; increase IN_BESTWEAPON_MAX\n"); + return; // sorry + } + strlcpy(in_bestweapon_info[i].name, name, sizeof(in_bestweapon_info[i].name)); + in_bestweapon_info[i].impulse = impulse; + if(weaponbit != -1) + in_bestweapon_info[i].weaponbit = weaponbit; + if(activeweaponcode != -1) + in_bestweapon_info[i].activeweaponcode = activeweaponcode; + if(ammostat != -1) + in_bestweapon_info[i].ammostat = ammostat; + if(ammomin != -1) + in_bestweapon_info[i].ammomin = ammomin; +} + +void IN_BestWeapon_ResetData (void) +{ + memset(in_bestweapon_info, 0, sizeof(in_bestweapon_info)); + IN_BestWeapon_Register("1", 1, IT_AXE, IT_AXE, STAT_SHELLS, 0); + IN_BestWeapon_Register("2", 2, IT_SHOTGUN, IT_SHOTGUN, STAT_SHELLS, 1); + IN_BestWeapon_Register("3", 3, IT_SUPER_SHOTGUN, IT_SUPER_SHOTGUN, STAT_SHELLS, 1); + IN_BestWeapon_Register("4", 4, IT_NAILGUN, IT_NAILGUN, STAT_NAILS, 1); + IN_BestWeapon_Register("5", 5, IT_SUPER_NAILGUN, IT_SUPER_NAILGUN, STAT_NAILS, 1); + IN_BestWeapon_Register("6", 6, IT_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER, STAT_ROCKETS, 1); + IN_BestWeapon_Register("7", 7, IT_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER, STAT_ROCKETS, 1); + IN_BestWeapon_Register("8", 8, IT_LIGHTNING, IT_LIGHTNING, STAT_CELLS, 1); + IN_BestWeapon_Register("9", 9, 128, 128, STAT_CELLS, 1); // generic energy weapon for mods + IN_BestWeapon_Register("p", 209, 128, 128, STAT_CELLS, 1); // dpmod plasma gun + IN_BestWeapon_Register("w", 210, 8388608, 8388608, STAT_CELLS, 1); // dpmod plasma wave cannon + IN_BestWeapon_Register("l", 225, HIT_LASER_CANNON, HIT_LASER_CANNON, STAT_CELLS, 1); // hipnotic laser cannon + IN_BestWeapon_Register("h", 226, HIT_MJOLNIR, HIT_MJOLNIR, STAT_CELLS, 0); // hipnotic mjolnir hammer +} + +static void IN_BestWeapon_Register_f (void) +{ + if(Cmd_Argc() == 7) + { + IN_BestWeapon_Register( + Cmd_Argv(1), + atoi(Cmd_Argv(2)), + atoi(Cmd_Argv(3)), + atoi(Cmd_Argv(4)), + atoi(Cmd_Argv(5)), + atoi(Cmd_Argv(6)) + ); + } + else if(Cmd_Argc() == 2 && !strcmp(Cmd_Argv(1), "clear")) + { + memset(in_bestweapon_info, 0, sizeof(in_bestweapon_info)); + } + else if(Cmd_Argc() == 2 && !strcmp(Cmd_Argv(1), "quake")) + { + IN_BestWeapon_ResetData(); + } + else + { + Con_Printf("Usage: %s weaponshortname impulse itemcode activeweaponcode ammostat ammomin; %s clear; %s quake\n", Cmd_Argv(0), Cmd_Argv(0), Cmd_Argv(0)); + } +} + +static void IN_BestWeapon (void) +{ + int i, n; + const char *t; + if (Cmd_Argc() < 2) + { + Con_Printf("bestweapon requires 1 or more parameters\n"); + return; + } + for (i = 1;i < Cmd_Argc();i++) + { + t = Cmd_Argv(i); + // figure out which weapon this character refers to + for (n = 0;n < IN_BESTWEAPON_MAX && in_bestweapon_info[n].impulse;n++) + { + if (!strcmp(in_bestweapon_info[n].name, t)) + { + // we found out what weapon this character refers to + // check if the inventory contains the weapon and enough ammo + if ((cl.stats[STAT_ITEMS] & in_bestweapon_info[n].weaponbit) && (cl.stats[in_bestweapon_info[n].ammostat] >= in_bestweapon_info[n].ammomin)) + { + // we found one of the weapons the player wanted + // send an impulse to switch to it + in_impulse = in_bestweapon_info[n].impulse; + return; + } + break; + } + } + // if we couldn't identify the weapon we just ignore it and continue checking for other weapons + } + // if we couldn't find any of the weapons, there's nothing more we can do... +} + +#if 0 +void IN_CycleWeapon (void) +{ + int i, n; + int first = -1; + qboolean found = false; + const char *t; + if (Cmd_Argc() < 2) + { + Con_Printf("bestweapon requires 1 or more parameters\n"); + return; + } + for (i = 1;i < Cmd_Argc();i++) + { + t = Cmd_Argv(i); + // figure out which weapon this character refers to + for (n = 0;n < IN_BESTWEAPON_MAX && in_bestweapon_info[n].impulse;n++) + { + if (!strcmp(in_bestweapon_info[n].name, t)) + { + // we found out what weapon this character refers to + // check if the inventory contains the weapon and enough ammo + if ((cl.stats[STAT_ITEMS] & in_bestweapon_info[n].weaponbit) && (cl.stats[in_bestweapon_info[n].ammostat] >= in_bestweapon_info[n].ammomin)) + { + // we found one of the weapons the player wanted + if(first == -1) + first = n; + if(found) + { + in_impulse = in_bestweapon_info[n].impulse; + return; + } + if(cl.stats[STAT_ACTIVEWEAPON] == in_bestweapon_info[n].activeweaponcode) + found = true; + } + break; + } + } + // if we couldn't identify the weapon we just ignore it and continue checking for other weapons + } + if(first != -1) + { + in_impulse = in_bestweapon_info[first].impulse; + return; + } + // if we couldn't find any of the weapons, there's nothing more we can do... +} +#endif + +/* +=============== +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 +=============== +*/ +extern float analogx; +extern float analogy; +extern int analogenabled; + +float CL_KeyState (kbutton_t *key) +{ + float val; + qboolean impulsedown, impulseup, down; + + impulsedown = (key->state & 2) != 0; + impulseup = (key->state & 4) != 0; + down = (key->state & 1) != 0; + 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 + + //ANALOG + if (analogenabled) + { + if (key==&in_moveright) + return max(0,analogx); + if (key==&in_moveleft) + return max(0,-analogx); + if (key==&in_forward) + return max(0,analogy); + if (key==&in_back) + return max(0,-analogy); + } + //END + + return val; +} + + + + +//========================================================================== + +cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400","vertical movement speed (while swimming or flying)"}; +cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","200","forward movement speed"}; +cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","200","backward movement speed"}; +cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","200","strafe movement speed"}; + +cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0","how much +speed multiplies keyboard movement speed"}; +cvar_t cl_movecliptokeyboard = {0, "cl_movecliptokeyboard", "0", "if set to 1, any move is clipped to the nine keyboard states; if set to 2, only the direction is clipped, not the amount"}; + +cvar_t cl_yawmode = {CVAR_SAVE, "cl_yawmode","0","0 = swivel-chair, 1 = comfort, 2 = stick, 3 = look-turn"}; +cvar_t cl_pitchmode = {CVAR_SAVE, "cl_pitchmode","0","0 = locked to hmd, 1 = free, 2 = free (inverted)"}; +cvar_t cl_comfort = {CVAR_SAVE, "cl_comfort","45.0","angle by which comfort mode adjusts yaw"}; +cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","150","keyboard yaw turning speed"}; +cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150","keyboard pitch turning speed"}; +cvar_t cl_yawmult = {CVAR_SAVE, "cl_yawmult","1.0","Multiplier for yaw (leave at 1.0)"}; +cvar_t cl_pitchmult = {CVAR_SAVE, "cl_pitchmult","1.0","Multiplier for yaw (leave at 1.0)"}; + +cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5","how much +speed multiplies keyboard turning speed"}; + +cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0", "enables clientside prediction of your player movement"}; +cvar_t cl_movement_replay = {0, "cl_movement_replay", "1", "use engine prediction"}; +cvar_t cl_movement_nettimeout = {CVAR_SAVE, "cl_movement_nettimeout", "0.3", "stops predicting moves when server is lagging badly (avoids major performance problems), timeout in seconds"}; +cvar_t cl_movement_minping = {CVAR_SAVE, "cl_movement_minping", "0", "whether to use prediction when ping is lower than this value in milliseconds"}; +cvar_t cl_movement_track_canjump = {CVAR_SAVE, "cl_movement_track_canjump", "1", "track if the player released the jump key between two jumps to decide if he is able to jump or not; when off, this causes some \"sliding\" slightly above the floor when the jump key is held too long; if the mod allows repeated jumping by holding space all the time, this has to be set to zero too"}; +cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320", "how fast you can move (should match sv_maxspeed)"}; +cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30", "how fast you can move while in the air (should match sv_maxairspeed)"}; +cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100", "speed below which you will be slowed rapidly to a stop rather than sliding endlessly (should match sv_stopspeed)"}; +cvar_t cl_movement_friction = {0, "cl_movement_friction", "4", "how fast you slow down (should match sv_friction)"}; +cvar_t cl_movement_wallfriction = {0, "cl_movement_wallfriction", "1", "how fast you slow down while sliding along a wall (should match sv_wallfriction)"}; +cvar_t cl_movement_waterfriction = {0, "cl_movement_waterfriction", "-1", "how fast you slow down (should match sv_waterfriction), if less than 0 the cl_movement_friction variable is used instead"}; +cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "1", "how much to slow down when you may be about to fall off a ledge (should match edgefriction)"}; +cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18", "how tall a step you can step in one instant (should match sv_stepheight)"}; +cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10", "how fast you accelerate (should match sv_accelerate)"}; +cvar_t cl_movement_airaccelerate = {0, "cl_movement_airaccelerate", "-1", "how fast you accelerate while in the air (should match sv_airaccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; +cvar_t cl_movement_wateraccelerate = {0, "cl_movement_wateraccelerate", "-1", "how fast you accelerate while in water (should match sv_wateraccelerate), if less than 0 the cl_movement_accelerate variable is used instead"}; +cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270", "how fast you move upward when you begin a jump (should match the quakec code)"}; +cvar_t cl_movement_airaccel_qw = {0, "cl_movement_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration (reduces speed gain when zigzagging) (should match sv_airaccel_qw); when < 0, the speed is clamped against the maximum allowed forward speed after the move"}; +cvar_t cl_movement_airaccel_sideways_friction = {0, "cl_movement_airaccel_sideways_friction", "0", "anti-sideways movement stabilization (should match sv_airaccel_sideways_friction); when < 0, only so much friction is applied that braking (by accelerating backwards) cannot be stronger"}; + +cvar_t in_pitch_min = {0, "in_pitch_min", "-90", "how far downward you can aim (quake used -70"}; +cvar_t in_pitch_max = {0, "in_pitch_max", "90", "how far upward you can aim (quake used 80"}; + +cvar_t m_filter = {CVAR_SAVE, "m_filter","0", "smoothes mouse movement, less responsive but smoother aiming"}; +cvar_t m_accelerate = {CVAR_SAVE, "m_accelerate","1", "mouse acceleration factor (try 2)"}; +cvar_t m_accelerate_minspeed = {CVAR_SAVE, "m_accelerate_minspeed","5000", "below this speed, no acceleration is done"}; +cvar_t m_accelerate_maxspeed = {CVAR_SAVE, "m_accelerate_maxspeed","10000", "above this speed, full acceleration is done"}; +cvar_t m_accelerate_filter = {CVAR_SAVE, "m_accelerate_filter","0.1", "mouse acceleration factor filtering"}; + +cvar_t cl_netfps = {CVAR_SAVE, "cl_netfps","72", "how many input packets to send to server each second"}; +cvar_t cl_netrepeatinput = {CVAR_SAVE, "cl_netrepeatinput", "1", "how many packets in a row can be lost without movement issues when using cl_movement (technically how many input messages to repeat in each packet that have not yet been acknowledged by the server), only affects DP7 and later servers (Quake uses 0, QuakeWorld uses 2, and just for comparison Quake3 uses 1)"}; +cvar_t cl_netimmediatebuttons = {CVAR_SAVE, "cl_netimmediatebuttons", "1", "sends extra packets whenever your buttons change or an impulse is used (basically: whenever you click fire or change weapon)"}; + +cvar_t cl_nodelta = {0, "cl_nodelta", "0", "disables delta compression of non-player entities in QW network protocol"}; + +cvar_t cl_csqc_generatemousemoveevents = {0, "cl_csqc_generatemousemoveevents", "1", "enables calls to CSQC_InputEvent with type 2, for compliance with EXT_CSQC spec"}; + +extern cvar_t v_flipped; + +qboolean headtracking = true; + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +static void CL_AdjustAngles (qboolean firstCall) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + speed = cl.realframetime * cl_anglespeedkey.value; + else + speed = cl.realframetime; + + if (!(in_strafe.state & 1)) + { + //Comfort mode + if ((cl_yawmode.integer == 1) && firstCall) + { + cl.viewangles[YAW] = (float)(cl.comfortInc) * cl_comfort.value; + } + //Stick control mode + if (cl_yawmode.integer == 2) + { + cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); + cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); + } + } + 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 (); + + cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]); + cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]); + if (cl.viewangles[YAW] >= 180) + cl.viewangles[YAW] -= 360; + if (cl.viewangles[PITCH] >= 180) + cl.viewangles[PITCH] -= 360; + cl.viewangles[PITCH] = bound(in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value); + cl.viewangles[ROLL] = bound(-180, cl.viewangles[ROLL], 180); +} + +int cl_ignoremousemoves = 2; + +/* +================ +CL_Input + +Send the intended movement message to the server +================ +*/ +void CL_Input (void) +{ + float mx, my; + static float old_mouse_x = 0, old_mouse_y = 0; + + // clamp before the move to prevent starting with bad angles + CL_AdjustAngles (true); + + if(v_flipped.integer) + cl.viewangles[YAW] = -cl.viewangles[YAW]; + + // reset some of the command fields + cl.cmd.forwardmove = 0; + cl.cmd.sidemove = 0; + cl.cmd.upmove = 0; + + // get basic movement from keyboard + if (in_strafe.state & 1) + { + cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right); + cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); + } + + cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); + cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); + + cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up); + cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down); + + if (! (in_klook.state & 1) ) + { + cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + } + + // adjust for speed key + if (in_speed.state & 1) + { + cl.cmd.forwardmove *= cl_movespeedkey.value; + cl.cmd.sidemove *= cl_movespeedkey.value; + cl.cmd.upmove *= cl_movespeedkey.value; + } + + // allow mice or other external controllers to add to the move + IN_Move (); + + // send mouse move to csqc + if (cl.csqc_loaded && cl_csqc_generatemousemoveevents.integer) + { + if (cl.csqc_wantsmousemove) + { + // event type 3 is a DP_CSQC thing + static int oldwindowmouse[2]; + if (oldwindowmouse[0] != in_windowmouse_x || oldwindowmouse[1] != in_windowmouse_y) + { + CL_VM_InputEvent(3, in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height); + oldwindowmouse[0] = in_windowmouse_x; + oldwindowmouse[1] = in_windowmouse_y; + } + } + else + { + if (in_mouse_x || in_mouse_y) + CL_VM_InputEvent(2, in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height); + } + } + + // apply m_accelerate if it is on + if(m_accelerate.value > 1) + { + static float averagespeed = 0; + float speed, f, mi, ma; + + speed = sqrt(in_mouse_x * in_mouse_x + in_mouse_y * in_mouse_y) / cl.realframetime; + if(m_accelerate_filter.value > 0) + f = bound(0, cl.realframetime / m_accelerate_filter.value, 1); + else + f = 1; + averagespeed = speed * f + averagespeed * (1 - f); + + mi = max(1, m_accelerate_minspeed.value); + ma = max(m_accelerate_minspeed.value + 1, m_accelerate_maxspeed.value); + + if(averagespeed <= mi) + { + f = 1; + } + else if(averagespeed >= ma) + { + f = m_accelerate.value; + } + else + { + f = averagespeed; + f = (f - mi) / (ma - mi) * (m_accelerate.value - 1) + 1; + } + + in_mouse_x *= f; + in_mouse_y *= f; + } + + // apply m_filter if it is on + mx = in_mouse_x; + my = in_mouse_y; + if (m_filter.integer) + { + in_mouse_x = (mx + old_mouse_x) * 0.5; + in_mouse_y = (my + old_mouse_y) * 0.5; + } + old_mouse_x = mx; + old_mouse_y = my; + + // ignore a mouse move if mouse was activated/deactivated this frame + if (cl_ignoremousemoves) + { + cl_ignoremousemoves--; + in_mouse_x = old_mouse_x = 0; + in_mouse_y = old_mouse_y = 0; + } + + // if not in menu, apply mouse move to viewangles/movement + if (!key_consoleactive && key_dest == key_game && !cl.csqc_wantsmousemove && cl_prydoncursor.integer <= 0) + { + float modulatedsensitivity = sensitivity.value * cl.sensitivityscale; + if (in_strafe.state & 1) + { + // strafing mode, all looking is movement + V_StopPitchDrift(); + cl.cmd.sidemove += m_side.value * in_mouse_x * modulatedsensitivity; + if (noclip_anglehack) + cl.cmd.upmove -= m_forward.value * in_mouse_y * modulatedsensitivity; + else + cl.cmd.forwardmove -= m_forward.value * in_mouse_y * modulatedsensitivity; + } + else if ((in_mlook.state & 1) || freelook.integer) + { + // mouselook, lookstrafe causes turning to become strafing + V_StopPitchDrift(); + if (lookstrafe.integer) + cl.cmd.sidemove += m_side.value * in_mouse_x * modulatedsensitivity; + else + cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * modulatedsensitivity * cl.viewzoom; + cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * modulatedsensitivity * cl.viewzoom; + } + else + { + // non-mouselook, yaw turning and forward/back movement + cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * modulatedsensitivity * cl.viewzoom; + cl.cmd.forwardmove -= m_forward.value * in_mouse_y * modulatedsensitivity; + } + } + else // don't pitch drift when csqc is controlling the mouse + { + // mouse interacting with the scene, mostly stationary view + V_StopPitchDrift(); + // update prydon cursor + cl.cmd.cursor_screen[0] = in_windowmouse_x * 2.0 / vid.width - 1.0; + cl.cmd.cursor_screen[1] = in_windowmouse_y * 2.0 / vid.height - 1.0; + } + + if(v_flipped.integer) + { + cl.viewangles[YAW] = -cl.viewangles[YAW]; + cl.cmd.sidemove = -cl.cmd.sidemove; + } + + // clamp after the move to prevent rendering with bad angles + CL_AdjustAngles (false); + + if(cl_movecliptokeyboard.integer) + { + vec_t f = 1; + if (in_speed.state & 1) + f *= cl_movespeedkey.value; + if(cl_movecliptokeyboard.integer == 2) + { + // digital direction, analog amount + vec_t wishvel_x, wishvel_y; + wishvel_x = fabs(cl.cmd.forwardmove); + wishvel_y = fabs(cl.cmd.sidemove); + if(wishvel_x != 0 && wishvel_y != 0 && wishvel_x != wishvel_y) + { + vec_t wishspeed = sqrt(wishvel_x * wishvel_x + wishvel_y * wishvel_y); + if(wishvel_x >= 2 * wishvel_y) + { + // pure X motion + if(cl.cmd.forwardmove > 0) + cl.cmd.forwardmove = wishspeed; + else + cl.cmd.forwardmove = -wishspeed; + cl.cmd.sidemove = 0; + } + else if(wishvel_y >= 2 * wishvel_x) + { + // pure Y motion + cl.cmd.forwardmove = 0; + if(cl.cmd.sidemove > 0) + cl.cmd.sidemove = wishspeed; + else + cl.cmd.sidemove = -wishspeed; + } + else + { + // diagonal + if(cl.cmd.forwardmove > 0) + cl.cmd.forwardmove = 0.70710678118654752440 * wishspeed; + else + cl.cmd.forwardmove = -0.70710678118654752440 * wishspeed; + if(cl.cmd.sidemove > 0) + cl.cmd.sidemove = 0.70710678118654752440 * wishspeed; + else + cl.cmd.sidemove = -0.70710678118654752440 * wishspeed; + } + } + } + else if(cl_movecliptokeyboard.integer) + { + // digital direction, digital amount + if(cl.cmd.sidemove >= cl_sidespeed.value * f * 0.5) + cl.cmd.sidemove = cl_sidespeed.value * f; + else if(cl.cmd.sidemove <= -cl_sidespeed.value * f * 0.5) + cl.cmd.sidemove = -cl_sidespeed.value * f; + else + cl.cmd.sidemove = 0; + if(cl.cmd.forwardmove >= cl_forwardspeed.value * f * 0.5) + cl.cmd.forwardmove = cl_forwardspeed.value * f; + else if(cl.cmd.forwardmove <= -cl_backspeed.value * f * 0.5) + cl.cmd.forwardmove = -cl_backspeed.value * f; + else + cl.cmd.forwardmove = 0; + } + } +} + +#include "cl_collision.h" + +static void CL_UpdatePrydonCursor(void) +{ + vec3_t temp; + + if (cl_prydoncursor.integer <= 0) + VectorClear(cl.cmd.cursor_screen); + + /* + if (cl.cmd.cursor_screen[0] < -1) + { + cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.width * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[0] = -1; + } + if (cl.cmd.cursor_screen[0] > 1) + { + cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.width * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[0] = 1; + } + if (cl.cmd.cursor_screen[1] < -1) + { + cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[1] = -1; + } + if (cl.cmd.cursor_screen[1] > 1) + { + cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom; + cl.cmd.cursor_screen[1] = 1; + } + */ + cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1); + cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1); + cl.cmd.cursor_screen[2] = 1; + + // calculate current view matrix + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, cl.cmd.cursor_start); + // calculate direction vector of cursor in viewspace by using frustum slopes + VectorSet(temp, cl.cmd.cursor_screen[2] * 1000000, (v_flipped.integer ? -1 : 1) * cl.cmd.cursor_screen[0] * -r_refdef.view.frustum_x * 1000000, cl.cmd.cursor_screen[1] * -r_refdef.view.frustum_y * 1000000); + Matrix4x4_Transform(&r_refdef.view.matrix, temp, cl.cmd.cursor_end); + // trace from view origin to the cursor + if (cl_prydoncursor_notrace.integer) + { + cl.cmd.cursor_fraction = 1.0f; + VectorCopy(cl.cmd.cursor_end, cl.cmd.cursor_impact); + VectorClear(cl.cmd.cursor_normal); + cl.cmd.cursor_entitynumber = 0; + } + else + cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL); +} + +#define NUMOFFSETS 27 +static vec3_t offsets[NUMOFFSETS] = +{ +// 1 no nudge (just return the original if this test passes) + { 0.000, 0.000, 0.000}, +// 6 simple nudges + { 0.000, 0.000, 0.125}, { 0.000, 0.000, -0.125}, + {-0.125, 0.000, 0.000}, { 0.125, 0.000, 0.000}, + { 0.000, -0.125, 0.000}, { 0.000, 0.125, 0.000}, +// 4 diagonal flat nudges + {-0.125, -0.125, 0.000}, { 0.125, -0.125, 0.000}, + {-0.125, 0.125, 0.000}, { 0.125, 0.125, 0.000}, +// 8 diagonal upward nudges + {-0.125, 0.000, 0.125}, { 0.125, 0.000, 0.125}, + { 0.000, -0.125, 0.125}, { 0.000, 0.125, 0.125}, + {-0.125, -0.125, 0.125}, { 0.125, -0.125, 0.125}, + {-0.125, 0.125, 0.125}, { 0.125, 0.125, 0.125}, +// 8 diagonal downward nudges + {-0.125, 0.000, -0.125}, { 0.125, 0.000, -0.125}, + { 0.000, -0.125, -0.125}, { 0.000, 0.125, -0.125}, + {-0.125, -0.125, -0.125}, { 0.125, -0.125, -0.125}, + {-0.125, 0.125, -0.125}, { 0.125, 0.125, -0.125}, +}; + +static qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s) +{ + int i; + vec3_t neworigin; + for (i = 0;i < NUMOFFSETS;i++) + { + VectorAdd(offsets[i], s->origin, neworigin); + if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid) + { + VectorCopy(neworigin, s->origin); + return true; + } + } + // if all offsets failed, give up + return false; +} + +static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s) +{ + vec_t f; + vec3_t origin1, origin2; + trace_t trace; + + // make sure player is not stuck + CL_ClientMovement_Unstick(s); + + // set crouched + if (s->cmd.crouch) + { + // wants to crouch, this always works.. + if (!s->crouched) + s->crouched = true; + } + else + { + // wants to stand, if currently crouching we need to check for a + // low ceiling first + if (s->crouched) + { + trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + if (!trace.startsolid) + s->crouched = false; + } + } + if (s->crouched) + { + VectorCopy(cl.playercrouchmins, s->mins); + VectorCopy(cl.playercrouchmaxs, s->maxs); + } + else + { + VectorCopy(cl.playerstandmins, s->mins); + VectorCopy(cl.playerstandmaxs, s->maxs); + } + + // set onground + VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1); + VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 1); // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :) + trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + if(trace.fraction < 1 && trace.plane.normal[2] > 0.7) + { + s->onground = true; + + // this code actually "predicts" an impact; so let's clip velocity first + f = DotProduct(s->velocity, trace.plane.normal); + if(f < 0) // only if moving downwards actually + VectorMA(s->velocity, -f, trace.plane.normal, s->velocity); + } + else + s->onground = false; + + // set watertype/waterlevel + VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1); + s->waterlevel = WATERLEVEL_NONE; + s->watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK; + if (s->watertype) + { + s->waterlevel = WATERLEVEL_WETFEET; + origin1[2] = s->origin[2] + (s->mins[2] + s->maxs[2]) * 0.5f; + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + { + s->waterlevel = WATERLEVEL_SWIMMING; + origin1[2] = s->origin[2] + 22; + if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) + s->waterlevel = WATERLEVEL_SUBMERGED; + } + } + + // water jump prediction + if (s->onground || s->velocity[2] <= 0 || s->waterjumptime <= 0) + s->waterjumptime = 0; +} + +static void CL_ClientMovement_Move(cl_clientmovement_state_t *s) +{ + int bump; + double t; + vec_t f; + vec3_t neworigin; + vec3_t currentorigin2; + vec3_t neworigin2; + vec3_t primalvelocity; + trace_t trace; + trace_t trace2; + trace_t trace3; + CL_ClientMovement_UpdateStatus(s); + VectorCopy(s->velocity, primalvelocity); + for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++) + { + VectorMA(s->origin, t, s->velocity, neworigin); + trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + if (trace.fraction < 1 && trace.plane.normal[2] == 0) + { + // may be a step or wall, try stepping up + // first move forward at a higher level + VectorSet(currentorigin2, s->origin[0], s->origin[1], s->origin[2] + cl.movevars_stepheight); + VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + cl.movevars_stepheight); + trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + if (!trace2.startsolid) + { + // then move down from there + VectorCopy(trace2.endpos, currentorigin2); + VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], s->origin[2]); + trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]); + // accept the new trace if it made some progress + if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125) + { + trace = trace2; + VectorCopy(trace3.endpos, trace.endpos); + } + } + } + + // check if it moved at all + if (trace.fraction >= 0.001) + VectorCopy(trace.endpos, s->origin); + + // check if it moved all the way + if (trace.fraction == 1) + break; + + // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate + // I'm pretty sure I commented it out solely because it seemed redundant + // this got commented out in a change that supposedly makes the code match QW better + // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block + if (trace.plane.normal[2] > 0.7) + s->onground = true; + + t -= t * trace.fraction; + + f = DotProduct(s->velocity, trace.plane.normal); + VectorMA(s->velocity, -f, trace.plane.normal, s->velocity); + } + if (s->waterjumptime > 0) + VectorCopy(primalvelocity, s->velocity); +} + + +static void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s) +{ + vec_t wishspeed; + vec_t f; + vec3_t wishvel; + vec3_t wishdir; + + // water jump only in certain situations + // this mimics quakeworld code + if (s->cmd.jump && s->waterlevel == 2 && s->velocity[2] >= -180) + { + vec3_t forward; + vec3_t yawangles; + vec3_t spot; + VectorSet(yawangles, 0, s->cmd.viewangles[1], 0); + AngleVectors(yawangles, forward, NULL, NULL); + VectorMA(s->origin, 24, forward, spot); + spot[2] += 8; + if (CL_TracePoint(spot, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsolid) + { + spot[2] += 24; + if (!CL_TracePoint(spot, MOVE_NOMONSTERS, s->self, 0, true, false, NULL, false).startsolid) + { + VectorScale(forward, 50, s->velocity); + s->velocity[2] = 310; + s->waterjumptime = 2; + s->onground = false; + s->cmd.canjump = false; + } + } + } + + if (!(s->cmd.forwardmove*s->cmd.forwardmove + s->cmd.sidemove*s->cmd.sidemove + s->cmd.upmove*s->cmd.upmove)) + { + // drift towards bottom + VectorSet(wishvel, 0, 0, -60); + } + else + { + // swim + vec3_t forward; + vec3_t right; + vec3_t up; + // calculate movement vector + AngleVectors(s->cmd.viewangles, forward, right, up); + VectorSet(up, 0, 0, 1); + VectorMAMAM(s->cmd.forwardmove, forward, s->cmd.sidemove, right, s->cmd.upmove, up, wishvel); + } + + // split wishvel into wishspeed and wishdir + wishspeed = VectorLength(wishvel); + if (wishspeed) + VectorScale(wishvel, 1 / wishspeed, wishdir); + else + VectorSet( wishdir, 0.0, 0.0, 0.0 ); + wishspeed = min(wishspeed, cl.movevars_maxspeed) * 0.7; + + if (s->crouched) + wishspeed *= 0.5; + + if (s->waterjumptime <= 0) + { + // water friction + f = 1 - s->cmd.frametime * cl.movevars_waterfriction * (cls.protocol == PROTOCOL_QUAKEWORLD ? s->waterlevel : 1); + f = bound(0, f, 1); + VectorScale(s->velocity, f, s->velocity); + + // water acceleration + f = wishspeed - DotProduct(s->velocity, wishdir); + if (f > 0) + { + f = min(cl.movevars_wateraccelerate * s->cmd.frametime * wishspeed, f); + VectorMA(s->velocity, f, wishdir, s->velocity); + } + + // holding jump button swims upward slowly + if (s->cmd.jump) + { + if (s->watertype & SUPERCONTENTS_LAVA) + s->velocity[2] = 50; + else if (s->watertype & SUPERCONTENTS_SLIME) + s->velocity[2] = 80; + else + { + if (gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + s->velocity[2] = 200; + else + s->velocity[2] = 100; + } + } + } + + CL_ClientMovement_Move(s); +} + +static vec_t CL_IsMoveInDirection(vec_t forward, vec_t side, vec_t angle) +{ + if(forward == 0 && side == 0) + return 0; // avoid division by zero + angle -= RAD2DEG(atan2(side, forward)); + angle = (ANGLEMOD(angle + 180) - 180) / 45; + if(angle > 1) + return 0; + if(angle < -1) + return 0; + return 1 - fabs(angle); +} + +static vec_t CL_GeomLerp(vec_t a, vec_t lerp, vec_t b) +{ + if(a == 0) + { + if(lerp < 1) + return 0; + else + return b; + } + if(b == 0) + { + if(lerp > 0) + return 0; + else + return a; + } + return a * pow(fabs(b / a), lerp); +} + +static void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed) +{ + vec_t zspeed, speed, dot, k; + +#if 0 + // this doesn't play well with analog input + if(s->cmd.forwardmove == 0 || s->cmd.sidemove != 0) + return; + k = 32; +#else + k = 32 * (2 * CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, 0) - 1); + if(k <= 0) + return; +#endif + + k *= bound(0, wishspeed / cl.movevars_maxairspeed, 1); + + zspeed = s->velocity[2]; + s->velocity[2] = 0; + speed = VectorNormalizeLength(s->velocity); + + dot = DotProduct(s->velocity, wishdir); + + if(dot > 0) { // we can't change direction while slowing down + k *= pow(dot, cl.movevars_aircontrol_power)*s->cmd.frametime; + speed = max(0, speed - cl.movevars_aircontrol_penalty * sqrt(max(0, 1 - dot*dot)) * k/32); + k *= cl.movevars_aircontrol; + VectorMAM(speed, s->velocity, k, wishdir, s->velocity); + VectorNormalize(s->velocity); + } + + VectorScale(s->velocity, speed, s->velocity); + s->velocity[2] = zspeed; +} + +static float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor) +{ + return + (accelqw < 0 ? -1 : +1) + * + bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1); +} + +static void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t wishspeed0, vec_t accel, vec_t accelqw, vec_t stretchfactor, vec_t sidefric, vec_t speedlimit) +{ + vec_t vel_straight; + vec_t vel_z; + vec3_t vel_perpend; + vec_t step; + vec3_t vel_xy; + vec_t vel_xy_current; + vec_t vel_xy_backward, vel_xy_forward; + vec_t speedclamp; + + if(stretchfactor > 0) + speedclamp = stretchfactor; + else if(accelqw < 0) + speedclamp = 1; + else + speedclamp = -1; // no clamping + + if(accelqw < 0) + accelqw = -accelqw; + + if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE) + wishspeed0 = wishspeed; // don't need to emulate this Q1 bug + + vel_straight = DotProduct(s->velocity, wishdir); + vel_z = s->velocity[2]; + VectorCopy(s->velocity, vel_xy); vel_xy[2] -= vel_z; + VectorMA(vel_xy, -vel_straight, wishdir, vel_perpend); + + step = accel * s->cmd.frametime * wishspeed0; + + vel_xy_current = VectorLength(vel_xy); + if(speedlimit > 0) + accelqw = CL_ClientMovement_Physics_AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed)); + vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); + vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw); + if(vel_xy_backward < 0) + vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards + + vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw); + + if(sidefric < 0 && VectorLength2(vel_perpend)) + // negative: only apply so much sideways friction to stay below the speed you could get by "braking" + { + vec_t f, fmin; + f = max(0, 1 + s->cmd.frametime * wishspeed * sidefric); + fmin = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / VectorLength2(vel_perpend); + // assume: fmin > 1 + // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy + // obviously, this cannot be + if(fmin <= 0) + VectorScale(vel_perpend, f, vel_perpend); + else + { + fmin = sqrt(fmin); + VectorScale(vel_perpend, max(fmin, f), vel_perpend); + } + } + else + VectorScale(vel_perpend, max(0, 1 - s->cmd.frametime * wishspeed * sidefric), vel_perpend); + + VectorMA(vel_perpend, vel_straight, wishdir, s->velocity); + + if(speedclamp >= 0) + { + vec_t vel_xy_preclamp; + vel_xy_preclamp = VectorLength(s->velocity); + if(vel_xy_preclamp > 0) // prevent division by zero + { + vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp; + if(vel_xy_current < vel_xy_preclamp) + VectorScale(s->velocity, (vel_xy_current / vel_xy_preclamp), s->velocity); + } + } + + s->velocity[2] += vel_z; +} + +static void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed) +{ + vec3_t curvel, wishvel, acceldir, curdir; + float addspeed, accelspeed, curspeed; + float dot; + + float airforwardaccel = cl.movevars_warsowbunny_airforwardaccel; + float bunnyaccel = cl.movevars_warsowbunny_accel; + float bunnytopspeed = cl.movevars_warsowbunny_topspeed; + float turnaccel = cl.movevars_warsowbunny_turnaccel; + float backtosideratio = cl.movevars_warsowbunny_backtosideratio; + + if( !wishspeed ) + return; + + VectorCopy( s->velocity, curvel ); + curvel[2] = 0; + curspeed = VectorLength( curvel ); + + if( wishspeed > curspeed * 1.01f ) + { + float accelspeed = curspeed + airforwardaccel * cl.movevars_maxairspeed * s->cmd.frametime; + if( accelspeed < wishspeed ) + wishspeed = accelspeed; + } + else + { + float f = ( bunnytopspeed - curspeed ) / ( bunnytopspeed - cl.movevars_maxairspeed ); + if( f < 0 ) + f = 0; + wishspeed = max( curspeed, cl.movevars_maxairspeed ) + bunnyaccel * f * cl.movevars_maxairspeed * s->cmd.frametime; + } + VectorScale( wishdir, wishspeed, wishvel ); + VectorSubtract( wishvel, curvel, acceldir ); + addspeed = VectorNormalizeLength( acceldir ); + + accelspeed = turnaccel * cl.movevars_maxairspeed /* wishspeed */ * s->cmd.frametime; + if( accelspeed > addspeed ) + accelspeed = addspeed; + + if( backtosideratio < 1.0f ) + { + VectorNormalize2( curvel, curdir ); + dot = DotProduct( acceldir, curdir ); + if( dot < 0 ) + VectorMA( acceldir, -( 1.0f - backtosideratio ) * dot, curdir, acceldir ); + } + + VectorMA( s->velocity, accelspeed, acceldir, s->velocity ); +} + +static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s) +{ + vec_t friction; + vec_t wishspeed; + vec_t addspeed; + vec_t accelspeed; + vec_t f; + vec_t gravity; + vec3_t forward; + vec3_t right; + vec3_t up; + vec3_t wishvel; + vec3_t wishdir; + vec3_t yawangles; + trace_t trace; + + // jump if on ground with jump button pressed but only if it has been + // released at least once since the last jump + if (s->cmd.jump) + { + if (s->onground && (s->cmd.canjump || !cl_movement_track_canjump.integer)) + { + s->velocity[2] += cl.movevars_jumpvelocity; + s->onground = false; + s->cmd.canjump = false; + } + } + else + s->cmd.canjump = true; + + // calculate movement vector + VectorSet(yawangles, 0, s->cmd.viewangles[1], 0); + AngleVectors(yawangles, forward, right, up); + VectorMAM(s->cmd.forwardmove, forward, s->cmd.sidemove, right, wishvel); + + // split wishvel into wishspeed and wishdir + wishspeed = VectorLength(wishvel); + if (wishspeed) + VectorScale(wishvel, 1 / wishspeed, wishdir); + else + VectorSet( wishdir, 0.0, 0.0, 0.0 ); + // check if onground + if (s->onground) + { + wishspeed = min(wishspeed, cl.movevars_maxspeed); + if (s->crouched) + wishspeed *= 0.5; + + // apply edge friction + f = sqrt(s->velocity[0] * s->velocity[0] + s->velocity[1] * s->velocity[1]); + if (f > 0) + { + friction = cl.movevars_friction; + if (cl.movevars_edgefriction != 1) + { + vec3_t neworigin2; + vec3_t neworigin3; + // note: QW uses the full player box for the trace, and yet still + // uses s->origin[2] + s->mins[2], which is clearly an bug, but + // this mimics it for compatibility + VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]); + VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34); + if (cls.protocol == PROTOCOL_QUAKEWORLD) + trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true); + else + trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false); + if (trace.fraction == 1 && !trace.startsolid) + friction *= cl.movevars_edgefriction; + } + // apply ground friction + f = 1 - s->cmd.frametime * friction * ((f < cl.movevars_stopspeed) ? (cl.movevars_stopspeed / f) : 1); + f = max(f, 0); + VectorScale(s->velocity, f, s->velocity); + } + addspeed = wishspeed - DotProduct(s->velocity, wishdir); + if (addspeed > 0) + { + accelspeed = min(cl.movevars_accelerate * s->cmd.frametime * wishspeed, addspeed); + VectorMA(s->velocity, accelspeed, wishdir, s->velocity); + } + gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime; + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND)) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + else + s->velocity[2] -= gravity; + } + if (cls.protocol == PROTOCOL_QUAKEWORLD) + s->velocity[2] = 0; + if (VectorLength2(s->velocity)) + CL_ClientMovement_Move(s); + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !s->onground) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + } + } + else + { + if (s->waterjumptime <= 0) + { + // apply air speed limit + vec_t accel, wishspeed0, wishspeed2, accelqw, strafity; + qboolean accelerating; + + accelqw = cl.movevars_airaccel_qw; + wishspeed0 = wishspeed; + wishspeed = min(wishspeed, cl.movevars_maxairspeed); + if (s->crouched) + wishspeed *= 0.5; + accel = cl.movevars_airaccelerate; + + accelerating = (DotProduct(s->velocity, wishdir) > 0); + wishspeed2 = wishspeed; + + // CPM: air control + if(cl.movevars_airstopaccelerate != 0) + { + vec3_t curdir; + curdir[0] = s->velocity[0]; + curdir[1] = s->velocity[1]; + curdir[2] = 0; + VectorNormalize(curdir); + accel = accel + (cl.movevars_airstopaccelerate - accel) * max(0, -DotProduct(curdir, wishdir)); + } + strafity = CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, -90) + CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, +90); // if one is nonzero, other is always zero + if(cl.movevars_maxairstrafespeed) + wishspeed = min(wishspeed, CL_GeomLerp(cl.movevars_maxairspeed, strafity, cl.movevars_maxairstrafespeed)); + if(cl.movevars_airstrafeaccelerate) + accel = CL_GeomLerp(cl.movevars_airaccelerate, strafity, cl.movevars_airstrafeaccelerate); + if(cl.movevars_airstrafeaccel_qw) + accelqw = + (((strafity > 0.5 ? cl.movevars_airstrafeaccel_qw : cl.movevars_airaccel_qw) >= 0) ? +1 : -1) + * + (1 - CL_GeomLerp(1 - fabs(cl.movevars_airaccel_qw), strafity, 1 - fabs(cl.movevars_airstrafeaccel_qw))); + // !CPM + + if(cl.movevars_warsowbunny_turnaccel && accelerating && s->cmd.sidemove == 0 && s->cmd.forwardmove != 0) + CL_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2); + else + CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_qw_stretchfactor, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed, cl.movevars_airspeedlimit_nonqw); + + if(cl.movevars_aircontrol) + CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2); + } + gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime; + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + else + s->velocity[2] -= gravity; + CL_ClientMovement_Move(s); + if(!(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !s->onground) + { + if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s->velocity[2] -= gravity * 0.5f; + } + } +} + +static void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s) +{ + //Con_Printf(" %f", frametime); + if (!s->cmd.jump) + s->cmd.canjump = true; + s->waterjumptime -= s->cmd.frametime; + CL_ClientMovement_UpdateStatus(s); + if (s->waterlevel >= WATERLEVEL_SWIMMING) + CL_ClientMovement_Physics_Swim(s); + else + CL_ClientMovement_Physics_Walk(s); +} + +extern cvar_t slowmo; +void CL_UpdateMoveVars(void) +{ + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + cl.moveflags = 0; + } + else if (cl.stats[STAT_MOVEVARS_TICRATE]) + { + cl.moveflags = cl.stats[STAT_MOVEFLAGS]; + cl.movevars_ticrate = cl.statsf[STAT_MOVEVARS_TICRATE]; + cl.movevars_timescale = cl.statsf[STAT_MOVEVARS_TIMESCALE]; + cl.movevars_gravity = cl.statsf[STAT_MOVEVARS_GRAVITY]; + cl.movevars_stopspeed = cl.statsf[STAT_MOVEVARS_STOPSPEED] ; + cl.movevars_maxspeed = cl.statsf[STAT_MOVEVARS_MAXSPEED]; + cl.movevars_spectatormaxspeed = cl.statsf[STAT_MOVEVARS_SPECTATORMAXSPEED]; + cl.movevars_accelerate = cl.statsf[STAT_MOVEVARS_ACCELERATE]; + cl.movevars_airaccelerate = cl.statsf[STAT_MOVEVARS_AIRACCELERATE]; + cl.movevars_wateraccelerate = cl.statsf[STAT_MOVEVARS_WATERACCELERATE]; + cl.movevars_entgravity = cl.statsf[STAT_MOVEVARS_ENTGRAVITY]; + cl.movevars_jumpvelocity = cl.statsf[STAT_MOVEVARS_JUMPVELOCITY]; + cl.movevars_edgefriction = cl.statsf[STAT_MOVEVARS_EDGEFRICTION]; + cl.movevars_maxairspeed = cl.statsf[STAT_MOVEVARS_MAXAIRSPEED]; + cl.movevars_stepheight = cl.statsf[STAT_MOVEVARS_STEPHEIGHT]; + cl.movevars_airaccel_qw = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW]; + cl.movevars_airaccel_qw_stretchfactor = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR]; + cl.movevars_airaccel_sideways_friction = cl.statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION]; + cl.movevars_friction = cl.statsf[STAT_MOVEVARS_FRICTION]; + cl.movevars_wallfriction = cl.statsf[STAT_MOVEVARS_WALLFRICTION]; + cl.movevars_waterfriction = cl.statsf[STAT_MOVEVARS_WATERFRICTION]; + cl.movevars_airstopaccelerate = cl.statsf[STAT_MOVEVARS_AIRSTOPACCELERATE]; + cl.movevars_airstrafeaccelerate = cl.statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE]; + cl.movevars_maxairstrafespeed = cl.statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED]; + cl.movevars_airstrafeaccel_qw = cl.statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW]; + cl.movevars_aircontrol = cl.statsf[STAT_MOVEVARS_AIRCONTROL]; + cl.movevars_aircontrol_power = cl.statsf[STAT_MOVEVARS_AIRCONTROL_POWER]; + cl.movevars_aircontrol_penalty = cl.statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY]; + cl.movevars_warsowbunny_airforwardaccel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL]; + cl.movevars_warsowbunny_accel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL]; + cl.movevars_warsowbunny_topspeed = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED]; + cl.movevars_warsowbunny_turnaccel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL]; + cl.movevars_warsowbunny_backtosideratio = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO]; + cl.movevars_airspeedlimit_nonqw = cl.statsf[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW]; + } + else + { + cl.moveflags = 0; + cl.movevars_ticrate = (cls.demoplayback ? 1.0f : slowmo.value) / bound(1.0f, cl_netfps.value, 1000.0f); + cl.movevars_timescale = (cls.demoplayback ? 1.0f : slowmo.value); + cl.movevars_gravity = sv_gravity.value; + cl.movevars_stopspeed = cl_movement_stopspeed.value; + cl.movevars_maxspeed = cl_movement_maxspeed.value; + cl.movevars_spectatormaxspeed = cl_movement_maxspeed.value; + cl.movevars_accelerate = cl_movement_accelerate.value; + cl.movevars_airaccelerate = cl_movement_airaccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_airaccelerate.value; + cl.movevars_wateraccelerate = cl_movement_wateraccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_wateraccelerate.value; + cl.movevars_friction = cl_movement_friction.value; + cl.movevars_wallfriction = cl_movement_wallfriction.value; + cl.movevars_waterfriction = cl_movement_waterfriction.value < 0 ? cl_movement_friction.value : cl_movement_waterfriction.value; + cl.movevars_entgravity = 1; + cl.movevars_jumpvelocity = cl_movement_jumpvelocity.value; + cl.movevars_edgefriction = cl_movement_edgefriction.value; + cl.movevars_maxairspeed = cl_movement_maxairspeed.value; + cl.movevars_stepheight = cl_movement_stepheight.value; + cl.movevars_airaccel_qw = cl_movement_airaccel_qw.value; + cl.movevars_airaccel_qw_stretchfactor = 0; + cl.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value; + cl.movevars_airstopaccelerate = 0; + cl.movevars_airstrafeaccelerate = 0; + cl.movevars_maxairstrafespeed = 0; + cl.movevars_airstrafeaccel_qw = 0; + cl.movevars_aircontrol = 0; + cl.movevars_aircontrol_power = 2; + cl.movevars_aircontrol_penalty = 0; + cl.movevars_warsowbunny_airforwardaccel = 0; + cl.movevars_warsowbunny_accel = 0; + cl.movevars_warsowbunny_topspeed = 0; + cl.movevars_warsowbunny_turnaccel = 0; + cl.movevars_warsowbunny_backtosideratio = 0; + cl.movevars_airspeedlimit_nonqw = 0; + } + + if(!(cl.moveflags & MOVEFLAG_VALID)) + { + if(gamemode == GAME_NEXUIZ) + cl.moveflags = MOVEFLAG_Q2AIRACCELERATE; + } + + if(cl.movevars_aircontrol_power <= 0) + cl.movevars_aircontrol_power = 2; // CPMA default +} + +void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s) +{ + // if a move is more than 50ms, do it as two moves (matching qwsv) + //Con_Printf("%i ", s.cmd.msec); + if(s->cmd.frametime > 0.0005) + { + if (s->cmd.frametime > 0.05) + { + s->cmd.frametime /= 2; + CL_ClientMovement_PlayerMove(s); + } + CL_ClientMovement_PlayerMove(s); + } + else + { + // we REALLY need this handling to happen, even if the move is not executed + if (!s->cmd.jump) + s->cmd.canjump = true; + } +} + +void CL_ClientMovement_Replay(void) +{ + int i; + double totalmovemsec; + cl_clientmovement_state_t s; + + VectorCopy(cl.mvelocity[0], cl.movement_velocity); + + if (cl.movement_predicted && !cl.movement_replay) + return; + + if (!cl_movement_replay.integer) + return; + + // set up starting state for the series of moves + memset(&s, 0, sizeof(s)); + VectorCopy(cl.entities[cl.playerentity].state_current.origin, s.origin); + VectorCopy(cl.mvelocity[0], s.velocity); + s.crouched = true; // will be updated on first move + //Con_Printf("movement replay starting org %f %f %f vel %f %f %f\n", s.origin[0], s.origin[1], s.origin[2], s.velocity[0], s.velocity[1], s.velocity[2]); + + totalmovemsec = 0; + for (i = 0;i < CL_MAX_USERCMDS;i++) + if (cl.movecmd[i].sequence > cls.servermovesequence) + totalmovemsec += cl.movecmd[i].msec; + cl.movement_predicted = totalmovemsec >= cl_movement_minping.value && cls.servermovesequence && (cl_movement.integer && !cls.demoplayback && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission); + //Con_Printf("%i = %.0f >= %.0f && %i && (%i && %i && %i == %i && %i > 0 && %i\n", cl.movement_predicted, totalmovemsec, cl_movement_minping.value, cls.servermovesequence, cl_movement.integer, !cls.demoplayback, cls.signon, SIGNONS, cl.stats[STAT_HEALTH], !cl.intermission); + if (cl.movement_predicted) + { + //Con_Printf("%ims\n", cl.movecmd[0].msec); + + // replay the input queue to predict current location + // note: this relies on the fact there's always one queue item at the end + + // find how many are still valid + for (i = 0;i < CL_MAX_USERCMDS;i++) + if (cl.movecmd[i].sequence <= cls.servermovesequence) + break; + // now walk them in oldest to newest order + for (i--;i >= 0;i--) + { + s.cmd = cl.movecmd[i]; + if (i < CL_MAX_USERCMDS - 1) + s.cmd.canjump = cl.movecmd[i+1].canjump; + + CL_ClientMovement_PlayerMove_Frame(&s); + + cl.movecmd[i].canjump = s.cmd.canjump; + } + //Con_Printf("\n"); + CL_ClientMovement_UpdateStatus(&s); + } + else + { + // get the first movement queue entry to know whether to crouch and such + s.cmd = cl.movecmd[0]; + } + + if (!cls.demoplayback) // for bob, speedometer + { + cl.movement_replay = false; + // update the interpolation target position and velocity + VectorCopy(s.origin, cl.movement_origin); + VectorCopy(s.velocity, cl.movement_velocity); + } + + // update the onground flag if appropriate + if (cl.movement_predicted) + { + // when predicted we simply set the flag according to the UpdateStatus + cl.onground = s.onground; + } + else + { + // when not predicted, cl.onground is cleared by cl_parse.c each time + // an update packet is received, but can be forced on here to hide + // server inconsistencies in the onground flag + // (which mostly occur when stepping up stairs at very high framerates + // where after the step up the move continues forward and not + // downward so the ground is not detected) + // + // such onground inconsistencies can cause jittery gun bobbing and + // stair smoothing, so we set onground if UpdateStatus says so + if (s.onground) + cl.onground = true; + } +} + +static void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to) +{ + int bits; + + bits = 0; + if (to->viewangles[0] != from->viewangles[0]) + bits |= QW_CM_ANGLE1; + if (to->viewangles[1] != from->viewangles[1]) + bits |= QW_CM_ANGLE2; + if (to->viewangles[2] != from->viewangles[2]) + bits |= QW_CM_ANGLE3; + if (to->forwardmove != from->forwardmove) + bits |= QW_CM_FORWARD; + if (to->sidemove != from->sidemove) + bits |= QW_CM_SIDE; + if (to->upmove != from->upmove) + bits |= QW_CM_UP; + if (to->buttons != from->buttons) + bits |= QW_CM_BUTTONS; + if (to->impulse != from->impulse) + bits |= QW_CM_IMPULSE; + + MSG_WriteByte(buf, bits); + if (bits & QW_CM_ANGLE1) + MSG_WriteAngle16i(buf, to->viewangles[0]); + if (bits & QW_CM_ANGLE2) + MSG_WriteAngle16i(buf, to->viewangles[1]); + if (bits & QW_CM_ANGLE3) + MSG_WriteAngle16i(buf, to->viewangles[2]); + if (bits & QW_CM_FORWARD) + MSG_WriteShort(buf, (short) to->forwardmove); + if (bits & QW_CM_SIDE) + MSG_WriteShort(buf, (short) to->sidemove); + if (bits & QW_CM_UP) + MSG_WriteShort(buf, (short) to->upmove); + if (bits & QW_CM_BUTTONS) + MSG_WriteByte(buf, to->buttons); + if (bits & QW_CM_IMPULSE) + MSG_WriteByte(buf, to->impulse); + MSG_WriteByte(buf, to->msec); +} + +void CL_NewFrameReceived(int num) +{ + if (developer_networkentities.integer >= 10) + Con_Printf("recv: svc_entities %i\n", num); + cl.latestframenums[cl.latestframenumsposition] = num; + cl.latestsendnums[cl.latestframenumsposition] = cl.cmd.sequence; + cl.latestframenumsposition = (cl.latestframenumsposition + 1) % LATESTFRAMENUMS; +} + +void CL_RotateMoves(const matrix4x4_t *m) +{ + // rotate viewangles in all previous moves + vec3_t v; + vec3_t f, r, u; + int i; + for (i = 0;i < CL_MAX_USERCMDS;i++) + { + if (cl.movecmd[i].sequence > cls.servermovesequence) + { + usercmd_t *c = &cl.movecmd[i]; + AngleVectors(c->viewangles, f, r, u); + Matrix4x4_Transform(m, f, v); VectorCopy(v, f); + Matrix4x4_Transform(m, u, v); VectorCopy(v, u); + AnglesFromVectors(c->viewangles, f, u, false); + } + } +} + +/* +============== +CL_SendMove +============== +*/ +usercmd_t nullcmd; // for delta compression of qw moves +void CL_SendMove(void) +{ + int i, j, packetloss; + int checksumindex; + int bits; + int maxusercmds; + usercmd_t *cmd; + sizebuf_t buf; + unsigned char data[1024]; + double packettime; + int msecdelta; + qboolean quemove; + qboolean important; + + // if playing a demo, do nothing + if (!cls.netcon) + return; + + // we don't que moves during a lag spike (potential network timeout) + quemove = realtime - cl.last_received_message < cl_movement_nettimeout.value; + + // we build up cl.cmd and then decide whether to send or not + // we store this into cl.movecmd[0] for prediction each frame even if we + // do not send, to make sure that prediction is instant + cl.cmd.time = cl.time; + cl.cmd.sequence = cls.netcon->outgoing_unreliable_sequence; + + // set button bits + // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button + bits = 0; + if (in_attack.state & 3) bits |= 1; + if (in_jump.state & 3) bits |= 2; + if (in_button3.state & 3) bits |= 4; + if (in_button4.state & 3) bits |= 8; + if (in_button5.state & 3) bits |= 16; + if (in_button6.state & 3) bits |= 32; + if (in_button7.state & 3) bits |= 64; + if (in_button8.state & 3) bits |= 128; + if (in_use.state & 3) bits |= 256; + if (key_dest != key_game || key_consoleactive) bits |= 512; + if (cl_prydoncursor.integer > 0) bits |= 1024; + if (in_button9.state & 3) bits |= 2048; + if (in_button10.state & 3) bits |= 4096; + if (in_button11.state & 3) bits |= 8192; + if (in_button12.state & 3) bits |= 16384; + if (in_button13.state & 3) bits |= 32768; + if (in_button14.state & 3) bits |= 65536; + if (in_button15.state & 3) bits |= 131072; + if (in_button16.state & 3) bits |= 262144; + // button bits 19-31 unused currently + // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen + if(cl_prydoncursor.integer > 0) + { + if (cl.cmd.cursor_screen[0] <= -1) bits |= 8; + if (cl.cmd.cursor_screen[0] >= 1) bits |= 16; + if (cl.cmd.cursor_screen[1] <= -1) bits |= 32; + if (cl.cmd.cursor_screen[1] >= 1) bits |= 64; + } + + // set buttons and impulse + cl.cmd.buttons = bits; + cl.cmd.impulse = in_impulse; + + // set viewangles + VectorCopy(cl.viewangles, cl.cmd.viewangles); + + msecdelta = (int)(floor(cl.cmd.time * 1000) - floor(cl.movecmd[1].time * 1000)); + cl.cmd.msec = (unsigned char)bound(0, msecdelta, 255); + // ridiculous value rejection (matches qw) + if (cl.cmd.msec > 250) + cl.cmd.msec = 100; + cl.cmd.frametime = cl.cmd.msec * (1.0 / 1000.0); + + cl.cmd.predicted = cl_movement.integer != 0; + + // movement is set by input code (forwardmove/sidemove/upmove) + // always dump the first two moves, because they may contain leftover inputs from the last level + if (cl.cmd.sequence <= 2) + cl.cmd.forwardmove = cl.cmd.sidemove = cl.cmd.upmove = cl.cmd.impulse = cl.cmd.buttons = 0; + + cl.cmd.jump = (cl.cmd.buttons & 2) != 0; + cl.cmd.crouch = 0; + switch (cls.protocol) + { + case PROTOCOL_QUAKEWORLD: + case PROTOCOL_QUAKE: + case PROTOCOL_QUAKEDP: + case PROTOCOL_NEHAHRAMOVIE: + case PROTOCOL_NEHAHRABJP: + case PROTOCOL_NEHAHRABJP2: + case PROTOCOL_NEHAHRABJP3: + case PROTOCOL_DARKPLACES1: + case PROTOCOL_DARKPLACES2: + case PROTOCOL_DARKPLACES3: + case PROTOCOL_DARKPLACES4: + case PROTOCOL_DARKPLACES5: + break; + case PROTOCOL_DARKPLACES6: + case PROTOCOL_DARKPLACES7: + // FIXME: cl.cmd.buttons & 16 is +button5, Nexuiz/Xonotic specific + cl.cmd.crouch = (cl.cmd.buttons & 16) != 0; + break; + case PROTOCOL_UNKNOWN: + break; + } + + if (quemove) + cl.movecmd[0] = cl.cmd; + + // don't predict more than 200fps + if (realtime >= cl.lastpackettime + 0.005) + cl.movement_replay = true; // redo the prediction + + // now decide whether to actually send this move + // (otherwise it is only for prediction) + + // don't send too often or else network connections can get clogged by a + // high renderer framerate + packettime = 1.0 / bound(1, cl_netfps.value, 1000); + if (cl.movevars_timescale && cl.movevars_ticrate) + { + float maxtic = cl.movevars_ticrate / cl.movevars_timescale; + packettime = min(packettime, maxtic); + } + + // do not send 0ms packets because they mess up physics + if(cl.cmd.msec == 0 && cl.time > cl.oldtime && (cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS)) + return; + // always send if buttons changed or an impulse is pending + // even if it violates the rate limit! + important = (cl.cmd.impulse || (cl_netimmediatebuttons.integer && cl.cmd.buttons != cl.movecmd[1].buttons)); + // don't send too often (cl_netfps) + if (!important && realtime < cl.lastpackettime + packettime) + return; + // don't choke the connection with packets (obey rate limit) + // it is important that this check be last, because it adds a new + // frame to the shownetgraph output and any cancelation after this + // will produce a nasty spike-like look to the netgraph + // we also still send if it is important + if (!NetConn_CanSend(cls.netcon) && !important) + return; + // try to round off the lastpackettime to a multiple of the packet interval + // (this causes it to emit packets at a steady beat) + if (packettime > 0) + cl.lastpackettime = floor(realtime / packettime) * packettime; + else + cl.lastpackettime = realtime; + + buf.maxsize = sizeof(data); + buf.cursize = 0; + buf.data = data; + + // send the movement message + // PROTOCOL_QUAKE clc_move = 16 bytes total + // PROTOCOL_QUAKEDP clc_move = 16 bytes total + // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total + // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total + // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total + // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total + // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total + // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total + // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total + // PROTOCOL_DARKPLACES7 clc_move = 56 bytes total per move (can be up to 16 moves) + // PROTOCOL_QUAKEWORLD clc_move = 34 bytes total (typically, but can reach 43 bytes, or even 49 bytes with roll) + + // set prydon cursor info + CL_UpdatePrydonCursor(); + + if (cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon == SIGNONS) + { + switch (cls.protocol) + { + case PROTOCOL_QUAKEWORLD: + MSG_WriteByte(&buf, qw_clc_move); + // save the position for a checksum byte + checksumindex = buf.cursize; + MSG_WriteByte(&buf, 0); + // packet loss percentage + for (j = 0, packetloss = 0;j < NETGRAPH_PACKETS;j++) + if (cls.netcon->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET) + packetloss++; + packetloss = packetloss * 100 / NETGRAPH_PACKETS; + MSG_WriteByte(&buf, packetloss); + // write most recent 3 moves + QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, &cl.movecmd[2]); + QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[2], &cl.movecmd[1]); + QW_MSG_WriteDeltaUsercmd(&buf, &cl.movecmd[1], &cl.cmd); + // calculate the checksum + buf.data[checksumindex] = COM_BlockSequenceCRCByteQW(buf.data + checksumindex + 1, buf.cursize - checksumindex - 1, cls.netcon->outgoing_unreliable_sequence); + // if delta compression history overflows, request no delta + if (cls.netcon->outgoing_unreliable_sequence - cl.qw_validsequence >= QW_UPDATE_BACKUP-1) + cl.qw_validsequence = 0; + // request delta compression if appropriate + if (cl.qw_validsequence && !cl_nodelta.integer && cls.state == ca_connected && !cls.demorecording) + { + cl.qw_deltasequence[cls.netcon->outgoing_unreliable_sequence & QW_UPDATE_MASK] = cl.qw_validsequence; + MSG_WriteByte(&buf, qw_clc_delta); + MSG_WriteByte(&buf, cl.qw_validsequence & 255); + } + else + cl.qw_deltasequence[cls.netcon->outgoing_unreliable_sequence & QW_UPDATE_MASK] = -1; + break; + case PROTOCOL_QUAKE: + case PROTOCOL_QUAKEDP: + case PROTOCOL_NEHAHRAMOVIE: + case PROTOCOL_NEHAHRABJP: + case PROTOCOL_NEHAHRABJP2: + case PROTOCOL_NEHAHRABJP3: + // 5 bytes + MSG_WriteByte (&buf, clc_move); + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time + // 3 bytes (6 bytes in proquake) + if (cls.proquake_servermod == 1) // MOD_PROQUAKE + { + for (i = 0;i < 3;i++) + MSG_WriteAngle16i (&buf, cl.cmd.viewangles[i]); + } + else + { + for (i = 0;i < 3;i++) + MSG_WriteAngle8i (&buf, cl.cmd.viewangles[i]); + } + // 6 bytes + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); + // 2 bytes + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); + break; + case PROTOCOL_DARKPLACES2: + case PROTOCOL_DARKPLACES3: + // 5 bytes + MSG_WriteByte (&buf, clc_move); + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time + // 12 bytes + for (i = 0;i < 3;i++) + MSG_WriteAngle32f (&buf, cl.cmd.viewangles[i]); + // 6 bytes + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); + // 2 bytes + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); + break; + case PROTOCOL_DARKPLACES1: + case PROTOCOL_DARKPLACES4: + case PROTOCOL_DARKPLACES5: + // 5 bytes + MSG_WriteByte (&buf, clc_move); + MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time + // 6 bytes + for (i = 0;i < 3;i++) + MSG_WriteAngle16i (&buf, cl.cmd.viewangles[i]); + // 6 bytes + MSG_WriteCoord16i (&buf, cl.cmd.forwardmove); + MSG_WriteCoord16i (&buf, cl.cmd.sidemove); + MSG_WriteCoord16i (&buf, cl.cmd.upmove); + // 2 bytes + MSG_WriteByte (&buf, cl.cmd.buttons); + MSG_WriteByte (&buf, cl.cmd.impulse); + case PROTOCOL_DARKPLACES6: + case PROTOCOL_DARKPLACES7: + // set the maxusercmds variable to limit how many should be sent + maxusercmds = bound(1, cl_netrepeatinput.integer + 1, min(3, CL_MAX_USERCMDS)); + // when movement prediction is off, there's not much point in repeating old input as it will just be ignored + if (!cl.cmd.predicted) + maxusercmds = 1; + + // send the latest moves in order, the old ones will be + // ignored by the server harmlessly, however if the previous + // packets were lost these moves will be used + // + // this reduces packet loss impact on gameplay. + for (j = 0, cmd = &cl.movecmd[maxusercmds-1];j < maxusercmds;j++, cmd--) + { + // don't repeat any stale moves + if (cmd->sequence && cmd->sequence < cls.servermovesequence) + continue; + // 5/9 bytes + MSG_WriteByte (&buf, clc_move); + if (cls.protocol != PROTOCOL_DARKPLACES6) + MSG_WriteLong (&buf, cmd->predicted ? cmd->sequence : 0); + MSG_WriteFloat (&buf, cmd->time); // last server packet time + // 6 bytes + for (i = 0;i < 3;i++) + MSG_WriteAngle16i (&buf, cmd->viewangles[i]); + // 6 bytes + MSG_WriteCoord16i (&buf, cmd->forwardmove); + MSG_WriteCoord16i (&buf, cmd->sidemove); + MSG_WriteCoord16i (&buf, cmd->upmove); + // 5 bytes + MSG_WriteLong (&buf, cmd->buttons); + MSG_WriteByte (&buf, cmd->impulse); + // PRYDON_CLIENTCURSOR + // 30 bytes + MSG_WriteShort (&buf, (short)(cmd->cursor_screen[0] * 32767.0f)); + MSG_WriteShort (&buf, (short)(cmd->cursor_screen[1] * 32767.0f)); + MSG_WriteFloat (&buf, cmd->cursor_start[0]); + MSG_WriteFloat (&buf, cmd->cursor_start[1]); + MSG_WriteFloat (&buf, cmd->cursor_start[2]); + MSG_WriteFloat (&buf, cmd->cursor_impact[0]); + MSG_WriteFloat (&buf, cmd->cursor_impact[1]); + MSG_WriteFloat (&buf, cmd->cursor_impact[2]); + MSG_WriteShort (&buf, cmd->cursor_entitynumber); + } + break; + case PROTOCOL_UNKNOWN: + break; + } + } + + if (cls.protocol != PROTOCOL_QUAKEWORLD && buf.cursize) + { + // ack entity frame numbers received since the last input was sent + // (redundent to improve handling of client->server packet loss) + // if cl_netrepeatinput is 1 and client framerate matches server + // framerate, this is 10 bytes, if client framerate is lower this + // will be more... + int i, j; + int oldsequence = cl.cmd.sequence - bound(1, cl_netrepeatinput.integer + 1, 3); + if (oldsequence < 1) + oldsequence = 1; + for (i = 0;i < LATESTFRAMENUMS;i++) + { + j = (cl.latestframenumsposition + i) % LATESTFRAMENUMS; + if (cl.latestsendnums[j] >= oldsequence) + { + if (developer_networkentities.integer >= 10) + Con_Printf("send clc_ackframe %i\n", cl.latestframenums[j]); + MSG_WriteByte(&buf, clc_ackframe); + MSG_WriteLong(&buf, cl.latestframenums[j]); + } + } + } + + // PROTOCOL_DARKPLACES6 = 67 bytes per packet + // PROTOCOL_DARKPLACES7 = 71 bytes per packet + + // acknowledge any recently received data blocks + for (i = 0;i < CL_MAX_DOWNLOADACKS && (cls.dp_downloadack[i].start || cls.dp_downloadack[i].size);i++) + { + MSG_WriteByte(&buf, clc_ackdownloaddata); + MSG_WriteLong(&buf, cls.dp_downloadack[i].start); + MSG_WriteShort(&buf, cls.dp_downloadack[i].size); + cls.dp_downloadack[i].start = 0; + cls.dp_downloadack[i].size = 0; + } + + // send the reliable message (forwarded commands) if there is one + if (buf.cursize || cls.netcon->message.cursize) + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, max(20*(buf.cursize+40), cl_rate.integer), false); + + if (quemove) + { + // update the cl.movecmd array which holds the most recent moves, + // because we now need a new slot for the next input + for (i = CL_MAX_USERCMDS - 1;i >= 1;i--) + cl.movecmd[i] = cl.movecmd[i-1]; + cl.movecmd[0].msec = 0; + cl.movecmd[0].frametime = 0; + } + + // clear button 'click' states + in_attack.state &= ~2; + in_jump.state &= ~2; + in_button3.state &= ~2; + in_button4.state &= ~2; + in_button5.state &= ~2; + in_button6.state &= ~2; + in_button7.state &= ~2; + in_button8.state &= ~2; + in_use.state &= ~2; + in_button9.state &= ~2; + in_button10.state &= ~2; + in_button11.state &= ~2; + in_button12.state &= ~2; + in_button13.state &= ~2; + in_button14.state &= ~2; + in_button15.state &= ~2; + in_button16.state &= ~2; + // clear impulse + in_impulse = 0; + + if (cls.netcon->message.overflowed) + { + Con_Print("CL_SendMove: lost server connection\n"); + CL_Disconnect(); + SV_LockThreadMutex(); + Host_ShutdownServer(); + SV_UnlockThreadMutex(); + } +} + +/* +============ +CL_InitInput +============ +*/ +void CL_InitInput (void) +{ + Cmd_AddCommand ("+moveup",IN_UpDown, "swim upward"); + Cmd_AddCommand ("-moveup",IN_UpUp, "stop swimming upward"); + Cmd_AddCommand ("+movedown",IN_DownDown, "swim downward"); + Cmd_AddCommand ("-movedown",IN_DownUp, "stop swimming downward"); + Cmd_AddCommand ("+left",IN_LeftDown, "turn left"); + Cmd_AddCommand ("-left",IN_LeftUp, "stop turning left"); + Cmd_AddCommand ("+right",IN_RightDown, "turn right"); + Cmd_AddCommand ("-right",IN_RightUp, "stop turning right"); + Cmd_AddCommand ("+forward",IN_ForwardDown, "move forward"); + Cmd_AddCommand ("-forward",IN_ForwardUp, "stop moving forward"); + Cmd_AddCommand ("+back",IN_BackDown, "move backward"); + Cmd_AddCommand ("-back",IN_BackUp, "stop moving backward"); + Cmd_AddCommand ("+lookup", IN_LookupDown, "look upward"); + Cmd_AddCommand ("-lookup", IN_LookupUp, "stop looking upward"); + Cmd_AddCommand ("+lookdown", IN_LookdownDown, "look downward"); + Cmd_AddCommand ("-lookdown", IN_LookdownUp, "stop looking downward"); + Cmd_AddCommand ("+strafe", IN_StrafeDown, "activate strafing mode (move instead of turn)"); + Cmd_AddCommand ("-strafe", IN_StrafeUp, "deactivate strafing mode"); + Cmd_AddCommand ("+moveleft", IN_MoveleftDown, "strafe left"); + Cmd_AddCommand ("-moveleft", IN_MoveleftUp, "stop strafing left"); + Cmd_AddCommand ("+moveright", IN_MoverightDown, "strafe right"); + Cmd_AddCommand ("-moveright", IN_MoverightUp, "stop strafing right"); + Cmd_AddCommand ("+speed", IN_SpeedDown, "activate run mode (faster movement and turning)"); + Cmd_AddCommand ("-speed", IN_SpeedUp, "deactivate run mode"); + Cmd_AddCommand ("+attack", IN_AttackDown, "begin firing"); + Cmd_AddCommand ("-attack", IN_AttackUp, "stop firing"); + Cmd_AddCommand ("+jump", IN_JumpDown, "jump"); + Cmd_AddCommand ("-jump", IN_JumpUp, "end jump (so you can jump again)"); + Cmd_AddCommand ("impulse", IN_Impulse, "send an impulse number to server (select weapon, use item, etc)"); + Cmd_AddCommand ("+klook", IN_KLookDown, "activate keyboard looking mode, do not recenter view"); + Cmd_AddCommand ("-klook", IN_KLookUp, "deactivate keyboard looking mode"); + Cmd_AddCommand ("+mlook", IN_MLookDown, "activate mouse looking mode, do not recenter view"); + Cmd_AddCommand ("-mlook", IN_MLookUp, "deactivate mouse looking mode"); + + // LordHavoc: added use button + Cmd_AddCommand ("+use", IN_UseDown, "use something (may be used by some mods)"); + Cmd_AddCommand ("-use", IN_UseUp, "stop using something"); + + // LordHavoc: added 6 new buttons + Cmd_AddCommand ("+button3", IN_Button3Down, "activate button3 (behavior depends on mod)"); + Cmd_AddCommand ("-button3", IN_Button3Up, "deactivate button3"); + Cmd_AddCommand ("+button4", IN_Button4Down, "activate button4 (behavior depends on mod)"); + Cmd_AddCommand ("-button4", IN_Button4Up, "deactivate button4"); + Cmd_AddCommand ("+button5", IN_Button5Down, "activate button5 (behavior depends on mod)"); + Cmd_AddCommand ("-button5", IN_Button5Up, "deactivate button5"); + Cmd_AddCommand ("+button6", IN_Button6Down, "activate button6 (behavior depends on mod)"); + Cmd_AddCommand ("-button6", IN_Button6Up, "deactivate button6"); + Cmd_AddCommand ("+button7", IN_Button7Down, "activate button7 (behavior depends on mod)"); + Cmd_AddCommand ("-button7", IN_Button7Up, "deactivate button7"); + Cmd_AddCommand ("+button8", IN_Button8Down, "activate button8 (behavior depends on mod)"); + Cmd_AddCommand ("-button8", IN_Button8Up, "deactivate button8"); + Cmd_AddCommand ("+button9", IN_Button9Down, "activate button9 (behavior depends on mod)"); + Cmd_AddCommand ("-button9", IN_Button9Up, "deactivate button9"); + Cmd_AddCommand ("+button10", IN_Button10Down, "activate button10 (behavior depends on mod)"); + Cmd_AddCommand ("-button10", IN_Button10Up, "deactivate button10"); + Cmd_AddCommand ("+button11", IN_Button11Down, "activate button11 (behavior depends on mod)"); + Cmd_AddCommand ("-button11", IN_Button11Up, "deactivate button11"); + Cmd_AddCommand ("+button12", IN_Button12Down, "activate button12 (behavior depends on mod)"); + Cmd_AddCommand ("-button12", IN_Button12Up, "deactivate button12"); + Cmd_AddCommand ("+button13", IN_Button13Down, "activate button13 (behavior depends on mod)"); + Cmd_AddCommand ("-button13", IN_Button13Up, "deactivate button13"); + Cmd_AddCommand ("+button14", IN_Button14Down, "activate button14 (behavior depends on mod)"); + Cmd_AddCommand ("-button14", IN_Button14Up, "deactivate button14"); + Cmd_AddCommand ("+button15", IN_Button15Down, "activate button15 (behavior depends on mod)"); + Cmd_AddCommand ("-button15", IN_Button15Up, "deactivate button15"); + Cmd_AddCommand ("+button16", IN_Button16Down, "activate button16 (behavior depends on mod)"); + Cmd_AddCommand ("-button16", IN_Button16Up, "deactivate button16"); + + // LordHavoc: added bestweapon command + Cmd_AddCommand ("bestweapon", IN_BestWeapon, "send an impulse number to server to select the first usable weapon out of several (example: 8 7 6 5 4 3 2 1)"); +#if 0 + Cmd_AddCommand ("cycleweapon", IN_CycleWeapon, "send an impulse number to server to select the next usable weapon out of several (example: 9 4 8) if you are holding one of these, and choose the first one if you are holding none of these"); +#endif + Cmd_AddCommand ("register_bestweapon", IN_BestWeapon_Register_f, "(for QC usage only) change weapon parameters to be used by bestweapon; stuffcmd this in ClientConnect"); + + Cvar_RegisterVariable(&cl_yawmode); + Cvar_RegisterVariable(&cl_pitchmode); + Cvar_RegisterVariable(&cl_comfort); + Cvar_RegisterVariable(&cl_yawspeed); + Cvar_RegisterVariable(&cl_pitchmult); + Cvar_RegisterVariable(&cl_yawmult); + + Cvar_RegisterVariable(&cl_movecliptokeyboard); + Cvar_RegisterVariable(&cl_movement); + Cvar_RegisterVariable(&cl_movement_replay); + Cvar_RegisterVariable(&cl_movement_nettimeout); + Cvar_RegisterVariable(&cl_movement_minping); + Cvar_RegisterVariable(&cl_movement_track_canjump); + Cvar_RegisterVariable(&cl_movement_maxspeed); + Cvar_RegisterVariable(&cl_movement_maxairspeed); + Cvar_RegisterVariable(&cl_movement_stopspeed); + Cvar_RegisterVariable(&cl_movement_friction); + Cvar_RegisterVariable(&cl_movement_wallfriction); + Cvar_RegisterVariable(&cl_movement_waterfriction); + Cvar_RegisterVariable(&cl_movement_edgefriction); + Cvar_RegisterVariable(&cl_movement_stepheight); + Cvar_RegisterVariable(&cl_movement_accelerate); + Cvar_RegisterVariable(&cl_movement_airaccelerate); + Cvar_RegisterVariable(&cl_movement_wateraccelerate); + Cvar_RegisterVariable(&cl_movement_jumpvelocity); + Cvar_RegisterVariable(&cl_movement_airaccel_qw); + Cvar_RegisterVariable(&cl_movement_airaccel_sideways_friction); + + Cvar_RegisterVariable(&in_pitch_min); + Cvar_RegisterVariable(&in_pitch_max); + Cvar_RegisterVariable(&m_filter); + Cvar_RegisterVariable(&m_accelerate); + Cvar_RegisterVariable(&m_accelerate_minspeed); + Cvar_RegisterVariable(&m_accelerate_maxspeed); + Cvar_RegisterVariable(&m_accelerate_filter); + + Cvar_RegisterVariable(&cl_netfps); + Cvar_RegisterVariable(&cl_netrepeatinput); + Cvar_RegisterVariable(&cl_netimmediatebuttons); + + Cvar_RegisterVariable(&cl_nodelta); + + Cvar_RegisterVariable(&cl_csqc_generatemousemoveevents); +} + diff --git a/app/jni/cl_main.c b/app/jni/cl_main.c new file mode 100644 index 0000000..567993f --- /dev/null +++ b/app/jni/cl_main.c @@ -0,0 +1,2499 @@ +/* +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" +#include "cl_collision.h" +#include "cl_video.h" +#include "image.h" +#include "csprogs.h" +#include "r_shadow.h" +#include "libcurl.h" +#include "snd_main.h" + +// we need to declare some mouse variables here, because the menu system +// references them even when on a unix system. + +cvar_t csqc_progname = {0, "csqc_progname","csprogs.dat","name of csprogs.dat file to load"}; +cvar_t csqc_progcrc = {CVAR_READONLY, "csqc_progcrc","-1","CRC of csprogs.dat file to load (-1 is none), only used during level changes and then reset to -1"}; +cvar_t csqc_progsize = {CVAR_READONLY, "csqc_progsize","-1","file size of csprogs.dat file to load (-1 is none), only used during level changes and then reset to -1"}; +cvar_t csqc_usedemoprogs = {0, "csqc_usedemoprogs","1","use csprogs stored in demos"}; + +cvar_t cl_shownet = {0, "cl_shownet","0","1 = print packet size, 2 = print packet message list"}; +cvar_t cl_nolerp = {0, "cl_nolerp", "0","network update smoothing"}; +cvar_t cl_lerpexcess = {0, "cl_lerpexcess", "0","maximum allowed lerp excess (hides, not fixes, some packet loss)"}; +cvar_t cl_lerpanim_maxdelta_server = {0, "cl_lerpanim_maxdelta_server", "0.1","maximum frame delta for smoothing between server-controlled animation frames (when 0, one network frame)"}; +cvar_t cl_lerpanim_maxdelta_framegroups = {0, "cl_lerpanim_maxdelta_framegroups", "0.1","maximum frame delta for smoothing between framegroups (when 0, one network frame)"}; + +cvar_t cl_itembobheight = {0, "cl_itembobheight", "0","how much items bob up and down (try 8)"}; +cvar_t cl_itembobspeed = {0, "cl_itembobspeed", "0.5","how frequently items bob up and down"}; + +cvar_t lookspring = {CVAR_SAVE, "lookspring","0","returns pitch to level with the floor when no longer holding a pitch key"}; +cvar_t lookstrafe = {CVAR_SAVE, "lookstrafe","0","move instead of turning"}; +cvar_t sensitivity = {CVAR_SAVE, "sensitivity","3","mouse speed multiplier"}; + +cvar_t m_pitch = {CVAR_SAVE, "m_pitch","0.022","mouse pitch speed multiplier"}; +cvar_t m_yaw = {CVAR_SAVE, "m_yaw","0.022","mouse yaw speed multiplier"}; +cvar_t m_forward = {CVAR_SAVE, "m_forward","1","mouse forward speed multiplier"}; +cvar_t m_side = {CVAR_SAVE, "m_side","0.8","mouse side speed multiplier"}; + +cvar_t freelook = {CVAR_SAVE, "freelook", "1","mouse controls pitch instead of forward/back"}; + +cvar_t cl_nosplashscreen = {CVAR_SAVE, "cl_nosplashscreen", "0", "prevents the credits splashscreen from being displayed on game start" }; + +cvar_t cl_autodemo = {CVAR_SAVE, "cl_autodemo", "0", "records every game played, using the date/time and map name to name the demo file" }; +cvar_t cl_autodemo_nameformat = {CVAR_SAVE, "cl_autodemo_nameformat", "autodemos/%Y-%m-%d_%H-%M", "The format of the cl_autodemo filename, followed by the map name (the date is encoded using strftime escapes)" }; +cvar_t cl_autodemo_delete = {0, "cl_autodemo_delete", "0", "Delete demos after recording. This is a bitmask, bit 1 gives the default, bit 0 the value for the current demo. Thus, the values are: 0 = disabled; 1 = delete current demo only; 2 = delete all demos except the current demo; 3 = delete all demos from now on" }; + +cvar_t r_draweffects = {0, "r_draweffects", "1","renders temporary sprite effects"}; + +cvar_t cl_explosions_alpha_start = {CVAR_SAVE, "cl_explosions_alpha_start", "1.5","starting alpha of an explosion shell"}; +cvar_t cl_explosions_alpha_end = {CVAR_SAVE, "cl_explosions_alpha_end", "0","end alpha of an explosion shell (just before it disappears)"}; +cvar_t cl_explosions_size_start = {CVAR_SAVE, "cl_explosions_size_start", "16","starting size of an explosion shell"}; +cvar_t cl_explosions_size_end = {CVAR_SAVE, "cl_explosions_size_end", "128","ending alpha of an explosion shell (just before it disappears)"}; +cvar_t cl_explosions_lifetime = {CVAR_SAVE, "cl_explosions_lifetime", "0.5","how long an explosion shell lasts"}; + +cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "0","stains lightmaps, much faster than decals but blurred"}; +cvar_t cl_stainmaps_clearonload = {CVAR_SAVE, "cl_stainmaps_clearonload", "1","clear stainmaps on map restart"}; + +cvar_t cl_beams_polygons = {CVAR_SAVE, "cl_beams_polygons", "1","use beam polygons instead of models"}; +cvar_t cl_beams_quakepositionhack = {CVAR_SAVE, "cl_beams_quakepositionhack", "1", "makes your lightning gun appear to fire from your waist (as in Quake and QuakeWorld)"}; +cvar_t cl_beams_instantaimhack = {CVAR_SAVE, "cl_beams_instantaimhack", "0", "makes your lightning gun aiming update instantly"}; +cvar_t cl_beams_lightatend = {CVAR_SAVE, "cl_beams_lightatend", "0", "make a light at the end of the beam"}; + +cvar_t cl_deathfade = {CVAR_SAVE, "cl_deathfade", "0", "fade screen to dark red when dead, value represents how fast the fade is (higher is faster)"}; + +cvar_t cl_noplayershadow = {CVAR_SAVE, "cl_noplayershadow", "0","hide player shadow"}; + +cvar_t cl_dlights_decayradius = {CVAR_SAVE, "cl_dlights_decayradius", "1", "reduces size of light flashes over time"}; +cvar_t cl_dlights_decaybrightness = {CVAR_SAVE, "cl_dlights_decaybrightness", "1", "reduces brightness of light flashes over time"}; + +cvar_t qport = {0, "qport", "0", "identification key for playing on qw servers (allows you to maintain a connection to a quakeworld server even if your port changes)"}; + +cvar_t cl_prydoncursor = {0, "cl_prydoncursor", "0", "enables a mouse pointer which is able to click on entities in the world, useful for point and click mods, see PRYDON_CLIENTCURSOR extension in dpextensions.qc"}; +cvar_t cl_prydoncursor_notrace = {0, "cl_prydoncursor_notrace", "0", "disables traceline used in prydon cursor reporting to the game, saving some cpu time"}; + +cvar_t cl_deathnoviewmodel = {0, "cl_deathnoviewmodel", "1", "hides gun model when dead"}; + +cvar_t cl_locs_enable = {CVAR_SAVE, "locs_enable", "1", "enables replacement of certain % codes in chat messages: %l (location), %d (last death location), %h (health), %a (armor), %x (rockets), %c (cells), %r (rocket launcher status), %p (powerup status), %w (weapon status), %t (current time in level)"}; +cvar_t cl_locs_show = {0, "locs_show", "0", "shows defined locations for editing purposes"}; + +extern cvar_t r_equalize_entities_fullbright; + +client_static_t cls; +client_state_t cl; + +/* +===================== +CL_ClearState + +===================== +*/ +void CL_ClearState(void) +{ + int i; + entity_t *ent; + + CL_VM_ShutDown(); + +// wipe the entire cl structure + Mem_EmptyPool(cls.levelmempool); + memset (&cl, 0, sizeof(cl)); + + S_StopAllSounds(); + + // reset the view zoom interpolation + cl.mviewzoom[0] = cl.mviewzoom[1] = 1; + cl.sensitivityscale = 1.0f; + + // enable rendering of the world and such + cl.csqc_vidvars.drawworld = r_drawworld.integer != 0; + cl.csqc_vidvars.drawenginesbar = true; + cl.csqc_vidvars.drawcrosshair = true; + + // set up the float version of the stats array for easier access to float stats + cl.statsf = (float *)cl.stats; + + cl.num_entities = 0; + cl.num_static_entities = 0; + cl.num_brushmodel_entities = 0; + + // tweak these if the game runs out + cl.max_csqcrenderentities = 0; + cl.max_entities = MAX_ENITIES_INITIAL; + cl.max_static_entities = MAX_STATICENTITIES; + cl.max_effects = MAX_EFFECTS; + cl.max_beams = MAX_BEAMS; + cl.max_dlights = MAX_DLIGHTS; + cl.max_lightstyle = MAX_LIGHTSTYLES; + cl.max_brushmodel_entities = MAX_EDICTS; + cl.max_particles = MAX_PARTICLES_INITIAL; // grows dynamically + cl.max_decals = MAX_DECALS_INITIAL; // grows dynamically + cl.max_showlmps = 0; + + cl.num_dlights = 0; + cl.num_effects = 0; + cl.num_beams = 0; + + cl.csqcrenderentities = NULL; + cl.entities = (entity_t *)Mem_Alloc(cls.levelmempool, cl.max_entities * sizeof(entity_t)); + cl.entities_active = (unsigned char *)Mem_Alloc(cls.levelmempool, cl.max_brushmodel_entities * sizeof(unsigned char)); + cl.static_entities = (entity_t *)Mem_Alloc(cls.levelmempool, cl.max_static_entities * sizeof(entity_t)); + cl.effects = (cl_effect_t *)Mem_Alloc(cls.levelmempool, cl.max_effects * sizeof(cl_effect_t)); + cl.beams = (beam_t *)Mem_Alloc(cls.levelmempool, cl.max_beams * sizeof(beam_t)); + cl.dlights = (dlight_t *)Mem_Alloc(cls.levelmempool, cl.max_dlights * sizeof(dlight_t)); + cl.lightstyle = (lightstyle_t *)Mem_Alloc(cls.levelmempool, cl.max_lightstyle * sizeof(lightstyle_t)); + cl.brushmodel_entities = (int *)Mem_Alloc(cls.levelmempool, cl.max_brushmodel_entities * sizeof(int)); + cl.particles = (particle_t *) Mem_Alloc(cls.levelmempool, cl.max_particles * sizeof(particle_t)); + cl.decals = (decal_t *) Mem_Alloc(cls.levelmempool, cl.max_decals * sizeof(decal_t)); + cl.showlmps = NULL; + + // LordHavoc: have to set up the baseline info for alpha and other stuff + for (i = 0;i < cl.max_entities;i++) + { + cl.entities[i].state_baseline = defaultstate; + cl.entities[i].state_previous = defaultstate; + cl.entities[i].state_current = defaultstate; + } + + if (gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + VectorSet(cl.playerstandmins, -16, -16, -24); + VectorSet(cl.playerstandmaxs, 16, 16, 45); + VectorSet(cl.playercrouchmins, -16, -16, -24); + VectorSet(cl.playercrouchmaxs, 16, 16, 25); + } + else + { + VectorSet(cl.playerstandmins, -16, -16, -24); + VectorSet(cl.playerstandmaxs, 16, 16, 24); + VectorSet(cl.playercrouchmins, -16, -16, -24); + VectorSet(cl.playercrouchmaxs, 16, 16, 24); + } + + // disable until we get textures for it + R_ResetSkyBox(); + + ent = &cl.entities[0]; + // entire entity array was cleared, so just fill in a few fields + ent->state_current.active = true; + ent->render.model = cl.worldmodel = NULL; // no world model yet + ent->render.alpha = 1; + ent->render.flags = RENDER_SHADOW | RENDER_LIGHT; + Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1); + ent->render.allowdecals = true; + CL_UpdateRenderEntity(&ent->render); + + // noclip is turned off at start + noclip_anglehack = false; + + // mark all frames invalid for delta + memset(cl.qw_deltasequence, -1, sizeof(cl.qw_deltasequence)); + + // set bestweapon data back to Quake data + IN_BestWeapon_ResetData(); + + CL_Screen_NewMap(); +} + +void CL_SetInfo(const char *key, const char *value, qboolean send, qboolean allowstarkey, qboolean allowmodel, qboolean quiet) +{ + int i; + qboolean fail = false; + char vabuf[1024]; + if (!allowstarkey && key[0] == '*') + fail = true; + if (!allowmodel && (!strcasecmp(key, "pmodel") || !strcasecmp(key, "emodel"))) + fail = true; + for (i = 0;key[i];i++) + if (ISWHITESPACE(key[i]) || key[i] == '\"') + fail = true; + for (i = 0;value[i];i++) + if (value[i] == '\r' || value[i] == '\n' || value[i] == '\"') + fail = true; + if (fail) + { + if (!quiet) + Con_Printf("Can't setinfo \"%s\" \"%s\"\n", key, value); + return; + } + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), key, value); + if (cls.state == ca_connected && cls.netcon) + { + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "setinfo \"%s\" \"%s\"", key, value)); + } + else if (!strcasecmp(key, "name")) + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "name \"%s\"", value)); + } + else if (!strcasecmp(key, "playermodel")) + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "playermodel \"%s\"", value)); + } + else if (!strcasecmp(key, "playerskin")) + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "playerskin \"%s\"", value)); + } + else if (!strcasecmp(key, "topcolor")) + { + // don't send anything, the combined color code will be updated manually + } + else if (!strcasecmp(key, "bottomcolor")) + { + // don't send anything, the combined color code will be updated manually + } + else if (!strcasecmp(key, "rate")) + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "rate \"%s\"", value)); + } + } +} + +void CL_ExpandEntities(int num) +{ + int i, oldmaxentities; + entity_t *oldentities; + if (num >= cl.max_entities) + { + if (!cl.entities) + Sys_Error("CL_ExpandEntities: cl.entities not initialized"); + if (num >= MAX_EDICTS) + Host_Error("CL_ExpandEntities: num %i >= %i", num, MAX_EDICTS); + oldmaxentities = cl.max_entities; + oldentities = cl.entities; + cl.max_entities = (num & ~255) + 256; + cl.entities = (entity_t *)Mem_Alloc(cls.levelmempool, cl.max_entities * sizeof(entity_t)); + memcpy(cl.entities, oldentities, oldmaxentities * sizeof(entity_t)); + Mem_Free(oldentities); + for (i = oldmaxentities;i < cl.max_entities;i++) + { + cl.entities[i].state_baseline = defaultstate; + cl.entities[i].state_previous = defaultstate; + cl.entities[i].state_current = defaultstate; + } + } +} + +void CL_ExpandCSQCRenderEntities(int num) +{ + int i; + int oldmaxcsqcrenderentities; + entity_render_t *oldcsqcrenderentities; + if (num >= cl.max_csqcrenderentities) + { + if (num >= MAX_EDICTS) + Host_Error("CL_ExpandEntities: num %i >= %i", num, MAX_EDICTS); + oldmaxcsqcrenderentities = cl.max_csqcrenderentities; + oldcsqcrenderentities = cl.csqcrenderentities; + cl.max_csqcrenderentities = (num & ~255) + 256; + cl.csqcrenderentities = (entity_render_t *)Mem_Alloc(cls.levelmempool, cl.max_csqcrenderentities * sizeof(entity_render_t)); + if (oldcsqcrenderentities) + { + memcpy(cl.csqcrenderentities, oldcsqcrenderentities, oldmaxcsqcrenderentities * sizeof(entity_render_t)); + for (i = 0;i < r_refdef.scene.numentities;i++) + if(r_refdef.scene.entities[i] >= oldcsqcrenderentities && r_refdef.scene.entities[i] < (oldcsqcrenderentities + oldmaxcsqcrenderentities)) + r_refdef.scene.entities[i] = cl.csqcrenderentities + (r_refdef.scene.entities[i] - oldcsqcrenderentities); + Mem_Free(oldcsqcrenderentities); + } + } +} + +/* +===================== +CL_Disconnect + +Sends a disconnect message to the server +This is also called on Host_Error, so it shouldn't cause any errors +===================== +*/ +void CL_Disconnect(void) +{ + if (cls.state == ca_dedicated) + return; + + if (COM_CheckParm("-profilegameonly")) + Sys_AllowProfiling(false); + + Curl_Clear_forthismap(); + + Con_DPrintf("CL_Disconnect\n"); + + Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); + CL_VM_ShutDown(); +// stop sounds (especially looping!) + S_StopAllSounds (); + + cl.parsingtextexpectingpingforscores = 0; // just in case no reply has come yet + + // clear contents blends + cl.cshifts[0].percent = 0; + cl.cshifts[1].percent = 0; + cl.cshifts[2].percent = 0; + cl.cshifts[3].percent = 0; + + cl.worldmodel = NULL; + + CL_Parse_ErrorCleanUp(); + + if (cls.demoplayback) + CL_StopPlayback(); + else if (cls.netcon) + { + sizebuf_t buf; + unsigned char bufdata[8]; + if (cls.demorecording) + CL_Stop_f(); + + // send disconnect message 3 times to improve chances of server + // receiving it (but it still fails sometimes) + memset(&buf, 0, sizeof(buf)); + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + Con_DPrint("Sending drop command\n"); + MSG_WriteByte(&buf, qw_clc_stringcmd); + MSG_WriteString(&buf, "drop"); + } + else + { + Con_DPrint("Sending clc_disconnect\n"); + MSG_WriteByte(&buf, clc_disconnect); + } + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, false); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, false); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, false); + NetConn_Close(cls.netcon); + cls.netcon = NULL; + } + cls.state = ca_disconnected; + cl.islocalgame = false; + + cls.demoplayback = cls.timedemo = false; + cls.signon = 0; +} + +void CL_Disconnect_f(void) +{ + CL_Disconnect (); + if (sv.active) + Host_ShutdownServer (); +} + + + + +/* +===================== +CL_EstablishConnection + +Host should be either "local" or a net address +===================== +*/ +void CL_EstablishConnection(const char *host, int firstarg) +{ + if (cls.state == ca_dedicated) + return; + + // don't connect to a server if we're benchmarking a demo + if (COM_CheckParm("-benchmark")) + return; + + // clear menu's connect error message + M_Update_Return_Reason(""); + cls.demonum = -1; + + // stop demo loop in case this fails + if (cls.demoplayback) + CL_StopPlayback(); + + // if downloads are running, cancel their finishing action + Curl_Clear_forthismap(); + + // make sure the client ports are open before attempting to connect + NetConn_UpdateSockets(); + + if (LHNETADDRESS_FromString(&cls.connect_address, host, 26000) && (cls.connect_mysocket = NetConn_ChooseClientSocketForAddress(&cls.connect_address))) + { + cls.connect_trying = true; + cls.connect_remainingtries = 3; + cls.connect_nextsendtime = 0; + + // only NOW, set connect_userinfo + if(firstarg >= 0) + { + int i; + *cls.connect_userinfo = 0; + for(i = firstarg; i+2 <= Cmd_Argc(); i += 2) + InfoString_SetValue(cls.connect_userinfo, sizeof(cls.connect_userinfo), Cmd_Argv(i), Cmd_Argv(i+1)); + } + else if(firstarg < -1) + { + // -1: keep as is (reconnect) + // -2: clear + *cls.connect_userinfo = 0; + } + + M_Update_Return_Reason("Trying to connect..."); + } + else + { + Con_Print("Unable to find a suitable network socket to connect to server.\n"); + M_Update_Return_Reason("No network"); + } +} + +/* +============== +CL_PrintEntities_f +============== +*/ +static void CL_PrintEntities_f(void) +{ + entity_t *ent; + int i; + + for (i = 0, ent = cl.entities;i < cl.num_entities;i++, ent++) + { + const char* modelname; + + if (!ent->state_current.active) + continue; + + if (ent->render.model) + modelname = ent->render.model->name; + else + modelname = "--no model--"; + Con_Printf("%3i: %-25s:%4i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, modelname, ent->render.framegroupblend[0].frame, (int) ent->state_current.origin[0], (int) ent->state_current.origin[1], (int) ent->state_current.origin[2], (int) ent->state_current.angles[0] % 360, (int) ent->state_current.angles[1] % 360, (int) ent->state_current.angles[2] % 360, ent->render.scale, ent->render.alpha); + } +} + +/* +=============== +CL_ModelIndexList_f + +List information on all models in the client modelindex +=============== +*/ +static void CL_ModelIndexList_f(void) +{ + int i; + dp_model_t *model; + + // Print Header + Con_Printf("%3s: %-30s %-8s %-8s\n", "ID", "Name", "Type", "Triangles"); + + for (i = -MAX_MODELS;i < MAX_MODELS;i++) + { + model = CL_GetModelByIndex(i); + if (!model) + continue; + if(model->loaded || i == 1) + Con_Printf("%3i: %-30s %-8s %-10i\n", i, model->name, model->modeldatatypestring, model->surfmesh.num_triangles); + else + Con_Printf("%3i: %-30s %-30s\n", i, model->name, "--no local model found--"); + i++; + } +} + +/* +=============== +CL_SoundIndexList_f + +List all sounds in the client soundindex +=============== +*/ +static void CL_SoundIndexList_f(void) +{ + int i = 1; + + while(cl.sound_precache[i] && i != MAX_SOUNDS) + { // Valid Sound + Con_Printf("%i : %s\n", i, cl.sound_precache[i]->name); + i++; + } +} + +/* +=============== +CL_UpdateRenderEntity + +Updates inversematrix, animation interpolation factors, scale, and mins/maxs +=============== +*/ +void CL_UpdateRenderEntity(entity_render_t *ent) +{ + vec3_t org; + vec_t scale; + dp_model_t *model = ent->model; + // update the inverse matrix for the renderer + Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix); + // update the animation blend state + VM_FrameBlendFromFrameGroupBlend(ent->frameblend, ent->framegroupblend, ent->model, cl.time); + // we need the matrix origin to center the box + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + // update entity->render.scale because the renderer needs it + ent->scale = scale = Matrix4x4_ScaleFromMatrix(&ent->matrix); + if (model) + { + // NOTE: this directly extracts vector components from the matrix, which relies on the matrix orientation! +#ifdef MATRIX4x4_OPENGLORIENTATION + if (ent->matrix.m[0][2] != 0 || ent->matrix.m[1][2] != 0) +#else + if (ent->matrix.m[2][0] != 0 || ent->matrix.m[2][1] != 0) +#endif + { + // pitch or roll + VectorMA(org, scale, model->rotatedmins, ent->mins); + VectorMA(org, scale, model->rotatedmaxs, ent->maxs); + } +#ifdef MATRIX4x4_OPENGLORIENTATION + else if (ent->matrix.m[1][0] != 0 || ent->matrix.m[0][1] != 0) +#else + else if (ent->matrix.m[0][1] != 0 || ent->matrix.m[1][0] != 0) +#endif + { + // yaw + VectorMA(org, scale, model->yawmins, ent->mins); + VectorMA(org, scale, model->yawmaxs, ent->maxs); + } + else + { + VectorMA(org, scale, model->normalmins, ent->mins); + VectorMA(org, scale, model->normalmaxs, ent->maxs); + } + } + else + { + ent->mins[0] = org[0] - 16; + ent->mins[1] = org[1] - 16; + ent->mins[2] = org[2] - 16; + ent->maxs[0] = org[0] + 16; + ent->maxs[1] = org[1] + 16; + ent->maxs[2] = org[2] + 16; + } +} + +/* +=============== +CL_LerpPoint + +Determines the fraction between the last two messages that the objects +should be put at. +=============== +*/ +static float CL_LerpPoint(void) +{ + float f; + + if (cl_nettimesyncboundmode.integer == 1) + cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); + + // LordHavoc: lerp in listen games as the server is being capped below the client (usually) + if (cl.mtime[0] <= cl.mtime[1]) + { + cl.time = cl.mtime[0]; + return 1; + } + + f = (cl.time - cl.mtime[1]) / (cl.mtime[0] - cl.mtime[1]); + return bound(0, f, 1 + cl_lerpexcess.value); +} + +void CL_ClearTempEntities (void) +{ + r_refdef.scene.numtempentities = 0; + // grow tempentities buffer on request + if (r_refdef.scene.expandtempentities) + { + Con_Printf("CL_NewTempEntity: grow maxtempentities from %i to %i\n", r_refdef.scene.maxtempentities, r_refdef.scene.maxtempentities * 2); + r_refdef.scene.maxtempentities *= 2; + r_refdef.scene.tempentities = (entity_render_t *)Mem_Realloc(cls.permanentmempool, r_refdef.scene.tempentities, sizeof(entity_render_t) * r_refdef.scene.maxtempentities); + r_refdef.scene.expandtempentities = false; + } +} + +entity_render_t *CL_NewTempEntity(double shadertime) +{ + entity_render_t *render; + + if (r_refdef.scene.numentities >= r_refdef.scene.maxentities) + return NULL; + if (r_refdef.scene.numtempentities >= r_refdef.scene.maxtempentities) + { + r_refdef.scene.expandtempentities = true; // will be reallocated next frame since current frame may have pointers set already + return NULL; + } + render = &r_refdef.scene.tempentities[r_refdef.scene.numtempentities++]; + memset (render, 0, sizeof(*render)); + r_refdef.scene.entities[r_refdef.scene.numentities++] = render; + + render->shadertime = shadertime; + render->alpha = 1; + VectorSet(render->colormod, 1, 1, 1); + VectorSet(render->glowmod, 1, 1, 1); + return render; +} + +void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate) +{ + int i; + cl_effect_t *e; + if (!modelindex) // sanity check + return; + if (framerate < 1) + { + Con_Printf("CL_Effect: framerate %f is < 1\n", framerate); + return; + } + if (framecount < 1) + { + Con_Printf("CL_Effect: framecount %i is < 1\n", framecount); + return; + } + for (i = 0, e = cl.effects;i < cl.max_effects;i++, e++) + { + if (e->active) + continue; + e->active = true; + VectorCopy(org, e->origin); + e->modelindex = modelindex; + e->starttime = cl.time; + e->startframe = startframe; + e->endframe = startframe + framecount; + e->framerate = framerate; + + e->frame = 0; + e->frame1time = cl.time; + e->frame2time = cl.time; + cl.num_effects = max(cl.num_effects, i + 1); + break; + } +} + +void CL_AllocLightFlash(entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags) +{ + int i; + dlight_t *dl; + +// then look for anything else + dl = cl.dlights; + for (i = 0;i < cl.max_dlights;i++, dl++) + if (!dl->radius) + break; + + // unable to find one + if (i == cl.max_dlights) + return; + + //Con_Printf("dlight %i : %f %f %f : %f %f %f\n", i, org[0], org[1], org[2], red * radius, green * radius, blue * radius); + memset (dl, 0, sizeof(*dl)); + cl.num_dlights = max(cl.num_dlights, i + 1); + Matrix4x4_Normalize(&dl->matrix, matrix); + dl->ent = ent; + Matrix4x4_OriginFromMatrix(&dl->matrix, dl->origin); + CL_FindNonSolidLocation(dl->origin, dl->origin, 6); + Matrix4x4_SetOrigin(&dl->matrix, dl->origin[0], dl->origin[1], dl->origin[2]); + dl->radius = radius; + dl->color[0] = red; + dl->color[1] = green; + dl->color[2] = blue; + dl->initialradius = radius; + dl->initialcolor[0] = red; + dl->initialcolor[1] = green; + dl->initialcolor[2] = blue; + dl->decay = decay / radius; // changed decay to be a percentage decrease + dl->intensity = 1; // this is what gets decayed + if (lifetime) + dl->die = cl.time + lifetime; + else + dl->die = 0; + if (cubemapnum > 0) + dpsnprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", cubemapnum); + else + dl->cubemapname[0] = 0; + dl->style = style; + dl->shadow = shadowenable; + dl->corona = corona; + dl->flags = flags; + dl->coronasizescale = coronasizescale; + dl->ambientscale = ambientscale; + dl->diffusescale = diffusescale; + dl->specularscale = specularscale; +} + +static void CL_DecayLightFlashes(void) +{ + int i, oldmax; + dlight_t *dl; + float time; + + time = bound(0, cl.time - cl.oldtime, 0.1); + oldmax = cl.num_dlights; + cl.num_dlights = 0; + for (i = 0, dl = cl.dlights;i < oldmax;i++, dl++) + { + if (dl->radius) + { + dl->intensity -= time * dl->decay; + if (cl.time < dl->die && dl->intensity > 0) + { + if (cl_dlights_decayradius.integer) + dl->radius = dl->initialradius * dl->intensity; + else + dl->radius = dl->initialradius; + if (cl_dlights_decaybrightness.integer) + VectorScale(dl->initialcolor, dl->intensity, dl->color); + else + VectorCopy(dl->initialcolor, dl->color); + cl.num_dlights = i + 1; + } + else + dl->radius = 0; + } + } +} + +// called before entity relinking +void CL_RelinkLightFlashes(void) +{ + int i, j, k, l; + dlight_t *dl; + float frac, f; + matrix4x4_t tempmatrix; + + if (r_dynamic.integer) + { + for (i = 0, dl = cl.dlights;i < cl.num_dlights && r_refdef.scene.numlights < MAX_DLIGHTS;i++, dl++) + { + if (dl->radius) + { + tempmatrix = dl->matrix; + Matrix4x4_Scale(&tempmatrix, dl->radius, 1); + // we need the corona fading to be persistent + R_RTLight_Update(&dl->rtlight, false, &tempmatrix, dl->color, dl->style, dl->cubemapname, dl->shadow, dl->corona, dl->coronasizescale, dl->ambientscale, dl->diffusescale, dl->specularscale, dl->flags); + r_refdef.scene.lights[r_refdef.scene.numlights++] = &dl->rtlight; + } + } + } + + if (!cl.lightstyle) + { + for (j = 0;j < cl.max_lightstyle;j++) + { + r_refdef.scene.rtlightstylevalue[j] = 1; + r_refdef.scene.lightstylevalue[j] = 256; + } + return; + } + +// light animations +// 'm' is normal light, 'a' is no light, 'z' is double bright + f = cl.time * 10; + i = (int)floor(f); + frac = f - i; + for (j = 0;j < cl.max_lightstyle;j++) + { + if (!cl.lightstyle[j].length) + { + r_refdef.scene.rtlightstylevalue[j] = 1; + r_refdef.scene.lightstylevalue[j] = 256; + continue; + } + // static lightstyle "=value" + if (cl.lightstyle[j].map[0] == '=') + { + r_refdef.scene.rtlightstylevalue[j] = atof(cl.lightstyle[j].map + 1); + if ( r_lerplightstyles.integer || ((int)f - f) < 0.01) + r_refdef.scene.lightstylevalue[j] = r_refdef.scene.rtlightstylevalue[j]; + continue; + } + k = i % cl.lightstyle[j].length; + l = (i-1) % cl.lightstyle[j].length; + k = cl.lightstyle[j].map[k] - 'a'; + l = cl.lightstyle[j].map[l] - 'a'; + // rtlightstylevalue is always interpolated because it has no bad + // consequences for performance + // lightstylevalue is subject to a cvar for performance reasons; + // skipping lightmap updates on most rendered frames substantially + // improves framerates (but makes light fades look bad) + r_refdef.scene.rtlightstylevalue[j] = ((k*frac)+(l*(1-frac)))*(22/256.0f); + r_refdef.scene.lightstylevalue[j] = r_lerplightstyles.integer ? (unsigned short)(((k*frac)+(l*(1-frac)))*22) : k*22; + } +} + +static void CL_AddQWCTFFlagModel(entity_t *player, int skin) +{ + int frame = player->render.framegroupblend[0].frame; + float f; + entity_render_t *flagrender; + matrix4x4_t flagmatrix; + + // this code taken from QuakeWorld + f = 14; + if (frame >= 29 && frame <= 40) + { + if (frame >= 29 && frame <= 34) + { //axpain + if (frame == 29) f = f + 2; + else if (frame == 30) f = f + 8; + else if (frame == 31) f = f + 12; + else if (frame == 32) f = f + 11; + else if (frame == 33) f = f + 10; + else if (frame == 34) f = f + 4; + } + else if (frame >= 35 && frame <= 40) + { // pain + if (frame == 35) f = f + 2; + else if (frame == 36) f = f + 10; + else if (frame == 37) f = f + 10; + else if (frame == 38) f = f + 8; + else if (frame == 39) f = f + 4; + else if (frame == 40) f = f + 2; + } + } + else if (frame >= 103 && frame <= 118) + { + if (frame >= 103 && frame <= 104) f = f + 6; //nailattack + else if (frame >= 105 && frame <= 106) f = f + 6; //light + else if (frame >= 107 && frame <= 112) f = f + 7; //rocketattack + else if (frame >= 112 && frame <= 118) f = f + 7; //shotattack + } + // end of code taken from QuakeWorld + + flagrender = CL_NewTempEntity(player->render.shadertime); + if (!flagrender) + return; + + flagrender->model = CL_GetModelByIndex(cl.qw_modelindex_flag); + flagrender->skinnum = skin; + flagrender->alpha = 1; + VectorSet(flagrender->colormod, 1, 1, 1); + VectorSet(flagrender->glowmod, 1, 1, 1); + // attach the flag to the player matrix + Matrix4x4_CreateFromQuakeEntity(&flagmatrix, -f, -22, 0, 0, 0, -45, 1); + Matrix4x4_Concat(&flagrender->matrix, &player->render.matrix, &flagmatrix); + CL_UpdateRenderEntity(flagrender); +} + +matrix4x4_t viewmodelmatrix_withbob; +matrix4x4_t viewmodelmatrix_nobob; + +static const vec3_t muzzleflashorigin = {18, 0, 0}; + +void CL_SetEntityColormapColors(entity_render_t *ent, int colormap) +{ + const unsigned char *cbcolor; + if (colormap >= 0) + { + cbcolor = palette_rgb_pantscolormap[colormap & 0xF]; + VectorScale(cbcolor, (1.0f / 255.0f), ent->colormap_pantscolor); + cbcolor = palette_rgb_shirtcolormap[(colormap & 0xF0) >> 4]; + VectorScale(cbcolor, (1.0f / 255.0f), ent->colormap_shirtcolor); + } + else + { + VectorClear(ent->colormap_pantscolor); + VectorClear(ent->colormap_shirtcolor); + } +} + +// note this is a recursive function, recursionlimit should be 32 or so on the initial call +static void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolate) +{ + const matrix4x4_t *matrix; + matrix4x4_t blendmatrix, tempmatrix, matrix2; + int frame; + vec_t origin[3], angles[3], lerp; + entity_t *t; + entity_render_t *r; + //entity_persistent_t *p = &e->persistent; + //entity_render_t *r = &e->render; + // skip inactive entities and world + if (!e->state_current.active || e == cl.entities) + return; + if (recursionlimit < 1) + return; + e->render.alpha = e->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate? + e->render.scale = e->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate? + e->render.flags = e->state_current.flags; + e->render.effects = e->state_current.effects; + VectorScale(e->state_current.colormod, (1.0f / 32.0f), e->render.colormod); + VectorScale(e->state_current.glowmod, (1.0f / 32.0f), e->render.glowmod); + if(e >= cl.entities && e < cl.entities + cl.num_entities) + e->render.entitynumber = e - cl.entities; + else + e->render.entitynumber = 0; + if (e->state_current.flags & RENDER_COLORMAPPED) + CL_SetEntityColormapColors(&e->render, e->state_current.colormap); + else if (e->state_current.colormap > 0 && e->state_current.colormap <= cl.maxclients && cl.scores != NULL) + CL_SetEntityColormapColors(&e->render, cl.scores[e->state_current.colormap-1].colors); + else + CL_SetEntityColormapColors(&e->render, -1); + e->render.skinnum = e->state_current.skin; + if (e->state_current.tagentity) + { + // attached entity (gun held in player model's hand, etc) + // if the tag entity is currently impossible, skip it + if (e->state_current.tagentity >= cl.num_entities) + return; + t = cl.entities + e->state_current.tagentity; + // if the tag entity is inactive, skip it + if (t->state_current.active) + { + // update the parent first + CL_UpdateNetworkEntity(t, recursionlimit - 1, interpolate); + r = &t->render; + } + else + { + // it may still be a CSQC entity... trying to use its + // info from last render frame (better than nothing) + if(!cl.csqc_server2csqcentitynumber[e->state_current.tagentity]) + return; + r = cl.csqcrenderentities + cl.csqc_server2csqcentitynumber[e->state_current.tagentity]; + if(!r->entitynumber) + return; // neither CSQC nor legacy entity... can't attach + } + // make relative to the entity + matrix = &r->matrix; + // some properties of the tag entity carry over + e->render.flags |= r->flags & (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL); + // if a valid tagindex is used, make it relative to that tag instead + if (e->state_current.tagentity && e->state_current.tagindex >= 1 && r->model) + { + if(!Mod_Alias_GetTagMatrix(r->model, r->frameblend, r->skeleton, e->state_current.tagindex - 1, &blendmatrix)) // i.e. no error + { + // concat the tag matrices onto the entity matrix + Matrix4x4_Concat(&tempmatrix, &r->matrix, &blendmatrix); + // use the constructed tag matrix + matrix = &tempmatrix; + } + } + } + else if (e->render.flags & RENDER_VIEWMODEL) + { + // view-relative entity (guns and such) + if (e->render.effects & EF_NOGUNBOB) + matrix = &viewmodelmatrix_nobob; // really attached to view + else + matrix = &viewmodelmatrix_withbob; // attached to gun bob matrix + } + else + { + // world-relative entity (the normal kind) + matrix = &identitymatrix; + } + + // movement lerp + // if it's the predicted player entity, update according to client movement + // but don't lerp if going through a teleporter as it causes a bad lerp + // also don't use the predicted location if fixangle was set on both of + // the most recent server messages, as that cause means you are spectating + // someone or watching a cutscene of some sort + if (cl_nolerp.integer || cls.timedemo) + interpolate = false; + if (e == cl.entities + cl.playerentity && cl.movement_predicted && (!cl.fixangle[1] || !cl.fixangle[0])) + { + VectorCopy(cl.movement_origin, origin); + VectorSet(angles, 0, cl.viewangles[1], 0); + } + else if (interpolate && e->persistent.lerpdeltatime > 0 && (lerp = (cl.time - e->persistent.lerpstarttime) / e->persistent.lerpdeltatime) < 1 + cl_lerpexcess.value) + { + // interpolate the origin and angles + lerp = max(0, lerp); + VectorLerp(e->persistent.oldorigin, lerp, e->persistent.neworigin, origin); +#if 0 + // this fails at the singularity of euler angles + VectorSubtract(e->persistent.newangles, e->persistent.oldangles, delta); + if (delta[0] < -180) delta[0] += 360;else if (delta[0] >= 180) delta[0] -= 360; + if (delta[1] < -180) delta[1] += 360;else if (delta[1] >= 180) delta[1] -= 360; + if (delta[2] < -180) delta[2] += 360;else if (delta[2] >= 180) delta[2] -= 360; + VectorMA(e->persistent.oldangles, lerp, delta, angles); +#else + { + vec3_t f0, u0, f1, u1; + AngleVectors(e->persistent.oldangles, f0, NULL, u0); + AngleVectors(e->persistent.newangles, f1, NULL, u1); + VectorMAM(1-lerp, f0, lerp, f1, f0); + VectorMAM(1-lerp, u0, lerp, u1, u0); + AnglesFromVectors(angles, f0, u0, false); + } +#endif + } + else + { + // no interpolation + VectorCopy(e->persistent.neworigin, origin); + VectorCopy(e->persistent.newangles, angles); + } + + // model setup and some modelflags + frame = e->state_current.frame; + e->render.model = CL_GetModelByIndex(e->state_current.modelindex); + if (e->render.model) + { + if (e->render.skinnum >= e->render.model->numskins) + e->render.skinnum = 0; + if (frame >= e->render.model->numframes) + frame = 0; + // models can set flags such as EF_ROCKET + // this 0xFF800000 mask is EF_NOMODELFLAGS plus all the higher EF_ flags such as EF_ROCKET + if (!(e->render.effects & 0xFF800000)) + e->render.effects |= e->render.model->effects; + // if model is alias or this is a tenebrae-like dlight, reverse pitch direction + if (e->render.model->type == mod_alias) + angles[0] = -angles[0]; + if ((e->render.effects & EF_SELECTABLE) && cl.cmd.cursor_entitynumber == e->state_current.number) + { + VectorScale(e->render.colormod, 2, e->render.colormod); + VectorScale(e->render.glowmod, 2, e->render.glowmod); + } + } + // if model is alias or this is a tenebrae-like dlight, reverse pitch direction + else if (e->state_current.lightpflags & PFLAGS_FULLDYNAMIC) + angles[0] = -angles[0]; + // NOTE: this must be synced to SV_GetPitchSign! + + if ((e->render.effects & EF_ROTATE) && !(e->render.flags & RENDER_VIEWMODEL)) + { + angles[1] = ANGLEMOD(100*cl.time); + if (cl_itembobheight.value) + origin[2] += (cos(cl.time * cl_itembobspeed.value * (2.0 * M_PI)) + 1.0) * 0.5 * cl_itembobheight.value; + } + + // animation lerp + e->render.skeleton = NULL; + if (e->render.flags & RENDER_COMPLEXANIMATION) + { + e->render.framegroupblend[0] = e->state_current.framegroupblend[0]; + e->render.framegroupblend[1] = e->state_current.framegroupblend[1]; + e->render.framegroupblend[2] = e->state_current.framegroupblend[2]; + e->render.framegroupblend[3] = e->state_current.framegroupblend[3]; + if (e->state_current.skeletonobject.model && e->state_current.skeletonobject.relativetransforms) + e->render.skeleton = &e->state_current.skeletonobject; + } + else if (e->render.framegroupblend[0].frame == frame) + { + // update frame lerp fraction + e->render.framegroupblend[0].lerp = 1; + e->render.framegroupblend[1].lerp = 0; + if (e->render.framegroupblend[0].start > e->render.framegroupblend[1].start) + { + // make sure frame lerp won't last longer than 100ms + // (this mainly helps with models that use framegroups and + // switch between them infrequently) + float maxdelta = cl_lerpanim_maxdelta_server.value; + if(e->render.model) + if(e->render.model->animscenes) + if(e->render.model->animscenes[e->render.framegroupblend[0].frame].framecount > 1 || e->render.model->animscenes[e->render.framegroupblend[1].frame].framecount > 1) + maxdelta = cl_lerpanim_maxdelta_framegroups.value; + maxdelta = max(maxdelta, cl.mtime[0] - cl.mtime[1]); + e->render.framegroupblend[0].lerp = (cl.time - e->render.framegroupblend[0].start) / min(e->render.framegroupblend[0].start - e->render.framegroupblend[1].start, maxdelta); + e->render.framegroupblend[0].lerp = bound(0, e->render.framegroupblend[0].lerp, 1); + e->render.framegroupblend[1].lerp = 1 - e->render.framegroupblend[0].lerp; + } + } + else + { + // begin a new frame lerp + e->render.framegroupblend[1] = e->render.framegroupblend[0]; + e->render.framegroupblend[1].lerp = 1; + e->render.framegroupblend[0].frame = frame; + e->render.framegroupblend[0].start = cl.time; + e->render.framegroupblend[0].lerp = 0; + } + + // set up the render matrix + if (matrix) + { + // attached entity, this requires a matrix multiply (concat) + // FIXME: e->render.scale should go away + Matrix4x4_CreateFromQuakeEntity(&matrix2, origin[0], origin[1], origin[2], angles[0], angles[1], angles[2], e->render.scale); + // concat the matrices to make the entity relative to its tag + Matrix4x4_Concat(&e->render.matrix, matrix, &matrix2); + // get the origin from the new matrix + Matrix4x4_OriginFromMatrix(&e->render.matrix, origin); + } + else + { + // unattached entities are faster to process + Matrix4x4_CreateFromQuakeEntity(&e->render.matrix, origin[0], origin[1], origin[2], angles[0], angles[1], angles[2], e->render.scale); + } + + // tenebrae's sprites are all additive mode (weird) + if (gamemode == GAME_TENEBRAE && e->render.model && e->render.model->type == mod_sprite) + e->render.flags |= RENDER_ADDITIVE; + // player model is only shown with chase_active on + if (e->state_current.number == cl.viewentity) + e->render.flags |= RENDER_EXTERIORMODEL; + // either fullbright or lit + if(!r_fullbright.integer) + { + if (!(e->render.effects & EF_FULLBRIGHT)) + e->render.flags |= RENDER_LIGHT; + else if(r_equalize_entities_fullbright.integer) + e->render.flags |= RENDER_LIGHT | RENDER_EQUALIZE; + } + // hide player shadow during intermission or nehahra movie + if (!(e->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) + && (e->render.alpha >= 1) + && !(e->render.flags & RENDER_VIEWMODEL) + && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) + e->render.flags |= RENDER_SHADOW; + if (e->render.flags & RENDER_VIEWMODEL) + e->render.flags |= RENDER_NOSELFSHADOW; + if (e->render.effects & EF_NOSELFSHADOW) + e->render.flags |= RENDER_NOSELFSHADOW; + if (e->render.effects & EF_NODEPTHTEST) + e->render.flags |= RENDER_NODEPTHTEST; + if (e->render.effects & EF_ADDITIVE) + e->render.flags |= RENDER_ADDITIVE; + if (e->render.effects & EF_DOUBLESIDED) + e->render.flags |= RENDER_DOUBLESIDED; + if (e->render.effects & EF_DYNAMICMODELLIGHT) + e->render.flags |= RENDER_DYNAMICMODELLIGHT; + + // make the other useful stuff + e->render.allowdecals = true; + CL_UpdateRenderEntity(&e->render); +} + +// creates light and trails from an entity +static void CL_UpdateNetworkEntityTrail(entity_t *e) +{ + effectnameindex_t trailtype; + vec3_t origin; + + // bmodels are treated specially since their origin is usually '0 0 0' and + // their actual geometry is far from '0 0 0' + if (e->render.model && e->render.model->soundfromcenter) + { + vec3_t o; + VectorMAM(0.5f, e->render.model->normalmins, 0.5f, e->render.model->normalmaxs, o); + Matrix4x4_Transform(&e->render.matrix, o, origin); + } + else + Matrix4x4_OriginFromMatrix(&e->render.matrix, origin); + + // handle particle trails and such effects now that we know where this + // entity is in the world... + trailtype = EFFECT_NONE; + // LordHavoc: if the entity has no effects, don't check each + if (e->render.effects & (EF_BRIGHTFIELD | EF_FLAME | EF_STARDUST)) + { + if (e->render.effects & EF_BRIGHTFIELD) + { + if (gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + trailtype = EFFECT_TR_NEXUIZPLASMA; + else + CL_EntityParticles(e); + } + if (e->render.effects & EF_FLAME) + CL_ParticleTrail(EFFECT_EF_FLAME, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0, false, true, NULL, NULL); + if (e->render.effects & EF_STARDUST) + CL_ParticleTrail(EFFECT_EF_STARDUST, bound(0, cl.time - cl.oldtime, 0.1), origin, origin, vec3_origin, vec3_origin, NULL, 0, false, true, NULL, NULL); + } + if (e->render.internaleffects & (INTEF_FLAG1QW | INTEF_FLAG2QW)) + { + // these are only set on player entities + CL_AddQWCTFFlagModel(e, (e->render.internaleffects & INTEF_FLAG2QW) != 0); + } + // muzzleflash fades over time + if (e->persistent.muzzleflash > 0) + e->persistent.muzzleflash -= bound(0, cl.time - cl.oldtime, 0.1) * 20; + // LordHavoc: if the entity has no effects, don't check each + if (e->render.effects && !(e->render.flags & RENDER_VIEWMODEL)) + { + if (e->render.effects & EF_GIB) + trailtype = EFFECT_TR_BLOOD; + else if (e->render.effects & EF_ZOMGIB) + trailtype = EFFECT_TR_SLIGHTBLOOD; + else if (e->render.effects & EF_TRACER) + trailtype = EFFECT_TR_WIZSPIKE; + else if (e->render.effects & EF_TRACER2) + trailtype = EFFECT_TR_KNIGHTSPIKE; + else if (e->render.effects & EF_ROCKET) + trailtype = EFFECT_TR_ROCKET; + else if (e->render.effects & EF_GRENADE) + { + // LordHavoc: e->render.alpha == -1 is for Nehahra dem compatibility (cigar smoke) + trailtype = e->render.alpha == -1 ? EFFECT_TR_NEHAHRASMOKE : EFFECT_TR_GRENADE; + } + else if (e->render.effects & EF_TRACER3) + trailtype = EFFECT_TR_VORESPIKE; + } + // do trails + if (e->render.flags & RENDER_GLOWTRAIL) + trailtype = EFFECT_TR_GLOWTRAIL; + if (e->state_current.traileffectnum) + trailtype = (effectnameindex_t)e->state_current.traileffectnum; + // check if a trail is allowed (it is not after a teleport for example) + if (trailtype && e->persistent.trail_allowed) + { + float len; + vec3_t vel; + VectorSubtract(e->state_current.origin, e->state_previous.origin, vel); + len = e->state_current.time - e->state_previous.time; + if (len > 0) + len = 1.0f / len; + VectorScale(vel, len, vel); + // pass time as count so that trails that are time based (such as an emitter) will emit properly as long as they don't use trailspacing + CL_ParticleTrail(trailtype, bound(0, cl.time - cl.oldtime, 0.1), e->persistent.trail_origin, origin, vel, vel, e, e->state_current.glowcolor, false, true, NULL, NULL); + } + // now that the entity has survived one trail update it is allowed to + // leave a real trail on later frames + e->persistent.trail_allowed = true; + VectorCopy(origin, e->persistent.trail_origin); +} + + +/* +=============== +CL_UpdateViewEntities +=============== +*/ +void CL_UpdateViewEntities(void) +{ + int i; + // update any RENDER_VIEWMODEL entities to use the new view matrix + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + entity_t *ent = cl.entities + i; + if ((ent->render.flags & RENDER_VIEWMODEL) || ent->state_current.tagentity) + CL_UpdateNetworkEntity(ent, 32, true); + } + } + // and of course the engine viewmodel needs updating as well + CL_UpdateNetworkEntity(&cl.viewent, 32, true); +} + +/* +=============== +CL_UpdateNetworkCollisionEntities +=============== +*/ +static void CL_UpdateNetworkCollisionEntities(void) +{ + entity_t *ent; + int i; + + // start on the entity after the world + cl.num_brushmodel_entities = 0; + for (i = cl.maxclients + 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + ent = cl.entities + i; + if (ent->state_current.active && ent->render.model && ent->render.model->name[0] == '*' && ent->render.model->TraceBox) + { + // do not interpolate the bmodels for this + CL_UpdateNetworkEntity(ent, 32, false); + cl.brushmodel_entities[cl.num_brushmodel_entities++] = i; + } + } + } +} + +/* +=============== +CL_UpdateNetworkEntities +=============== +*/ +static void CL_UpdateNetworkEntities(void) +{ + entity_t *ent; + int i; + + // start on the entity after the world + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + ent = cl.entities + i; + if (ent->state_current.active) + { + CL_UpdateNetworkEntity(ent, 32, true); + // view models should never create light/trails + if (!(ent->render.flags & RENDER_VIEWMODEL)) + CL_UpdateNetworkEntityTrail(ent); + } + else + { + R_DecalSystem_Reset(&ent->render.decalsystem); + cl.entities_active[i] = false; + } + } + } +} + +static void CL_UpdateViewModel(void) +{ + entity_t *ent; + ent = &cl.viewent; + ent->state_previous = ent->state_current; + ent->state_current = defaultstate; + ent->state_current.time = cl.time; + ent->state_current.number = (unsigned short)-1; + ent->state_current.active = true; + ent->state_current.modelindex = cl.stats[STAT_WEAPON]; + ent->state_current.frame = cl.stats[STAT_WEAPONFRAME]; + ent->state_current.flags = RENDER_VIEWMODEL; + if ((cl.stats[STAT_HEALTH] <= 0 && cl_deathnoviewmodel.integer) || cl.intermission) + ent->state_current.modelindex = 0; + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) + { + if (gamemode == GAME_TRANSFUSION) + ent->state_current.alpha = 128; + else + ent->state_current.modelindex = 0; + } + ent->state_current.alpha = cl.entities[cl.viewentity].state_current.alpha; + ent->state_current.effects = EF_NOSHADOW | (cl.entities[cl.viewentity].state_current.effects & (EF_ADDITIVE | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB)); + + // reset animation interpolation on weaponmodel if model changed + if (ent->state_previous.modelindex != ent->state_current.modelindex) + { + ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame; + ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time; + ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0; + } + CL_UpdateNetworkEntity(ent, 32, true); +} + +// note this is a recursive function, but it can never get in a runaway loop (because of the delayedlink flags) +static void CL_LinkNetworkEntity(entity_t *e) +{ + effectnameindex_t trailtype; + vec3_t origin; + vec3_t dlightcolor; + vec_t dlightradius; + char vabuf[1024]; + + // skip inactive entities and world + if (!e->state_current.active || e == cl.entities) + return; + if (e->state_current.tagentity) + { + // if the tag entity is currently impossible, skip it + if (e->state_current.tagentity >= cl.num_entities) + return; + // if the tag entity is inactive, skip it + if (!cl.entities[e->state_current.tagentity].state_current.active) + { + if(!cl.csqc_server2csqcentitynumber[e->state_current.tagentity]) + return; + if(!cl.csqcrenderentities[cl.csqc_server2csqcentitynumber[e->state_current.tagentity]].entitynumber) + return; + // if we get here, it's properly csqc networked and attached + } + } + + // create entity dlights associated with this entity + if (e->render.model && e->render.model->soundfromcenter) + { + // bmodels are treated specially since their origin is usually '0 0 0' + vec3_t o; + VectorMAM(0.5f, e->render.model->normalmins, 0.5f, e->render.model->normalmaxs, o); + Matrix4x4_Transform(&e->render.matrix, o, origin); + } + else + Matrix4x4_OriginFromMatrix(&e->render.matrix, origin); + trailtype = EFFECT_NONE; + dlightradius = 0; + dlightcolor[0] = 0; + dlightcolor[1] = 0; + dlightcolor[2] = 0; + // LordHavoc: if the entity has no effects, don't check each + if (e->render.effects & (EF_BRIGHTFIELD | EF_DIMLIGHT | EF_BRIGHTLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST)) + { + if (e->render.effects & EF_BRIGHTFIELD) + { + if (gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + trailtype = EFFECT_TR_NEXUIZPLASMA; + } + if (e->render.effects & EF_DIMLIGHT) + { + dlightradius = max(dlightradius, 200); + dlightcolor[0] += 1.50f; + dlightcolor[1] += 1.50f; + dlightcolor[2] += 1.50f; + } + if (e->render.effects & EF_BRIGHTLIGHT) + { + dlightradius = max(dlightradius, 400); + dlightcolor[0] += 3.00f; + dlightcolor[1] += 3.00f; + dlightcolor[2] += 3.00f; + } + // LordHavoc: more effects + if (e->render.effects & EF_RED) // red + { + dlightradius = max(dlightradius, 200); + dlightcolor[0] += 1.50f; + dlightcolor[1] += 0.15f; + dlightcolor[2] += 0.15f; + } + if (e->render.effects & EF_BLUE) // blue + { + dlightradius = max(dlightradius, 200); + dlightcolor[0] += 0.15f; + dlightcolor[1] += 0.15f; + dlightcolor[2] += 1.50f; + } + if (e->render.effects & EF_FLAME) + CL_ParticleTrail(EFFECT_EF_FLAME, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0, true, false, NULL, NULL); + if (e->render.effects & EF_STARDUST) + CL_ParticleTrail(EFFECT_EF_STARDUST, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0, true, false, NULL, NULL); + } + // muzzleflash fades over time, and is offset a bit + if (e->persistent.muzzleflash > 0 && r_refdef.scene.numlights < MAX_DLIGHTS) + { + vec3_t v2; + vec3_t color; + trace_t trace; + matrix4x4_t tempmatrix; + Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2); + trace = CL_TraceLine(origin, v2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, NULL, false, false); + Matrix4x4_Normalize(&tempmatrix, &e->render.matrix); + Matrix4x4_SetOrigin(&tempmatrix, trace.endpos[0], trace.endpos[1], trace.endpos[2]); + Matrix4x4_Scale(&tempmatrix, 150, 1); + VectorSet(color, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f, e->persistent.muzzleflash * 4.0f); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, color, -1, NULL, true, 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + // LordHavoc: if the model has no flags, don't check each + if (e->render.model && e->render.effects && !(e->render.flags & RENDER_VIEWMODEL)) + { + if (e->render.effects & EF_GIB) + trailtype = EFFECT_TR_BLOOD; + else if (e->render.effects & EF_ZOMGIB) + trailtype = EFFECT_TR_SLIGHTBLOOD; + else if (e->render.effects & EF_TRACER) + trailtype = EFFECT_TR_WIZSPIKE; + else if (e->render.effects & EF_TRACER2) + trailtype = EFFECT_TR_KNIGHTSPIKE; + else if (e->render.effects & EF_ROCKET) + trailtype = EFFECT_TR_ROCKET; + else if (e->render.effects & EF_GRENADE) + { + // LordHavoc: e->render.alpha == -1 is for Nehahra dem compatibility (cigar smoke) + trailtype = e->render.alpha == -1 ? EFFECT_TR_NEHAHRASMOKE : EFFECT_TR_GRENADE; + } + else if (e->render.effects & EF_TRACER3) + trailtype = EFFECT_TR_VORESPIKE; + } + // LordHavoc: customizable glow + if (e->state_current.glowsize) + { + // * 4 for the expansion from 0-255 to 0-1023 range, + // / 255 to scale down byte colors + dlightradius = max(dlightradius, e->state_current.glowsize * 4); + VectorMA(dlightcolor, (1.0f / 255.0f), palette_rgb[e->state_current.glowcolor], dlightcolor); + } + // custom rtlight + if ((e->state_current.lightpflags & PFLAGS_FULLDYNAMIC) && r_refdef.scene.numlights < MAX_DLIGHTS) + { + matrix4x4_t dlightmatrix; + vec4_t light; + VectorScale(e->state_current.light, (1.0f / 256.0f), light); + light[3] = e->state_current.light[3]; + if (light[0] == 0 && light[1] == 0 && light[2] == 0) + VectorSet(light, 1, 1, 1); + if (light[3] == 0) + light[3] = 350; + // FIXME: add ambient/diffuse/specular scales as an extension ontop of TENEBRAE_GFX_DLIGHTS? + Matrix4x4_Normalize(&dlightmatrix, &e->render.matrix); + Matrix4x4_Scale(&dlightmatrix, light[3], 1); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &dlightmatrix, light, e->state_current.lightstyle, e->state_current.skin > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", e->state_current.skin) : NULL, !(e->state_current.lightpflags & PFLAGS_NOSHADOW), (e->state_current.lightpflags & PFLAGS_CORONA) != 0, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + // make the glow dlight + else if (dlightradius > 0 && (dlightcolor[0] || dlightcolor[1] || dlightcolor[2]) && !(e->render.flags & RENDER_VIEWMODEL) && r_refdef.scene.numlights < MAX_DLIGHTS) + { + matrix4x4_t dlightmatrix; + Matrix4x4_Normalize(&dlightmatrix, &e->render.matrix); + // hack to make glowing player light shine on their gun + //if (e->state_current.number == cl.viewentity/* && !chase_active.integer*/) + // Matrix4x4_AdjustOrigin(&dlightmatrix, 0, 0, 30); + Matrix4x4_Scale(&dlightmatrix, dlightradius, 1); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &dlightmatrix, dlightcolor, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + // do trail light + if (e->render.flags & RENDER_GLOWTRAIL) + trailtype = EFFECT_TR_GLOWTRAIL; + if (e->state_current.traileffectnum) + trailtype = (effectnameindex_t)e->state_current.traileffectnum; + if (trailtype) + CL_ParticleTrail(trailtype, 1, origin, origin, vec3_origin, vec3_origin, NULL, e->state_current.glowcolor, true, false, NULL, NULL); + + // don't show entities with no modelindex (note: this still shows + // entities which have a modelindex that resolved to a NULL model) + if (e->render.model && !(e->render.effects & EF_NODRAW) && r_refdef.scene.numentities < r_refdef.scene.maxentities) + r_refdef.scene.entities[r_refdef.scene.numentities++] = &e->render; + //if (cl.viewentity && e->state_current.number == cl.viewentity) + // Matrix4x4_Print(&e->render.matrix); +} + +static void CL_RelinkWorld(void) +{ + entity_t *ent = &cl.entities[0]; + // FIXME: this should be done at load + ent->render.matrix = identitymatrix; + ent->render.flags = RENDER_SHADOW; + if (!r_fullbright.integer) + ent->render.flags |= RENDER_LIGHT; + VectorSet(ent->render.colormod, 1, 1, 1); + VectorSet(ent->render.glowmod, 1, 1, 1); + ent->render.allowdecals = true; + CL_UpdateRenderEntity(&ent->render); + r_refdef.scene.worldentity = &ent->render; + r_refdef.scene.worldmodel = cl.worldmodel; +} + +static void CL_RelinkStaticEntities(void) +{ + int i; + entity_t *e; + for (i = 0, e = cl.static_entities;i < cl.num_static_entities && r_refdef.scene.numentities < r_refdef.scene.maxentities;i++, e++) + { + e->render.flags = 0; + // if the model was not loaded when the static entity was created we + // need to re-fetch the model pointer + e->render.model = CL_GetModelByIndex(e->state_baseline.modelindex); + // either fullbright or lit + if(!r_fullbright.integer) + { + if (!(e->render.effects & EF_FULLBRIGHT)) + e->render.flags |= RENDER_LIGHT; + else if(r_equalize_entities_fullbright.integer) + e->render.flags |= RENDER_LIGHT | RENDER_EQUALIZE; + } + // hide player shadow during intermission or nehahra movie + if (!(e->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (e->render.alpha >= 1)) + e->render.flags |= RENDER_SHADOW; + VectorSet(e->render.colormod, 1, 1, 1); + VectorSet(e->render.glowmod, 1, 1, 1); + VM_FrameBlendFromFrameGroupBlend(e->render.frameblend, e->render.framegroupblend, e->render.model, cl.time); + e->render.allowdecals = true; + CL_UpdateRenderEntity(&e->render); + r_refdef.scene.entities[r_refdef.scene.numentities++] = &e->render; + } +} + +/* +=============== +CL_RelinkEntities +=============== +*/ +static void CL_RelinkNetworkEntities(void) +{ + entity_t *ent; + int i; + + // start on the entity after the world + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + ent = cl.entities + i; + if (ent->state_current.active) + CL_LinkNetworkEntity(ent); + else + cl.entities_active[i] = false; + } + } +} + +static void CL_RelinkEffects(void) +{ + int i, intframe; + cl_effect_t *e; + entity_render_t *entrender; + float frame; + + for (i = 0, e = cl.effects;i < cl.num_effects;i++, e++) + { + if (e->active) + { + frame = (cl.time - e->starttime) * e->framerate + e->startframe; + intframe = (int)frame; + if (intframe < 0 || intframe >= e->endframe) + { + memset(e, 0, sizeof(*e)); + while (cl.num_effects > 0 && !cl.effects[cl.num_effects - 1].active) + cl.num_effects--; + continue; + } + + if (intframe != e->frame) + { + e->frame = intframe; + e->frame1time = e->frame2time; + e->frame2time = cl.time; + } + + // if we're drawing effects, get a new temp entity + // (NewTempEntity adds it to the render entities list for us) + if (r_draweffects.integer && (entrender = CL_NewTempEntity(e->starttime))) + { + // interpolation stuff + entrender->framegroupblend[0].frame = intframe; + entrender->framegroupblend[0].lerp = 1 - frame - intframe; + entrender->framegroupblend[0].start = e->frame1time; + if (intframe + 1 >= e->endframe) + { + entrender->framegroupblend[1].frame = 0; // disappear + entrender->framegroupblend[1].lerp = 0; + entrender->framegroupblend[1].start = 0; + } + else + { + entrender->framegroupblend[1].frame = intframe + 1; + entrender->framegroupblend[1].lerp = frame - intframe; + entrender->framegroupblend[1].start = e->frame2time; + } + + // normal stuff + entrender->model = CL_GetModelByIndex(e->modelindex); + entrender->alpha = 1; + VectorSet(entrender->colormod, 1, 1, 1); + VectorSet(entrender->glowmod, 1, 1, 1); + + Matrix4x4_CreateFromQuakeEntity(&entrender->matrix, e->origin[0], e->origin[1], e->origin[2], 0, 0, 0, 1); + CL_UpdateRenderEntity(entrender); + } + } + } +} + +void CL_Beam_CalculatePositions(const beam_t *b, vec3_t start, vec3_t end) +{ + VectorCopy(b->start, start); + VectorCopy(b->end, end); + + // if coming from the player, update the start position + if (b->entity == cl.viewentity) + { + if (cl_beams_quakepositionhack.integer && !chase_active.integer) + { + // LordHavoc: this is a stupid hack from Quake that makes your + // lightning appear to come from your waist and cover less of your + // view + // in Quake this hack was applied to all players (causing the + // infamous crotch-lightning), but in darkplaces and QuakeWorld it + // only applies to your own lightning, and only in first person + Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, start); + } + if (cl_beams_instantaimhack.integer) + { + vec3_t dir, localend; + vec_t len; + // LordHavoc: this updates the beam direction to match your + // viewangles + VectorSubtract(end, start, dir); + len = VectorLength(dir); + VectorNormalize(dir); + VectorSet(localend, len, 0, 0); + Matrix4x4_Transform(&r_refdef.view.matrix, localend, end); + } + } +} + +void CL_RelinkBeams(void) +{ + int i; + beam_t *b; + vec3_t dist, org, start, end; + float d; + entity_render_t *entrender; + double yaw, pitch; + float forward; + matrix4x4_t tempmatrix; + + for (i = 0, b = cl.beams;i < cl.num_beams;i++, b++) + { + if (!b->model) + continue; + if (b->endtime < cl.time) + { + b->model = NULL; + continue; + } + + CL_Beam_CalculatePositions(b, start, end); + + if (b->lightning) + { + if (cl_beams_lightatend.integer && r_refdef.scene.numlights < MAX_DLIGHTS) + { + // FIXME: create a matrix from the beam start/end orientation + vec3_t dlightcolor; + VectorSet(dlightcolor, 0.3, 0.7, 1); + Matrix4x4_CreateFromQuakeEntity(&tempmatrix, end[0], end[1], end[2], 0, 0, 0, 200); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, dlightcolor, -1, NULL, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + if (cl_beams_polygons.integer) + continue; + } + + // calculate pitch and yaw + // (this is similar to the QuakeC builtin function vectoangles) + VectorSubtract(end, start, dist); + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = atan2(dist[1], dist[0]) * 180 / M_PI; + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = atan2(dist[2], forward) * 180 / M_PI; + if (pitch < 0) + pitch += 360; + } + + // add new entities for the lightning + VectorCopy (start, org); + d = VectorNormalizeLength(dist); + while (d > 0) + { + entrender = CL_NewTempEntity (0); + if (!entrender) + return; + //VectorCopy (org, ent->render.origin); + entrender->model = b->model; + //ent->render.effects = EF_FULLBRIGHT; + //ent->render.angles[0] = pitch; + //ent->render.angles[1] = yaw; + //ent->render.angles[2] = rand()%360; + Matrix4x4_CreateFromQuakeEntity(&entrender->matrix, org[0], org[1], org[2], -pitch, yaw, lhrandom(0, 360), 1); + CL_UpdateRenderEntity(entrender); + VectorMA(org, 30, dist, org); + d -= 30; + } + } + + while (cl.num_beams > 0 && !cl.beams[cl.num_beams - 1].model) + cl.num_beams--; +} + +static void CL_RelinkQWNails(void) +{ + int i; + vec_t *v; + entity_render_t *entrender; + + for (i = 0;i < cl.qw_num_nails;i++) + { + v = cl.qw_nails[i]; + + // if we're drawing effects, get a new temp entity + // (NewTempEntity adds it to the render entities list for us) + if (!(entrender = CL_NewTempEntity(0))) + continue; + + // normal stuff + entrender->model = CL_GetModelByIndex(cl.qw_modelindex_spike); + entrender->alpha = 1; + VectorSet(entrender->colormod, 1, 1, 1); + VectorSet(entrender->glowmod, 1, 1, 1); + + Matrix4x4_CreateFromQuakeEntity(&entrender->matrix, v[0], v[1], v[2], v[3], v[4], v[5], 1); + CL_UpdateRenderEntity(entrender); + } +} + +static void CL_LerpPlayer(float frac) +{ + int i; + + cl.viewzoom = cl.mviewzoom[1] + frac * (cl.mviewzoom[0] - cl.mviewzoom[1]); + for (i = 0;i < 3;i++) + { + cl.punchangle[i] = cl.mpunchangle[1][i] + frac * (cl.mpunchangle[0][i] - cl.mpunchangle[1][i]); + cl.punchvector[i] = cl.mpunchvector[1][i] + frac * (cl.mpunchvector[0][i] - cl.mpunchvector[1][i]); + cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + } + + // interpolate the angles if playing a demo or spectating someone + if (cls.demoplayback || cl.fixangle[0]) + { + for (i = 0;i < 3;i++) + { + float d = cl.mviewangles[0][i] - cl.mviewangles[1][i]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + cl.viewangles[i] = cl.mviewangles[1][i] + frac * d; + } + } +} + +void CSQC_RelinkAllEntities (int drawmask) +{ + // link stuff + CL_RelinkWorld(); + CL_RelinkStaticEntities(); + CL_RelinkBeams(); + CL_RelinkEffects(); + + // link stuff + if (drawmask & ENTMASK_ENGINE) + { + CL_RelinkNetworkEntities(); + if (drawmask & ENTMASK_ENGINEVIEWMODELS) + CL_LinkNetworkEntity(&cl.viewent); // link gun model + CL_RelinkQWNails(); + } + + // update view blend + V_CalcViewBlend(); +} + +/* +=============== +CL_UpdateWorld + +Update client game world for a new frame +=============== +*/ +void CL_UpdateWorld(void) +{ + r_refdef.scene.extraupdate = !r_speeds.integer; + r_refdef.scene.numentities = 0; + r_refdef.scene.numlights = 0; + r_refdef.view.matrix = identitymatrix; + r_refdef.view.quality = 1; + + cl.num_brushmodel_entities = 0; + + if (cls.state == ca_connected && cls.signon == SIGNONS) + { + // prepare for a new frame + CL_LerpPlayer(CL_LerpPoint()); + CL_DecayLightFlashes(); + CL_ClearTempEntities(); + V_DriftPitch(); + V_FadeViewFlashs(); + + // if prediction is enabled we have to update all the collidable + // network entities before the prediction code can be run + CL_UpdateNetworkCollisionEntities(); + + // now update the player prediction + CL_ClientMovement_Replay(); + + // update the player entity (which may be predicted) + CL_UpdateNetworkEntity(cl.entities + cl.viewentity, 32, true); + + // now update the view (which depends on that player entity) + V_CalcRefdef(); + + // now update all the network entities and create particle trails + // (some entities may depend on the view) + CL_UpdateNetworkEntities(); + + // update the engine-based viewmodel + CL_UpdateViewModel(); + + CL_RelinkLightFlashes(); + CSQC_RelinkAllEntities(ENTMASK_ENGINE | ENTMASK_ENGINEVIEWMODELS); + + // decals, particles, and explosions will be updated during rneder + } + + r_refdef.scene.time = cl.time; +} + +// LordHavoc: pausedemo command +static void CL_PauseDemo_f (void) +{ + cls.demopaused = !cls.demopaused; + if (cls.demopaused) + Con_Print("Demo paused\n"); + else + Con_Print("Demo unpaused\n"); +} + +/* +====================== +CL_Fog_f +====================== +*/ +static void CL_Fog_f (void) +{ + if (Cmd_Argc () == 1) + { + Con_Printf("\"fog\" is \"%f %f %f %f %f %f %f %f %f\"\n", r_refdef.fog_density, r_refdef.fog_red, r_refdef.fog_green, r_refdef.fog_blue, r_refdef.fog_alpha, r_refdef.fog_start, r_refdef.fog_end, r_refdef.fog_height, r_refdef.fog_fadedepth); + return; + } + FOG_clear(); // so missing values get good defaults + if(Cmd_Argc() > 1) + r_refdef.fog_density = atof(Cmd_Argv(1)); + if(Cmd_Argc() > 2) + r_refdef.fog_red = atof(Cmd_Argv(2)); + if(Cmd_Argc() > 3) + r_refdef.fog_green = atof(Cmd_Argv(3)); + if(Cmd_Argc() > 4) + r_refdef.fog_blue = atof(Cmd_Argv(4)); + if(Cmd_Argc() > 5) + r_refdef.fog_alpha = atof(Cmd_Argv(5)); + if(Cmd_Argc() > 6) + r_refdef.fog_start = atof(Cmd_Argv(6)); + if(Cmd_Argc() > 7) + r_refdef.fog_end = atof(Cmd_Argv(7)); + if(Cmd_Argc() > 8) + r_refdef.fog_height = atof(Cmd_Argv(8)); + if(Cmd_Argc() > 9) + r_refdef.fog_fadedepth = atof(Cmd_Argv(9)); +} + +/* +====================== +CL_FogHeightTexture_f +====================== +*/ +static void CL_Fog_HeightTexture_f (void) +{ + if (Cmd_Argc () < 11) + { + Con_Printf("\"fog_heighttexture\" is \"%f %f %f %f %f %f %f %f %f %s\"\n", r_refdef.fog_density, r_refdef.fog_red, r_refdef.fog_green, r_refdef.fog_blue, r_refdef.fog_alpha, r_refdef.fog_start, r_refdef.fog_end, r_refdef.fog_height, r_refdef.fog_fadedepth, r_refdef.fog_height_texturename); + return; + } + FOG_clear(); // so missing values get good defaults + r_refdef.fog_density = atof(Cmd_Argv(1)); + r_refdef.fog_red = atof(Cmd_Argv(2)); + r_refdef.fog_green = atof(Cmd_Argv(3)); + r_refdef.fog_blue = atof(Cmd_Argv(4)); + r_refdef.fog_alpha = atof(Cmd_Argv(5)); + r_refdef.fog_start = atof(Cmd_Argv(6)); + r_refdef.fog_end = atof(Cmd_Argv(7)); + r_refdef.fog_height = atof(Cmd_Argv(8)); + r_refdef.fog_fadedepth = atof(Cmd_Argv(9)); + strlcpy(r_refdef.fog_height_texturename, Cmd_Argv(10), sizeof(r_refdef.fog_height_texturename)); +} + + +/* +==================== +CL_TimeRefresh_f + +For program optimization +==================== +*/ +static void CL_TimeRefresh_f (void) +{ + int i; + double timestart, timedelta; + + r_refdef.scene.extraupdate = false; + + timestart = Sys_DirtyTime(); + for (i = 0;i < 128;i++) + { + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], 0, i / 128.0 * 360.0, 0, 1); + r_refdef.view.quality = 1; + CL_BeginUpdateScreen(); + SCR_DrawScreen(0, 0); + CL_EndUpdateScreen(); + } + timedelta = Sys_DirtyTime() - timestart; + + Con_Printf("%f seconds (%f fps)\n", timedelta, 128/timedelta); +} + +static void CL_AreaStats_f(void) +{ + World_PrintAreaStats(&cl.world, "client"); +} + +cl_locnode_t *CL_Locs_FindNearest(const vec3_t point) +{ + int i; + cl_locnode_t *loc; + cl_locnode_t *best; + vec3_t nearestpoint; + vec_t dist, bestdist; + best = NULL; + bestdist = 0; + for (loc = cl.locnodes;loc;loc = loc->next) + { + for (i = 0;i < 3;i++) + nearestpoint[i] = bound(loc->mins[i], point[i], loc->maxs[i]); + dist = VectorDistance2(nearestpoint, point); + if (bestdist > dist || !best) + { + bestdist = dist; + best = loc; + if (bestdist < 1) + break; + } + } + return best; +} + +void CL_Locs_FindLocationName(char *buffer, size_t buffersize, vec3_t point) +{ + cl_locnode_t *loc; + loc = CL_Locs_FindNearest(point); + if (loc) + strlcpy(buffer, loc->name, buffersize); + else + dpsnprintf(buffer, buffersize, "LOC=%.0f:%.0f:%.0f", point[0], point[1], point[2]); +} + +static void CL_Locs_FreeNode(cl_locnode_t *node) +{ + cl_locnode_t **pointer, **next; + for (pointer = &cl.locnodes;*pointer;pointer = next) + { + next = &(*pointer)->next; + if (*pointer == node) + { + *pointer = node->next; + Mem_Free(node); + return; + } + } + Con_Printf("CL_Locs_FreeNode: no such node! (%p)\n", (void *)node); +} + +static void CL_Locs_AddNode(vec3_t mins, vec3_t maxs, const char *name) +{ + cl_locnode_t *node, **pointer; + int namelen; + if (!name) + name = ""; + namelen = strlen(name); + node = (cl_locnode_t *) Mem_Alloc(cls.levelmempool, sizeof(cl_locnode_t) + namelen + 1); + VectorSet(node->mins, min(mins[0], maxs[0]), min(mins[1], maxs[1]), min(mins[2], maxs[2])); + VectorSet(node->maxs, max(mins[0], maxs[0]), max(mins[1], maxs[1]), max(mins[2], maxs[2])); + node->name = (char *)(node + 1); + memcpy(node->name, name, namelen); + node->name[namelen] = 0; + // link it into the tail of the list to preserve the order + for (pointer = &cl.locnodes;*pointer;pointer = &(*pointer)->next) + ; + *pointer = node; +} + +static void CL_Locs_Add_f(void) +{ + vec3_t mins, maxs; + if (Cmd_Argc() != 5 && Cmd_Argc() != 8) + { + Con_Printf("usage: %s x y z[ x y z] name\n", Cmd_Argv(0)); + return; + } + mins[0] = atof(Cmd_Argv(1)); + mins[1] = atof(Cmd_Argv(2)); + mins[2] = atof(Cmd_Argv(3)); + if (Cmd_Argc() == 8) + { + maxs[0] = atof(Cmd_Argv(4)); + maxs[1] = atof(Cmd_Argv(5)); + maxs[2] = atof(Cmd_Argv(6)); + CL_Locs_AddNode(mins, maxs, Cmd_Argv(7)); + } + else + CL_Locs_AddNode(mins, mins, Cmd_Argv(4)); +} + +static void CL_Locs_RemoveNearest_f(void) +{ + cl_locnode_t *loc; + loc = CL_Locs_FindNearest(r_refdef.view.origin); + if (loc) + CL_Locs_FreeNode(loc); + else + Con_Printf("no loc point or box found for your location\n"); +} + +static void CL_Locs_Clear_f(void) +{ + while (cl.locnodes) + CL_Locs_FreeNode(cl.locnodes); +} + +static void CL_Locs_Save_f(void) +{ + cl_locnode_t *loc; + qfile_t *outfile; + char locfilename[MAX_QPATH]; + if (!cl.locnodes) + { + Con_Printf("No loc points/boxes exist!\n"); + return; + } + if (cls.state != ca_connected || !cl.worldmodel) + { + Con_Printf("No level loaded!\n"); + return; + } + dpsnprintf(locfilename, sizeof(locfilename), "%s.loc", cl.worldnamenoextension); + + outfile = FS_OpenRealFile(locfilename, "w", false); + if (!outfile) + return; + // if any boxes are used then this is a proquake-format loc file, which + // allows comments, so add some relevant information at the start + for (loc = cl.locnodes;loc;loc = loc->next) + if (!VectorCompare(loc->mins, loc->maxs)) + break; + if (loc) + { + FS_Printf(outfile, "// %s %s saved by %s\n// x,y,z,x,y,z,\"name\"\n\n", locfilename, Sys_TimeString("%Y-%m-%d"), engineversion); + for (loc = cl.locnodes;loc;loc = loc->next) + if (VectorCompare(loc->mins, loc->maxs)) + break; + if (loc) + Con_Printf("Warning: writing loc file containing a mixture of qizmo-style points and proquake-style boxes may not work in qizmo or proquake!\n"); + } + for (loc = cl.locnodes;loc;loc = loc->next) + { + if (VectorCompare(loc->mins, loc->maxs)) + { + int len; + const char *s; + const char *in = loc->name; + char name[MAX_INPUTLINE]; + for (len = 0;len < (int)sizeof(name) - 1 && *in;) + { + if (*in == ' ') {s = "$loc_name_separator";in++;} + else if (!strncmp(in, "SSG", 3)) {s = "$loc_name_ssg";in += 3;} + else if (!strncmp(in, "NG", 2)) {s = "$loc_name_ng";in += 2;} + else if (!strncmp(in, "SNG", 3)) {s = "$loc_name_sng";in += 3;} + else if (!strncmp(in, "GL", 2)) {s = "$loc_name_gl";in += 2;} + else if (!strncmp(in, "RL", 2)) {s = "$loc_name_rl";in += 2;} + else if (!strncmp(in, "LG", 2)) {s = "$loc_name_lg";in += 2;} + else if (!strncmp(in, "GA", 2)) {s = "$loc_name_ga";in += 2;} + else if (!strncmp(in, "YA", 2)) {s = "$loc_name_ya";in += 2;} + else if (!strncmp(in, "RA", 2)) {s = "$loc_name_ra";in += 2;} + else if (!strncmp(in, "MEGA", 4)) {s = "$loc_name_mh";in += 4;} + else s = NULL; + if (s) + { + while (len < (int)sizeof(name) - 1 && *s) + name[len++] = *s++; + continue; + } + name[len++] = *in++; + } + name[len] = 0; + FS_Printf(outfile, "%.0f %.0f %.0f %s\n", loc->mins[0]*8, loc->mins[1]*8, loc->mins[2]*8, name); + } + else + FS_Printf(outfile, "%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,\"%s\"\n", loc->mins[0], loc->mins[1], loc->mins[2], loc->maxs[0], loc->maxs[1], loc->maxs[2], loc->name); + } + FS_Close(outfile); +} + +void CL_Locs_Reload_f(void) +{ + int i, linenumber, limit, len; + const char *s; + char *filedata, *text, *textend, *linestart, *linetext, *lineend; + fs_offset_t filesize; + vec3_t mins, maxs; + char locfilename[MAX_QPATH]; + char name[MAX_INPUTLINE]; + + if (cls.state != ca_connected || !cl.worldmodel) + { + Con_Printf("No level loaded!\n"); + return; + } + + CL_Locs_Clear_f(); + + // try maps/something.loc first (LordHavoc: where I think they should be) + dpsnprintf(locfilename, sizeof(locfilename), "%s.loc", cl.worldnamenoextension); + filedata = (char *)FS_LoadFile(locfilename, cls.levelmempool, false, &filesize); + if (!filedata) + { + // try proquake name as well (LordHavoc: I hate path mangling) + dpsnprintf(locfilename, sizeof(locfilename), "locs/%s.loc", cl.worldbasename); + filedata = (char *)FS_LoadFile(locfilename, cls.levelmempool, false, &filesize); + if (!filedata) + return; + } + text = filedata; + textend = filedata + filesize; + for (linenumber = 1;text < textend;linenumber++) + { + linestart = text; + for (;text < textend && *text != '\r' && *text != '\n';text++) + ; + lineend = text; + if (text + 1 < textend && *text == '\r' && text[1] == '\n') + text++; + if (text < textend) + text++; + // trim trailing whitespace + while (lineend > linestart && ISWHITESPACE(lineend[-1])) + lineend--; + // trim leading whitespace + while (linestart < lineend && ISWHITESPACE(*linestart)) + linestart++; + // check if this is a comment + if (linestart + 2 <= lineend && !strncmp(linestart, "//", 2)) + continue; + linetext = linestart; + limit = 3; + for (i = 0;i < limit;i++) + { + if (linetext >= lineend) + break; + // note: a missing number is interpreted as 0 + if (i < 3) + mins[i] = atof(linetext); + else + maxs[i - 3] = atof(linetext); + // now advance past the number + while (linetext < lineend && !ISWHITESPACE(*linetext) && *linetext != ',') + linetext++; + // advance through whitespace + if (linetext < lineend) + { + if (*linetext == ',') + { + linetext++; + limit = 6; + // note: comma can be followed by whitespace + } + if (ISWHITESPACE(*linetext)) + { + // skip whitespace + while (linetext < lineend && ISWHITESPACE(*linetext)) + linetext++; + } + } + } + // if this is a quoted name, remove the quotes + if (i == 6) + { + if (linetext >= lineend || *linetext != '"') + continue; // proquake location names are always quoted + lineend--; + linetext++; + len = min(lineend - linetext, (int)sizeof(name) - 1); + memcpy(name, linetext, len); + name[len] = 0; + // add the box to the list + CL_Locs_AddNode(mins, maxs, name); + } + // if a point was parsed, it needs to be scaled down by 8 (since + // point-based loc files were invented by a proxy which dealt + // directly with quake protocol coordinates, which are *8), turn + // it into a box + else if (i == 3) + { + // interpret silly fuhquake macros + for (len = 0;len < (int)sizeof(name) - 1 && linetext < lineend;) + { + if (*linetext == '$') + { + if (linetext + 18 <= lineend && !strncmp(linetext, "$loc_name_separator", 19)) {s = " ";linetext += 19;} + else if (linetext + 13 <= lineend && !strncmp(linetext, "$loc_name_ssg", 13)) {s = "SSG";linetext += 13;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_ng", 12)) {s = "NG";linetext += 12;} + else if (linetext + 13 <= lineend && !strncmp(linetext, "$loc_name_sng", 13)) {s = "SNG";linetext += 13;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_gl", 12)) {s = "GL";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_rl", 12)) {s = "RL";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_lg", 12)) {s = "LG";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_ga", 12)) {s = "GA";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_ya", 12)) {s = "YA";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_ra", 12)) {s = "RA";linetext += 12;} + else if (linetext + 12 <= lineend && !strncmp(linetext, "$loc_name_mh", 12)) {s = "MEGA";linetext += 12;} + else s = NULL; + if (s) + { + while (len < (int)sizeof(name) - 1 && *s) + name[len++] = *s++; + continue; + } + } + name[len++] = *linetext++; + } + name[len] = 0; + // add the point to the list + VectorScale(mins, (1.0 / 8.0), mins); + CL_Locs_AddNode(mins, mins, name); + } + else + continue; + } +} + +/* +=========== +CL_Shutdown +=========== +*/ +void CL_Shutdown (void) +{ + CL_Screen_Shutdown(); + CL_Particles_Shutdown(); + CL_Parse_Shutdown(); + + Mem_FreePool (&cls.permanentmempool); + Mem_FreePool (&cls.levelmempool); +} + +/* +================= +CL_Init +================= +*/ +void CL_Init (void) +{ + + cls.levelmempool = Mem_AllocPool("client (per-level memory)", 0, NULL); + cls.permanentmempool = Mem_AllocPool("client (long term memory)", 0, NULL); + + memset(&r_refdef, 0, sizeof(r_refdef)); + // max entities sent to renderer per frame + r_refdef.scene.maxentities = MAX_EDICTS + 256 + 512; + r_refdef.scene.entities = (entity_render_t **)Mem_Alloc(cls.permanentmempool, sizeof(entity_render_t *) * r_refdef.scene.maxentities); + + // max temp entities + r_refdef.scene.maxtempentities = MAX_TEMPENTITIES; + r_refdef.scene.tempentities = (entity_render_t *)Mem_Alloc(cls.permanentmempool, sizeof(entity_render_t) * r_refdef.scene.maxtempentities); + + CL_InitInput (); + +// +// register our commands +// + 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_shownet); + Cvar_RegisterVariable (&cl_nolerp); + Cvar_RegisterVariable (&cl_lerpexcess); + Cvar_RegisterVariable (&cl_lerpanim_maxdelta_server); + Cvar_RegisterVariable (&cl_lerpanim_maxdelta_framegroups); + Cvar_RegisterVariable (&cl_deathfade); + Cvar_RegisterVariable (&lookspring); + Cvar_RegisterVariable (&lookstrafe); + Cvar_RegisterVariable (&sensitivity); + Cvar_RegisterVariable (&freelook); + + Cvar_RegisterVariable (&m_pitch); + Cvar_RegisterVariable (&m_yaw); + Cvar_RegisterVariable (&m_forward); + Cvar_RegisterVariable (&m_side); + + Cvar_RegisterVariable (&cl_itembobspeed); + Cvar_RegisterVariable (&cl_itembobheight); + + Cmd_AddCommand ("entities", CL_PrintEntities_f, "print information on network entities known to client"); + Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server (or disconnect all clients if running a server)"); + Cmd_AddCommand ("record", CL_Record_f, "record a demo"); + Cmd_AddCommand ("stop", CL_Stop_f, "stop recording or playing a demo"); + Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "watch a demo file"); + Cmd_AddCommand ("timedemo", CL_TimeDemo_f, "play back a demo as fast as possible and save statistics to benchmark.log"); + + // Support Client-side Model Index List + Cmd_AddCommand ("cl_modelindexlist", CL_ModelIndexList_f, "list information on all models in the client modelindex"); + // Support Client-side Sound Index List + Cmd_AddCommand ("cl_soundindexlist", CL_SoundIndexList_f, "list all sounds in the client soundindex"); + + + Cvar_RegisterVariable (&cl_nosplashscreen); + + Cvar_RegisterVariable (&cl_autodemo); + Cvar_RegisterVariable (&cl_autodemo_nameformat); + Cvar_RegisterVariable (&cl_autodemo_delete); + + Cmd_AddCommand ("fog", CL_Fog_f, "set global fog parameters (density red green blue [alpha [mindist [maxdist [top [fadedepth]]]]])"); + Cmd_AddCommand ("fog_heighttexture", CL_Fog_HeightTexture_f, "set global fog parameters (density red green blue alpha mindist maxdist top depth textures/mapname/fogheight.tga)"); + + // LordHavoc: added pausedemo + Cmd_AddCommand ("pausedemo", CL_PauseDemo_f, "pause demo playback (can also safely pause demo recording if using QUAKE, QUAKEDP or NEHAHRAMOVIE protocol, useful for making movies)"); + + Cmd_AddCommand ("cl_areastats", CL_AreaStats_f, "prints statistics on entity culling during collision traces"); + + Cvar_RegisterVariable(&r_draweffects); + Cvar_RegisterVariable(&cl_explosions_alpha_start); + Cvar_RegisterVariable(&cl_explosions_alpha_end); + Cvar_RegisterVariable(&cl_explosions_size_start); + Cvar_RegisterVariable(&cl_explosions_size_end); + Cvar_RegisterVariable(&cl_explosions_lifetime); + Cvar_RegisterVariable(&cl_stainmaps); + Cvar_RegisterVariable(&cl_stainmaps_clearonload); + Cvar_RegisterVariable(&cl_beams_polygons); + Cvar_RegisterVariable(&cl_beams_quakepositionhack); + Cvar_RegisterVariable(&cl_beams_instantaimhack); + Cvar_RegisterVariable(&cl_beams_lightatend); + Cvar_RegisterVariable(&cl_noplayershadow); + Cvar_RegisterVariable(&cl_dlights_decayradius); + Cvar_RegisterVariable(&cl_dlights_decaybrightness); + + Cvar_RegisterVariable(&cl_prydoncursor); + Cvar_RegisterVariable(&cl_prydoncursor_notrace); + + Cvar_RegisterVariable(&cl_deathnoviewmodel); + + // for QW connections + Cvar_RegisterVariable(&qport); + Cvar_SetValueQuick(&qport, (rand() * RAND_MAX + rand()) & 0xffff); + + Cmd_AddCommand("timerefresh", CL_TimeRefresh_f, "turn quickly and print rendering statistcs"); + + Cvar_RegisterVariable(&cl_locs_enable); + Cvar_RegisterVariable(&cl_locs_show); + Cmd_AddCommand("locs_add", CL_Locs_Add_f, "add a point or box location (usage: x y z[ x y z] \"name\", if two sets of xyz are supplied it is a box, otherwise point)"); + Cmd_AddCommand("locs_removenearest", CL_Locs_RemoveNearest_f, "remove the nearest point or box (note: you need to be very near a box to remove it)"); + Cmd_AddCommand("locs_clear", CL_Locs_Clear_f, "remove all loc points/boxes"); + Cmd_AddCommand("locs_reload", CL_Locs_Reload_f, "reload .loc file for this map"); + Cmd_AddCommand("locs_save", CL_Locs_Save_f, "save .loc file for this map containing currently defined points and boxes"); + + CL_Parse_Init(); + CL_Particles_Init(); + CL_Screen_Init(); + + CL_Video_Init(); +} diff --git a/app/jni/cl_parse.c b/app/jni/cl_parse.c new file mode 100644 index 0000000..0a93685 --- /dev/null +++ b/app/jni/cl_parse.c @@ -0,0 +1,4278 @@ +/* +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" +#include "cdaudio.h" +#include "cl_collision.h" +#include "csprogs.h" +#include "libcurl.h" +#include "utf8lib.h" +#include "menu.h" +#include "cl_video.h" + +const char *svc_strings[128] = +{ + "svc_bad", + "svc_nop", + "svc_disconnect", + "svc_updatestat", + "svc_version", // [int] 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", // [int] 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", + "svc_showlmp", // [string] iconlabel [string] lmpfile [short] x [short] y + "svc_hidelmp", // [string] iconlabel + "svc_skybox", // [string] skyname + "", // 38 + "", // 39 + "", // 40 + "", // 41 + "", // 42 + "", // 43 + "", // 44 + "", // 45 + "", // 46 + "", // 47 + "", // 48 + "", // 49 + "svc_downloaddata", // 50 // [int] start [short] size [variable length] data + "svc_updatestatubyte", // 51 // [byte] stat [byte] value + "svc_effect", // 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate + "svc_effect2", // 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate + "svc_sound2", // 54 // short soundindex instead of byte + "svc_spawnbaseline2", // 55 // short modelindex instead of byte + "svc_spawnstatic2", // 56 // short modelindex instead of byte + "svc_entities", // 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata + "svc_csqcentities", // 58 // [short] entnum [variable length] entitydata ... [short] 0x0000 + "svc_spawnstaticsound2", // 59 // [coord3] [short] samp [byte] vol [byte] aten + "svc_trailparticles", // 60 // [short] entnum [short] effectnum [vector] start [vector] end + "svc_pointparticles", // 61 // [short] effectnum [vector] start [vector] velocity [short] count + "svc_pointparticles1", // 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 +}; + +const char *qw_svc_strings[128] = +{ + "qw_svc_bad", // 0 + "qw_svc_nop", // 1 + "qw_svc_disconnect", // 2 + "qw_svc_updatestat", // 3 // [byte] [byte] + "", // 4 + "qw_svc_setview", // 5 // [short] entity number + "qw_svc_sound", // 6 // + "", // 7 + "qw_svc_print", // 8 // [byte] id [string] null terminated string + "qw_svc_stufftext", // 9 // [string] stuffed into client's console buffer + "qw_svc_setangle", // 10 // [angle3] set the view angle to this absolute value + "qw_svc_serverdata", // 11 // [long] protocol ... + "qw_svc_lightstyle", // 12 // [byte] [string] + "", // 13 + "qw_svc_updatefrags", // 14 // [byte] [short] + "", // 15 + "qw_svc_stopsound", // 16 // + "", // 17 + "", // 18 + "qw_svc_damage", // 19 + "qw_svc_spawnstatic", // 20 + "", // 21 + "qw_svc_spawnbaseline", // 22 + "qw_svc_temp_entity", // 23 // variable + "qw_svc_setpause", // 24 // [byte] on / off + "", // 25 + "qw_svc_centerprint", // 26 // [string] to put in center of the screen + "qw_svc_killedmonster", // 27 + "qw_svc_foundsecret", // 28 + "qw_svc_spawnstaticsound", // 29 // [coord3] [byte] samp [byte] vol [byte] aten + "qw_svc_intermission", // 30 // [vec3_t] origin [vec3_t] angle + "qw_svc_finale", // 31 // [string] text + "qw_svc_cdtrack", // 32 // [byte] track + "qw_svc_sellscreen", // 33 + "qw_svc_smallkick", // 34 // set client punchangle to 2 + "qw_svc_bigkick", // 35 // set client punchangle to 4 + "qw_svc_updateping", // 36 // [byte] [short] + "qw_svc_updateentertime", // 37 // [byte] [float] + "qw_svc_updatestatlong", // 38 // [byte] [long] + "qw_svc_muzzleflash", // 39 // [short] entity + "qw_svc_updateuserinfo", // 40 // [byte] slot [long] uid + "qw_svc_download", // 41 // [short] size [size bytes] + "qw_svc_playerinfo", // 42 // variable + "qw_svc_nails", // 43 // [byte] num [48 bits] xyzpy 12 12 12 4 8 + "qw_svc_chokecount", // 44 // [byte] packets choked + "qw_svc_modellist", // 45 // [strings] + "qw_svc_soundlist", // 46 // [strings] + "qw_svc_packetentities", // 47 // [...] + "qw_svc_deltapacketentities", // 48 // [...] + "qw_svc_maxspeed", // 49 // maxspeed change, for prediction + "qw_svc_entgravity", // 50 // gravity change, for prediction + "qw_svc_setinfo", // 51 // setinfo on a client + "qw_svc_serverinfo", // 52 // serverinfo + "qw_svc_updatepl", // 53 // [byte] [byte] +}; + +//============================================================================= + +cvar_t cl_worldmessage = {CVAR_READONLY, "cl_worldmessage", "", "title of current level"}; +cvar_t cl_worldname = {CVAR_READONLY, "cl_worldname", "", "name of current worldmodel"}; +cvar_t cl_worldnamenoextension = {CVAR_READONLY, "cl_worldnamenoextension", "", "name of current worldmodel without extension"}; +cvar_t cl_worldbasename = {CVAR_READONLY, "cl_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; + +cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-10 (higher for more info, 10 being the most verbose)"}; +cvar_t cl_gameplayfix_soundsmovewithentities = {0, "cl_gameplayfix_soundsmovewithentities", "1", "causes sounds made by lifts, players, projectiles, and any other entities, to move with the entity, so for example a rocket noise follows the rocket rather than staying at the starting position"}; +cvar_t cl_sound_wizardhit = {0, "cl_sound_wizardhit", "wizard/hit.wav", "sound to play during TE_WIZSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_hknighthit = {0, "cl_sound_hknighthit", "hknight/hit.wav", "sound to play during TE_KNIGHTSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_tink1 = {0, "cl_sound_tink1", "weapons/tink1.wav", "sound to play with 80% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_ric1 = {0, "cl_sound_ric1", "weapons/ric1.wav", "sound to play with 5% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_ric2 = {0, "cl_sound_ric2", "weapons/ric2.wav", "sound to play with 5% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_sound_ric3 = {0, "cl_sound_ric3", "weapons/ric3.wav", "sound to play with 10% chance during TE_SPIKE/TE_SUPERSPIKE (empty cvar disables sound)"}; +cvar_t cl_readpicture_force = {0, "cl_readpicture_force", "0", "when enabled, the low quality pictures read by ReadPicture() are preferred over the high quality pictures on the file system"}; + +#define RIC_GUNSHOT 1 +#define RIC_GUNSHOTQUAD 2 +cvar_t cl_sound_ric_gunshot = {0, "cl_sound_ric_gunshot", "0", "specifies if and when the related cl_sound_ric and cl_sound_tink sounds apply to TE_GUNSHOT/TE_GUNSHOTQUAD, 0 = no sound, 1 = TE_GUNSHOT, 2 = TE_GUNSHOTQUAD, 3 = TE_GUNSHOT and TE_GUNSHOTQUAD"}; +cvar_t cl_sound_r_exp3 = {0, "cl_sound_r_exp3", "weapons/r_exp3.wav", "sound to play during TE_EXPLOSION and related effects (empty cvar disables sound)"}; +cvar_t cl_serverextension_download = {0, "cl_serverextension_download", "0", "indicates whether the server supports the download command"}; +cvar_t cl_joinbeforedownloadsfinish = {CVAR_SAVE, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"}; +cvar_t cl_nettimesyncfactor = {CVAR_SAVE, "cl_nettimesyncfactor", "0", "rate at which client time adapts to match server time, 1 = instantly, 0.125 = slowly, 0 = not at all (bounding still applies)"}; +cvar_t cl_nettimesyncboundmode = {CVAR_SAVE, "cl_nettimesyncboundmode", "6", "method of restricting client time to valid values, 0 = no correction, 1 = tight bounding (jerky with packet loss), 2 = loose bounding (corrects it if out of bounds), 3 = leniant bounding (ignores temporary errors due to varying framerate), 4 = slow adjustment method from Quake3, 5 = slighttly nicer version of Quake3 method, 6 = bounding + Quake3"}; +cvar_t cl_nettimesyncboundtolerance = {CVAR_SAVE, "cl_nettimesyncboundtolerance", "0.25", "how much error is tolerated by bounding check, as a fraction of frametime, 0.25 = up to 25% margin of error tolerated, 1 = use only new time, 0 = use only old time (same effect as setting cl_nettimesyncfactor to 1)"}; +cvar_t cl_iplog_name = {CVAR_SAVE, "cl_iplog_name", "darkplaces_iplog.txt", "name of iplog file containing player addresses for iplog_list command and automatic ip logging when parsing status command"}; + +static qboolean QW_CL_CheckOrDownloadFile(const char *filename); +static void QW_CL_RequestNextDownload(void); +static void QW_CL_NextUpload(void); +//static qboolean QW_CL_IsUploading(void); +static void QW_CL_StopUpload(void); + +/* +================== +CL_ParseStartSoundPacket +================== +*/ +static void CL_ParseStartSoundPacket(int largesoundindex) +{ + vec3_t pos; + int channel, ent; + int sound_num; + int volume; + int field_mask; + float attenuation; + float speed; + int fflags = CHANNELFLAG_NONE; + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + channel = MSG_ReadShort(&cl_message); + + if (channel & (1<<15)) + volume = MSG_ReadByte(&cl_message); + else + volume = DEFAULT_SOUND_PACKET_VOLUME; + + if (channel & (1<<14)) + attenuation = MSG_ReadByte(&cl_message) / 64.0; + else + attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + + speed = 1.0f; + + ent = (channel>>3)&1023; + channel &= 7; + + sound_num = MSG_ReadByte(&cl_message); + } + else + { + field_mask = MSG_ReadByte(&cl_message); + + if (field_mask & SND_VOLUME) + volume = MSG_ReadByte(&cl_message); + else + volume = DEFAULT_SOUND_PACKET_VOLUME; + + if (field_mask & SND_ATTENUATION) + attenuation = MSG_ReadByte(&cl_message) / 64.0; + else + attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + + if (field_mask & SND_SPEEDUSHORT4000) + speed = ((unsigned short)MSG_ReadShort(&cl_message)) / 4000.0f; + else + speed = 1.0f; + + if (field_mask & SND_LARGEENTITY) + { + ent = (unsigned short) MSG_ReadShort(&cl_message); + channel = MSG_ReadChar(&cl_message); + } + else + { + channel = (unsigned short) MSG_ReadShort(&cl_message); + ent = channel >> 3; + channel &= 7; + } + + if (largesoundindex || (field_mask & SND_LARGESOUND) || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3) + sound_num = (unsigned short) MSG_ReadShort(&cl_message); + else + sound_num = MSG_ReadByte(&cl_message); + } + + channel = CHAN_NET2ENGINE(channel); + + MSG_ReadVector(&cl_message, pos, cls.protocol); + + if (sound_num >= MAX_SOUNDS) + { + Con_Printf("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS); + return; + } + + if (ent >= MAX_EDICTS) + { + Con_Printf("CL_ParseStartSoundPacket: ent = %i", ent); + return; + } + + if (ent >= cl.max_entities) + CL_ExpandEntities(ent); + + if( !CL_VM_Event_Sound(sound_num, volume / 255.0f, channel, attenuation, ent, pos, fflags, speed) ) + S_StartSound_StartPosition_Flags (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0f, attenuation, 0, fflags, speed); +} + +/* +================== +CL_KeepaliveMessage + +When the client is taking a long time to load stuff, send keepalive messages +so the server doesn't disconnect. +================== +*/ + +static unsigned char olddata[NET_MAXMESSAGE]; +void CL_KeepaliveMessage (qboolean readmessages) +{ + static double lastdirtytime = 0; + static qboolean recursive = false; + double dirtytime; + double deltatime; + static double countdownmsg = 0; + static double countdownupdate = 0; + sizebuf_t old; + + qboolean thisrecursive; + + thisrecursive = recursive; + recursive = true; + + dirtytime = Sys_DirtyTime(); + deltatime = dirtytime - lastdirtytime; + lastdirtytime = dirtytime; + if (deltatime <= 0 || deltatime >= 1800.0) + return; + + countdownmsg -= deltatime; + countdownupdate -= deltatime; + + if(!thisrecursive) + { + if(cls.state != ca_dedicated) + { + if(countdownupdate <= 0) // check if time stepped backwards + { + SCR_UpdateLoadingScreenIfShown(); + countdownupdate = 2; + } + } + } + + // no need if server is local and definitely not if this is a demo + if (sv.active || !cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD || cls.signon >= SIGNONS) + { + recursive = thisrecursive; + return; + } + + if (readmessages) + { + // read messages from server, should just be nops + old = cl_message; + memcpy(olddata, cl_message.data, cl_message.cursize); + + NetConn_ClientFrame(); + + cl_message = old; + memcpy(cl_message.data, olddata, cl_message.cursize); + } + + if (cls.netcon && countdownmsg <= 0) // check if time stepped backwards + { + sizebuf_t msg; + unsigned char buf[4]; + countdownmsg = 5; + // write out a nop + // LordHavoc: must use unreliable because reliable could kill the sigon message! + Con_Print("--> client to server keepalive\n"); + memset(&msg, 0, sizeof(msg)); + msg.data = buf; + msg.maxsize = sizeof(buf); + MSG_WriteChar(&msg, clc_nop); + NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false); + } + + recursive = thisrecursive; +} + +void CL_ParseEntityLump(char *entdata) +{ + const char *data; + char key[128], value[MAX_INPUTLINE]; + FOG_clear(); // LordHavoc: no fog until set + // LordHavoc: default to the map's sky (q3 shader parsing sets this) + R_SetSkyBox(cl.worldmodel->brush.skybox); + data = entdata; + if (!data) + return; + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] != '{') + return; // error + while (1) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strlcpy (key, com_token + 1, sizeof (key)); + else + strlcpy (key, com_token, sizeof (key)); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + strlcpy (value, com_token, sizeof (value)); + if (!strcmp("sky", key)) + R_SetSkyBox(value); + else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh. + R_SetSkyBox(value); + else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK) + R_SetSkyBox(value); + else if (!strcmp("fog", key)) + { + FOG_clear(); // so missing values get good defaults + r_refdef.fog_start = 0; + r_refdef.fog_alpha = 1; + r_refdef.fog_end = 16384; + r_refdef.fog_height = 1<<30; + r_refdef.fog_fadedepth = 128; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + sscanf(value, "%f %f %f %f %f %f %f %f %f", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth); + } + else if (!strcmp("fog_density", key)) + r_refdef.fog_density = atof(value); + else if (!strcmp("fog_red", key)) + r_refdef.fog_red = atof(value); + else if (!strcmp("fog_green", key)) + r_refdef.fog_green = atof(value); + else if (!strcmp("fog_blue", key)) + r_refdef.fog_blue = atof(value); + else if (!strcmp("fog_alpha", key)) + r_refdef.fog_alpha = atof(value); + else if (!strcmp("fog_start", key)) + r_refdef.fog_start = atof(value); + else if (!strcmp("fog_end", key)) + r_refdef.fog_end = atof(value); + else if (!strcmp("fog_height", key)) + r_refdef.fog_height = atof(value); + else if (!strcmp("fog_fadedepth", key)) + r_refdef.fog_fadedepth = atof(value); + else if (!strcmp("fog_heighttexture", key)) + { + FOG_clear(); // so missing values get good defaults +#if _MSC_VER >= 1400 + sscanf_s(value, "%f %f %f %f %f %f %f %f %f %s", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth, r_refdef.fog_height_texturename, (unsigned int)sizeof(r_refdef.fog_height_texturename)); +#else + sscanf(value, "%f %f %f %f %f %f %f %f %f %63s", &r_refdef.fog_density, &r_refdef.fog_red, &r_refdef.fog_green, &r_refdef.fog_blue, &r_refdef.fog_alpha, &r_refdef.fog_start, &r_refdef.fog_end, &r_refdef.fog_height, &r_refdef.fog_fadedepth, r_refdef.fog_height_texturename); +#endif + r_refdef.fog_height_texturename[63] = 0; + } + } +} + +static const vec3_t defaultmins = {-4096, -4096, -4096}; +static const vec3_t defaultmaxs = {4096, 4096, 4096}; +static void CL_SetupWorldModel(void) +{ + prvm_prog_t *prog = CLVM_prog; + // update the world model + cl.entities[0].render.model = cl.worldmodel = CL_GetModelByIndex(1); + CL_UpdateRenderEntity(&cl.entities[0].render); + + // make sure the cl.worldname and related cvars are set up now that we know the world model name + // set up csqc world for collision culling + if (cl.worldmodel) + { + strlcpy(cl.worldname, cl.worldmodel->name, sizeof(cl.worldname)); + FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, !strncmp(cl.worldnamenoextension, "maps/", 5) ? cl.worldnamenoextension + 5 : cl.worldnamenoextension, sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + World_SetSize(&cl.world, cl.worldname, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs, prog); + } + else + { + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldnamenoextension, ""); + Cvar_SetQuick(&cl_worldbasename, ""); + World_SetSize(&cl.world, "", defaultmins, defaultmaxs, prog); + } + World_Start(&cl.world); + + // load or reload .loc file for team chat messages + CL_Locs_Reload_f(); + + // make sure we send enough keepalives + CL_KeepaliveMessage(false); + + // reset particles and other per-level things + R_Modules_NewMap(); + + // make sure we send enough keepalives + CL_KeepaliveMessage(false); + + // load the team chat beep if possible + cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav"); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // make menu know + MR_NewMap(); + + // load the csqc now + if (cl.loadcsqc) + { + cl.loadcsqc = false; + + CL_VM_Init(); + } +} + +static qboolean QW_CL_CheckOrDownloadFile(const char *filename) +{ + qfile_t *file; + char vabuf[1024]; + + // see if the file already exists + file = FS_OpenVirtualFile(filename, true); + if (file) + { + FS_Close(file); + return true; + } + + // download messages in a demo would be bad + if (cls.demorecording) + { + Con_Printf("Unable to download \"%s\" when recording.\n", filename); + return true; + } + + // don't try to download when playing a demo + if (!cls.netcon) + return true; + + strlcpy(cls.qw_downloadname, filename, sizeof(cls.qw_downloadname)); + Con_Printf("Downloading %s\n", filename); + + if (!cls.qw_downloadmemory) + { + cls.qw_downloadmemory = NULL; + cls.qw_downloadmemorycursize = 0; + cls.qw_downloadmemorymaxsize = 1024*1024; // start out with a 1MB buffer + } + + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "download %s", filename)); + + cls.qw_downloadnumber++; + cls.qw_downloadpercent = 0; + cls.qw_downloadmemorycursize = 0; + + return false; +} + +static void QW_CL_ProcessUserInfo(int slot); +static void QW_CL_RequestNextDownload(void) +{ + int i; + char vabuf[1024]; + + // clear name of file that just finished + cls.qw_downloadname[0] = 0; + + switch (cls.qw_downloadtype) + { + case dl_single: + break; + case dl_skin: + if (cls.qw_downloadnumber == 0) + Con_Printf("Checking skins...\n"); + for (;cls.qw_downloadnumber < cl.maxclients;cls.qw_downloadnumber++) + { + if (!cl.scores[cls.qw_downloadnumber].name[0]) + continue; + // check if we need to download the file, and return if so + if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "skins/%s.pcx", cl.scores[cls.qw_downloadnumber].qw_skin))) + return; + } + + cls.qw_downloadtype = dl_none; + + // load any newly downloaded skins + for (i = 0;i < cl.maxclients;i++) + QW_CL_ProcessUserInfo(i); + + // if we're still in signon stages, request the next one + if (cls.signon != SIGNONS) + { + cls.signon = SIGNONS-1; + // we'll go to SIGNONS when the first entity update is received + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "begin %i", cl.qw_servercount)); + } + break; + case dl_model: + if (cls.qw_downloadnumber == 0) + { + Con_Printf("Checking models...\n"); + cls.qw_downloadnumber = 1; + } + + for (;cls.qw_downloadnumber < MAX_MODELS && cl.model_name[cls.qw_downloadnumber][0];cls.qw_downloadnumber++) + { + // skip submodels + if (cl.model_name[cls.qw_downloadnumber][0] == '*') + continue; + if (!strcmp(cl.model_name[cls.qw_downloadnumber], "progs/spike.mdl")) + cl.qw_modelindex_spike = cls.qw_downloadnumber; + if (!strcmp(cl.model_name[cls.qw_downloadnumber], "progs/player.mdl")) + cl.qw_modelindex_player = cls.qw_downloadnumber; + if (!strcmp(cl.model_name[cls.qw_downloadnumber], "progs/flag.mdl")) + cl.qw_modelindex_flag = cls.qw_downloadnumber; + if (!strcmp(cl.model_name[cls.qw_downloadnumber], "progs/s_explod.spr")) + cl.qw_modelindex_s_explod = cls.qw_downloadnumber; + // check if we need to download the file, and return if so + if (!QW_CL_CheckOrDownloadFile(cl.model_name[cls.qw_downloadnumber])) + return; + } + + cls.qw_downloadtype = dl_none; + + // touch all of the precached models that are still loaded so we can free + // anything that isn't needed + if (!sv.active) + Mod_ClearUsed(); + for (i = 1;i < MAX_MODELS && cl.model_name[i][0];i++) + Mod_FindName(cl.model_name[i], cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL); + // precache any models used by the client (this also marks them used) + cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, NULL); + cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL); + cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL); + cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL); + + // we purge the models and sounds later in CL_SignonReply + //Mod_PurgeUnused(); + + // now we try to load everything that is new + + // world model + cl.model_precache[1] = Mod_ForName(cl.model_name[1], false, false, NULL); + if (cl.model_precache[1]->Draw == NULL) + Con_Printf("Map %s could not be found or downloaded\n", cl.model_name[1]); + + // normal models + for (i = 2;i < MAX_MODELS && cl.model_name[i][0];i++) + if ((cl.model_precache[i] = Mod_ForName(cl.model_name[i], false, false, cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL))->Draw == NULL) + Con_Printf("Model %s could not be found or downloaded\n", cl.model_name[i]); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // now that we have a world model, set up the world entity, renderer + // modules and csqc + CL_SetupWorldModel(); + + // add pmodel/emodel CRCs to userinfo + CL_SetInfo("pmodel", va(vabuf, sizeof(vabuf), "%i", FS_CRCFile("progs/player.mdl", NULL)), true, true, true, true); + CL_SetInfo("emodel", va(vabuf, sizeof(vabuf), "%i", FS_CRCFile("progs/eyes.mdl", NULL)), true, true, true, true); + + // done checking sounds and models, send a prespawn command now + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "prespawn %i 0 %i", cl.qw_servercount, cl.model_precache[1]->brush.qw_md4sum2)); + + if (cls.qw_downloadmemory) + { + Mem_Free(cls.qw_downloadmemory); + cls.qw_downloadmemory = NULL; + } + + // done loading + cl.loadfinished = true; + break; + case dl_sound: + if (cls.qw_downloadnumber == 0) + { + Con_Printf("Checking sounds...\n"); + cls.qw_downloadnumber = 1; + } + + for (;cl.sound_name[cls.qw_downloadnumber][0];cls.qw_downloadnumber++) + { + // check if we need to download the file, and return if so + if (!QW_CL_CheckOrDownloadFile(va(vabuf, sizeof(vabuf), "sound/%s", cl.sound_name[cls.qw_downloadnumber]))) + return; + } + + cls.qw_downloadtype = dl_none; + + // clear sound usage flags for purging of unused sounds + S_ClearUsed(); + + // precache any sounds used by the client + cl.sfx_wizhit = S_PrecacheSound(cl_sound_wizardhit.string, false, true); + cl.sfx_knighthit = S_PrecacheSound(cl_sound_hknighthit.string, false, true); + cl.sfx_tink1 = S_PrecacheSound(cl_sound_tink1.string, false, true); + cl.sfx_ric1 = S_PrecacheSound(cl_sound_ric1.string, false, true); + cl.sfx_ric2 = S_PrecacheSound(cl_sound_ric2.string, false, true); + cl.sfx_ric3 = S_PrecacheSound(cl_sound_ric3.string, false, true); + cl.sfx_r_exp3 = S_PrecacheSound(cl_sound_r_exp3.string, false, true); + + // sounds used by the game + for (i = 1;i < MAX_SOUNDS && cl.sound_name[i][0];i++) + cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i], true, true); + + // we purge the models and sounds later in CL_SignonReply + //S_PurgeUnused(); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // done with sound downloads, next we check models + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, 0)); + break; + case dl_none: + default: + Con_Printf("Unknown download type.\n"); + } +} + +static void QW_CL_ParseDownload(void) +{ + int size = (signed short)MSG_ReadShort(&cl_message); + int percent = MSG_ReadByte(&cl_message); + + //Con_Printf("download %i %i%% (%i/%i)\n", size, percent, cls.qw_downloadmemorycursize, cls.qw_downloadmemorymaxsize); + + // skip the download fragment if playing a demo + if (!cls.netcon) + { + if (size > 0) + cl_message.readcount += size; + return; + } + + if (size == -1) + { + Con_Printf("File not found.\n"); + QW_CL_RequestNextDownload(); + return; + } + + if (cl_message.readcount + (unsigned short)size > cl_message.cursize) + Host_Error("corrupt download message\n"); + + // make sure the buffer is big enough to include this new fragment + if (!cls.qw_downloadmemory || cls.qw_downloadmemorymaxsize < cls.qw_downloadmemorycursize + size) + { + unsigned char *old; + while (cls.qw_downloadmemorymaxsize < cls.qw_downloadmemorycursize + size) + cls.qw_downloadmemorymaxsize *= 2; + old = cls.qw_downloadmemory; + cls.qw_downloadmemory = (unsigned char *)Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorymaxsize); + if (old) + { + memcpy(cls.qw_downloadmemory, old, cls.qw_downloadmemorycursize); + Mem_Free(old); + } + } + + // read the fragment out of the packet + MSG_ReadBytes(&cl_message, size, cls.qw_downloadmemory + cls.qw_downloadmemorycursize); + cls.qw_downloadmemorycursize += size; + cls.qw_downloadspeedcount += size; + + cls.qw_downloadpercent = percent; + + if (percent != 100) + { + // request next fragment + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "nextdl"); + } + else + { + // finished file + Con_Printf("Downloaded \"%s\"\n", cls.qw_downloadname); + + FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + + cls.qw_downloadpercent = 0; + + // start downloading the next file (or join the game) + QW_CL_RequestNextDownload(); + } +} + +static void QW_CL_ParseModelList(void) +{ + int n; + int nummodels = MSG_ReadByte(&cl_message); + char *str; + char vabuf[1024]; + + // parse model precache list + for (;;) + { + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (!str[0]) + break; + nummodels++; + if (nummodels==MAX_MODELS) + Host_Error("Server sent too many model precaches"); + if (strlen(str) >= MAX_QPATH) + Host_Error("Server sent a precache name of %i characters (max %i)", (int)strlen(str), MAX_QPATH - 1); + strlcpy(cl.model_name[nummodels], str, sizeof (cl.model_name[nummodels])); + } + + n = MSG_ReadByte(&cl_message); + if (n) + { + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "modellist %i %i", cl.qw_servercount, n)); + return; + } + + cls.signon = 2; + cls.qw_downloadnumber = 0; + cls.qw_downloadtype = dl_model; + QW_CL_RequestNextDownload(); +} + +static void QW_CL_ParseSoundList(void) +{ + int n; + int numsounds = MSG_ReadByte(&cl_message); + char *str; + char vabuf[1024]; + + // parse sound precache list + for (;;) + { + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (!str[0]) + break; + numsounds++; + if (numsounds==MAX_SOUNDS) + Host_Error("Server sent too many sound precaches"); + if (strlen(str) >= MAX_QPATH) + Host_Error("Server sent a precache name of %i characters (max %i)", (int)strlen(str), MAX_QPATH - 1); + strlcpy(cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds])); + } + + n = MSG_ReadByte(&cl_message); + + if (n) + { + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, n)); + return; + } + + cls.signon = 2; + cls.qw_downloadnumber = 0; + cls.qw_downloadtype = dl_sound; + QW_CL_RequestNextDownload(); +} + +static void QW_CL_Skins_f(void) +{ + cls.qw_downloadnumber = 0; + cls.qw_downloadtype = dl_skin; + QW_CL_RequestNextDownload(); +} + +static void QW_CL_Changing_f(void) +{ + if (cls.qw_downloadmemory) // don't change when downloading + return; + + S_StopAllSounds(); + cl.intermission = 0; + cls.signon = 1; // not active anymore, but not disconnected + Con_Printf("\nChanging map...\n"); +} + +void QW_CL_NextUpload(void) +{ + int r, percent, size; + + if (!cls.qw_uploaddata) + return; + + r = cls.qw_uploadsize - cls.qw_uploadpos; + if (r > 768) + r = 768; + size = min(1, cls.qw_uploadsize); + percent = (cls.qw_uploadpos+r)*100/size; + + MSG_WriteByte(&cls.netcon->message, qw_clc_upload); + MSG_WriteShort(&cls.netcon->message, r); + MSG_WriteByte(&cls.netcon->message, percent); + SZ_Write(&cls.netcon->message, cls.qw_uploaddata + cls.qw_uploadpos, r); + + Con_DPrintf("UPLOAD: %6d: %d written\n", cls.qw_uploadpos, r); + + cls.qw_uploadpos += r; + + if (cls.qw_uploadpos < cls.qw_uploadsize) + return; + + Con_Printf("Upload completed\n"); + + QW_CL_StopUpload(); +} + +void QW_CL_StartUpload(unsigned char *data, int size) +{ + // do nothing in demos or if not connected + if (!cls.netcon) + return; + + // abort existing upload if in progress + QW_CL_StopUpload(); + + Con_DPrintf("Starting upload of %d bytes...\n", size); + + cls.qw_uploaddata = (unsigned char *)Mem_Alloc(cls.permanentmempool, size); + memcpy(cls.qw_uploaddata, data, size); + cls.qw_uploadsize = size; + cls.qw_uploadpos = 0; + + QW_CL_NextUpload(); +} + +#if 0 +qboolean QW_CL_IsUploading(void) +{ + return cls.qw_uploaddata != NULL; +} +#endif + +void QW_CL_StopUpload(void) +{ + if (cls.qw_uploaddata) + Mem_Free(cls.qw_uploaddata); + cls.qw_uploaddata = NULL; + cls.qw_uploadsize = 0; + cls.qw_uploadpos = 0; +} + +static void QW_CL_ProcessUserInfo(int slot) +{ + int topcolor, bottomcolor; + char temp[2048]; + InfoString_GetValue(cl.scores[slot].qw_userinfo, "name", cl.scores[slot].name, sizeof(cl.scores[slot].name)); + InfoString_GetValue(cl.scores[slot].qw_userinfo, "topcolor", temp, sizeof(temp));topcolor = atoi(temp); + InfoString_GetValue(cl.scores[slot].qw_userinfo, "bottomcolor", temp, sizeof(temp));bottomcolor = atoi(temp); + cl.scores[slot].colors = topcolor * 16 + bottomcolor; + InfoString_GetValue(cl.scores[slot].qw_userinfo, "*spectator", temp, sizeof(temp)); + cl.scores[slot].qw_spectator = temp[0] != 0; + InfoString_GetValue(cl.scores[slot].qw_userinfo, "team", cl.scores[slot].qw_team, sizeof(cl.scores[slot].qw_team)); + InfoString_GetValue(cl.scores[slot].qw_userinfo, "skin", cl.scores[slot].qw_skin, sizeof(cl.scores[slot].qw_skin)); + if (!cl.scores[slot].qw_skin[0]) + strlcpy(cl.scores[slot].qw_skin, "base", sizeof(cl.scores[slot].qw_skin)); + // TODO: skin cache +} + +static void QW_CL_UpdateUserInfo(void) +{ + int slot; + slot = MSG_ReadByte(&cl_message); + if (slot >= cl.maxclients) + { + Con_Printf("svc_updateuserinfo >= cl.maxclients\n"); + MSG_ReadLong(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + return; + } + cl.scores[slot].qw_userid = MSG_ReadLong(&cl_message); + strlcpy(cl.scores[slot].qw_userinfo, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(cl.scores[slot].qw_userinfo)); + + QW_CL_ProcessUserInfo(slot); +} + +static void QW_CL_SetInfo(void) +{ + int slot; + char key[2048]; + char value[2048]; + slot = MSG_ReadByte(&cl_message); + strlcpy(key, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(key)); + strlcpy(value, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(value)); + if (slot >= cl.maxclients) + { + Con_Printf("svc_setinfo >= cl.maxclients\n"); + return; + } + InfoString_SetValue(cl.scores[slot].qw_userinfo, sizeof(cl.scores[slot].qw_userinfo), key, value); + + QW_CL_ProcessUserInfo(slot); +} + +static void QW_CL_ServerInfo(void) +{ + char key[2048]; + char value[2048]; + char temp[32]; + strlcpy(key, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(key)); + strlcpy(value, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(value)); + Con_DPrintf("SERVERINFO: %s=%s\n", key, value); + InfoString_SetValue(cl.qw_serverinfo, sizeof(cl.qw_serverinfo), key, value); + InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp)); + cl.qw_teamplay = atoi(temp); +} + +static void QW_CL_ParseNails(void) +{ + int i, j; + int numnails = MSG_ReadByte(&cl_message); + vec_t *v; + unsigned char bits[6]; + for (i = 0;i < numnails;i++) + { + for (j = 0;j < 6;j++) + bits[j] = MSG_ReadByte(&cl_message); + if (cl.qw_num_nails > 255) + continue; + v = cl.qw_nails[cl.qw_num_nails++]; + v[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096; + v[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096; + v[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096; + v[3] = -360*(bits[4]>>4)/16; + v[4] = 360*bits[5]/256; + v[5] = 0; + } +} + +static void CL_UpdateItemsAndWeapon(void) +{ + int j; + // check for important changes + + // set flash times + if (cl.olditems != cl.stats[STAT_ITEMS]) + for (j = 0;j < 32;j++) + if ((cl.stats[STAT_ITEMS] & (1<= 0 + && cl_serverextension_download.integer + && (FS_CRCFile(csqc_progname.string, &progsize) != csqc_progcrc.integer || ((int)progsize != csqc_progsize.integer && csqc_progsize.integer != -1)) + && !FS_FileExists(va(vabuf, sizeof(vabuf), "dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer))) + { + Con_Printf("Downloading new CSQC code to dlcache/%s.%i.%i\n", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer); + if(cl_serverextension_download.integer == 2 && FS_HasZlib()) + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s deflate", csqc_progname.string)); + else + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", csqc_progname.string)); + return; + } + } + + if (cl.loadmodel_current < cl.loadmodel_total) + { + // loading models + if(cl.loadmodel_current == 1) + { + // worldmodel counts as 16 models (15 + world model setup), for better progress bar + SCR_PushLoadingScreen(false, "Loading precached models", + ( + (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + + LOADPROGRESSWEIGHT_WORLDMODEL + + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + ) / ( + (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + + LOADPROGRESSWEIGHT_WORLDMODEL + + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND + ) + ); + SCR_BeginLoadingPlaque(false); + } + for (;cl.loadmodel_current < cl.loadmodel_total;cl.loadmodel_current++) + { + SCR_PushLoadingScreen(false, cl.model_name[cl.loadmodel_current], + ( + (cl.loadmodel_current == 1) ? LOADPROGRESSWEIGHT_WORLDMODEL : LOADPROGRESSWEIGHT_MODEL + ) / ( + (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + + LOADPROGRESSWEIGHT_WORLDMODEL + + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + ) + ); + if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw) + { + SCR_PopLoadingScreen(false); + if(cl.loadmodel_current == 1) + { + SCR_PushLoadingScreen(false, cl.model_name[cl.loadmodel_current], 1.0 / cl.loadmodel_total); + SCR_PopLoadingScreen(false); + } + continue; + } + CL_KeepaliveMessage(true); + + // if running a local game, calling Mod_ForName is a completely wasted effort... + if (sv.active) + cl.model_precache[cl.loadmodel_current] = sv.models[cl.loadmodel_current]; + else + { + if(cl.loadmodel_current == 1) + { + // they'll be soon loaded, but make sure we apply freshly downloaded shaders from a curled pk3 + Mod_FreeQ3Shaders(); + } + cl.model_precache[cl.loadmodel_current] = Mod_ForName(cl.model_name[cl.loadmodel_current], false, false, cl.model_name[cl.loadmodel_current][0] == '*' ? cl.model_name[1] : NULL); + } + SCR_PopLoadingScreen(false); + if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw && cl.loadmodel_current == 1) + { + // we now have the worldmodel so we can set up the game world + SCR_PushLoadingScreen(true, "world model setup", + ( + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + ) / ( + (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + + LOADPROGRESSWEIGHT_WORLDMODEL + + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + ) + ); + CL_SetupWorldModel(); + SCR_PopLoadingScreen(true); + if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer) + { + cl.loadfinished = true; + // now issue the spawn to move on to signon 2 like normal + if (cls.netcon) + Cmd_ForwardStringToServer("prespawn"); + } + } + } + SCR_PopLoadingScreen(false); + // finished loading models + } + + if (cl.loadsound_current < cl.loadsound_total) + { + // loading sounds + if(cl.loadsound_current == 1) + SCR_PushLoadingScreen(false, "Loading precached sounds", + ( + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND + ) / ( + (cl.loadmodel_total - 1) * LOADPROGRESSWEIGHT_MODEL + + LOADPROGRESSWEIGHT_WORLDMODEL + + LOADPROGRESSWEIGHT_WORLDMODEL_INIT + + cl.loadsound_total * LOADPROGRESSWEIGHT_SOUND + ) + ); + for (;cl.loadsound_current < cl.loadsound_total;cl.loadsound_current++) + { + SCR_PushLoadingScreen(false, cl.sound_name[cl.loadsound_current], 1.0 / cl.loadsound_total); + if (cl.sound_precache[cl.loadsound_current] && S_IsSoundPrecached(cl.sound_precache[cl.loadsound_current])) + { + SCR_PopLoadingScreen(false); + continue; + } + CL_KeepaliveMessage(true); + cl.sound_precache[cl.loadsound_current] = S_PrecacheSound(cl.sound_name[cl.loadsound_current], false, true); + SCR_PopLoadingScreen(false); + } + SCR_PopLoadingScreen(false); + // finished loading sounds + } + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + Cvar_SetValueQuick(&cl_serverextension_download, false); + // in Nexuiz/Xonotic, the built in download protocol is kinda broken (misses lots + // of dependencies) anyway, and can mess around with the game directory; + // until this is fixed, only support pk3 downloads via curl, and turn off + // individual file downloads other than for CSQC + // on the other end of the download protocol, GAME_NEXUIZ/GAME_XONOTIC enforces writing + // to dlcache only + // idea: support download of pk3 files using this protocol later + + // note: the reason these loops skip already-loaded things is that it + // enables this command to be issued during the game if desired + + if (cl.downloadmodel_current < cl.loadmodel_total) + { + // loading models + + for (;cl.downloadmodel_current < cl.loadmodel_total;cl.downloadmodel_current++) + { + if (aborteddownload) + { + + if (cl.downloadmodel_current == 1) + { + // the worldmodel failed, but we need to set up anyway + Mod_FreeQ3Shaders(); + CL_SetupWorldModel(); + if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer) + { + cl.loadfinished = true; + // now issue the spawn to move on to signon 2 like normal + if (cls.netcon) + Cmd_ForwardStringToServer("prespawn"); + } + } + aborteddownload = false; + continue; + } + if (cl.model_precache[cl.downloadmodel_current] && cl.model_precache[cl.downloadmodel_current]->Draw) + continue; + CL_KeepaliveMessage(true); + if (cl.model_name[cl.downloadmodel_current][0] != '*' && strcmp(cl.model_name[cl.downloadmodel_current], "null") && !FS_FileExists(cl.model_name[cl.downloadmodel_current])) + { + if (cl.downloadmodel_current == 1) + Con_Printf("Map %s not found\n", cl.model_name[cl.downloadmodel_current]); + else + Con_Printf("Model %s not found\n", cl.model_name[cl.downloadmodel_current]); + // regarding the * check: don't try to download submodels + if (cl_serverextension_download.integer && cls.netcon && cl.model_name[cl.downloadmodel_current][0] != '*' && !sv.active) + { + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", cl.model_name[cl.downloadmodel_current])); + // we'll try loading again when the download finishes + return; + } + } + + if(cl.downloadmodel_current == 1) + { + // they'll be soon loaded, but make sure we apply freshly downloaded shaders from a curled pk3 + Mod_FreeQ3Shaders(); + } + + cl.model_precache[cl.downloadmodel_current] = Mod_ForName(cl.model_name[cl.downloadmodel_current], false, true, cl.model_name[cl.downloadmodel_current][0] == '*' ? cl.model_name[1] : NULL); + if (cl.downloadmodel_current == 1) + { + // we now have the worldmodel so we can set up the game world + // or maybe we do not have it (cl_serverextension_download 0) + // then we need to continue loading ANYWAY! + CL_SetupWorldModel(); + if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer) + { + cl.loadfinished = true; + // now issue the spawn to move on to signon 2 like normal + if (cls.netcon) + Cmd_ForwardStringToServer("prespawn"); + } + } + } + + // finished loading models + } + + if (cl.downloadsound_current < cl.loadsound_total) + { + // loading sounds + + for (;cl.downloadsound_current < cl.loadsound_total;cl.downloadsound_current++) + { + char soundname[MAX_QPATH]; + if (aborteddownload) + { + aborteddownload = false; + continue; + } + if (cl.sound_precache[cl.downloadsound_current] && S_IsSoundPrecached(cl.sound_precache[cl.downloadsound_current])) + continue; + CL_KeepaliveMessage(true); + dpsnprintf(soundname, sizeof(soundname), "sound/%s", cl.sound_name[cl.downloadsound_current]); + if (!FS_FileExists(soundname) && !FS_FileExists(cl.sound_name[cl.downloadsound_current])) + { + Con_Printf("Sound %s not found\n", soundname); + if (cl_serverextension_download.integer && cls.netcon && !sv.active) + { + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "download %s", soundname)); + // we'll try loading again when the download finishes + return; + } + } + cl.sound_precache[cl.downloadsound_current] = S_PrecacheSound(cl.sound_name[cl.downloadsound_current], false, true); + } + + // finished loading sounds + } + + SCR_PopLoadingScreen(false); + + if (!cl.loadfinished) + { + cl.loadfinished = true; + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // now issue the spawn to move on to signon 2 like normal + if (cls.netcon) + Cmd_ForwardStringToServer("prespawn"); + } +} + +static void CL_BeginDownloads_f(void) +{ + // prevent cl_begindownloads from being issued multiple times in one match + // to prevent accidentally cancelled downloads + if(cl.loadbegun) + Con_Printf("cl_begindownloads is only valid once per match\n"); + else + CL_BeginDownloads(false); +} + +static void CL_StopDownload(int size, int crc) +{ + if (cls.qw_downloadmemory && cls.qw_downloadmemorycursize == size && CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize) == crc) + { + int existingcrc; + size_t existingsize; + const char *extension; + + if(cls.qw_download_deflate) + { + unsigned char *out; + size_t inflated_size; + out = FS_Inflate(cls.qw_downloadmemory, cls.qw_downloadmemorycursize, &inflated_size, tempmempool); + Mem_Free(cls.qw_downloadmemory); + if(out) + { + Con_Printf("Inflated download: new size: %u (%g%%)\n", (unsigned)inflated_size, 100.0 - 100.0*(cls.qw_downloadmemorycursize / (float)inflated_size)); + cls.qw_downloadmemory = out; + cls.qw_downloadmemorycursize = inflated_size; + } + else + { + cls.qw_downloadmemory = NULL; + cls.qw_downloadmemorycursize = 0; + Con_Printf("Cannot inflate download, possibly corrupt or zlib not present\n"); + } + } + + if(!cls.qw_downloadmemory) + { + Con_Printf("Download \"%s\" is corrupt (see above!)\n", cls.qw_downloadname); + } + else + { + crc = CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + size = cls.qw_downloadmemorycursize; + // finished file + // save to disk only if we don't already have it + // (this is mainly for playing back demos) + existingcrc = FS_CRCFile(cls.qw_downloadname, &existingsize); + if (existingsize || gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC || !strcmp(cls.qw_downloadname, csqc_progname.string)) + // let csprogs ALWAYS go to dlcache, to prevent "viral csprogs"; also, never put files outside dlcache for Nexuiz/Xonotic + { + if ((int)existingsize != size || existingcrc != crc) + { + // we have a mismatching file, pick another name for it + char name[MAX_QPATH*2]; + dpsnprintf(name, sizeof(name), "dlcache/%s.%i.%i", cls.qw_downloadname, size, crc); + if (!FS_FileExists(name)) + { + Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", name, size, crc); + FS_WriteFile(name, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + if(!strcmp(cls.qw_downloadname, csqc_progname.string)) + { + if(cls.caughtcsprogsdata) + Mem_Free(cls.caughtcsprogsdata); + cls.caughtcsprogsdata = (unsigned char *) Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorycursize); + memcpy(cls.caughtcsprogsdata, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + cls.caughtcsprogsdatasize = cls.qw_downloadmemorycursize; + Con_DPrintf("Buffered \"%s\"\n", name); + } + } + } + } + else + { + // we either don't have it or have a mismatching file... + // so it's time to accept the file + // but if we already have a mismatching file we need to rename + // this new one, and if we already have this file in renamed form, + // we do nothing + Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", cls.qw_downloadname, size, crc); + FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + extension = FS_FileExtension(cls.qw_downloadname); + if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) + FS_Rescan(); + } + } + } + else if (cls.qw_downloadmemory && size) + { + Con_Printf("Download \"%s\" is corrupt (%i bytes, %i CRC, should be %i bytes, %i CRC), discarding\n", cls.qw_downloadname, size, crc, (int)cls.qw_downloadmemorycursize, (int)CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize)); + CL_BeginDownloads(true); + } + + if (cls.qw_downloadmemory) + Mem_Free(cls.qw_downloadmemory); + cls.qw_downloadmemory = NULL; + cls.qw_downloadname[0] = 0; + cls.qw_downloadmemorymaxsize = 0; + cls.qw_downloadmemorycursize = 0; + cls.qw_downloadpercent = 0; +} + +static void CL_ParseDownload(void) +{ + int i, start, size; + static unsigned char data[NET_MAXMESSAGE]; + start = MSG_ReadLong(&cl_message); + size = (unsigned short)MSG_ReadShort(&cl_message); + + // record the start/size information to ack in the next input packet + for (i = 0;i < CL_MAX_DOWNLOADACKS;i++) + { + if (!cls.dp_downloadack[i].start && !cls.dp_downloadack[i].size) + { + cls.dp_downloadack[i].start = start; + cls.dp_downloadack[i].size = size; + break; + } + } + + MSG_ReadBytes(&cl_message, size, data); + + if (!cls.qw_downloadname[0]) + { + if (size > 0) + Con_Printf("CL_ParseDownload: received %i bytes with no download active\n", size); + return; + } + + if (start + size > cls.qw_downloadmemorymaxsize) + Host_Error("corrupt download message\n"); + + // only advance cursize if the data is at the expected position + // (gaps are unacceptable) + memcpy(cls.qw_downloadmemory + start, data, size); + cls.qw_downloadmemorycursize = start + size; + cls.qw_downloadpercent = (int)floor((start+size) * 100.0 / cls.qw_downloadmemorymaxsize); + cls.qw_downloadpercent = bound(0, cls.qw_downloadpercent, 100); + cls.qw_downloadspeedcount += size; +} + +static void CL_DownloadBegin_f(void) +{ + int size = atoi(Cmd_Argv(1)); + + if (size < 0 || size > 1<<30 || FS_CheckNastyPath(Cmd_Argv(2), false)) + { + Con_Printf("cl_downloadbegin: received bogus information\n"); + CL_StopDownload(0, 0); + return; + } + + if (cls.qw_downloadname[0]) + Con_Printf("Download of %s aborted\n", cls.qw_downloadname); + + CL_StopDownload(0, 0); + + // we're really beginning a download now, so initialize stuff + strlcpy(cls.qw_downloadname, Cmd_Argv(2), sizeof(cls.qw_downloadname)); + cls.qw_downloadmemorymaxsize = size; + cls.qw_downloadmemory = (unsigned char *) Mem_Alloc(cls.permanentmempool, cls.qw_downloadmemorymaxsize); + cls.qw_downloadnumber++; + + cls.qw_download_deflate = false; + if(Cmd_Argc() >= 4) + { + if(!strcmp(Cmd_Argv(3), "deflate")) + cls.qw_download_deflate = true; + // check further encodings here + } + + Cmd_ForwardStringToServer("sv_startdownload"); +} + +static void CL_StopDownload_f(void) +{ + Curl_CancelAll(); + if (cls.qw_downloadname[0]) + { + Con_Printf("Download of %s aborted\n", cls.qw_downloadname); + CL_StopDownload(0, 0); + } + CL_BeginDownloads(true); +} + +static void CL_DownloadFinished_f(void) +{ + if (Cmd_Argc() < 3) + { + Con_Printf("Malformed cl_downloadfinished command\n"); + return; + } + CL_StopDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2))); + CL_BeginDownloads(false); +} + +static void CL_SendPlayerInfo(void) +{ + char vabuf[1024]; + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "name \"%s\"", cl_name.string)); + + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "color %i %i", cl_color.integer >> 4, cl_color.integer & 15)); + + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "rate %i", cl_rate.integer)); + + if (cl_pmodel.integer) + { + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "pmodel %i", cl_pmodel.integer)); + } + if (*cl_playermodel.string) + { + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "playermodel %s", cl_playermodel.string)); + } + if (*cl_playerskin.string) + { + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, va(vabuf, sizeof(vabuf), "playerskin %s", cl_playerskin.string)); + } +} + +/* +===================== +CL_SignonReply + +An svc_signonnum has been received, perform a client side setup +===================== +*/ +static void CL_SignonReply (void) +{ + Con_DPrintf("CL_SignonReply: %i\n", cls.signon); + + switch (cls.signon) + { + case 1: + if (cls.netcon) + { + // send player info before we begin downloads + // (so that the server can see the player name while downloading) + CL_SendPlayerInfo(); + + // execute cl_begindownloads next frame + // (after any commands added by svc_stufftext have been executed) + // when done with downloads the "prespawn" will be sent + Cbuf_AddText("\ncl_begindownloads\n"); + + //MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + //MSG_WriteString (&cls.netcon->message, "prespawn"); + } + else // playing a demo... make sure loading occurs as soon as possible + CL_BeginDownloads(false); + break; + + case 2: + if (cls.netcon) + { + // LordHavoc: quake sent the player info here but due to downloads + // it is sent earlier instead + // CL_SendPlayerInfo(); + + // LordHavoc: changed to begin a loading stage and issue this when done + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, "spawn"); + } + break; + + case 3: + if (cls.netcon) + { + MSG_WriteByte (&cls.netcon->message, clc_stringcmd); + MSG_WriteString (&cls.netcon->message, "begin"); + } + break; + + case 4: + // after the level has been loaded, we shouldn't need the shaders, and + // if they are needed again they will be automatically loaded... + // we also don't need the unused models or sounds from the last level + Mod_FreeQ3Shaders(); + Mod_PurgeUnused(); + S_PurgeUnused(); + + Con_ClearNotify(); + if (COM_CheckParm("-profilegameonly")) + Sys_AllowProfiling(true); + break; + } +} + +/* +================== +CL_ParseServerInfo +================== +*/ +static void CL_ParseServerInfo (void) +{ + char *str; + int i; + protocolversion_t protocol; + int nummodels, numsounds; + char vabuf[1024]; + + // if we start loading a level and a video is still playing, stop it + CL_VideoStop(); + + Con_DPrint("Serverinfo packet received.\n"); + Collision_Cache_Reset(true); + + // if server is active, we already began a loading plaque + if (!sv.active) + { + SCR_BeginLoadingPlaque(false); + S_StopAllSounds(); + // free q3 shaders so that any newly downloaded shaders will be active + Mod_FreeQ3Shaders(); + } + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // clear cl_serverextension cvars + Cvar_SetValueQuick(&cl_serverextension_download, 0); + +// +// wipe the client_state_t struct +// + CL_ClearState (); + +// parse protocol version number + i = MSG_ReadLong(&cl_message); + protocol = Protocol_EnumForNumber(i); + if (protocol == PROTOCOL_UNKNOWN) + { + Host_Error("CL_ParseServerInfo: Server is unrecognized protocol number (%i)", i); + return; + } + // hack for unmarked Nehahra movie demos which had a custom protocol + if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA) + protocol = PROTOCOL_NEHAHRAMOVIE; + cls.protocol = protocol; + Con_DPrintf("Server protocol is %s\n", Protocol_NameForEnum(cls.protocol)); + + cl.num_entities = 1; + + if (protocol == PROTOCOL_QUAKEWORLD) + { + char gamedir[1][MAX_QPATH]; + + cl.qw_servercount = MSG_ReadLong(&cl_message); + + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + Con_Printf("server gamedir is %s\n", str); + strlcpy(gamedir[0], str, sizeof(gamedir[0])); + + // change gamedir if needed + if (!FS_ChangeGameDirs(1, gamedir, true, false)) + Host_Error("CL_ParseServerInfo: unable to switch to server specified gamedir"); + + cl.gametype = GAME_DEATHMATCH; + cl.maxclients = 32; + + // parse player number + i = MSG_ReadByte(&cl_message); + // cl.qw_spectator is an unneeded flag, cl.scores[cl.playerentity].qw_spectator works better (it can be updated by the server during the game) + //cl.qw_spectator = (i & 128) != 0; + cl.realplayerentity = cl.playerentity = cl.viewentity = (i & 127) + 1; + cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores)); + + // get the full level name + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); + + // get the movevars that are defined in the qw protocol + cl.movevars_gravity = MSG_ReadFloat(&cl_message); + cl.movevars_stopspeed = MSG_ReadFloat(&cl_message); + cl.movevars_maxspeed = MSG_ReadFloat(&cl_message); + cl.movevars_spectatormaxspeed = MSG_ReadFloat(&cl_message); + cl.movevars_accelerate = MSG_ReadFloat(&cl_message); + cl.movevars_airaccelerate = MSG_ReadFloat(&cl_message); + cl.movevars_wateraccelerate = MSG_ReadFloat(&cl_message); + cl.movevars_friction = MSG_ReadFloat(&cl_message); + cl.movevars_waterfriction = MSG_ReadFloat(&cl_message); + cl.movevars_entgravity = MSG_ReadFloat(&cl_message); + + // other movevars not in the protocol... + cl.movevars_wallfriction = 0; + cl.movevars_timescale = 1; + cl.movevars_jumpvelocity = 270; + cl.movevars_edgefriction = 1; + cl.movevars_maxairspeed = 30; + cl.movevars_stepheight = 18; + cl.movevars_airaccel_qw = 1; + cl.movevars_airaccel_sideways_friction = 0; + + // seperate the printfs so the server message can have a color + Con_Printf("\n\n<===================================>\n\n\2%s\n", str); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + if (cls.netcon) + { + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "soundlist %i %i", cl.qw_servercount, 0)); + } + + cl.loadbegun = false; + cl.loadfinished = false; + + cls.state = ca_connected; + cls.signon = 1; + + // note: on QW protocol we can't set up the gameworld until after + // downloads finish... + // (we don't even know the name of the map yet) + // this also means cl_autodemo does not work on QW protocol... + + strlcpy(cl.worldname, "", sizeof(cl.worldname)); + strlcpy(cl.worldnamenoextension, "", sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, "qw", sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + } + else + { + // parse maxclients + cl.maxclients = MSG_ReadByte(&cl_message); + if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) + { + Host_Error("Bad maxclients (%u) from server", cl.maxclients); + return; + } + cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores)); + + // parse gametype + cl.gametype = MSG_ReadByte(&cl_message); + // the original id singleplayer demos are bugged and contain + // GAME_DEATHMATCH even for singleplayer + if (cl.maxclients == 1 && cls.protocol == PROTOCOL_QUAKE) + cl.gametype = GAME_COOP; + + // parse signon message + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); + + // seperate the printfs so the server message can have a color + if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie + Con_Printf("\n<===================================>\n\n\2%s\n", str); + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // parse model precache list + for (nummodels=1 ; ; nummodels++) + { + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (!str[0]) + break; + if (nummodels==MAX_MODELS) + Host_Error ("Server sent too many model precaches"); + if (strlen(str) >= MAX_QPATH) + Host_Error ("Server sent a precache name of %i characters (max %i)", (int)strlen(str), MAX_QPATH - 1); + strlcpy (cl.model_name[nummodels], str, sizeof (cl.model_name[nummodels])); + } + // parse sound precache list + for (numsounds=1 ; ; numsounds++) + { + str = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (!str[0]) + break; + if (numsounds==MAX_SOUNDS) + Host_Error("Server sent too many sound precaches"); + if (strlen(str) >= MAX_QPATH) + Host_Error("Server sent a precache name of %i characters (max %i)", (int)strlen(str), MAX_QPATH - 1); + strlcpy (cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds])); + } + + // set the base name for level-specific things... this gets updated again by CL_SetupWorldModel later + strlcpy(cl.worldname, cl.model_name[1], sizeof(cl.worldname)); + FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, !strncmp(cl.worldnamenoextension, "maps/", 5) ? cl.worldnamenoextension + 5 : cl.worldnamenoextension, sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + + // touch all of the precached models that are still loaded so we can free + // anything that isn't needed + if (!sv.active) + Mod_ClearUsed(); + for (i = 1;i < nummodels;i++) + Mod_FindName(cl.model_name[i], cl.model_name[i][0] == '*' ? cl.model_name[1] : NULL); + // precache any models used by the client (this also marks them used) + cl.model_bolt = Mod_ForName("progs/bolt.mdl", false, false, NULL); + cl.model_bolt2 = Mod_ForName("progs/bolt2.mdl", false, false, NULL); + cl.model_bolt3 = Mod_ForName("progs/bolt3.mdl", false, false, NULL); + cl.model_beam = Mod_ForName("progs/beam.mdl", false, false, NULL); + + // we purge the models and sounds later in CL_SignonReply + //Mod_PurgeUnused(); + //S_PurgeUnused(); + + // clear sound usage flags for purging of unused sounds + S_ClearUsed(); + + // precache any sounds used by the client + cl.sfx_wizhit = S_PrecacheSound(cl_sound_wizardhit.string, false, true); + cl.sfx_knighthit = S_PrecacheSound(cl_sound_hknighthit.string, false, true); + cl.sfx_tink1 = S_PrecacheSound(cl_sound_tink1.string, false, true); + cl.sfx_ric1 = S_PrecacheSound(cl_sound_ric1.string, false, true); + cl.sfx_ric2 = S_PrecacheSound(cl_sound_ric2.string, false, true); + cl.sfx_ric3 = S_PrecacheSound(cl_sound_ric3.string, false, true); + cl.sfx_r_exp3 = S_PrecacheSound(cl_sound_r_exp3.string, false, true); + + // sounds used by the game + for (i = 1;i < MAX_SOUNDS && cl.sound_name[i][0];i++) + cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i], true, true); + + // now we try to load everything that is new + cl.loadmodel_current = 1; + cl.downloadmodel_current = 1; + cl.loadmodel_total = nummodels; + cl.loadsound_current = 1; + cl.downloadsound_current = 1; + cl.loadsound_total = numsounds; + cl.downloadcsqc = true; + cl.loadbegun = false; + cl.loadfinished = false; + cl.loadcsqc = true; + + // check memory integrity + Mem_CheckSentinelsGlobal(); + + // if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already + if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD) + { + char demofile[MAX_OSPATH]; + + if (cls.demorecording) + { + // finish the previous level's demo file + CL_Stop_f(); + } + + // start a new demo file + dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), cl.worldbasename); + + Con_Printf ("Auto-recording to %s.\n", demofile); + + // Reset bit 0 for every new demo + Cvar_SetValueQuick(&cl_autodemo_delete, + (cl_autodemo_delete.integer & ~0x1) + | + ((cl_autodemo_delete.integer & 0x2) ? 0x1 : 0) + ); + + cls.demofile = FS_OpenRealFile(demofile, "wb", false); + if (cls.demofile) + { + cls.forcetrack = -1; + FS_Printf (cls.demofile, "%i\n", cls.forcetrack); + cls.demorecording = true; + strlcpy(cls.demoname, demofile, sizeof(cls.demoname)); + cls.demo_lastcsprogssize = -1; + cls.demo_lastcsprogscrc = -1; + } + else + Con_Print ("ERROR: couldn't open.\n"); + } + } + cl.islocalgame = NetConn_IsLocalGame(); +} + +void CL_ValidateState(entity_state_t *s) +{ + dp_model_t *model; + + if (!s->active) + return; + + if (s->modelindex >= MAX_MODELS) + Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS); + + // these warnings are only warnings, no corrections are made to the state + // because states are often copied for decoding, which otherwise would + // propogate some of the corrections accidentally + // (this used to happen, sometimes affecting skin and frame) + + // colormap is client index + 1 + if (!(s->flags & RENDER_COLORMAPPED) && s->colormap > cl.maxclients) + Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)\n", s->colormap, cl.maxclients); + + if (developer_extra.integer) + { + model = CL_GetModelByIndex(s->modelindex); + if (model && model->type && s->frame >= model->numframes) + Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\" (which has %i frames)\n", s->frame, model->name, model->numframes); + if (model && model->type && s->skin > 0 && s->skin >= model->numskins && !(s->lightpflags & PFLAGS_FULLDYNAMIC)) + Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\" (which has %i skins)\n", s->skin, model->name, model->numskins); + } +} + +void CL_MoveLerpEntityStates(entity_t *ent) +{ + float odelta[3], adelta[3]; + VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta); + VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta); + if (!ent->state_previous.active || ent->state_previous.modelindex != ent->state_current.modelindex) + { + // reset all persistent stuff if this is a new entity + ent->persistent.lerpdeltatime = 0; + ent->persistent.lerpstarttime = cl.mtime[1]; + VectorCopy(ent->state_current.origin, ent->persistent.oldorigin); + VectorCopy(ent->state_current.angles, ent->persistent.oldangles); + VectorCopy(ent->state_current.origin, ent->persistent.neworigin); + VectorCopy(ent->state_current.angles, ent->persistent.newangles); + // reset animation interpolation as well + ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame; + ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time; + ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0; + ent->render.shadertime = cl.time; + // reset various persistent stuff + ent->persistent.muzzleflash = 0; + ent->persistent.trail_allowed = false; + } + else if ((ent->state_previous.effects & EF_TELEPORT_BIT) != (ent->state_current.effects & EF_TELEPORT_BIT)) + { + // don't interpolate the move + ent->persistent.lerpdeltatime = 0; + ent->persistent.lerpstarttime = cl.mtime[1]; + VectorCopy(ent->state_current.origin, ent->persistent.oldorigin); + VectorCopy(ent->state_current.angles, ent->persistent.oldangles); + VectorCopy(ent->state_current.origin, ent->persistent.neworigin); + VectorCopy(ent->state_current.angles, ent->persistent.newangles); + ent->persistent.trail_allowed = false; + + // if(ent->state_current.frame != ent->state_previous.frame) + // do this even if we did change the frame + // teleport bit is only used if an animation restart, or a jump, is necessary + // so it should be always harmless to do this + { + ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame; + ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time; + ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0; + } + + // note that this case must do everything the following case does too + } + else if ((ent->state_previous.effects & EF_RESTARTANIM_BIT) != (ent->state_current.effects & EF_RESTARTANIM_BIT)) + { + ent->render.framegroupblend[1] = ent->render.framegroupblend[0]; + ent->render.framegroupblend[1].lerp = 1; + ent->render.framegroupblend[0].frame = ent->state_current.frame; + ent->render.framegroupblend[0].start = cl.time; + ent->render.framegroupblend[0].lerp = 0; + } + else if (DotProduct(odelta, odelta) > 1000*1000 + || (cl.fixangle[0] && !cl.fixangle[1]) + || (ent->state_previous.tagindex != ent->state_current.tagindex) + || (ent->state_previous.tagentity != ent->state_current.tagentity)) + { + // don't interpolate the move + // (the fixangle[] check detects teleports, but not constant fixangles + // such as when spectating) + ent->persistent.lerpdeltatime = 0; + ent->persistent.lerpstarttime = cl.mtime[1]; + VectorCopy(ent->state_current.origin, ent->persistent.oldorigin); + VectorCopy(ent->state_current.angles, ent->persistent.oldangles); + VectorCopy(ent->state_current.origin, ent->persistent.neworigin); + VectorCopy(ent->state_current.angles, ent->persistent.newangles); + ent->persistent.trail_allowed = false; + } + else if (ent->state_current.flags & RENDER_STEP) + { + // monster interpolation + if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01) + { + ent->persistent.lerpdeltatime = bound(0, cl.mtime[1] - ent->persistent.lerpstarttime, 0.1); + ent->persistent.lerpstarttime = cl.mtime[1]; + VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin); + VectorCopy(ent->persistent.newangles, ent->persistent.oldangles); + VectorCopy(ent->state_current.origin, ent->persistent.neworigin); + VectorCopy(ent->state_current.angles, ent->persistent.newangles); + } + } + else + { + // not a monster + ent->persistent.lerpstarttime = ent->state_previous.time; + // no lerp if it's singleplayer + if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) + ent->persistent.lerpdeltatime = 0; + else + ent->persistent.lerpdeltatime = bound(0, ent->state_current.time - ent->state_previous.time, 0.1); + VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin); + VectorCopy(ent->persistent.newangles, ent->persistent.oldangles); + VectorCopy(ent->state_current.origin, ent->persistent.neworigin); + VectorCopy(ent->state_current.angles, ent->persistent.newangles); + } + // trigger muzzleflash effect if necessary + if (ent->state_current.effects & EF_MUZZLEFLASH) + ent->persistent.muzzleflash = 1; + + // restart animation bit + if ((ent->state_previous.effects & EF_RESTARTANIM_BIT) != (ent->state_current.effects & EF_RESTARTANIM_BIT)) + { + ent->render.framegroupblend[1] = ent->render.framegroupblend[0]; + ent->render.framegroupblend[1].lerp = 1; + ent->render.framegroupblend[0].frame = ent->state_current.frame; + ent->render.framegroupblend[0].start = cl.time; + ent->render.framegroupblend[0].lerp = 0; + } +} + +/* +================== +CL_ParseBaseline +================== +*/ +static void CL_ParseBaseline (entity_t *ent, int large) +{ + int i; + + ent->state_baseline = defaultstate; + // FIXME: set ent->state_baseline.number? + ent->state_baseline.active = true; + if (large) + { + ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message); + ent->state_baseline.frame = (unsigned short) MSG_ReadShort(&cl_message); + } + else if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3) + { + ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort(&cl_message); + ent->state_baseline.frame = MSG_ReadByte(&cl_message); + } + else + { + ent->state_baseline.modelindex = MSG_ReadByte(&cl_message); + ent->state_baseline.frame = MSG_ReadByte(&cl_message); + } + ent->state_baseline.colormap = MSG_ReadByte(&cl_message); + ent->state_baseline.skin = MSG_ReadByte(&cl_message); + for (i = 0;i < 3;i++) + { + ent->state_baseline.origin[i] = MSG_ReadCoord(&cl_message, cls.protocol); + ent->state_baseline.angles[i] = MSG_ReadAngle(&cl_message, cls.protocol); + } + ent->state_previous = ent->state_current = ent->state_baseline; +} + + +/* +================== +CL_ParseClientdata + +Server information pertaining to this client only +================== +*/ +static void CL_ParseClientdata (void) +{ + int i, bits; + + VectorCopy (cl.mpunchangle[0], cl.mpunchangle[1]); + VectorCopy (cl.mpunchvector[0], cl.mpunchvector[1]); + VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + cl.mviewzoom[1] = cl.mviewzoom[0]; + + if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5) + { + cl.stats[STAT_VIEWHEIGHT] = DEFAULT_VIEWHEIGHT; + cl.stats[STAT_ITEMS] = 0; + cl.stats[STAT_VIEWZOOM] = 255; + } + cl.idealpitch = 0; + cl.mpunchangle[0][0] = 0; + cl.mpunchangle[0][1] = 0; + cl.mpunchangle[0][2] = 0; + cl.mpunchvector[0][0] = 0; + cl.mpunchvector[0][1] = 0; + cl.mpunchvector[0][2] = 0; + cl.mvelocity[0][0] = 0; + cl.mvelocity[0][1] = 0; + cl.mvelocity[0][2] = 0; + cl.mviewzoom[0] = 1; + + bits = (unsigned short) MSG_ReadShort(&cl_message); + if (bits & SU_EXTEND1) + bits |= (MSG_ReadByte(&cl_message) << 16); + if (bits & SU_EXTEND2) + bits |= (MSG_ReadByte(&cl_message) << 24); + + if (bits & SU_VIEWHEIGHT) + cl.stats[STAT_VIEWHEIGHT] = MSG_ReadChar(&cl_message); + + if (bits & SU_IDEALPITCH) + cl.idealpitch = MSG_ReadChar(&cl_message); + + for (i = 0;i < 3;i++) + { + if (bits & (SU_PUNCH1<= cl.max_static_entities) + Host_Error ("Too many static entities"); + ent = &cl.static_entities[cl.num_static_entities++]; + CL_ParseBaseline (ent, large); + + if (ent->state_baseline.modelindex == 0) + { + Con_DPrintf("svc_parsestatic: static entity without model at %f %f %f\n", ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2]); + cl.num_static_entities--; + // This is definitely a cheesy way to conserve resources... + return; + } + +// copy it to the current state + ent->render.model = CL_GetModelByIndex(ent->state_baseline.modelindex); + ent->render.framegroupblend[0].frame = ent->state_baseline.frame; + ent->render.framegroupblend[0].lerp = 1; + // make torchs play out of sync + ent->render.framegroupblend[0].start = lhrandom(-10, -1); + ent->render.skinnum = ent->state_baseline.skin; + ent->render.effects = ent->state_baseline.effects; + ent->render.alpha = 1; + + //VectorCopy (ent->state_baseline.origin, ent->render.origin); + //VectorCopy (ent->state_baseline.angles, ent->render.angles); + + Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1); + ent->render.allowdecals = true; + CL_UpdateRenderEntity(&ent->render); +} + +/* +=================== +CL_ParseStaticSound +=================== +*/ +static void CL_ParseStaticSound (int large) +{ + vec3_t org; + int sound_num, vol, atten; + + MSG_ReadVector(&cl_message, org, cls.protocol); + if (large || cls.protocol == PROTOCOL_NEHAHRABJP2) + sound_num = (unsigned short) MSG_ReadShort(&cl_message); + else + sound_num = MSG_ReadByte(&cl_message); + vol = MSG_ReadByte(&cl_message); + atten = MSG_ReadByte(&cl_message); + + S_StaticSound (cl.sound_precache[sound_num], org, vol/255.0f, atten); +} + +static void CL_ParseEffect (void) +{ + vec3_t org; + int modelindex, startframe, framecount, framerate; + + MSG_ReadVector(&cl_message, org, cls.protocol); + modelindex = MSG_ReadByte(&cl_message); + startframe = MSG_ReadByte(&cl_message); + framecount = MSG_ReadByte(&cl_message); + framerate = MSG_ReadByte(&cl_message); + + CL_Effect(org, modelindex, startframe, framecount, framerate); +} + +static void CL_ParseEffect2 (void) +{ + vec3_t org; + int modelindex, startframe, framecount, framerate; + + MSG_ReadVector(&cl_message, org, cls.protocol); + modelindex = (unsigned short) MSG_ReadShort(&cl_message); + startframe = (unsigned short) MSG_ReadShort(&cl_message); + framecount = MSG_ReadByte(&cl_message); + framerate = MSG_ReadByte(&cl_message); + + CL_Effect(org, modelindex, startframe, framecount, framerate); +} + +void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning) +{ + int i; + beam_t *b = NULL; + + if (ent >= MAX_EDICTS) + { + Con_Printf("CL_NewBeam: invalid entity number %i\n", ent); + ent = 0; + } + + if (ent >= cl.max_entities) + CL_ExpandEntities(ent); + + // override any beam with the same entity + i = cl.max_beams; + if (ent) + for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++) + if (b->entity == ent) + break; + // if the entity was not found then just replace an unused beam + if (i == cl.max_beams) + for (i = 0, b = cl.beams;i < cl.max_beams;i++, b++) + if (!b->model) + break; + if (i < cl.max_beams) + { + cl.num_beams = max(cl.num_beams, i + 1); + b->entity = ent; + b->lightning = lightning; + b->model = m; + b->endtime = cl.mtime[0] + 0.2; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + } + else + Con_Print("beam list overflow!\n"); +} + +static void CL_ParseBeam (dp_model_t *m, int lightning) +{ + int ent; + vec3_t start, end; + + ent = (unsigned short) MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, start, cls.protocol); + MSG_ReadVector(&cl_message, end, cls.protocol); + + if (ent >= MAX_EDICTS) + { + Con_Printf("CL_ParseBeam: invalid entity number %i\n", ent); + ent = 0; + } + + CL_NewBeam(ent, start, end, m, lightning); +} + +static void CL_ParseTempEntity(void) +{ + int type; + vec3_t pos, pos2; + vec3_t vel1, vel2; + vec3_t dir; + vec3_t color; + int rnd; + int colorStart, colorLength, count; + float velspeed, radius; + unsigned char *tempcolor; + matrix4x4_t tempmatrix; + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + type = MSG_ReadByte(&cl_message); + switch (type) + { + case QW_TE_WIZSPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1); + break; + + case QW_TE_KNIGHTSPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1); + break; + + case QW_TE_SPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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 QW_TE_SUPERSPIKE: + // super spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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 QW_TE_EXPLOSION: + // rocket explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + CL_Effect(pos, cl.qw_modelindex_s_explod, 0, 6, 10); + break; + + case QW_TE_TAREXPLOSION: + // tarbaby explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case QW_TE_LIGHTNING1: + // lightning bolts + CL_ParseBeam(cl.model_bolt, true); + break; + + case QW_TE_LIGHTNING2: + // lightning bolts + CL_ParseBeam(cl.model_bolt2, true); + break; + + case QW_TE_LIGHTNING3: + // lightning bolts + CL_ParseBeam(cl.model_bolt3, false); + break; + + case QW_TE_LAVASPLASH: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case QW_TE_TELEPORT: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case QW_TE_GUNSHOT: + // bullet hitting wall + radius = MSG_ReadByte(&cl_message); + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + VectorSet(pos2, pos[0] + radius, pos[1] + radius, pos[2] + radius); + VectorSet(pos, pos[0] - radius, pos[1] - radius, pos[2] - radius); + CL_ParticleEffect(EFFECT_TE_GUNSHOT, radius, pos, pos2, vec3_origin, vec3_origin, NULL, 0); + if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT) + { + 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 QW_TE_BLOOD: + count = MSG_ReadByte(&cl_message); + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case QW_TE_LIGHTNINGBLOOD: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_BLOOD, 2.5, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + default: + Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type); + } + } + else + { + type = MSG_ReadByte(&cl_message); + switch (type) + { + case TE_WIZSPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_wizhit, pos, 1, 1); + break; + + case TE_KNIGHTSPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_knighthit, pos, 1, 1); + break; + + case TE_SPIKE: + // spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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_SPIKEQUAD: + // quad spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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 + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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_SUPERSPIKEQUAD: + // quad super spike hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + 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; + // LordHavoc: added for improved blood splatters + case TE_BLOOD: + // blood puff + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + dir[0] = MSG_ReadChar(&cl_message); + dir[1] = MSG_ReadChar(&cl_message); + dir[2] = MSG_ReadChar(&cl_message); + count = MSG_ReadByte(&cl_message); + CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos, dir, dir, NULL, 0); + break; + case TE_SPARK: + // spark shower + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + dir[0] = MSG_ReadChar(&cl_message); + dir[1] = MSG_ReadChar(&cl_message); + dir[2] = MSG_ReadChar(&cl_message); + count = MSG_ReadByte(&cl_message); + CL_ParticleEffect(EFFECT_TE_SPARK, count, pos, pos, dir, dir, NULL, 0); + break; + case TE_PLASMABURN: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + // LordHavoc: added for improved gore + case TE_BLOODSHOWER: + // vaporized body + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // speed + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + vel1[0] = -velspeed; + vel1[1] = -velspeed; + vel1[2] = -velspeed; + vel2[0] = velspeed; + vel2[1] = velspeed; + vel2[2] = velspeed; + CL_ParticleEffect(EFFECT_TE_BLOOD, count, pos, pos2, vel1, vel2, NULL, 0); + break; + + case TE_PARTICLECUBE: + // general purpose particle effect + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color + colorLength = MSG_ReadByte(&cl_message); // gravity (1 or 0) + velspeed = MSG_ReadCoord(&cl_message, cls.protocol); // randomvel + CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength != 0, velspeed); + break; + + case TE_PARTICLERAIN: + // general purpose particle effect + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color + CL_ParticleRain(pos, pos2, dir, count, colorStart, 0); + break; + + case TE_PARTICLESNOW: + // general purpose particle effect + MSG_ReadVector(&cl_message, pos, cls.protocol); // mins + MSG_ReadVector(&cl_message, pos2, cls.protocol); // maxs + MSG_ReadVector(&cl_message, dir, cls.protocol); // dir + count = (unsigned short) MSG_ReadShort(&cl_message); // number of particles + colorStart = MSG_ReadByte(&cl_message); // color + CL_ParticleRain(pos, pos2, dir, count, colorStart, 1); + break; + + case TE_GUNSHOT: + // bullet hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + if(cl_sound_ric_gunshot.integer & RIC_GUNSHOT) + { + 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_GUNSHOTQUAD: + // quad bullet hitting wall + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + if(cl_sound_ric_gunshot.integer & RIC_GUNSHOTQUAD) + { + 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_EXPLOSION: + // rocket explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_EXPLOSIONQUAD: + // quad rocket explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_EXPLOSION3: + // Nehahra movie colored lighting explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + color[0] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); + color[1] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); + color[2] = MSG_ReadCoord(&cl_message, cls.protocol) * (2.0f / 1.0f); + CL_ParticleExplosion(pos); + Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_EXPLOSIONRGB: + // colored lighting explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleExplosion(pos); + color[0] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[1] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[2] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_TAREXPLOSION: + // tarbaby explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_SMALLFLASH: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case TE_CUSTOMFLASH: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 4); + radius = (MSG_ReadByte(&cl_message) + 1) * 8; + velspeed = (MSG_ReadByte(&cl_message) + 1) * (1.0 / 256.0); + color[0] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[1] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + color[2] = MSG_ReadByte(&cl_message) * (2.0f / 255.0f); + Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); + CL_AllocLightFlash(NULL, &tempmatrix, radius, color[0], color[1], color[2], radius / velspeed, velspeed, 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + break; + + case TE_FLAMEJET: + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); + CL_ParticleEffect(EFFECT_TE_FLAMEJET, count, pos, pos, dir, dir, NULL, 0); + break; + + case TE_LIGHTNING1: + // lightning bolts + CL_ParseBeam(cl.model_bolt, true); + break; + + case TE_LIGHTNING2: + // lightning bolts + CL_ParseBeam(cl.model_bolt2, true); + break; + + case TE_LIGHTNING3: + // lightning bolts + CL_ParseBeam(cl.model_bolt3, false); + break; + + // PGM 01/21/97 + case TE_BEAM: + // grappling hook beam + CL_ParseBeam(cl.model_beam, false); + break; + // PGM 01/21/97 + + // LordHavoc: for compatibility with the Nehahra movie... + case TE_LIGHTNING4NEH: + CL_ParseBeam(Mod_ForName(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), true, false, NULL), false); + break; + + case TE_LAVASPLASH: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case TE_TELEPORT: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case TE_EXPLOSION2: + // color mapped explosion + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + colorStart = MSG_ReadByte(&cl_message); + colorLength = MSG_ReadByte(&cl_message); + CL_ParticleExplosion2(pos, colorStart, colorLength); + tempcolor = palette_rgb[(rand()%colorLength) + colorStart]; + color[0] = tempcolor[0] * (2.0f / 255.0f); + color[1] = tempcolor[1] * (2.0f / 255.0f); + color[2] = tempcolor[2] * (2.0f / 255.0f); + Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_TEI_G3: + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, pos2, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + CL_ParticleEffect(EFFECT_TE_TEI_G3, 1, pos, pos2, dir, dir, NULL, 0); + break; + + case TE_TEI_SMOKE: + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); + CL_FindNonSolidLocation(pos, pos, 4); + CL_ParticleEffect(EFFECT_TE_TEI_SMOKE, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + case TE_TEI_BIGEXPLOSION: + MSG_ReadVector(&cl_message, pos, cls.protocol); + CL_FindNonSolidLocation(pos, pos, 10); + CL_ParticleEffect(EFFECT_TE_TEI_BIGEXPLOSION, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos, 1, 1); + break; + + case TE_TEI_PLASMAHIT: + MSG_ReadVector(&cl_message, pos, cls.protocol); + MSG_ReadVector(&cl_message, dir, cls.protocol); + count = MSG_ReadByte(&cl_message); + CL_FindNonSolidLocation(pos, pos, 5); + CL_ParticleEffect(EFFECT_TE_TEI_PLASMAHIT, count, pos, pos, vec3_origin, vec3_origin, NULL, 0); + break; + + default: + Host_Error("CL_ParseTempEntity: bad type %d (hex %02X)", type, type); + } + } +} + +static void CL_ParseTrailParticles(void) +{ + int entityindex; + int effectindex; + vec3_t start, end; + entityindex = (unsigned short)MSG_ReadShort(&cl_message); + if (entityindex >= MAX_EDICTS) + entityindex = 0; + if (entityindex >= cl.max_entities) + CL_ExpandEntities(entityindex); + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, start, cls.protocol); + MSG_ReadVector(&cl_message, end, cls.protocol); + CL_ParticleEffect(effectindex, 1, start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0); +} + +static void CL_ParsePointParticles(void) +{ + int effectindex, count; + vec3_t origin, velocity; + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, origin, cls.protocol); + MSG_ReadVector(&cl_message, velocity, cls.protocol); + count = (unsigned short)MSG_ReadShort(&cl_message); + CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0); +} + +static void CL_ParsePointParticles1(void) +{ + int effectindex; + vec3_t origin; + effectindex = (unsigned short)MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, origin, cls.protocol); + CL_ParticleEffect(effectindex, 1, origin, origin, vec3_origin, vec3_origin, NULL, 0); +} + +typedef struct cl_iplog_item_s +{ + char *address; + char *name; +} +cl_iplog_item_t; + +static qboolean cl_iplog_loaded = false; +static int cl_iplog_numitems = 0; +static int cl_iplog_maxitems = 0; +static cl_iplog_item_t *cl_iplog_items; + +static void CL_IPLog_Load(void); +static void CL_IPLog_Add(const char *address, const char *name, qboolean checkexisting, qboolean addtofile) +{ + int i; + size_t sz_name, sz_address; + if (!address || !address[0] || !name || !name[0]) + return; + if (!cl_iplog_loaded) + CL_IPLog_Load(); + if (developer_extra.integer) + Con_DPrintf("CL_IPLog_Add(\"%s\", \"%s\", %i, %i);\n", address, name, checkexisting, addtofile); + // see if it already exists + if (checkexisting) + { + for (i = 0;i < cl_iplog_numitems;i++) + { + if (!strcmp(cl_iplog_items[i].address, address) && !strcmp(cl_iplog_items[i].name, name)) + { + if (developer_extra.integer) + Con_DPrintf("... found existing \"%s\" \"%s\"\n", cl_iplog_items[i].address, cl_iplog_items[i].name); + return; + } + } + } + // it does not already exist in the iplog, so add it + if (cl_iplog_maxitems <= cl_iplog_numitems || !cl_iplog_items) + { + cl_iplog_item_t *olditems = cl_iplog_items; + cl_iplog_maxitems = max(1024, cl_iplog_maxitems + 256); + cl_iplog_items = (cl_iplog_item_t *) Mem_Alloc(cls.permanentmempool, cl_iplog_maxitems * sizeof(cl_iplog_item_t)); + if (olditems) + { + if (cl_iplog_numitems) + memcpy(cl_iplog_items, olditems, cl_iplog_numitems * sizeof(cl_iplog_item_t)); + Mem_Free(olditems); + } + } + sz_address = strlen(address) + 1; + sz_name = strlen(name) + 1; + cl_iplog_items[cl_iplog_numitems].address = (char *) Mem_Alloc(cls.permanentmempool, sz_address); + cl_iplog_items[cl_iplog_numitems].name = (char *) Mem_Alloc(cls.permanentmempool, sz_name); + strlcpy(cl_iplog_items[cl_iplog_numitems].address, address, sz_address); + // TODO: maybe it would be better to strip weird characters from name when + // copying it here rather than using a straight strcpy? + strlcpy(cl_iplog_items[cl_iplog_numitems].name, name, sz_name); + cl_iplog_numitems++; + if (addtofile) + { + // add it to the iplog.txt file + // TODO: this ought to open the one in the userpath version of the base + // gamedir, not the current gamedir + Log_Printf(cl_iplog_name.string, "%s %s\n", address, name); + if (developer_extra.integer) + Con_DPrintf("CL_IPLog_Add: appending this line to %s: %s %s\n", cl_iplog_name.string, address, name); + } +} + +static void CL_IPLog_Load(void) +{ + int i, len, linenumber; + char *text, *textend; + unsigned char *filedata; + fs_offset_t filesize; + char line[MAX_INPUTLINE]; + char address[MAX_INPUTLINE]; + cl_iplog_loaded = true; + // TODO: this ought to open the one in the userpath version of the base + // gamedir, not the current gamedir + filedata = FS_LoadFile(cl_iplog_name.string, tempmempool, true, &filesize); + if (!filedata) + return; + text = (char *)filedata; + textend = text + filesize; + for (linenumber = 1;text < textend;linenumber++) + { + for (len = 0;text < textend && *text != '\r' && *text != '\n';text++) + if (len < (int)sizeof(line) - 1) + line[len++] = *text; + line[len] = 0; + if (text < textend && *text == '\r' && text[1] == '\n') + text++; + if (text < textend && *text == '\n') + text++; + if (line[0] == '/' && line[1] == '/') + continue; // skip comments if anyone happens to add them + for (i = 0;i < len && !ISWHITESPACE(line[i]);i++) + address[i] = line[i]; + address[i] = 0; + // skip exactly one space character + i++; + // address contains the address with termination, + // line + i contains the name with termination + if (address[0] && line[i]) + CL_IPLog_Add(address, line + i, false, false); + else + Con_Printf("%s:%i: could not parse address and name:\n%s\n", cl_iplog_name.string, linenumber, line); + } +} + +static void CL_IPLog_List_f(void) +{ + int i, j; + const char *addressprefix; + if (Cmd_Argc() > 2) + { + Con_Printf("usage: %s 123.456.789.\n", Cmd_Argv(0)); + return; + } + addressprefix = ""; + if (Cmd_Argc() >= 2) + addressprefix = Cmd_Argv(1); + if (!cl_iplog_loaded) + CL_IPLog_Load(); + if (addressprefix && addressprefix[0]) + Con_Printf("Listing iplog addresses beginning with %s\n", addressprefix); + else + Con_Printf("Listing all iplog entries\n"); + Con_Printf("address name\n"); + for (i = 0;i < cl_iplog_numitems;i++) + { + if (addressprefix && addressprefix[0]) + { + for (j = 0;addressprefix[j];j++) + if (addressprefix[j] != cl_iplog_items[i].address[j]) + break; + // if this address does not begin with the addressprefix string + // simply omit it from the output + if (addressprefix[j]) + continue; + } + // if name is less than 15 characters, left justify it and pad + // if name is more than 15 characters, print all of it, not worrying + // about the fact it will misalign the columns + if (strlen(cl_iplog_items[i].address) < 15) + Con_Printf("%-15s %s\n", cl_iplog_items[i].address, cl_iplog_items[i].name); + else + Con_Printf("%5s %s\n", cl_iplog_items[i].address, cl_iplog_items[i].name); + } +} + +// look for anything interesting like player IP addresses or ping reports +static qboolean CL_ExaminePrintString(const char *text) +{ + int len; + const char *t; + char temp[MAX_INPUTLINE]; + if (!strcmp(text, "Client ping times:\n")) + { + cl.parsingtextmode = CL_PARSETEXTMODE_PING; + // hide ping reports in demos + if (cls.demoplayback) + cl.parsingtextexpectingpingforscores = 1; + for(cl.parsingtextplayerindex = 0; cl.parsingtextplayerindex < cl.maxclients && !cl.scores[cl.parsingtextplayerindex].name[0]; cl.parsingtextplayerindex++) + ; + if (cl.parsingtextplayerindex >= cl.maxclients) // should never happen, since the client itself should be in cl.scores + { + Con_Printf("ping reply but empty scoreboard?!?\n"); + cl.parsingtextmode = CL_PARSETEXTMODE_NONE; + cl.parsingtextexpectingpingforscores = 0; + } + cl.parsingtextexpectingpingforscores = cl.parsingtextexpectingpingforscores ? 2 : 0; + return !cl.parsingtextexpectingpingforscores; + } + if (!strncmp(text, "host: ", 9)) + { + // cl.parsingtextexpectingpingforscores = false; // really? + cl.parsingtextmode = CL_PARSETEXTMODE_STATUS; + cl.parsingtextplayerindex = 0; + return true; + } + if (cl.parsingtextmode == CL_PARSETEXTMODE_PING) + { + // if anything goes wrong, we'll assume this is not a ping report + qboolean expected = cl.parsingtextexpectingpingforscores != 0; + cl.parsingtextexpectingpingforscores = 0; + cl.parsingtextmode = CL_PARSETEXTMODE_NONE; + t = text; + while (*t == ' ') + t++; + if ((*t >= '0' && *t <= '9') || *t == '-') + { + int ping = atoi(t); + while ((*t >= '0' && *t <= '9') || *t == '-') + t++; + if (*t == ' ') + { + int charindex = 0; + t++; + if(cl.parsingtextplayerindex < cl.maxclients) + { + for (charindex = 0;cl.scores[cl.parsingtextplayerindex].name[charindex] == t[charindex];charindex++) + ; + // note: the matching algorithm stops at the end of the player name because some servers append text such as " READY" after the player name in the scoreboard but not in the ping report + //if (cl.scores[cl.parsingtextplayerindex].name[charindex] == 0 && t[charindex] == '\n') + if (t[charindex] == '\n') + { + cl.scores[cl.parsingtextplayerindex].qw_ping = bound(0, ping, 9999); + for (cl.parsingtextplayerindex++;cl.parsingtextplayerindex < cl.maxclients && !cl.scores[cl.parsingtextplayerindex].name[0];cl.parsingtextplayerindex++) + ; + //if (cl.parsingtextplayerindex < cl.maxclients) // we could still get unconnecteds! + { + // we parsed a valid ping entry, so expect another to follow + cl.parsingtextmode = CL_PARSETEXTMODE_PING; + cl.parsingtextexpectingpingforscores = expected; + } + return !expected; + } + } + if (!strncmp(t, "unconnected\n", 12)) + { + // just ignore + cl.parsingtextmode = CL_PARSETEXTMODE_PING; + cl.parsingtextexpectingpingforscores = expected; + return !expected; + } + else + Con_DPrintf("player names '%s' and '%s' didn't match\n", cl.scores[cl.parsingtextplayerindex].name, t); + } + } + } + if (cl.parsingtextmode == CL_PARSETEXTMODE_STATUS) + { + if (!strncmp(text, "players: ", 9)) + { + cl.parsingtextmode = CL_PARSETEXTMODE_STATUS_PLAYERID; + cl.parsingtextplayerindex = 0; + return true; + } + else if (!strstr(text, ": ")) + { + cl.parsingtextmode = CL_PARSETEXTMODE_NONE; // status report ended + return true; + } + } + if (cl.parsingtextmode == CL_PARSETEXTMODE_STATUS_PLAYERID) + { + // if anything goes wrong, we'll assume this is not a status report + cl.parsingtextmode = CL_PARSETEXTMODE_NONE; + if (text[0] == '#' && text[1] >= '0' && text[1] <= '9') + { + t = text + 1; + cl.parsingtextplayerindex = atoi(t) - 1; + while (*t >= '0' && *t <= '9') + t++; + if (*t == ' ') + { + cl.parsingtextmode = CL_PARSETEXTMODE_STATUS_PLAYERIP; + return true; + } + // the player name follows here, along with frags and time + } + } + if (cl.parsingtextmode == CL_PARSETEXTMODE_STATUS_PLAYERIP) + { + // if anything goes wrong, we'll assume this is not a status report + cl.parsingtextmode = CL_PARSETEXTMODE_NONE; + if (text[0] == ' ') + { + t = text; + while (*t == ' ') + t++; + for (len = 0;*t && *t != '\n';t++) + if (len < (int)sizeof(temp) - 1) + temp[len++] = *t; + temp[len] = 0; + // botclient is perfectly valid, but we don't care about bots + // also don't try to look up the name of an invalid player index + if (strcmp(temp, "botclient") + && cl.parsingtextplayerindex >= 0 + && cl.parsingtextplayerindex < cl.maxclients + && cl.scores[cl.parsingtextplayerindex].name[0]) + { + // log the player name and IP address string + // (this operates entirely on strings to avoid issues with the + // nature of a network address) + CL_IPLog_Add(temp, cl.scores[cl.parsingtextplayerindex].name, true, true); + } + cl.parsingtextmode = CL_PARSETEXTMODE_STATUS_PLAYERID; + return true; + } + } + return true; +} + +extern cvar_t slowmo; +extern cvar_t cl_lerpexcess; +static void CL_NetworkTimeReceived(double newtime) +{ + double timehigh; + cl.mtime[1] = cl.mtime[0]; + cl.mtime[0] = newtime; + if (cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) || cl.mtime[1] == cl.mtime[0] || cls.signon < SIGNONS) + cl.time = cl.mtime[1] = newtime; + else if (cls.demoplayback) + { + // when time falls behind during demo playback it means the cl.mtime[1] was altered + // due to a large time gap, so treat it as an instant change in time + // (this can also happen during heavy packet loss in the demo) + if (cl.time < newtime - 0.1) + cl.mtime[1] = cl.time = newtime; + } + else if (cls.protocol != PROTOCOL_QUAKEWORLD) + { + cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1); + if (developer_extra.integer && vid_activewindow) + { + if (cl.time < cl.mtime[1] - (cl.mtime[0] - cl.mtime[1])) + Con_DPrintf("--- cl.time < cl.mtime[1] (%f < %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]); + else if (cl.time > cl.mtime[0] + (cl.mtime[0] - cl.mtime[1])) + Con_DPrintf("--- cl.time > cl.mtime[0] (%f > %f ... %f)\n", cl.time, cl.mtime[1], cl.mtime[0]); + } + cl.time += (cl.mtime[1] - cl.time) * bound(0, cl_nettimesyncfactor.value, 1); + timehigh = cl.mtime[1] + (cl.mtime[0] - cl.mtime[1]) * cl_nettimesyncboundtolerance.value; + if (cl_nettimesyncboundmode.integer == 1) + cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); + else if (cl_nettimesyncboundmode.integer == 2) + { + if (cl.time < cl.mtime[1] || cl.time > timehigh) + cl.time = cl.mtime[1]; + } + else if (cl_nettimesyncboundmode.integer == 3) + { + if ((cl.time < cl.mtime[1] && cl.oldtime < cl.mtime[1]) || (cl.time > timehigh && cl.oldtime > timehigh)) + cl.time = cl.mtime[1]; + } + else if (cl_nettimesyncboundmode.integer == 4) + { + if (fabs(cl.time - cl.mtime[1]) > 0.5) + cl.time = cl.mtime[1]; // reset + else if (fabs(cl.time - cl.mtime[1]) > 0.1) + cl.time += 0.5 * (cl.mtime[1] - cl.time); // fast + else if (cl.time > cl.mtime[1]) + cl.time -= 0.002 * cl.movevars_timescale; // fall into the past by 2ms + else + cl.time += 0.001 * cl.movevars_timescale; // creep forward 1ms + } + else if (cl_nettimesyncboundmode.integer == 5) + { + if (fabs(cl.time - cl.mtime[1]) > 0.5) + cl.time = cl.mtime[1]; // reset + else if (fabs(cl.time - cl.mtime[1]) > 0.1) + cl.time += 0.5 * (cl.mtime[1] - cl.time); // fast + else + cl.time = bound(cl.time - 0.002 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale); + } + else if (cl_nettimesyncboundmode.integer == 6) + { + cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]); + cl.time = bound(cl.time - 0.002 * cl.movevars_timescale, cl.mtime[1], cl.time + 0.001 * cl.movevars_timescale); + } + } + // this packet probably contains a player entity update, so we will need + // to update the prediction + cl.movement_replay = true; + // this may get updated later in parsing by svc_clientdata + cl.onground = false; + // if true the cl.viewangles are interpolated from cl.mviewangles[] + // during this frame + // (makes spectating players much smoother and prevents mouse movement from turning) + cl.fixangle[1] = cl.fixangle[0]; + cl.fixangle[0] = false; + if (!cls.demoplayback) + VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); + // update the csqc's server timestamps, critical for proper sync + CSQC_UpdateNetworkTimes(cl.mtime[0], cl.mtime[1]); + + if (cl.mtime[0] > cl.mtime[1]) + World_Physics_Frame(&cl.world, cl.mtime[0] - cl.mtime[1], cl.movevars_gravity); + + // only lerp entities that also get an update in this frame, when lerp excess is used + if(cl_lerpexcess.value > 0) + { + int i; + for (i = 1;i < cl.num_entities;i++) + { + if (cl.entities_active[i]) + { + entity_t *ent = cl.entities + i; + ent->persistent.lerpdeltatime = 0; + } + } + } +} + +#define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s(%i)\n", cl_message.readcount-1, x, cmd); + +/* +===================== +CL_ParseServerMessage +===================== +*/ +int parsingerror = false; +void CL_ParseServerMessage(void) +{ + int cmd; + int i; + protocolversion_t protocol; + unsigned char cmdlog[32]; + const char *cmdlogname[32], *temp; + int cmdindex, cmdcount = 0; + qboolean qwplayerupdatereceived; + qboolean strip_pqc; + char vabuf[1024]; + + // LordHavoc: moved demo message writing from before the packet parse to + // after the packet parse so that CL_Stop_f can be called by cl_autodemo + // code in CL_ParseServerinfo + //if (cls.demorecording) + // CL_WriteDemoMessage (&cl_message); + + cl.last_received_message = realtime; + + CL_KeepaliveMessage(false); + +// +// if recording demos, copy the message out +// + if (cl_shownet.integer == 1) + Con_Printf("%f %i\n", realtime, cl_message.cursize); + else if (cl_shownet.integer == 2) + Con_Print("------------------\n"); + +// +// parse the message +// + //MSG_BeginReading (); + + parsingerror = true; + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + CL_NetworkTimeReceived(realtime); // qw has no clock + + // kill all qw nails + cl.qw_num_nails = 0; + + // fade weapon view kick + cl.qw_weaponkick = min(cl.qw_weaponkick + 10 * bound(0, cl.time - cl.oldtime, 0.1), 0); + + cls.servermovesequence = cls.netcon->qw.incoming_sequence; + + qwplayerupdatereceived = false; + + while (1) + { + if (cl_message.badread) + Host_Error ("CL_ParseServerMessage: Bad QW server message"); + + cmd = MSG_ReadByte(&cl_message); + + if (cmd == -1) + { + SHOWNET("END OF MESSAGE"); + break; // end of message + } + + cmdindex = cmdcount & 31; + cmdcount++; + cmdlog[cmdindex] = cmd; + + SHOWNET(qw_svc_strings[cmd]); + cmdlogname[cmdindex] = qw_svc_strings[cmd]; + if (!cmdlogname[cmdindex]) + { + // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + temp = ""; + cmdlogname[cmdindex] = temp; + } + + // other commands + switch (cmd) + { + default: + { + char description[32*64], temp[64]; + int count; + strlcpy(description, "packet dump: ", sizeof(description)); + i = cmdcount - 32; + if (i < 0) + i = 0; + count = cmdcount - i; + i &= 31; + while(count > 0) + { + dpsnprintf(temp, sizeof(temp), "%3i:%s ", cmdlog[i], cmdlogname[i]); + strlcat(description, temp, sizeof(description)); + count--; + i++; + i &= 31; + } + description[strlen(description)-1] = '\n'; // replace the last space with a newline + Con_Print(description); + Host_Error("CL_ParseServerMessage: Illegible server message"); + } + break; + + case qw_svc_nop: + //Con_Printf("qw_svc_nop\n"); + break; + + case qw_svc_disconnect: + Con_Printf("Server disconnected\n"); + if (cls.demonum != -1) + CL_NextDemo(); + else + CL_Disconnect(); + return; + + case qw_svc_print: + i = MSG_ReadByte(&cl_message); + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports + { + if (i == 3) // chat + CSQC_AddPrintText(va(vabuf, sizeof(vabuf), "\1%s", temp)); //[515]: csqc + else + CSQC_AddPrintText(temp); + } + break; + + case qw_svc_centerprint: + CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc + break; + + case qw_svc_stufftext: + CL_VM_Parse_StuffCmd(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc + break; + + case qw_svc_damage: + // svc_damage protocol is identical to nq + V_ParseDamage (); + break; + + case qw_svc_serverdata: + //Cbuf_Execute(); // make sure any stuffed commands are done + CL_ParseServerInfo(); + break; + + case qw_svc_setangle: + for (i=0 ; i<3 ; i++) + cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol); + if (!cls.demoplayback) + { + cl.fixangle[0] = true; + VectorCopy(cl.viewangles, cl.mviewangles[0]); + // disable interpolation if this is new + if (!cl.fixangle[1]) + VectorCopy(cl.viewangles, cl.mviewangles[1]); + } + break; + + case qw_svc_lightstyle: + i = MSG_ReadByte(&cl_message); + if (i >= cl.max_lightstyle) + { + Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES"); + break; + } + strlcpy (cl.lightstyle[i].map, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map)); + cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0; + cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map); + break; + + case qw_svc_sound: + CL_ParseStartSoundPacket(false); + break; + + case qw_svc_stopsound: + i = (unsigned short) MSG_ReadShort(&cl_message); + S_StopSound(i>>3, i&7); + break; + + case qw_svc_updatefrags: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients"); + cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message); + break; + + case qw_svc_updateping: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error("CL_ParseServerMessage: svc_updateping >= cl.maxclients"); + cl.scores[i].qw_ping = MSG_ReadShort(&cl_message); + break; + + case qw_svc_updatepl: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error("CL_ParseServerMessage: svc_updatepl >= cl.maxclients"); + cl.scores[i].qw_packetloss = MSG_ReadByte(&cl_message); + break; + + case qw_svc_updateentertime: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error("CL_ParseServerMessage: svc_updateentertime >= cl.maxclients"); + // seconds ago + cl.scores[i].qw_entertime = cl.time - MSG_ReadFloat(&cl_message); + break; + + case qw_svc_spawnbaseline: + i = (unsigned short) MSG_ReadShort(&cl_message); + if (i < 0 || i >= MAX_EDICTS) + Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); + if (i >= cl.max_entities) + CL_ExpandEntities(i); + CL_ParseBaseline(cl.entities + i, false); + break; + case qw_svc_spawnstatic: + CL_ParseStatic(false); + break; + case qw_svc_temp_entity: + if(!CL_VM_Parse_TempEntity()) + CL_ParseTempEntity (); + break; + + case qw_svc_killedmonster: + cl.stats[STAT_MONSTERS]++; + break; + + case qw_svc_foundsecret: + cl.stats[STAT_SECRETS]++; + break; + + case qw_svc_updatestat: + i = MSG_ReadByte(&cl_message); + if (i < 0 || i >= MAX_CL_STATS) + Host_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadByte(&cl_message); + break; + + case qw_svc_updatestatlong: + i = MSG_ReadByte(&cl_message); + if (i < 0 || i >= MAX_CL_STATS) + Host_Error ("svc_updatestatlong: %i is invalid", i); + cl.stats[i] = MSG_ReadLong(&cl_message); + break; + + case qw_svc_spawnstaticsound: + CL_ParseStaticSound (false); + break; + + case qw_svc_cdtrack: + cl.cdtrack = cl.looptrack = MSG_ReadByte(&cl_message); + if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) + CDAudio_Play ((unsigned char)cls.forcetrack, true); + else + CDAudio_Play ((unsigned char)cl.cdtrack, true); + break; + + case qw_svc_intermission: + if(!cl.intermission) + cl.completed_time = cl.time; + cl.intermission = 1; + MSG_ReadVector(&cl_message, cl.qw_intermission_origin, cls.protocol); + for (i = 0;i < 3;i++) + cl.qw_intermission_angles[i] = MSG_ReadAngle(&cl_message, cls.protocol); + break; + + case qw_svc_finale: + if(!cl.intermission) + cl.completed_time = cl.time; + cl.intermission = 2; + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + + case qw_svc_sellscreen: + Cmd_ExecuteString ("help", src_command, true); + break; + + case qw_svc_smallkick: + cl.qw_weaponkick = -2; + break; + case qw_svc_bigkick: + cl.qw_weaponkick = -4; + break; + + case qw_svc_muzzleflash: + i = (unsigned short) MSG_ReadShort(&cl_message); + // NOTE: in QW this only worked on clients + if (i < 0 || i >= MAX_EDICTS) + Host_Error("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); + if (i >= cl.max_entities) + CL_ExpandEntities(i); + cl.entities[i].persistent.muzzleflash = 1.0f; + break; + + case qw_svc_updateuserinfo: + QW_CL_UpdateUserInfo(); + break; + + case qw_svc_setinfo: + QW_CL_SetInfo(); + break; + + case qw_svc_serverinfo: + QW_CL_ServerInfo(); + break; + + case qw_svc_download: + QW_CL_ParseDownload(); + break; + + case qw_svc_playerinfo: + // slightly kill qw player entities now that we know there is + // an update of player entities this frame... + if (!qwplayerupdatereceived) + { + qwplayerupdatereceived = true; + for (i = 1;i < cl.maxclients;i++) + cl.entities_active[i] = false; + } + EntityStateQW_ReadPlayerUpdate(); + break; + + case qw_svc_nails: + QW_CL_ParseNails(); + break; + + case qw_svc_chokecount: + (void) MSG_ReadByte(&cl_message); + // FIXME: apply to netgraph + //for (j = 0;j < i;j++) + // cl.frames[(cls.netcon->qw.incoming_acknowledged-1-j)&QW_UPDATE_MASK].receivedtime = -2; + break; + + case qw_svc_modellist: + QW_CL_ParseModelList(); + break; + + case qw_svc_soundlist: + QW_CL_ParseSoundList(); + break; + + case qw_svc_packetentities: + EntityFrameQW_CL_ReadFrame(false); + // first update is the final signon stage + if (cls.signon == SIGNONS - 1) + { + cls.signon = SIGNONS; + CL_SignonReply (); + } + break; + + case qw_svc_deltapacketentities: + EntityFrameQW_CL_ReadFrame(true); + // first update is the final signon stage + if (cls.signon == SIGNONS - 1) + { + cls.signon = SIGNONS; + CL_SignonReply (); + } + break; + + case qw_svc_maxspeed: + cl.movevars_maxspeed = MSG_ReadFloat(&cl_message); + break; + + case qw_svc_entgravity: + cl.movevars_entgravity = MSG_ReadFloat(&cl_message); + if (!cl.movevars_entgravity) + cl.movevars_entgravity = 1.0f; + break; + + case qw_svc_setpause: + cl.paused = MSG_ReadByte(&cl_message) != 0; + if (cl.paused) + CDAudio_Pause (); + else + CDAudio_Resume (); + S_PauseGameSounds (cl.paused); + break; + } + } + + if (qwplayerupdatereceived) + { + // fully kill any player entities that were not updated this frame + for (i = 1;i <= cl.maxclients;i++) + if (!cl.entities_active[i]) + cl.entities[i].state_current.active = false; + } + } + else + { + while (1) + { + if (cl_message.badread) + Host_Error ("CL_ParseServerMessage: Bad server message"); + + cmd = MSG_ReadByte(&cl_message); + + if (cmd == -1) + { +// R_TimeReport("END OF MESSAGE"); + SHOWNET("END OF MESSAGE"); + break; // end of message + } + + cmdindex = cmdcount & 31; + cmdcount++; + cmdlog[cmdindex] = cmd; + + // if the high bit of the command byte is set, it is a fast update + if (cmd & 128) + { + // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + temp = "entity"; + cmdlogname[cmdindex] = temp; + SHOWNET("fast update"); + if (cls.signon == SIGNONS - 1) + { + // first update is the final signon stage + cls.signon = SIGNONS; + CL_SignonReply (); + } + EntityFrameQuake_ReadEntity (cmd&127); + continue; + } + + SHOWNET(svc_strings[cmd]); + cmdlogname[cmdindex] = svc_strings[cmd]; + if (!cmdlogname[cmdindex]) + { + // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) + temp = ""; + cmdlogname[cmdindex] = temp; + } + + // other commands + switch (cmd) + { + default: + { + char description[32*64], temp[64]; + int count; + strlcpy (description, "packet dump: ", sizeof(description)); + i = cmdcount - 32; + if (i < 0) + i = 0; + count = cmdcount - i; + i &= 31; + while(count > 0) + { + dpsnprintf (temp, sizeof (temp), "%3i:%s ", cmdlog[i], cmdlogname[i]); + strlcat (description, temp, sizeof (description)); + count--; + i++; + i &= 31; + } + description[strlen(description)-1] = '\n'; // replace the last space with a newline + Con_Print(description); + Host_Error ("CL_ParseServerMessage: Illegible server message"); + } + break; + + case svc_nop: + if (cls.signon < SIGNONS) + Con_Print("<-- server to client keepalive\n"); + break; + + case svc_time: + CL_NetworkTimeReceived(MSG_ReadFloat(&cl_message)); + break; + + case svc_clientdata: + CL_ParseClientdata(); + break; + + case svc_version: + i = MSG_ReadLong(&cl_message); + protocol = Protocol_EnumForNumber(i); + if (protocol == PROTOCOL_UNKNOWN) + Host_Error("CL_ParseServerMessage: Server is unrecognized protocol number (%i)", i); + // hack for unmarked Nehahra movie demos which had a custom protocol + if (protocol == PROTOCOL_QUAKEDP && cls.demoplayback && gamemode == GAME_NEHAHRA) + protocol = PROTOCOL_NEHAHRAMOVIE; + cls.protocol = protocol; + break; + + case svc_disconnect: + Con_Printf ("Server disconnected\n"); + if (cls.demonum != -1) + CL_NextDemo (); + else + CL_Disconnect (); + break; + + case svc_print: + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (CL_ExaminePrintString(temp)) // look for anything interesting like player IP addresses or ping reports + CSQC_AddPrintText(temp); //[515]: csqc + break; + + case svc_centerprint: + CL_VM_Parse_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); //[515]: csqc + break; + + case svc_stufftext: + temp = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + /* if(utf8_enable.integer) + { + strip_pqc = true; + // we can safely strip and even + // interpret these in utf8 mode + } + else */ switch(cls.protocol) + { + case PROTOCOL_QUAKE: + case PROTOCOL_QUAKEDP: + // maybe add other protocols if + // so desired, but not DP7 + strip_pqc = true; + break; + case PROTOCOL_DARKPLACES7: + default: + // ProQuake does not support + // these protocols + strip_pqc = false; + break; + } + if(strip_pqc) + { + // skip over ProQuake messages, + // TODO actually interpret them + // (they are sbar team score + // updates), see proquake cl_parse.c + if(*temp == 0x01) + { + ++temp; + while(*temp >= 0x01 && *temp <= 0x1F) + ++temp; + } + } + CL_VM_Parse_StuffCmd(temp); //[515]: csqc + break; + + case svc_damage: + V_ParseDamage (); + break; + + case svc_serverinfo: + CL_ParseServerInfo (); + break; + + case svc_setangle: + for (i=0 ; i<3 ; i++) + cl.viewangles[i] = MSG_ReadAngle(&cl_message, cls.protocol); + if (!cls.demoplayback) + { + cl.fixangle[0] = true; + VectorCopy(cl.viewangles, cl.mviewangles[0]); + // disable interpolation if this is new + if (!cl.fixangle[1]) + VectorCopy(cl.viewangles, cl.mviewangles[1]); + } + break; + + case svc_setview: + cl.viewentity = (unsigned short)MSG_ReadShort(&cl_message); + if (cl.viewentity >= MAX_EDICTS) + Host_Error("svc_setview >= MAX_EDICTS"); + if (cl.viewentity >= cl.max_entities) + CL_ExpandEntities(cl.viewentity); + // LordHavoc: assume first setview recieved is the real player entity + if (!cl.realplayerentity) + cl.realplayerentity = cl.viewentity; + // update cl.playerentity to this one if it is a valid player + if (cl.viewentity >= 1 && cl.viewentity <= cl.maxclients) + cl.playerentity = cl.viewentity; + break; + + case svc_lightstyle: + i = MSG_ReadByte(&cl_message); + if (i >= cl.max_lightstyle) + { + Con_Printf ("svc_lightstyle >= MAX_LIGHTSTYLES"); + break; + } + strlcpy (cl.lightstyle[i].map, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.lightstyle[i].map)); + cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0; + cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map); + break; + + case svc_sound: + CL_ParseStartSoundPacket(false); + break; + + case svc_precache: + if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3) + { + // was svc_sound2 in protocols 1, 2, 3, removed in 4, 5, changed to svc_precache in 6 + CL_ParseStartSoundPacket(true); + } + else + { + int i = (unsigned short)MSG_ReadShort(&cl_message); + char *s = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + if (i < 32768) + { + if (i >= 1 && i < MAX_MODELS) + { + dp_model_t *model = Mod_ForName(s, false, false, s[0] == '*' ? cl.model_name[1] : NULL); + if (!model) + Con_DPrintf("svc_precache: Mod_ForName(\"%s\") failed\n", s); + cl.model_precache[i] = model; + } + else + Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_MODELS); + } + else + { + i -= 32768; + if (i >= 1 && i < MAX_SOUNDS) + { + sfx_t *sfx = S_PrecacheSound (s, true, true); + if (!sfx && snd_initialized.integer) + Con_DPrintf("svc_precache: S_PrecacheSound(\"%s\") failed\n", s); + cl.sound_precache[i] = sfx; + } + else + Con_Printf("svc_precache: index %i outside range %i...%i\n", i, 1, MAX_SOUNDS); + } + } + break; + + case svc_stopsound: + i = (unsigned short) MSG_ReadShort(&cl_message); + S_StopSound(i>>3, i&7); + break; + + case svc_updatename: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients"); + strlcpy (cl.scores[i].name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (cl.scores[i].name)); + break; + + case svc_updatefrags: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients"); + cl.scores[i].frags = (signed short) MSG_ReadShort(&cl_message); + break; + + case svc_updatecolors: + i = MSG_ReadByte(&cl_message); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients"); + cl.scores[i].colors = MSG_ReadByte(&cl_message); + break; + + case svc_particle: + CL_ParseParticleEffect (); + break; + + case svc_effect: + CL_ParseEffect (); + break; + + case svc_effect2: + CL_ParseEffect2 (); + break; + + case svc_spawnbaseline: + i = (unsigned short) MSG_ReadShort(&cl_message); + if (i < 0 || i >= MAX_EDICTS) + Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i); + if (i >= cl.max_entities) + CL_ExpandEntities(i); + CL_ParseBaseline (cl.entities + i, false); + break; + case svc_spawnbaseline2: + i = (unsigned short) MSG_ReadShort(&cl_message); + if (i < 0 || i >= MAX_EDICTS) + Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i); + if (i >= cl.max_entities) + CL_ExpandEntities(i); + CL_ParseBaseline (cl.entities + i, true); + break; + case svc_spawnstatic: + CL_ParseStatic (false); + break; + case svc_spawnstatic2: + CL_ParseStatic (true); + break; + case svc_temp_entity: + if(!CL_VM_Parse_TempEntity()) + CL_ParseTempEntity (); + break; + + case svc_setpause: + cl.paused = MSG_ReadByte(&cl_message) != 0; + if (cl.paused) + CDAudio_Pause (); + else + CDAudio_Resume (); + S_PauseGameSounds (cl.paused); + break; + + case svc_signonnum: + i = MSG_ReadByte(&cl_message); + // LordHavoc: it's rude to kick off the client if they missed the + // reconnect somehow, so allow signon 1 even if at signon 1 + if (i <= cls.signon && i != 1) + 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(&cl_message); + if (i < 0 || i >= MAX_CL_STATS) + Host_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadLong(&cl_message); + break; + + case svc_updatestatubyte: + i = MSG_ReadByte(&cl_message); + if (i < 0 || i >= MAX_CL_STATS) + Host_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadByte(&cl_message); + break; + + case svc_spawnstaticsound: + CL_ParseStaticSound (false); + break; + + case svc_spawnstaticsound2: + CL_ParseStaticSound (true); + break; + + case svc_cdtrack: + cl.cdtrack = MSG_ReadByte(&cl_message); + cl.looptrack = MSG_ReadByte(&cl_message); + if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) + CDAudio_Play ((unsigned char)cls.forcetrack, true); + else + CDAudio_Play ((unsigned char)cl.cdtrack, true); + break; + + case svc_intermission: + if(!cl.intermission) + cl.completed_time = cl.time; + cl.intermission = 1; + CL_VM_UpdateIntermissionState(cl.intermission); + break; + + case svc_finale: + if(!cl.intermission) + cl.completed_time = cl.time; + cl.intermission = 2; + CL_VM_UpdateIntermissionState(cl.intermission); + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + + case svc_cutscene: + if(!cl.intermission) + cl.completed_time = cl.time; + cl.intermission = 3; + CL_VM_UpdateIntermissionState(cl.intermission); + SCR_CenterPrint(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + + case svc_sellscreen: + Cmd_ExecuteString ("help", src_command, true); + break; + case svc_hidelmp: + if (gamemode == GAME_TENEBRAE) + { + // repeating particle effect + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + (void) MSG_ReadByte(&cl_message); + MSG_ReadLong(&cl_message); + MSG_ReadLong(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + } + else + SHOWLMP_decodehide(); + break; + case svc_showlmp: + if (gamemode == GAME_TENEBRAE) + { + // particle effect + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + MSG_ReadCoord(&cl_message, cls.protocol); + (void) MSG_ReadByte(&cl_message); + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + } + else + SHOWLMP_decodeshow(); + break; + case svc_skybox: + R_SetSkyBox(MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + case svc_entities: + if (cls.signon == SIGNONS - 1) + { + // first update is the final signon stage + cls.signon = SIGNONS; + CL_SignonReply (); + } + if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3) + EntityFrame_CL_ReadFrame(); + else if (cls.protocol == PROTOCOL_DARKPLACES4) + EntityFrame4_CL_ReadFrame(); + else + EntityFrame5_CL_ReadFrame(); + break; + case svc_csqcentities: + CSQC_ReadEntities(); + break; + case svc_downloaddata: + CL_ParseDownload(); + break; + case svc_trailparticles: + CL_ParseTrailParticles(); + break; + case svc_pointparticles: + CL_ParsePointParticles(); + break; + case svc_pointparticles1: + CL_ParsePointParticles1(); + break; + } +// R_TimeReport(svc_strings[cmd]); + } + } + + if (cls.signon == SIGNONS) + CL_UpdateItemsAndWeapon(); +// R_TimeReport("UpdateItems"); + + EntityFrameQuake_ISeeDeadEntities(); +// R_TimeReport("ISeeDeadEntities"); + + CL_UpdateMoveVars(); +// R_TimeReport("UpdateMoveVars"); + + parsingerror = false; + + // LordHavoc: this was at the start of the function before cl_autodemo was + // implemented + if (cls.demorecording) + { + CL_WriteDemoMessage (&cl_message); +// R_TimeReport("WriteDemo"); + } +} + +void CL_Parse_DumpPacket(void) +{ + if (!parsingerror) + return; + Con_Print("Packet dump:\n"); + SZ_HexDumpToConsole(&cl_message); + parsingerror = false; +} + +void CL_Parse_ErrorCleanUp(void) +{ + CL_StopDownload(0, 0); + QW_CL_StopUpload(); +} + +void CL_Parse_Init(void) +{ + Cvar_RegisterVariable(&cl_worldmessage); + Cvar_RegisterVariable(&cl_worldname); + Cvar_RegisterVariable(&cl_worldnamenoextension); + Cvar_RegisterVariable(&cl_worldbasename); + + Cvar_RegisterVariable(&developer_networkentities); + Cvar_RegisterVariable(&cl_gameplayfix_soundsmovewithentities); + + Cvar_RegisterVariable(&cl_sound_wizardhit); + Cvar_RegisterVariable(&cl_sound_hknighthit); + Cvar_RegisterVariable(&cl_sound_tink1); + Cvar_RegisterVariable(&cl_sound_ric1); + Cvar_RegisterVariable(&cl_sound_ric2); + Cvar_RegisterVariable(&cl_sound_ric3); + Cvar_RegisterVariable(&cl_sound_ric_gunshot); + Cvar_RegisterVariable(&cl_sound_r_exp3); + + Cvar_RegisterVariable(&cl_joinbeforedownloadsfinish); + + // server extension cvars set by commands issued from the server during connect + Cvar_RegisterVariable(&cl_serverextension_download); + + Cvar_RegisterVariable(&cl_nettimesyncfactor); + Cvar_RegisterVariable(&cl_nettimesyncboundmode); + Cvar_RegisterVariable(&cl_nettimesyncboundtolerance); + Cvar_RegisterVariable(&cl_iplog_name); + Cvar_RegisterVariable(&cl_readpicture_force); + + Cmd_AddCommand("nextul", QW_CL_NextUpload, "sends next fragment of current upload buffer (screenshot for example)"); + Cmd_AddCommand("stopul", QW_CL_StopUpload, "aborts current upload (screenshot for example)"); + Cmd_AddCommand("skins", QW_CL_Skins_f, "downloads missing qw skins from server"); + Cmd_AddCommand("changing", QW_CL_Changing_f, "sent by qw servers to tell client to wait for level change"); + Cmd_AddCommand("cl_begindownloads", CL_BeginDownloads_f, "used internally by qvr client while connecting (causes loading of models and sounds or triggers downloads for missing ones)"); + Cmd_AddCommand("cl_downloadbegin", CL_DownloadBegin_f, "(networking) informs client of download file information, client replies with sv_startsoundload to begin the transfer"); + Cmd_AddCommand("stopdownload", CL_StopDownload_f, "terminates a download"); + Cmd_AddCommand("cl_downloadfinished", CL_DownloadFinished_f, "signals that a download has finished and provides the client with file size and crc to check its integrity"); + Cmd_AddCommand("iplog_list", CL_IPLog_List_f, "lists names of players whose IP address begins with the supplied text (example: iplog_list 123.456.789)"); +} + +void CL_Parse_Shutdown(void) +{ +} diff --git a/app/jni/cl_particles.c b/app/jni/cl_particles.c new file mode 100644 index 0000000..1a7e446 --- /dev/null +++ b/app/jni/cl_particles.c @@ -0,0 +1,3101 @@ +/* +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 "cl_collision.h" +#include "image.h" +#include "r_shadow.h" + +// must match ptype_t values +particletype_t particletype[pt_total] = +{ + {PBLEND_INVALID, PARTICLE_INVALID, false}, //pt_dead (should never happen) + {PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_alphastatic + {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_static + {PBLEND_ADD, PARTICLE_SPARK, false}, //pt_spark + {PBLEND_ADD, PARTICLE_HBEAM, false}, //pt_beam + {PBLEND_ADD, PARTICLE_SPARK, false}, //pt_rain + {PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, false}, //pt_raindecal + {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_snow + {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_bubble + {PBLEND_INVMOD, PARTICLE_BILLBOARD, false}, //pt_blood + {PBLEND_ADD, PARTICLE_BILLBOARD, false}, //pt_smoke + {PBLEND_INVMOD, PARTICLE_ORIENTED_DOUBLESIDED, false}, //pt_decal + {PBLEND_ALPHA, PARTICLE_BILLBOARD, false}, //pt_entityparticle +}; + +#define PARTICLEEFFECT_UNDERWATER 1 +#define PARTICLEEFFECT_NOTUNDERWATER 2 + +typedef struct particleeffectinfo_s +{ + int effectnameindex; // which effect this belongs to + // PARTICLEEFFECT_* bits + int flags; + // blood effects may spawn very few particles, so proper fraction-overflow + // handling is very important, this variable keeps track of the fraction + double particleaccumulator; + // the math is: countabsolute + requestedcount * countmultiplier * quality + // absolute number of particles to spawn, often used for decals + // (unaffected by quality and requestedcount) + float countabsolute; + // multiplier for the number of particles CL_ParticleEffect was told to + // spawn, most effects do not really have a count and hence use 1, so + // this is often the actual count to spawn, not merely a multiplier + float countmultiplier; + // if > 0 this causes the particle to spawn in an evenly spaced line from + // originmins to originmaxs (causing them to describe a trail, not a box) + float trailspacing; + // type of particle to spawn (defines some aspects of behavior) + ptype_t particletype; + // blending mode used on this particle type + pblend_t blendmode; + // orientation of this particle type (BILLBOARD, SPARK, BEAM, etc) + porientation_t orientation; + // range of colors to choose from in hex RRGGBB (like HTML color tags), + // randomly interpolated at spawn + unsigned int color[2]; + // a random texture is chosen in this range (note the second value is one + // past the last choosable, so for example 8,16 chooses any from 8 up and + // including 15) + // if start and end of the range are the same, no randomization is done + int tex[2]; + // range of size values randomly chosen when spawning, plus size increase over time + float size[3]; + // range of alpha values randomly chosen when spawning, plus alpha fade + float alpha[3]; + // how long the particle should live (note it is also removed if alpha drops to 0) + float time[2]; + // how much gravity affects this particle (negative makes it fly up!) + float gravity; + // how much bounce the particle has when it hits a surface + // if negative the particle is removed on impact + float bounce; + // if in air this friction is applied + // if negative the particle accelerates + float airfriction; + // if in liquid (water/slime/lava) this friction is applied + // if negative the particle accelerates + float liquidfriction; + // these offsets are added to the values given to particleeffect(), and + // then an ellipsoid-shaped jitter is added as defined by these + // (they are the 3 radii) + float stretchfactor; + // stretch velocity factor (used for sparks) + float originoffset[3]; + float relativeoriginoffset[3]; + float velocityoffset[3]; + float relativevelocityoffset[3]; + float originjitter[3]; + float velocityjitter[3]; + float velocitymultiplier; + // an effect can also spawn a dlight + float lightradiusstart; + float lightradiusfade; + float lighttime; + float lightcolor[3]; + qboolean lightshadow; + int lightcubemapnum; + float lightcorona[2]; + unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! + int staintex[2]; + float stainalpha[2]; + float stainsize[2]; + // other parameters + float rotate[4]; // min/max base angle, min/max rotation over time +} +particleeffectinfo_t; + +char particleeffectname[MAX_PARTICLEEFFECTNAME][64]; + +int numparticleeffectinfo; +particleeffectinfo_t particleeffectinfo[MAX_PARTICLEEFFECTINFO]; + +static int particlepalette[256]; +/* + 0x000000,0x0f0f0f,0x1f1f1f,0x2f2f2f,0x3f3f3f,0x4b4b4b,0x5b5b5b,0x6b6b6b, // 0-7 + 0x7b7b7b,0x8b8b8b,0x9b9b9b,0xababab,0xbbbbbb,0xcbcbcb,0xdbdbdb,0xebebeb, // 8-15 + 0x0f0b07,0x170f0b,0x1f170b,0x271b0f,0x2f2313,0x372b17,0x3f2f17,0x4b371b, // 16-23 + 0x533b1b,0x5b431f,0x634b1f,0x6b531f,0x73571f,0x7b5f23,0x836723,0x8f6f23, // 24-31 + 0x0b0b0f,0x13131b,0x1b1b27,0x272733,0x2f2f3f,0x37374b,0x3f3f57,0x474767, // 32-39 + 0x4f4f73,0x5b5b7f,0x63638b,0x6b6b97,0x7373a3,0x7b7baf,0x8383bb,0x8b8bcb, // 40-47 + 0x000000,0x070700,0x0b0b00,0x131300,0x1b1b00,0x232300,0x2b2b07,0x2f2f07, // 48-55 + 0x373707,0x3f3f07,0x474707,0x4b4b0b,0x53530b,0x5b5b0b,0x63630b,0x6b6b0f, // 56-63 + 0x070000,0x0f0000,0x170000,0x1f0000,0x270000,0x2f0000,0x370000,0x3f0000, // 64-71 + 0x470000,0x4f0000,0x570000,0x5f0000,0x670000,0x6f0000,0x770000,0x7f0000, // 72-79 + 0x131300,0x1b1b00,0x232300,0x2f2b00,0x372f00,0x433700,0x4b3b07,0x574307, // 80-87 + 0x5f4707,0x6b4b0b,0x77530f,0x835713,0x8b5b13,0x975f1b,0xa3631f,0xaf6723, // 88-95 + 0x231307,0x2f170b,0x3b1f0f,0x4b2313,0x572b17,0x632f1f,0x733723,0x7f3b2b, // 96-103 + 0x8f4333,0x9f4f33,0xaf632f,0xbf772f,0xcf8f2b,0xdfab27,0xefcb1f,0xfff31b, // 104-111 + 0x0b0700,0x1b1300,0x2b230f,0x372b13,0x47331b,0x533723,0x633f2b,0x6f4733, // 112-119 + 0x7f533f,0x8b5f47,0x9b6b53,0xa77b5f,0xb7876b,0xc3937b,0xd3a38b,0xe3b397, // 120-127 + 0xab8ba3,0x9f7f97,0x937387,0x8b677b,0x7f5b6f,0x775363,0x6b4b57,0x5f3f4b, // 128-135 + 0x573743,0x4b2f37,0x43272f,0x371f23,0x2b171b,0x231313,0x170b0b,0x0f0707, // 136-143 + 0xbb739f,0xaf6b8f,0xa35f83,0x975777,0x8b4f6b,0x7f4b5f,0x734353,0x6b3b4b, // 144-151 + 0x5f333f,0x532b37,0x47232b,0x3b1f23,0x2f171b,0x231313,0x170b0b,0x0f0707, // 152-159 + 0xdbc3bb,0xcbb3a7,0xbfa39b,0xaf978b,0xa3877b,0x977b6f,0x876f5f,0x7b6353, // 160-167 + 0x6b5747,0x5f4b3b,0x533f33,0x433327,0x372b1f,0x271f17,0x1b130f,0x0f0b07, // 168-175 + 0x6f837b,0x677b6f,0x5f7367,0x576b5f,0x4f6357,0x475b4f,0x3f5347,0x374b3f, // 176-183 + 0x2f4337,0x2b3b2f,0x233327,0x1f2b1f,0x172317,0x0f1b13,0x0b130b,0x070b07, // 184-191 + 0xfff31b,0xefdf17,0xdbcb13,0xcbb70f,0xbba70f,0xab970b,0x9b8307,0x8b7307, // 192-199 + 0x7b6307,0x6b5300,0x5b4700,0x4b3700,0x3b2b00,0x2b1f00,0x1b0f00,0x0b0700, // 200-207 + 0x0000ff,0x0b0bef,0x1313df,0x1b1bcf,0x2323bf,0x2b2baf,0x2f2f9f,0x2f2f8f, // 208-215 + 0x2f2f7f,0x2f2f6f,0x2f2f5f,0x2b2b4f,0x23233f,0x1b1b2f,0x13131f,0x0b0b0f, // 216-223 + 0x2b0000,0x3b0000,0x4b0700,0x5f0700,0x6f0f00,0x7f1707,0x931f07,0xa3270b, // 224-231 + 0xb7330f,0xc34b1b,0xcf632b,0xdb7f3b,0xe3974f,0xe7ab5f,0xefbf77,0xf7d38b, // 232-239 + 0xa77b3b,0xb79b37,0xc7c337,0xe7e357,0x7fbfff,0xabe7ff,0xd7ffff,0x670000, // 240-247 + 0x8b0000,0xb30000,0xd70000,0xff0000,0xfff393,0xfff7c7,0xffffff,0x9f5b53 // 248-255 +*/ + +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}; + +//static int explosparkramp[8] = {0x4b0700, 0x6f0f00, 0x931f07, 0xb7330f, 0xcf632b, 0xe3974f, 0xffe7b5, 0xffffff}; + +// particletexture_t is a rectangle in the particlefonttexture +typedef struct particletexture_s +{ + rtexture_t *texture; + float s1, t1, s2, t2; +} +particletexture_t; + +static rtexturepool_t *particletexturepool; +static rtexture_t *particlefonttexture; +static particletexture_t particletexture[MAX_PARTICLETEXTURES]; +skinframe_t *decalskinframe; + +// texture numbers in particle font +static const int tex_smoke[8] = {0, 1, 2, 3, 4, 5, 6, 7}; +static const int tex_bulletdecal[8] = {8, 9, 10, 11, 12, 13, 14, 15}; +static const int tex_blooddecal[8] = {16, 17, 18, 19, 20, 21, 22, 23}; +static const int tex_bloodparticle[8] = {24, 25, 26, 27, 28, 29, 30, 31}; +static const int tex_rainsplash = 32; +static const int tex_particle = 63; +static const int tex_bubble = 62; +static const int tex_raindrop = 61; +static const int tex_beam = 60; + +particleeffectinfo_t baselineparticleeffectinfo = +{ + 0, //int effectnameindex; // which effect this belongs to + // PARTICLEEFFECT_* bits + 0, //int flags; + // blood effects may spawn very few particles, so proper fraction-overflow + // handling is very important, this variable keeps track of the fraction + 0.0, //double particleaccumulator; + // the math is: countabsolute + requestedcount * countmultiplier * quality + // absolute number of particles to spawn, often used for decals + // (unaffected by quality and requestedcount) + 0.0f, //float countabsolute; + // multiplier for the number of particles CL_ParticleEffect was told to + // spawn, most effects do not really have a count and hence use 1, so + // this is often the actual count to spawn, not merely a multiplier + 0.0f, //float countmultiplier; + // if > 0 this causes the particle to spawn in an evenly spaced line from + // originmins to originmaxs (causing them to describe a trail, not a box) + 0.0f, //float trailspacing; + // type of particle to spawn (defines some aspects of behavior) + pt_alphastatic, //ptype_t particletype; + // blending mode used on this particle type + PBLEND_ALPHA, //pblend_t blendmode; + // orientation of this particle type (BILLBOARD, SPARK, BEAM, etc) + PARTICLE_BILLBOARD, //porientation_t orientation; + // range of colors to choose from in hex RRGGBB (like HTML color tags), + // randomly interpolated at spawn + {0xFFFFFF, 0xFFFFFF}, //unsigned int color[2]; + // a random texture is chosen in this range (note the second value is one + // past the last choosable, so for example 8,16 chooses any from 8 up and + // including 15) + // if start and end of the range are the same, no randomization is done + {63, 63 /* tex_particle */}, //int tex[2]; + // range of size values randomly chosen when spawning, plus size increase over time + {1, 1, 0.0f}, //float size[3]; + // range of alpha values randomly chosen when spawning, plus alpha fade + {0.0f, 256.0f, 256.0f}, //float alpha[3]; + // how long the particle should live (note it is also removed if alpha drops to 0) + {16777216.0f, 16777216.0f}, //float time[2]; + // how much gravity affects this particle (negative makes it fly up!) + 0.0f, //float gravity; + // how much bounce the particle has when it hits a surface + // if negative the particle is removed on impact + 0.0f, //float bounce; + // if in air this friction is applied + // if negative the particle accelerates + 0.0f, //float airfriction; + // if in liquid (water/slime/lava) this friction is applied + // if negative the particle accelerates + 0.0f, //float liquidfriction; + // these offsets are added to the values given to particleeffect(), and + // then an ellipsoid-shaped jitter is added as defined by these + // (they are the 3 radii) + 1.0f, //float stretchfactor; + // stretch velocity factor (used for sparks) + {0.0f, 0.0f, 0.0f}, //float originoffset[3]; + {0.0f, 0.0f, 0.0f}, //float relativeoriginoffset[3]; + {0.0f, 0.0f, 0.0f}, //float velocityoffset[3]; + {0.0f, 0.0f, 0.0f}, //float relativevelocityoffset[3]; + {0.0f, 0.0f, 0.0f}, //float originjitter[3]; + {0.0f, 0.0f, 0.0f}, //float velocityjitter[3]; + 0.0f, //float velocitymultiplier; + // an effect can also spawn a dlight + 0.0f, //float lightradiusstart; + 0.0f, //float lightradiusfade; + 16777216.0f, //float lighttime; + {1.0f, 1.0f, 1.0f}, //float lightcolor[3]; + true, //qboolean lightshadow; + 0, //int lightcubemapnum; + {1.0f, 0.25f}, //float lightcorona[2]; + {(unsigned int)-1, (unsigned int)-1}, //unsigned int staincolor[2]; // note: 0x808080 = neutral (particle's own color), these are modding factors for the particle's original color! + {-1, -1}, //int staintex[2]; + {1.0f, 1.0f}, //float stainalpha[2]; + {2.0f, 2.0f}, //float stainsize[2]; + // other parameters + {0.0f, 360.0f, 0.0f, 0.0f}, //float rotate[4]; // min/max base angle, min/max rotation over time +}; + +cvar_t cl_particles = {CVAR_SAVE, "cl_particles", "1", "enables particle effects"}; +cvar_t cl_particles_quality = {CVAR_SAVE, "cl_particles_quality", "1", "multiplies number of particles"}; +cvar_t cl_particles_alpha = {CVAR_SAVE, "cl_particles_alpha", "1", "multiplies opacity of particles"}; +cvar_t cl_particles_size = {CVAR_SAVE, "cl_particles_size", "1", "multiplies particle size"}; +cvar_t cl_particles_quake = {CVAR_SAVE, "cl_particles_quake", "0", "makes particle effects look mostly like the ones in Quake"}; +cvar_t cl_particles_blood = {CVAR_SAVE, "cl_particles_blood", "1", "enables blood effects"}; +cvar_t cl_particles_blood_alpha = {CVAR_SAVE, "cl_particles_blood_alpha", "1", "opacity of blood, does not affect decals"}; +cvar_t cl_particles_blood_decal_alpha = {CVAR_SAVE, "cl_particles_blood_decal_alpha", "1", "opacity of blood decal"}; +cvar_t cl_particles_blood_decal_scalemin = {CVAR_SAVE, "cl_particles_blood_decal_scalemin", "1.5", "minimal random scale of decal"}; +cvar_t cl_particles_blood_decal_scalemax = {CVAR_SAVE, "cl_particles_blood_decal_scalemax", "2", "maximal random scale of decal"}; +cvar_t cl_particles_blood_bloodhack = {CVAR_SAVE, "cl_particles_blood_bloodhack", "1", "make certain quake particle() calls create blood effects instead"}; +cvar_t cl_particles_bulletimpacts = {CVAR_SAVE, "cl_particles_bulletimpacts", "1", "enables bulletimpact effects"}; +cvar_t cl_particles_explosions_sparks = {CVAR_SAVE, "cl_particles_explosions_sparks", "1", "enables sparks from explosions"}; +cvar_t cl_particles_explosions_shell = {CVAR_SAVE, "cl_particles_explosions_shell", "0", "enables polygonal shell from explosions"}; +cvar_t cl_particles_rain = {CVAR_SAVE, "cl_particles_rain", "1", "enables rain effects"}; +cvar_t cl_particles_snow = {CVAR_SAVE, "cl_particles_snow", "1", "enables snow effects"}; +cvar_t cl_particles_smoke = {CVAR_SAVE, "cl_particles_smoke", "1", "enables smoke (used by multiple effects)"}; +cvar_t cl_particles_smoke_alpha = {CVAR_SAVE, "cl_particles_smoke_alpha", "0.5", "smoke brightness"}; +cvar_t cl_particles_smoke_alphafade = {CVAR_SAVE, "cl_particles_smoke_alphafade", "0.55", "brightness fade per second"}; +cvar_t cl_particles_sparks = {CVAR_SAVE, "cl_particles_sparks", "1", "enables sparks (used by multiple effects)"}; +cvar_t cl_particles_bubbles = {CVAR_SAVE, "cl_particles_bubbles", "1", "enables bubbles (used by multiple effects)"}; +cvar_t cl_particles_visculling = {CVAR_SAVE, "cl_particles_visculling", "0", "perform a costly check if each particle is visible before drawing"}; +cvar_t cl_particles_collisions = {CVAR_SAVE, "cl_particles_collisions", "1", "allow costly collision detection on particles (sparks that bounce, particles not going through walls, blood hitting surfaces, etc)"}; +cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "0", "enables decals (bullet holes, blood, etc)"}; +cvar_t cl_decals_visculling = {CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"}; +cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"}; +cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"}; +cvar_t cl_decals_newsystem = {CVAR_SAVE, "cl_decals_newsystem", "1", "enables new advanced decal system"}; +cvar_t cl_decals_newsystem_intensitymultiplier = {CVAR_SAVE, "cl_decals_newsystem_intensitymultiplier", "2", "boosts intensity of decals (because the distance fade can make them hard to see otherwise)"}; +cvar_t cl_decals_newsystem_immediatebloodstain = {CVAR_SAVE, "cl_decals_newsystem_immediatebloodstain", "2", "0: no on-spawn blood stains; 1: on-spawn blood stains for pt_blood; 2: always use on-spawn blood stains"}; +cvar_t cl_decals_newsystem_bloodsmears = {CVAR_SAVE, "cl_decals_newsystem_bloodsmears", "1", "enable use of particle velocity as decal projection direction rather than surface normal"}; +cvar_t cl_decals_models = {CVAR_SAVE, "cl_decals_models", "0", "enables decals on animated models (if newsystem is also 1)"}; +cvar_t cl_decals_bias = {CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"}; +cvar_t cl_decals_max = {CVAR_SAVE, "cl_decals_max", "4096", "maximum number of decals allowed to exist in the world at once"}; + + +static void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend, const char *filename) +{ + int arrayindex; + int argc; + int linenumber; + particleeffectinfo_t *info = NULL; + const char *text = textstart; + char argv[16][1024]; + for (linenumber = 1;;linenumber++) + { + argc = 0; + for (arrayindex = 0;arrayindex < 16;arrayindex++) + argv[arrayindex][0] = 0; + for (;;) + { + if (!COM_ParseToken_Simple(&text, true, false, true)) + return; + if (!strcmp(com_token, "\n")) + break; + if (argc < 16) + { + strlcpy(argv[argc], com_token, sizeof(argv[argc])); + argc++; + } + } + if (argc < 1) + continue; +#define checkparms(n) if (argc != (n)) {Con_Printf("%s:%i: error while parsing: %s given %i parameters, should be %i parameters\n", filename, linenumber, argv[0], argc, (n));break;} +#define readints(array, n) checkparms(n+1);for (arrayindex = 0;arrayindex < argc - 1;arrayindex++) array[arrayindex] = strtol(argv[1+arrayindex], NULL, 0) +#define readfloats(array, n) checkparms(n+1);for (arrayindex = 0;arrayindex < argc - 1;arrayindex++) array[arrayindex] = atof(argv[1+arrayindex]) +#define readint(var) checkparms(2);var = strtol(argv[1], NULL, 0) +#define readfloat(var) checkparms(2);var = atof(argv[1]) +#define readbool(var) checkparms(2);var = strtol(argv[1], NULL, 0) != 0 + if (!strcmp(argv[0], "effect")) + { + int effectnameindex; + checkparms(2); + if (numparticleeffectinfo >= MAX_PARTICLEEFFECTINFO) + { + Con_Printf("%s:%i: too many effects!\n", filename, linenumber); + break; + } + for (effectnameindex = 1;effectnameindex < MAX_PARTICLEEFFECTNAME;effectnameindex++) + { + if (particleeffectname[effectnameindex][0]) + { + if (!strcmp(particleeffectname[effectnameindex], argv[1])) + break; + } + else + { + strlcpy(particleeffectname[effectnameindex], argv[1], sizeof(particleeffectname[effectnameindex])); + break; + } + } + // if we run out of names, abort + if (effectnameindex == MAX_PARTICLEEFFECTNAME) + { + Con_Printf("%s:%i: too many effects!\n", filename, linenumber); + break; + } + info = particleeffectinfo + numparticleeffectinfo++; + // copy entire info from baseline, then fix up the nameindex + *info = baselineparticleeffectinfo; + info->effectnameindex = effectnameindex; + } + else if (info == NULL) + { + Con_Printf("%s:%i: command %s encountered before effect\n", filename, linenumber, argv[0]); + break; + } + else if (!strcmp(argv[0], "countabsolute")) {readfloat(info->countabsolute);} + else if (!strcmp(argv[0], "count")) {readfloat(info->countmultiplier);} + else if (!strcmp(argv[0], "type")) + { + checkparms(2); + if (!strcmp(argv[1], "alphastatic")) info->particletype = pt_alphastatic; + else if (!strcmp(argv[1], "static")) info->particletype = pt_static; + else if (!strcmp(argv[1], "spark")) info->particletype = pt_spark; + else if (!strcmp(argv[1], "beam")) info->particletype = pt_beam; + else if (!strcmp(argv[1], "rain")) info->particletype = pt_rain; + else if (!strcmp(argv[1], "raindecal")) info->particletype = pt_raindecal; + else if (!strcmp(argv[1], "snow")) info->particletype = pt_snow; + else if (!strcmp(argv[1], "bubble")) info->particletype = pt_bubble; + else if (!strcmp(argv[1], "blood")) {info->particletype = pt_blood;info->gravity = 1;} + else if (!strcmp(argv[1], "smoke")) info->particletype = pt_smoke; + else if (!strcmp(argv[1], "decal")) info->particletype = pt_decal; + else if (!strcmp(argv[1], "entityparticle")) info->particletype = pt_entityparticle; + else Con_Printf("%s:%i: unrecognized particle type %s\n", filename, linenumber, argv[1]); + info->blendmode = particletype[info->particletype].blendmode; + info->orientation = particletype[info->particletype].orientation; + } + else if (!strcmp(argv[0], "blend")) + { + checkparms(2); + if (!strcmp(argv[1], "alpha")) info->blendmode = PBLEND_ALPHA; + else if (!strcmp(argv[1], "add")) info->blendmode = PBLEND_ADD; + else if (!strcmp(argv[1], "invmod")) info->blendmode = PBLEND_INVMOD; + else Con_Printf("%s:%i: unrecognized blendmode %s\n", filename, linenumber, argv[1]); + } + else if (!strcmp(argv[0], "orientation")) + { + checkparms(2); + if (!strcmp(argv[1], "billboard")) info->orientation = PARTICLE_BILLBOARD; + else if (!strcmp(argv[1], "spark")) info->orientation = PARTICLE_SPARK; + else if (!strcmp(argv[1], "oriented")) info->orientation = PARTICLE_ORIENTED_DOUBLESIDED; + else if (!strcmp(argv[1], "beam")) info->orientation = PARTICLE_HBEAM; + else Con_Printf("%s:%i: unrecognized orientation %s\n", filename, linenumber, argv[1]); + } + else if (!strcmp(argv[0], "color")) {readints(info->color, 2);} + else if (!strcmp(argv[0], "tex")) {readints(info->tex, 2);} + else if (!strcmp(argv[0], "size")) {readfloats(info->size, 2);} + else if (!strcmp(argv[0], "sizeincrease")) {readfloat(info->size[2]);} + else if (!strcmp(argv[0], "alpha")) {readfloats(info->alpha, 3);} + else if (!strcmp(argv[0], "time")) {readfloats(info->time, 2);} + else if (!strcmp(argv[0], "gravity")) {readfloat(info->gravity);} + else if (!strcmp(argv[0], "bounce")) {readfloat(info->bounce);} + else if (!strcmp(argv[0], "airfriction")) {readfloat(info->airfriction);} + else if (!strcmp(argv[0], "liquidfriction")) {readfloat(info->liquidfriction);} + else if (!strcmp(argv[0], "originoffset")) {readfloats(info->originoffset, 3);} + else if (!strcmp(argv[0], "relativeoriginoffset")) {readfloats(info->relativeoriginoffset, 3);} + else if (!strcmp(argv[0], "velocityoffset")) {readfloats(info->velocityoffset, 3);} + else if (!strcmp(argv[0], "relativevelocityoffset")) {readfloats(info->relativevelocityoffset, 3);} + else if (!strcmp(argv[0], "originjitter")) {readfloats(info->originjitter, 3);} + else if (!strcmp(argv[0], "velocityjitter")) {readfloats(info->velocityjitter, 3);} + else if (!strcmp(argv[0], "velocitymultiplier")) {readfloat(info->velocitymultiplier);} + else if (!strcmp(argv[0], "lightradius")) {readfloat(info->lightradiusstart);} + else if (!strcmp(argv[0], "lightradiusfade")) {readfloat(info->lightradiusfade);} + else if (!strcmp(argv[0], "lighttime")) {readfloat(info->lighttime);} + else if (!strcmp(argv[0], "lightcolor")) {readfloats(info->lightcolor, 3);} + else if (!strcmp(argv[0], "lightshadow")) {readbool(info->lightshadow);} + else if (!strcmp(argv[0], "lightcubemapnum")) {readint(info->lightcubemapnum);} + else if (!strcmp(argv[0], "lightcorona")) {readints(info->lightcorona, 2);} + else if (!strcmp(argv[0], "underwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_UNDERWATER;} + else if (!strcmp(argv[0], "notunderwater")) {checkparms(1);info->flags |= PARTICLEEFFECT_NOTUNDERWATER;} + else if (!strcmp(argv[0], "trailspacing")) {readfloat(info->trailspacing);if (info->trailspacing > 0) info->countmultiplier = 1.0f / info->trailspacing;} + else if (!strcmp(argv[0], "stretchfactor")) {readfloat(info->stretchfactor);} + else if (!strcmp(argv[0], "staincolor")) {readints(info->staincolor, 2);} + else if (!strcmp(argv[0], "stainalpha")) {readfloats(info->stainalpha, 2);} + else if (!strcmp(argv[0], "stainsize")) {readfloats(info->stainsize, 2);} + else if (!strcmp(argv[0], "staintex")) {readints(info->staintex, 2);} + else if (!strcmp(argv[0], "stainless")) {info->staintex[0] = -2; info->staincolor[0] = (unsigned int)-1; info->staincolor[1] = (unsigned int)-1; info->stainalpha[0] = 1; info->stainalpha[1] = 1; info->stainsize[0] = 2; info->stainsize[1] = 2; } + else if (!strcmp(argv[0], "rotate")) {readfloats(info->rotate, 4);} + else + Con_Printf("%s:%i: skipping unknown command %s\n", filename, linenumber, argv[0]); +#undef checkparms +#undef readints +#undef readfloats +#undef readint +#undef readfloat + } +} + +int CL_ParticleEffectIndexForName(const char *name) +{ + int i; + for (i = 1;i < MAX_PARTICLEEFFECTNAME && particleeffectname[i][0];i++) + if (!strcmp(particleeffectname[i], name)) + return i; + return 0; +} + +const char *CL_ParticleEffectNameForIndex(int i) +{ + if (i < 1 || i >= MAX_PARTICLEEFFECTNAME) + return NULL; + return particleeffectname[i]; +} + +// MUST match effectnameindex_t in client.h +static const char *standardeffectnames[EFFECT_TOTAL] = +{ + "", + "TE_GUNSHOT", + "TE_GUNSHOTQUAD", + "TE_SPIKE", + "TE_SPIKEQUAD", + "TE_SUPERSPIKE", + "TE_SUPERSPIKEQUAD", + "TE_WIZSPIKE", + "TE_KNIGHTSPIKE", + "TE_EXPLOSION", + "TE_EXPLOSIONQUAD", + "TE_TAREXPLOSION", + "TE_TELEPORT", + "TE_LAVASPLASH", + "TE_SMALLFLASH", + "TE_FLAMEJET", + "EF_FLAME", + "TE_BLOOD", + "TE_SPARK", + "TE_PLASMABURN", + "TE_TEI_G3", + "TE_TEI_SMOKE", + "TE_TEI_BIGEXPLOSION", + "TE_TEI_PLASMAHIT", + "EF_STARDUST", + "TR_ROCKET", + "TR_GRENADE", + "TR_BLOOD", + "TR_WIZSPIKE", + "TR_SLIGHTBLOOD", + "TR_KNIGHTSPIKE", + "TR_VORESPIKE", + "TR_NEHAHRASMOKE", + "TR_NEXUIZPLASMA", + "TR_GLOWTRAIL", + "SVC_PARTICLE" +}; + +static void CL_Particles_LoadEffectInfo(const char *customfile) +{ + int i; + int filepass; + unsigned char *filedata; + fs_offset_t filesize; + char filename[MAX_QPATH]; + numparticleeffectinfo = 0; + memset(particleeffectinfo, 0, sizeof(particleeffectinfo)); + memset(particleeffectname, 0, sizeof(particleeffectname)); + for (i = 0;i < EFFECT_TOTAL;i++) + strlcpy(particleeffectname[i], standardeffectnames[i], sizeof(particleeffectname[i])); + for (filepass = 0;;filepass++) + { + if (filepass == 0) + { + if (customfile) + strlcpy(filename, customfile, sizeof(filename)); + else + strlcpy(filename, "effectinfo.txt", sizeof(filename)); + } + else if (filepass == 1) + { + if (!cl.worldbasename[0] || customfile) + continue; + dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", cl.worldnamenoextension); + } + else + break; + filedata = FS_LoadFile(filename, tempmempool, true, &filesize); + if (!filedata) + continue; + CL_Particles_ParseEffectInfo((const char *)filedata, (const char *)filedata + filesize, filename); + Mem_Free(filedata); + } +} + +static void CL_Particles_LoadEffectInfo_f(void) +{ + CL_Particles_LoadEffectInfo(Cmd_Argc() > 1 ? Cmd_Argv(1) : NULL); +} + +/* +=============== +CL_InitParticles +=============== +*/ +void CL_ReadPointFile_f (void); +void CL_Particles_Init (void) +{ + Cmd_AddCommand ("pointfile", CL_ReadPointFile_f, "display point file produced by qbsp when a leak was detected in the map (a line leading through the leak hole, to an entity inside the level)"); + Cmd_AddCommand ("cl_particles_reloadeffects", CL_Particles_LoadEffectInfo_f, "reloads effectinfo.txt and maps/levelname_effectinfo.txt (where levelname is the current map) if parameter is given, loads from custom file (no levelname_effectinfo are loaded in this case)"); + + Cvar_RegisterVariable (&cl_particles); + Cvar_RegisterVariable (&cl_particles_quality); + Cvar_RegisterVariable (&cl_particles_alpha); + Cvar_RegisterVariable (&cl_particles_size); + Cvar_RegisterVariable (&cl_particles_quake); + Cvar_RegisterVariable (&cl_particles_blood); + Cvar_RegisterVariable (&cl_particles_blood_alpha); + Cvar_RegisterVariable (&cl_particles_blood_decal_alpha); + Cvar_RegisterVariable (&cl_particles_blood_decal_scalemin); + Cvar_RegisterVariable (&cl_particles_blood_decal_scalemax); + Cvar_RegisterVariable (&cl_particles_blood_bloodhack); + Cvar_RegisterVariable (&cl_particles_explosions_sparks); + Cvar_RegisterVariable (&cl_particles_explosions_shell); + Cvar_RegisterVariable (&cl_particles_bulletimpacts); + Cvar_RegisterVariable (&cl_particles_rain); + Cvar_RegisterVariable (&cl_particles_snow); + Cvar_RegisterVariable (&cl_particles_smoke); + Cvar_RegisterVariable (&cl_particles_smoke_alpha); + Cvar_RegisterVariable (&cl_particles_smoke_alphafade); + Cvar_RegisterVariable (&cl_particles_sparks); + Cvar_RegisterVariable (&cl_particles_bubbles); + Cvar_RegisterVariable (&cl_particles_visculling); + Cvar_RegisterVariable (&cl_particles_collisions); + Cvar_RegisterVariable (&cl_decals); + Cvar_RegisterVariable (&cl_decals_visculling); + Cvar_RegisterVariable (&cl_decals_time); + Cvar_RegisterVariable (&cl_decals_fadetime); + Cvar_RegisterVariable (&cl_decals_newsystem); + Cvar_RegisterVariable (&cl_decals_newsystem_intensitymultiplier); + Cvar_RegisterVariable (&cl_decals_newsystem_immediatebloodstain); + Cvar_RegisterVariable (&cl_decals_newsystem_bloodsmears); + Cvar_RegisterVariable (&cl_decals_models); + Cvar_RegisterVariable (&cl_decals_bias); + Cvar_RegisterVariable (&cl_decals_max); +} + +void CL_Particles_Shutdown (void) +{ +} + +void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha); +void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2); + +// list of all 26 parameters: +// ptype - any of the pt_ enum values (pt_static, pt_blood, etc), see ptype_t near the top of this file +// pcolor1,pcolor2 - minimum and maximum ranges of color, randomly interpolated to decide particle color +// ptex - any of the tex_ values such as tex_smoke[rand()&7] or tex_particle +// psize - size of particle (or thickness for PARTICLE_SPARK and PARTICLE_*BEAM) +// palpha - opacity of particle as 0-255 (can be more than 255) +// palphafade - rate of fade per second (so 256 would mean a 256 alpha particle would fade to nothing in 1 second) +// ptime - how long the particle can live (note it is also removed if alpha drops to nothing) +// pgravity - how much effect gravity has on the particle (0-1) +// pbounce - how much bounce the particle has when it hits a surface (0-1), -1 makes a blood splat when it hits a surface, 0 does not even check for collisions +// px,py,pz - starting origin of particle +// pvx,pvy,pvz - starting velocity of particle +// pfriction - how much the particle slows down per second (0-1 typically, can slowdown faster than 1) +// blendmode - one of the PBLEND_ values +// orientation - one of the PARTICLE_ values +// staincolor1, staincolor2: minimum and maximum ranges of stain color, randomly interpolated to decide stain color (-1 to use none) +// staintex: any of the tex_ values such as tex_smoke[rand()&7] or tex_particle (-1 to use none) +// stainalpha: opacity of the stain as factor for alpha +// stainsize: size of the stain as factor for palpha +// angle: base rotation of the particle geometry around its center normal +// spin: rotation speed of the particle geometry around its center normal +particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex, float stainalpha, float stainsize, float angle, float spin, float tint[4]) +{ + int l1, l2, r, g, b; + particle_t *part; + vec3_t v; + if (!cl_particles.integer) + return NULL; + for (;cl.free_particle < cl.max_particles && cl.particles[cl.free_particle].typeindex;cl.free_particle++); + if (cl.free_particle >= cl.max_particles) + return NULL; + if (!lifetime) + lifetime = palpha / min(1, palphafade); + part = &cl.particles[cl.free_particle++]; + if (cl.num_particles < cl.free_particle) + cl.num_particles = cl.free_particle; + memset(part, 0, sizeof(*part)); + VectorCopy(sortorigin, part->sortorigin); + part->typeindex = ptypeindex; + part->blendmode = blendmode; + if(orientation == PARTICLE_HBEAM || orientation == PARTICLE_VBEAM) + { + particletexture_t *tex = &particletexture[ptex]; + if(tex->t1 == 0 && tex->t2 == 1) // full height of texture? + part->orientation = PARTICLE_VBEAM; + else + part->orientation = PARTICLE_HBEAM; + } + else + part->orientation = orientation; + l2 = (int)lhrandom(0.5, 256.5); + l1 = 256 - l2; + part->color[0] = ((((pcolor1 >> 16) & 0xFF) * l1 + ((pcolor2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; + part->color[1] = ((((pcolor1 >> 8) & 0xFF) * l1 + ((pcolor2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; + part->color[2] = ((((pcolor1 >> 0) & 0xFF) * l1 + ((pcolor2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + if (vid.sRGB3D) + { + part->color[0] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[0]) * 255.0f + 0.5f); + part->color[1] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[1]) * 255.0f + 0.5f); + part->color[2] = (unsigned char)floor(Image_LinearFloatFromsRGB(part->color[2]) * 255.0f + 0.5f); + } + part->alpha = palpha; + part->alphafade = palphafade; + part->staintexnum = staintex; + if(staincolor1 >= 0 && staincolor2 >= 0) + { + l2 = (int)lhrandom(0.5, 256.5); + l1 = 256 - l2; + if(blendmode == PBLEND_INVMOD) + { + r = ((((staincolor1 >> 16) & 0xFF) * l1 + ((staincolor2 >> 16) & 0xFF) * l2) * (255 - part->color[0])) / 0x8000; // staincolor 0x808080 keeps color invariant + g = ((((staincolor1 >> 8) & 0xFF) * l1 + ((staincolor2 >> 8) & 0xFF) * l2) * (255 - part->color[1])) / 0x8000; + b = ((((staincolor1 >> 0) & 0xFF) * l1 + ((staincolor2 >> 0) & 0xFF) * l2) * (255 - part->color[2])) / 0x8000; + } + else + { + r = ((((staincolor1 >> 16) & 0xFF) * l1 + ((staincolor2 >> 16) & 0xFF) * l2) * part->color[0]) / 0x8000; // staincolor 0x808080 keeps color invariant + g = ((((staincolor1 >> 8) & 0xFF) * l1 + ((staincolor2 >> 8) & 0xFF) * l2) * part->color[1]) / 0x8000; + b = ((((staincolor1 >> 0) & 0xFF) * l1 + ((staincolor2 >> 0) & 0xFF) * l2) * part->color[2]) / 0x8000; + } + if(r > 0xFF) r = 0xFF; + if(g > 0xFF) g = 0xFF; + if(b > 0xFF) b = 0xFF; + } + else + { + r = part->color[0]; // -1 is shorthand for stain = particle color + g = part->color[1]; + b = part->color[2]; + } + part->staincolor[0] = r; + part->staincolor[1] = g; + part->staincolor[2] = b; + part->stainalpha = palpha * stainalpha; + part->stainsize = psize * stainsize; + if(tint) + { + if(blendmode != PBLEND_INVMOD) // invmod is immune to tinting + { + part->color[0] *= tint[0]; + part->color[1] *= tint[1]; + part->color[2] *= tint[2]; + } + part->alpha *= tint[3]; + part->alphafade *= tint[3]; + part->stainalpha *= tint[3]; + } + part->texnum = ptex; + part->size = psize; + part->sizeincrease = psizeincrease; + part->gravity = pgravity; + part->bounce = pbounce; + part->stretch = stretch; + VectorRandom(v); + part->org[0] = px + originjitter * v[0]; + part->org[1] = py + originjitter * v[1]; + part->org[2] = pz + originjitter * v[2]; + part->vel[0] = pvx + velocityjitter * v[0]; + part->vel[1] = pvy + velocityjitter * v[1]; + part->vel[2] = pvz + velocityjitter * v[2]; + part->time2 = 0; + part->airfriction = pairfriction; + part->liquidfriction = pliquidfriction; + part->die = cl.time + lifetime; + part->delayedspawn = cl.time; +// part->delayedcollisions = 0; + part->qualityreduction = pqualityreduction; + part->angle = angle; + part->spin = spin; + // if it is rain or snow, trace ahead and shut off collisions until an actual collision event needs to occur to improve performance + if (part->typeindex == pt_rain) + { + int i; + particle_t *part2; + float lifetime = part->die - cl.time; + vec3_t endvec; + trace_t trace; + // turn raindrop into simple spark and create delayedspawn splash effect + part->typeindex = pt_spark; + part->bounce = 0; + VectorMA(part->org, lifetime, part->vel, endvec); + trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false, false); + part->die = cl.time + lifetime * trace.fraction; + part2 = CL_NewParticle(endvec, pt_raindecal, pcolor1, pcolor2, tex_rainsplash, part->size, part->size * 20, part->alpha, part->alpha / 0.4, 0, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2], 0, 0, 0, 0, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, -1, -1, -1, 1, 1, 0, 0, NULL); + if (part2) + { + part2->delayedspawn = part->die; + part2->die += part->die - cl.time; + for (i = rand() & 7;i < 10;i++) + { + part2 = CL_NewParticle(endvec, pt_spark, pcolor1, pcolor2, tex_particle, 0.25f, 0, part->alpha * 2, part->alpha * 4, 1, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0] * 16, trace.plane.normal[1] * 16, trace.plane.normal[2] * 16 + cl.movevars_gravity * 0.04, 0, 0, 0, 32, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + if (part2) + { + part2->delayedspawn = part->die; + part2->die += part->die - cl.time; + } + } + } + } +#if 0 + else if (part->bounce != 0 && part->gravity == 0 && part->typeindex != pt_snow) + { + float lifetime = part->alpha / (part->alphafade ? part->alphafade : 1); + vec3_t endvec; + trace_t trace; + VectorMA(part->org, lifetime, part->vel, endvec); + trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, true, false, NULL, false); + part->delayedcollisions = cl.time + lifetime * trace.fraction - 0.1; + } +#endif + + return part; +} + +static void CL_ImmediateBloodStain(particle_t *part) +{ + vec3_t v; + int staintex; + + // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot + if (part->staintexnum >= 0 && cl_decals_newsystem.integer && cl_decals.integer) + { + VectorCopy(part->vel, v); + VectorNormalize(v); + staintex = part->staintexnum; + R_DecalSystem_SplatEntities(part->org, v, 1-part->staincolor[0]*(1.0f/255.0f), 1-part->staincolor[1]*(1.0f/255.0f), 1-part->staincolor[2]*(1.0f/255.0f), part->stainalpha*(1.0f/255.0f), particletexture[staintex].s1, particletexture[staintex].t1, particletexture[staintex].s2, particletexture[staintex].t2, part->stainsize); + } + + // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot + if (part->typeindex == pt_blood && cl_decals_newsystem.integer && cl_decals.integer) + { + VectorCopy(part->vel, v); + VectorNormalize(v); + staintex = tex_blooddecal[rand()&7]; + R_DecalSystem_SplatEntities(part->org, v, part->color[0]*(1.0f/255.0f), part->color[1]*(1.0f/255.0f), part->color[2]*(1.0f/255.0f), part->alpha*(1.0f/255.0f), particletexture[staintex].s1, particletexture[staintex].t1, particletexture[staintex].s2, particletexture[staintex].t2, part->size * 2); + } +} + +void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha) +{ + int l1, l2; + decal_t *decal; + entity_render_t *ent = &cl.entities[hitent].render; + unsigned char color[3]; + if (!cl_decals.integer) + return; + if (!ent->allowdecals) + return; + + l2 = (int)lhrandom(0.5, 256.5); + l1 = 256 - l2; + color[0] = ((((color1 >> 16) & 0xFF) * l1 + ((color2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; + color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; + color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + + if (cl_decals_newsystem.integer) + { + if (vid.sRGB3D) + R_DecalSystem_SplatEntities(org, normal, Image_LinearFloatFromsRGB(color[0]), Image_LinearFloatFromsRGB(color[1]), Image_LinearFloatFromsRGB(color[2]), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); + else + R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); + return; + } + + for (;cl.free_decal < cl.max_decals && cl.decals[cl.free_decal].typeindex;cl.free_decal++); + if (cl.free_decal >= cl.max_decals) + return; + decal = &cl.decals[cl.free_decal++]; + if (cl.num_decals < cl.free_decal) + cl.num_decals = cl.free_decal; + memset(decal, 0, sizeof(*decal)); + decal->decalsequence = cl.decalsequence++; + decal->typeindex = pt_decal; + decal->texnum = texnum; + VectorMA(org, cl_decals_bias.value, normal, decal->org); + VectorCopy(normal, decal->normal); + decal->size = size; + decal->alpha = alpha; + decal->time2 = cl.time; + decal->color[0] = color[0]; + decal->color[1] = color[1]; + decal->color[2] = color[2]; + if (vid.sRGB3D) + { + decal->color[0] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[0]) * 256.0f); + decal->color[1] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[1]) * 256.0f); + decal->color[2] = (unsigned char)(Image_LinearFloatFromsRGB(decal->color[2]) * 256.0f); + } + decal->owner = hitent; + decal->clusterindex = -1000; // no vis culling unless we're sure + if (hitent) + { + // these relative things are only used to regenerate p->org and p->vel if decal->owner is not world (0) + decal->ownermodel = cl.entities[decal->owner].render.model; + Matrix4x4_Transform(&cl.entities[decal->owner].render.inversematrix, org, decal->relativeorigin); + Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.inversematrix, normal, decal->relativenormal); + } + else + { + if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf) + { + mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, decal->org); + if(leaf) + decal->clusterindex = leaf->clusterindex; + } + } +} + +void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2) +{ + int i; + vec_t bestfrac; + vec3_t bestorg; + vec3_t bestnormal; + vec3_t org2; + int besthitent = 0, hitent; + trace_t trace; + bestfrac = 10; + for (i = 0;i < 32;i++) + { + VectorRandom(org2); + VectorMA(org, maxdist, org2, org2); + trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false, true); + // take the closest trace result that doesn't end up hitting a NOMARKS + // surface (sky for example) + if (bestfrac > trace.fraction && !(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)) + { + bestfrac = trace.fraction; + besthitent = hitent; + VectorCopy(trace.endpos, bestorg); + VectorCopy(trace.plane.normal, bestnormal); + } + } + if (bestfrac < 1) + CL_SpawnDecalParticleForSurface(besthitent, bestorg, bestnormal, color1, color2, texnum, size, alpha); +} + +static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount); +static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount); +static void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles) +{ + vec3_t center; + matrix4x4_t tempmatrix; + particle_t *part; + + VectorLerp(originmins, 0.5, originmaxs, center); + Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]); + if (effectnameindex == EFFECT_SVC_PARTICLE) + { + if (cl_particles.integer) + { + // bloodhack checks if this effect's color matches regular or lightning blood and if so spawns a blood effect instead + if (count == 1024) + CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + else if (cl_particles_blood_bloodhack.integer && !cl_particles_quake.integer && (palettecolor == 73 || palettecolor == 225)) + CL_ParticleEffect(EFFECT_TE_BLOOD, count / 2.0f, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + else + { + count *= cl_particles_quality.value; + for (;count > 0;count--) + { + int k = particlepalette[(palettecolor & ~7) + (rand()&7)]; + CL_NewParticle(center, pt_alphastatic, k, k, tex_particle, 1.5, 0, 255, 0, 0.05, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 8, 0, true, lhrandom(0.1, 0.5), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + } + else if (effectnameindex == EFFECT_TE_WIZSPIKE) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 30*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 20); + else if (effectnameindex == EFFECT_TE_KNIGHTSPIKE) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 226); + else if (effectnameindex == EFFECT_TE_SPIKE) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + { + if (cl_particles_smoke.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + } + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + } + else if (effectnameindex == EFFECT_TE_SPIKEQUAD) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + { + if (cl_particles_smoke.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 10*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + } + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 15*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_SUPERSPIKE) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + { + if (cl_particles_smoke.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + } + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 8*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + } + else if (effectnameindex == EFFECT_TE_SUPERSPIKEQUAD) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + { + if (cl_particles_smoke.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + } + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 8*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 30*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_BLOOD) + { + if (!cl_particles_blood.integer) + return; + if (cl_particles_quake.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 2*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 73); + else + { + static double bloodaccumulator = 0; + qboolean immediatebloodstain = (cl_decals_newsystem_immediatebloodstain.integer >= 1); + //CL_NewParticle(center, pt_alphastatic, 0x4f0000,0x7f0000, tex_particle, 2.5, 0, 256, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 1, 4, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, NULL); + bloodaccumulator += count * 0.333 * cl_particles_quality.value; + for (;bloodaccumulator > 0;bloodaccumulator--) + { + part = CL_NewParticle(center, pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, cl_particles_blood_alpha.value * 768, cl_particles_blood_alpha.value * 384, 1, -1, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64, true, 0, 1, PBLEND_INVMOD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + if (immediatebloodstain && part) + { + immediatebloodstain = false; + CL_ImmediateBloodStain(part); + } + } + } + } + else if (effectnameindex == EFFECT_TE_SPARK) + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, count); + else if (effectnameindex == EFFECT_TE_PLASMABURN) + { + // plasma scorch mark + R_Stain(center, 40, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 6, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + CL_AllocLightFlash(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_GUNSHOT) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 20*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + } + else if (effectnameindex == EFFECT_TE_GUNSHOTQUAD) + { + if (cl_particles_bulletimpacts.integer) + { + if (cl_particles_quake.integer) + CL_ParticleEffect(EFFECT_SVC_PARTICLE, 20*count, originmins, originmaxs, velocitymins, velocitymaxs, NULL, 0); + else + { + CL_Smoke(originmins, originmaxs, velocitymins, velocitymaxs, 4*count); + CL_Sparks(originmins, originmaxs, velocitymins, velocitymaxs, 20*count); + CL_NewParticle(center, pt_static, 0x808080,0x808080, tex_particle, 3, 0, 256, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + // bullet hole + R_Stain(center, 16, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 3, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + CL_AllocLightFlash(NULL, &tempmatrix, 100, 0.15f, 0.15f, 1.5f, 500, 0.2, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_EXPLOSION) + { + CL_ParticleExplosion(center); + CL_AllocLightFlash(NULL, &tempmatrix, 350, 4.0f, 2.0f, 0.50f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_EXPLOSIONQUAD) + { + CL_ParticleExplosion(center); + CL_AllocLightFlash(NULL, &tempmatrix, 350, 2.5f, 2.0f, 4.0f, 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_TAREXPLOSION) + { + if (cl_particles_quake.integer) + { + int i; + for (i = 0;i < 1024 * cl_particles_quality.value;i++) + { + if (i & 1) + CL_NewParticle(center, pt_alphastatic, particlepalette[66], particlepalette[71], tex_particle, 1.5f, 0, 255, 0, 0, 0, center[0], center[1], center[2], 0, 0, 0, -4, -4, 16, 256, true, (rand() & 1) ? 1.4 : 1.0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + else + CL_NewParticle(center, pt_alphastatic, particlepalette[150], particlepalette[155], tex_particle, 1.5f, 0, 255, 0, 0, 0, center[0], center[1], center[2], 0, 0, lhrandom(-256, 256), 0, 0, 16, 0, true, (rand() & 1) ? 1.4 : 1.0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else + CL_ParticleExplosion(center); + CL_AllocLightFlash(NULL, &tempmatrix, 600, 1.6f, 0.8f, 2.0f, 1200, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_SMALLFLASH) + CL_AllocLightFlash(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + else if (effectnameindex == EFFECT_TE_FLAMEJET) + { + count *= cl_particles_quality.value; + while (count-- > 0) + CL_NewParticle(center, pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 1.1, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (effectnameindex == EFFECT_TE_LAVASPLASH) + { + float i, j, inc, vel; + vec3_t dir, org; + + inc = 8 / cl_particles_quality.value; + for (i = -128;i < 128;i += inc) + { + for (j = -128;j < 128;j += inc) + { + dir[0] = j + lhrandom(0, inc); + dir[1] = i + lhrandom(0, inc); + dir[2] = 256; + org[0] = center[0] + dir[0]; + org[1] = center[1] + dir[1]; + org[2] = center[2] + lhrandom(0, 64); + vel = lhrandom(50, 120) / VectorLength(dir); // normalize and scale + CL_NewParticle(center, pt_alphastatic, particlepalette[224], particlepalette[231], tex_particle, 1.5f, 0, 255, 0, 0.05, 0, org[0], org[1], org[2], dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, true, lhrandom(2, 2.62), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + else if (effectnameindex == EFFECT_TE_TELEPORT) + { + float i, j, k, inc, vel; + vec3_t dir; + + if (cl_particles_quake.integer) + inc = 4 / cl_particles_quality.value; + else + inc = 8 / cl_particles_quality.value; + for (i = -16;i < 16;i += inc) + { + for (j = -16;j < 16;j += inc) + { + for (k = -24;k < 32;k += inc) + { + VectorSet(dir, i*8, j*8, k*8); + VectorNormalize(dir); + vel = lhrandom(50, 113); + if (cl_particles_quake.integer) + CL_NewParticle(center, pt_alphastatic, particlepalette[7], particlepalette[14], tex_particle, 1.5f, 0, 255, 0, 0, 0, center[0] + i + lhrandom(0, inc), center[1] + j + lhrandom(0, inc), center[2] + k + lhrandom(0, inc), dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, true, lhrandom(0.2, 0.34), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + else + CL_NewParticle(center, pt_alphastatic, particlepalette[7], particlepalette[14], tex_particle, 1.5f, 0, inc * lhrandom(37, 63), inc * 187, 0, 0, center[0] + i + lhrandom(0, inc), center[1] + j + lhrandom(0, inc), center[2] + k + lhrandom(0, inc), dir[0] * vel, dir[1] * vel, dir[2] * vel, 0, 0, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + if (!cl_particles_quake.integer) + CL_NewParticle(center, pt_static, 0xffffff, 0xffffff, tex_particle, 30, 0, 256, 512, 0, 0, center[0], center[1], center[2], 0, 0, 0, 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 2.0f, 2.0f, 400, 99.0f, 0, -1, true, 1, 0.25, 1, 0, 0, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_TEI_G3) + CL_NewParticle(center, pt_beam, 0xFFFFFF, 0xFFFFFF, tex_beam, 8, 0, 256, 256, 0, 0, originmins[0], originmins[1], originmins[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, 0, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); + else if (effectnameindex == EFFECT_TE_TEI_SMOKE) + { + if (cl_particles_smoke.integer) + { + count *= 0.25f * cl_particles_quality.value; + while (count-- > 0) + CL_NewParticle(center, pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 0, 255, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 1.5f, 6.0f, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TE_TEI_BIGEXPLOSION) + { + CL_ParticleExplosion(center); + CL_AllocLightFlash(NULL, &tempmatrix, 500, 2.5f, 2.0f, 1.0f, 500, 9999, 0, -1, true, 1, 0.25, 0.5, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_TE_TEI_PLASMAHIT) + { + float f; + R_Stain(center, 40, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(center, 6, 8, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + if (cl_particles_smoke.integer) + for (f = 0;f < count;f += 4.0f / cl_particles_quality.value) + CL_NewParticle(center, pt_smoke, 0x202020, 0x404040, tex_smoke[rand()&7], 5, 0, 255, 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 20, 155, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + if (cl_particles_sparks.integer) + for (f = 0;f < count;f += 1.0f / cl_particles_quality.value) + CL_NewParticle(center, pt_spark, 0x2030FF, 0x80C0FF, tex_particle, 2.0f, 0, lhrandom(64, 255), 512, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, 465, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_AllocLightFlash(NULL, &tempmatrix, 500, 0.6f, 1.2f, 2.0f, 2000, 9999, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_EF_FLAME) + { + if (!spawnparticles) + count = 0; + count *= 300 * cl_particles_quality.value; + while (count-- > 0) + CL_NewParticle(center, pt_smoke, 0x6f0f00, 0xe3974f, tex_particle, 4, 0, lhrandom(64, 128), 384, -1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_AllocLightFlash(NULL, &tempmatrix, 200, 2.0f, 1.5f, 0.5f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (effectnameindex == EFFECT_EF_STARDUST) + { + if (!spawnparticles) + count = 0; + count *= 200 * cl_particles_quality.value; + while (count-- > 0) + CL_NewParticle(center, pt_static, 0x903010, 0xFFD030, tex_particle, 4, 0, lhrandom(64, 128), 128, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0.2, 0.8, 16, 128, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_AllocLightFlash(NULL, &tempmatrix, 200, 1.0f, 0.7f, 0.3f, 0, 0, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (!strncmp(particleeffectname[effectnameindex], "TR_", 3)) + { + vec3_t dir, pos; + float len, dec, qd; + int smoke, blood, bubbles, r, color; + + if (spawndlight && r_refdef.scene.numlights < MAX_DLIGHTS) + { + vec4_t light; + Vector4Set(light, 0, 0, 0, 0); + + if (effectnameindex == EFFECT_TR_ROCKET) + Vector4Set(light, 3.0f, 1.5f, 0.5f, 200); + else if (effectnameindex == EFFECT_TR_VORESPIKE) + { + if (gamemode == GAME_PRYDON && !cl_particles_quake.integer) + Vector4Set(light, 0.3f, 0.6f, 1.2f, 100); + else + Vector4Set(light, 1.2f, 0.5f, 1.0f, 200); + } + else if (effectnameindex == EFFECT_TR_NEXUIZPLASMA) + Vector4Set(light, 0.75f, 1.5f, 3.0f, 200); + + if (light[3]) + { + matrix4x4_t tempmatrix; + Matrix4x4_CreateFromQuakeEntity(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, light[3]); + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, light, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + } + + if (!spawnparticles) + return; + + if (originmaxs[0] == originmins[0] && originmaxs[1] == originmins[1] && originmaxs[2] == originmins[2]) + return; + + VectorSubtract(originmaxs, originmins, dir); + len = VectorNormalizeLength(dir); + if (ent) + { + dec = -ent->persistent.trail_time; + ent->persistent.trail_time += len; + if (ent->persistent.trail_time < 0.01f) + return; + + // if we skip out, leave it reset + ent->persistent.trail_time = 0.0f; + } + else + dec = 0; + + // advance into this frame to reach the first puff location + VectorMA(originmins, dec, dir, pos); + len -= dec; + + smoke = cl_particles.integer && cl_particles_smoke.integer; + blood = cl_particles.integer && cl_particles_blood.integer; + bubbles = cl_particles.integer && cl_particles_bubbles.integer && !cl_particles_quake.integer && (CL_PointSuperContents(pos) & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME)); + qd = 1.0f / cl_particles_quality.value; + + while (len >= 0) + { + dec = 3; + if (blood) + { + if (effectnameindex == EFFECT_TR_BLOOD) + { + if (cl_particles_quake.integer) + { + color = particlepalette[67 + (rand()&3)]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 2, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + dec = 16; + CL_NewParticle(center, pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 1, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64, true, 0, 1, PBLEND_INVMOD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TR_SLIGHTBLOOD) + { + if (cl_particles_quake.integer) + { + dec = 6; + color = particlepalette[67 + (rand()&3)]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 2, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + dec = 32; + CL_NewParticle(center, pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, qd * cl_particles_blood_alpha.value * 768.0f, qd * cl_particles_blood_alpha.value * 384.0f, 1, -1, pos[0], pos[1], pos[2], lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64, true, 0, 1, PBLEND_INVMOD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + if (smoke) + { + if (effectnameindex == EFFECT_TR_ROCKET) + { + if (cl_particles_quake.integer) + { + r = rand()&3; + color = particlepalette[ramp3[r]]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, -0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 0.1372549*(6-r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + CL_NewParticle(center, pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*62, cl_particles_smoke_alphafade.value*62, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_NewParticle(center, pt_static, 0x801010, 0xFFA020, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*288, cl_particles_smoke_alphafade.value*1400, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 20, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TR_GRENADE) + { + if (cl_particles_quake.integer) + { + r = 2 + (rand()%5); + color = particlepalette[ramp3[r]]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, -0.05, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 3, 0, true, 0.1372549*(6-r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + CL_NewParticle(center, pt_smoke, 0x303030, 0x606060, tex_smoke[rand()&7], 3, 0, cl_particles_smoke_alpha.value*50, cl_particles_smoke_alphafade.value*75, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TR_WIZSPIKE) + { + if (cl_particles_quake.integer) + { + dec = 6; + color = particlepalette[52 + (rand()&7)]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (gamemode == GAME_GOODVSBAD2) + { + dec = 6; + CL_NewParticle(center, pt_static, 0x00002E, 0x000030, tex_particle, 6, 0, 128, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + color = particlepalette[20 + (rand()&7)]; + CL_NewParticle(center, pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TR_KNIGHTSPIKE) + { + if (cl_particles_quake.integer) + { + dec = 6; + color = particlepalette[230 + (rand()&7)]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*dir[1], 30*-dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 30*-dir[1], 30*dir[0], 0, 0, 0, 0, 0, true, 0.5, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + color = particlepalette[226 + (rand()&7)]; + CL_NewParticle(center, pt_static, color, color, tex_particle, 2, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + else if (effectnameindex == EFFECT_TR_VORESPIKE) + { + if (cl_particles_quake.integer) + { + color = particlepalette[152 + (rand()&3)]; + CL_NewParticle(center, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 8, 0, true, 0.3, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (gamemode == GAME_GOODVSBAD2) + { + dec = 6; + CL_NewParticle(center, pt_alphastatic, particlepalette[0 + (rand()&255)], particlepalette[0 + (rand()&255)], tex_particle, 6, 0, 255, 384, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (gamemode == GAME_PRYDON) + { + dec = 6; + CL_NewParticle(center, pt_static, 0x103040, 0x204050, tex_particle, 6, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + CL_NewParticle(center, pt_static, 0x502030, 0x502030, tex_particle, 3, 0, 64, 192, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (effectnameindex == EFFECT_TR_NEHAHRASMOKE) + { + dec = 7; + CL_NewParticle(center, pt_alphastatic, 0x303030, 0x606060, tex_smoke[rand()&7], 7, 0, 64, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, lhrandom(4, 12), 0, 0, 0, 4, false, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (effectnameindex == EFFECT_TR_NEXUIZPLASMA) + { + dec = 4; + CL_NewParticle(center, pt_static, 0x283880, 0x283880, tex_particle, 4, 0, 255, 1024, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 16, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else if (effectnameindex == EFFECT_TR_GLOWTRAIL) + CL_NewParticle(center, pt_alphastatic, particlepalette[palettecolor], particlepalette[palettecolor], tex_particle, 5, 0, 128, 320, 0, 0, pos[0], pos[1], pos[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + if (bubbles) + { + if (effectnameindex == EFFECT_TR_ROCKET) + CL_NewParticle(center, pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 512), 512, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + else if (effectnameindex == EFFECT_TR_GRENADE) + CL_NewParticle(center, pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 512), 512, -0.25, 1.5, pos[0], pos[1], pos[2], 0, 0, 0, 0.0625, 0.25, 0, 16, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + // advance to next time and position + dec *= qd; + len -= dec; + VectorMA (pos, dec, dir, pos); + } + if (ent) + ent->persistent.trail_time = len; + } + else + Con_DPrintf("CL_ParticleEffect_Fallback: no fallback found for effect %s\n", particleeffectname[effectnameindex]); +} + +// this is also called on point effects with spawndlight = true and +// spawnparticles = true +// it is called CL_ParticleTrail because most code does not want to supply +// these parameters, only trail handling does +void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4]) +{ + qboolean found = false; + char vabuf[1024]; + if (effectnameindex < 1 || effectnameindex >= MAX_PARTICLEEFFECTNAME || !particleeffectname[effectnameindex][0]) + { + Con_DPrintf("Unknown effect number %i received from server\n", effectnameindex); + return; // no such effect + } + if (!cl_particles_quake.integer && particleeffectinfo[0].effectnameindex) + { + int effectinfoindex; + int supercontents; + int tex, staintex; + particleeffectinfo_t *info; + vec3_t center; + vec3_t traildir; + vec3_t trailpos; + vec3_t rvec; + vec3_t angles; + vec3_t velocity; + vec3_t forward; + vec3_t right; + vec3_t up; + vec_t traillen; + vec_t trailstep; + qboolean underwater; + qboolean immediatebloodstain; + particle_t *part; + float avgtint[4], tint[4], tintlerp; + // note this runs multiple effects with the same name, each one spawns only one kind of particle, so some effects need more than one + VectorLerp(originmins, 0.5, originmaxs, center); + supercontents = CL_PointSuperContents(center); + underwater = (supercontents & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME)) != 0; + VectorSubtract(originmaxs, originmins, traildir); + traillen = VectorLength(traildir); + VectorNormalize(traildir); + if(tintmins) + { + Vector4Lerp(tintmins, 0.5, tintmaxs, avgtint); + } + else + { + Vector4Set(avgtint, 1, 1, 1, 1); + } + for (effectinfoindex = 0, info = particleeffectinfo;effectinfoindex < MAX_PARTICLEEFFECTINFO && info->effectnameindex;effectinfoindex++, info++) + { + if (info->effectnameindex == effectnameindex) + { + found = true; + if ((info->flags & PARTICLEEFFECT_UNDERWATER) && !underwater) + continue; + if ((info->flags & PARTICLEEFFECT_NOTUNDERWATER) && underwater) + continue; + + // spawn a dlight if requested + if (info->lightradiusstart > 0 && spawndlight) + { + matrix4x4_t tempmatrix; + if (info->trailspacing > 0) + Matrix4x4_CreateTranslate(&tempmatrix, originmaxs[0], originmaxs[1], originmaxs[2]); + else + Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]); + if (info->lighttime > 0 && info->lightradiusfade > 0) + { + // light flash (explosion, etc) + // called when effect starts + CL_AllocLightFlash(NULL, &tempmatrix, info->lightradiusstart, info->lightcolor[0]*avgtint[0]*avgtint[3], info->lightcolor[1]*avgtint[1]*avgtint[3], info->lightcolor[2]*avgtint[2]*avgtint[3], info->lightradiusfade, info->lighttime, info->lightcubemapnum, -1, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + } + else if (r_refdef.scene.numlights < MAX_DLIGHTS) + { + // glowing entity + // called by CL_LinkNetworkEntity + Matrix4x4_Scale(&tempmatrix, info->lightradiusstart, 1); + rvec[0] = info->lightcolor[0]*avgtint[0]*avgtint[3]; + rvec[1] = info->lightcolor[1]*avgtint[1]*avgtint[3]; + rvec[2] = info->lightcolor[2]*avgtint[2]*avgtint[3]; + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &tempmatrix, rvec, -1, info->lightcubemapnum > 0 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", info->lightcubemapnum) : NULL, info->lightshadow, info->lightcorona[0], info->lightcorona[1], 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + } + } + + if (!spawnparticles) + continue; + + // spawn particles + tex = info->tex[0]; + if (info->tex[1] > info->tex[0]) + { + tex = (int)lhrandom(info->tex[0], info->tex[1]); + tex = min(tex, info->tex[1] - 1); + } + if(info->staintex[0] < 0) + staintex = info->staintex[0]; + else + { + staintex = (int)lhrandom(info->staintex[0], info->staintex[1]); + staintex = min(staintex, info->staintex[1] - 1); + } + if (info->particletype == pt_decal) + { + VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity); + AnglesFromVectors(angles, velocity, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, center, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + + CL_SpawnDecalParticleForPoint(trailpos, info->originjitter[0], lhrandom(info->size[0], info->size[1]), lhrandom(info->alpha[0], info->alpha[1])*avgtint[3], tex, info->color[0], info->color[1]); + } + else if (info->orientation == PARTICLE_HBEAM) + { + AnglesFromVectors(angles, traildir, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAM(info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + + CL_NewParticle(center, info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], 0, 0, originmins[0] + trailpos[0], originmins[1] + trailpos[1], originmins[2] + trailpos[2], originmaxs[0], originmaxs[1], originmaxs[2], 0, 0, 0, 0, false, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), 0, 0, tintmins ? avgtint : NULL); + } + else + { + if (!cl_particles.integer) + continue; + switch (info->particletype) + { + case pt_smoke: if (!cl_particles_smoke.integer) continue;break; + case pt_spark: if (!cl_particles_sparks.integer) continue;break; + case pt_bubble: if (!cl_particles_bubbles.integer) continue;break; + case pt_blood: if (!cl_particles_blood.integer) continue;break; + case pt_rain: if (!cl_particles_rain.integer) continue;break; + case pt_snow: if (!cl_particles_snow.integer) continue;break; + default: break; + } + VectorCopy(originmins, trailpos); + if (info->trailspacing > 0) + { + info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value; + trailstep = info->trailspacing / cl_particles_quality.value; + immediatebloodstain = false; + + AnglesFromVectors(angles, traildir, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], forward, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + VectorMAMAM(info->relativevelocityoffset[0], forward, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); + } + else + { + info->particleaccumulator += info->countabsolute + pcount * info->countmultiplier * cl_particles_quality.value; + trailstep = 0; + immediatebloodstain = + ((cl_decals_newsystem_immediatebloodstain.integer >= 1) && (info->particletype == pt_blood)) + || + ((cl_decals_newsystem_immediatebloodstain.integer >= 2) && staintex); + + VectorMAM(0.5f, velocitymins, 0.5f, velocitymaxs, velocity); + AnglesFromVectors(angles, velocity, NULL, false); + AngleVectors(angles, forward, right, up); + VectorMAMAMAM(1.0f, trailpos, info->relativeoriginoffset[0], traildir, info->relativeoriginoffset[1], right, info->relativeoriginoffset[2], up, trailpos); + VectorMAMAM(info->relativevelocityoffset[0], traildir, info->relativevelocityoffset[1], right, info->relativevelocityoffset[2], up, velocity); + } + info->particleaccumulator = bound(0, info->particleaccumulator, 16384); + for (;info->particleaccumulator >= 1;info->particleaccumulator--) + { + if (info->tex[1] > info->tex[0]) + { + tex = (int)lhrandom(info->tex[0], info->tex[1]); + tex = min(tex, info->tex[1] - 1); + } + if (!trailstep) + { + trailpos[0] = lhrandom(originmins[0], originmaxs[0]); + trailpos[1] = lhrandom(originmins[1], originmaxs[1]); + trailpos[2] = lhrandom(originmins[2], originmaxs[2]); + } + if(tintmins) + { + tintlerp = lhrandom(0, 1); + Vector4Lerp(tintmins, tintlerp, tintmaxs, tint); + } + VectorRandom(rvec); + part = CL_NewParticle(center, info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], info->gravity, info->bounce, trailpos[0] + info->originoffset[0] + info->originjitter[0] * rvec[0], trailpos[1] + info->originoffset[1] + info->originjitter[1] * rvec[1], trailpos[2] + info->originoffset[2] + info->originjitter[2] * rvec[2], lhrandom(velocitymins[0], velocitymaxs[0]) * info->velocitymultiplier + info->velocityoffset[0] + info->velocityjitter[0] * rvec[0] + velocity[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1] + velocity[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2] + velocity[2], info->airfriction, info->liquidfriction, 0, 0, info->countabsolute <= 0, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex, lhrandom(info->stainalpha[0], info->stainalpha[1]), lhrandom(info->stainsize[0], info->stainsize[1]), lhrandom(info->rotate[0], info->rotate[1]), lhrandom(info->rotate[2], info->rotate[3]), tintmins ? tint : NULL); + if (immediatebloodstain && part) + { + immediatebloodstain = false; + CL_ImmediateBloodStain(part); + } + if (trailstep) + VectorMA(trailpos, trailstep, traildir, trailpos); + } + } + } + } + } + if (!found) + CL_ParticleEffect_Fallback(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, spawndlight, spawnparticles); +} + +void CL_ParticleEffect(int effectnameindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor) +{ + CL_ParticleTrail(effectnameindex, pcount, originmins, originmaxs, velocitymins, velocitymaxs, ent, palettecolor, true, true, NULL, NULL); +} + +/* +=============== +CL_EntityParticles +=============== +*/ +void CL_EntityParticles (const entity_t *ent) +{ + int i, j; + vec_t pitch, yaw, dist = 64, beamlength = 16; + vec3_t org, v; + static vec3_t avelocities[NUMVERTEXNORMALS]; + if (!cl_particles.integer) return; + if (cl.time <= cl.oldtime) return; // don't spawn new entity particles while paused + + Matrix4x4_OriginFromMatrix(&ent->render.matrix, org); + + if (!avelocities[0][0]) + for (i = 0;i < NUMVERTEXNORMALS;i++) + for (j = 0;j < 3;j++) + avelocities[i][j] = lhrandom(0, 2.55); + + for (i = 0;i < NUMVERTEXNORMALS;i++) + { + yaw = cl.time * avelocities[i][0]; + pitch = cl.time * avelocities[i][1]; + v[0] = org[0] + m_bytenormals[i][0] * dist + (cos(pitch)*cos(yaw)) * beamlength; + v[1] = org[1] + m_bytenormals[i][1] * dist + (cos(pitch)*sin(yaw)) * beamlength; + v[2] = org[2] + m_bytenormals[i][2] * dist + (-sin(pitch)) * beamlength; + CL_NewParticle(org, pt_entityparticle, particlepalette[0x6f], particlepalette[0x6f], tex_particle, 1, 0, 255, 0, 0, 0, v[0], v[1], v[2], 0, 0, 0, 0, 0, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } +} + + +void CL_ReadPointFile_f (void) +{ + double org[3], leakorg[3]; + vec3_t vecorg; + int r, c, s; + char *pointfile = NULL, *pointfilepos, *t, tchar; + char name[MAX_QPATH]; + + if (!cl.worldmodel) + return; + + dpsnprintf(name, sizeof(name), "%s.pts", cl.worldnamenoextension); + pointfile = (char *)FS_LoadFile(name, tempmempool, true, NULL); + if (!pointfile) + { + Con_Printf("Could not open %s\n", name); + return; + } + + Con_Printf("Reading %s...\n", name); + VectorClear(leakorg); + c = 0; + s = 0; + pointfilepos = pointfile; + while (*pointfilepos) + { + while (*pointfilepos == '\n' || *pointfilepos == '\r') + pointfilepos++; + if (!*pointfilepos) + break; + t = pointfilepos; + while (*t && *t != '\n' && *t != '\r') + t++; + tchar = *t; + *t = 0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + r = sscanf (pointfilepos,"%lf %lf %lf", &org[0], &org[1], &org[2]); + VectorCopy(org, vecorg); + *t = tchar; + pointfilepos = t; + if (r != 3) + break; + if (c == 0) + VectorCopy(org, leakorg); + c++; + + if (cl.num_particles < cl.max_particles - 3) + { + s++; + CL_NewParticle(vecorg, pt_alphastatic, particlepalette[(-c)&15], particlepalette[(-c)&15], tex_particle, 2, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 0, 0, 0, 0, true, 1<<30, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + Mem_Free(pointfile); + VectorCopy(leakorg, vecorg); + Con_Printf("%i points read (%i particles spawned)\nLeak at %f %f %f\n", c, s, leakorg[0], leakorg[1], leakorg[2]); + + CL_NewParticle(vecorg, pt_beam, 0xFF0000, 0xFF0000, tex_beam, 64, 0, 255, 0, 0, 0, org[0] - 4096, org[1], org[2], org[0] + 4096, org[1], org[2], 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_NewParticle(vecorg, pt_beam, 0x00FF00, 0x00FF00, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1] - 4096, org[2], org[0], org[1] + 4096, org[2], 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); + CL_NewParticle(vecorg, pt_beam, 0x0000FF, 0x0000FF, tex_beam, 64, 0, 255, 0, 0, 0, org[0], org[1], org[2] - 4096, org[0], org[1], org[2] + 4096, 0, 0, 0, 0, false, 1<<30, 1, PBLEND_ADD, PARTICLE_HBEAM, -1, -1, -1, 1, 1, 0, 0, NULL); +} + +/* +=============== +CL_ParseParticleEffect + +Parse an effect out of the server message +=============== +*/ +void CL_ParseParticleEffect (void) +{ + vec3_t org, dir; + int i, count, msgcount, color; + + MSG_ReadVector(&cl_message, org, cls.protocol); + for (i=0 ; i<3 ; i++) + dir[i] = MSG_ReadChar(&cl_message) * (1.0 / 16.0); + msgcount = MSG_ReadByte(&cl_message); + color = MSG_ReadByte(&cl_message); + + if (msgcount == 255) + count = 1024; + else + count = msgcount; + + CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color); +} + +/* +=============== +CL_ParticleExplosion + +=============== +*/ +void CL_ParticleExplosion (const vec3_t org) +{ + int i; + trace_t trace; + //vec3_t v; + //vec3_t v2; + R_Stain(org, 96, 40, 40, 40, 64, 88, 88, 88, 64); + CL_SpawnDecalParticleForPoint(org, 40, 48, 255, tex_bulletdecal[rand()&7], 0xFFFFFF, 0xFFFFFF); + + if (cl_particles_quake.integer) + { + for (i = 0;i < 1024;i++) + { + int r, color; + r = rand()&3; + if (i & 1) + { + color = particlepalette[ramp1[r]]; + CL_NewParticle(org, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256, true, 0.1006 * (8 - r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + color = particlepalette[ramp2[r]]; + CL_NewParticle(org, pt_alphastatic, color, color, tex_particle, 1.5f, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, 1, 1, 16, 256, true, 0.0669 * (8 - r), 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + else + { + i = CL_PointSuperContents(org); + if (i & (SUPERCONTENTS_SLIME | SUPERCONTENTS_WATER)) + { + if (cl_particles.integer && cl_particles_bubbles.integer) + for (i = 0;i < 128 * cl_particles_quality.value;i++) + CL_NewParticle(org, pt_bubble, 0x404040, 0x808080, tex_bubble, 2, 0, lhrandom(128, 255), 128, -0.125, 1.5, org[0], org[1], org[2], 0, 0, 0, 0.0625, 0.25, 16, 96, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + else + { + if (cl_particles.integer && cl_particles_sparks.integer && cl_particles_explosions_sparks.integer) + { + for (i = 0;i < 512 * cl_particles_quality.value;i++) + { + int k = 0; + vec3_t v, v2; + do + { + VectorRandom(v2); + VectorMA(org, 128, v2, v); + trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false); + } + while (k < 16 && trace.fraction < 0.1f); + VectorSubtract(trace.endpos, org, v2); + VectorScale(v2, 2.0f, v2); + CL_NewParticle(org, pt_spark, 0x903010, 0xFFD030, tex_particle, 1.0f, 0, lhrandom(0, 255), 512, 0, 0, org[0], org[1], org[2], v2[0], v2[1], v2[2], 0, 0, 0, 0, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + } + } + } + } + + if (cl_particles_explosions_shell.integer) + R_NewExplosion(org); +} + +/* +=============== +CL_ParticleExplosion2 + +=============== +*/ +void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength) +{ + int i, k; + if (!cl_particles.integer) return; + + for (i = 0;i < 512 * cl_particles_quality.value;i++) + { + k = particlepalette[colorStart + (i % colorLength)]; + if (cl_particles_quake.integer) + CL_NewParticle(org, pt_alphastatic, k, k, tex_particle, 1, 0, 255, 0, 0, 0, org[0], org[1], org[2], 0, 0, 0, -4, -4, 16, 256, true, 0.3, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + else + CL_NewParticle(org, pt_alphastatic, k, k, tex_particle, lhrandom(0.5, 1.5), 0, 255, 512, 0, 0, org[0], org[1], org[2], 0, 0, 0, lhrandom(1.5, 3), lhrandom(1.5, 3), 8, 192, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } +} + +static void CL_Sparks(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float sparkcount) +{ + vec3_t center; + VectorMAM(0.5f, originmins, 0.5f, originmaxs, center); + if (cl_particles_sparks.integer) + { + sparkcount *= cl_particles_quality.value; + while(sparkcount-- > 0) + CL_NewParticle(center, pt_spark, particlepalette[0x68], particlepalette[0x6f], tex_particle, 0.5f, 0, lhrandom(64, 255), 512, 1, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]) + cl.movevars_gravity * 0.1f, 0, 0, 0, 64, true, 0, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + } +} + +static void CL_Smoke(const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, float smokecount) +{ + vec3_t center; + VectorMAM(0.5f, originmins, 0.5f, originmaxs, center); + if (cl_particles_smoke.integer) + { + smokecount *= cl_particles_quality.value; + while(smokecount-- > 0) + CL_NewParticle(center, pt_smoke, 0x101010, 0x101010, tex_smoke[rand()&7], 2, 2, 255, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 0, 0, 0, smokecount > 0 ? 16 : 0, true, 0, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } +} + +void CL_ParticleCube (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, vec_t gravity, vec_t randomvel) +{ + vec3_t center; + int k; + if (!cl_particles.integer) return; + VectorMAM(0.5f, mins, 0.5f, maxs, center); + + count = (int)(count * cl_particles_quality.value); + while (count--) + { + k = particlepalette[colorbase + (rand()&3)]; + CL_NewParticle(center, pt_alphastatic, k, k, tex_particle, 2, 0, 255, 128, gravity, 0, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(mins[2], maxs[2]), dir[0], dir[1], dir[2], 0, 0, 0, randomvel, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } +} + +void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, int type) +{ + int k; + float minz, maxz, lifetime = 30; + vec3_t org; + if (!cl_particles.integer) return; + if (dir[2] < 0) // falling + { + minz = maxs[2] + dir[2] * 0.1; + maxz = maxs[2]; + if (cl.worldmodel) + lifetime = (maxz - cl.worldmodel->normalmins[2]) / max(1, -dir[2]); + } + else // rising?? + { + minz = mins[2]; + maxz = maxs[2] + dir[2] * 0.1; + if (cl.worldmodel) + lifetime = (cl.worldmodel->normalmaxs[2] - minz) / max(1, dir[2]); + } + + count = (int)(count * cl_particles_quality.value); + + switch(type) + { + case 0: + if (!cl_particles_rain.integer) break; + count *= 4; // ick, this should be in the mod or maps? + + while(count--) + { + k = particlepalette[colorbase + (rand()&3)]; + VectorSet(org, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz)); + if (gamemode == GAME_GOODVSBAD2) + CL_NewParticle(org, pt_rain, k, k, tex_particle, 20, 0, lhrandom(32, 64), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + else + CL_NewParticle(org, pt_rain, k, k, tex_particle, 0.5, 0, lhrandom(32, 64), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_SPARK, -1, -1, -1, 1, 1, 0, 0, NULL); + } + break; + case 1: + if (!cl_particles_snow.integer) break; + while(count--) + { + k = particlepalette[colorbase + (rand()&3)]; + VectorSet(org, lhrandom(mins[0], maxs[0]), lhrandom(mins[1], maxs[1]), lhrandom(minz, maxz)); + if (gamemode == GAME_GOODVSBAD2) + CL_NewParticle(org, pt_snow, k, k, tex_particle, 20, 0, lhrandom(64, 128), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + else + CL_NewParticle(org, pt_snow, k, k, tex_particle, 1, 0, lhrandom(64, 128), 0, 0, -1, org[0], org[1], org[2], dir[0], dir[1], dir[2], 0, 0, 0, 0, true, lifetime, 1, PBLEND_ADD, PARTICLE_BILLBOARD, -1, -1, -1, 1, 1, 0, 0, NULL); + } + break; + default: + Con_Printf ("CL_ParticleRain: unknown type %i (0 = rain, 1 = snow)\n", type); + } +} + +cvar_t r_drawparticles = {0, "r_drawparticles", "1", "enables drawing of particles"}; +static cvar_t r_drawparticles_drawdistance = {CVAR_SAVE, "r_drawparticles_drawdistance", "2000", "particles further than drawdistance*size will not be drawn"}; +static cvar_t r_drawparticles_nearclip_min = {CVAR_SAVE, "r_drawparticles_nearclip_min", "4", "particles closer than drawnearclip_min will not be drawn"}; +static cvar_t r_drawparticles_nearclip_max = {CVAR_SAVE, "r_drawparticles_nearclip_max", "4", "particles closer than drawnearclip_min will be faded"}; +cvar_t r_drawdecals = {0, "r_drawdecals", "1", "enables drawing of decals"}; +static cvar_t r_drawdecals_drawdistance = {CVAR_SAVE, "r_drawdecals_drawdistance", "500", "decals further than drawdistance*size will not be drawn"}; + +#define PARTICLETEXTURESIZE 64 +#define PARTICLEFONTSIZE (PARTICLETEXTURESIZE*8) + +static unsigned char shadebubble(float dx, float dy, vec3_t light) +{ + float dz, f, dot; + vec3_t normal; + dz = 1 - (dx*dx+dy*dy); + if (dz > 0) // it does hit the sphere + { + f = 0; + // back side + normal[0] = dx;normal[1] = dy;normal[2] = dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + // front side + normal[0] = dx;normal[1] = dy;normal[2] = -dz; + VectorNormalize(normal); + dot = DotProduct(normal, light); + if (dot > 0.5) // interior reflection + f += ((dot * 2) - 1); + else if (dot < -0.5) // exterior reflection + f += ((dot * -2) - 1); + f *= 128; + f += 16; // just to give it a haze so you can see the outline + f = bound(0, f, 255); + return (unsigned char) f; + } + else + return 0; +} + +int particlefontwidth, particlefontheight, particlefontcellwidth, particlefontcellheight, particlefontrows, particlefontcols; +static void CL_Particle_PixelCoordsForTexnum(int texnum, int *basex, int *basey, int *width, int *height) +{ + *basex = (texnum % particlefontcols) * particlefontcellwidth; + *basey = ((texnum / particlefontcols) % particlefontrows) * particlefontcellheight; + *width = particlefontcellwidth; + *height = particlefontcellheight; +} + +static void setuptex(int texnum, unsigned char *data, unsigned char *particletexturedata) +{ + int basex, basey, w, h, y; + CL_Particle_PixelCoordsForTexnum(texnum, &basex, &basey, &w, &h); + if(w != PARTICLETEXTURESIZE || h != PARTICLETEXTURESIZE) + Sys_Error("invalid particle texture size for autogenerating"); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + memcpy(particletexturedata + ((basey + y) * PARTICLEFONTSIZE + basex) * 4, data + y * PARTICLETEXTURESIZE * 4, PARTICLETEXTURESIZE * 4); +} + +static void particletextureblotch(unsigned char *data, float radius, float red, float green, float blue, float alpha) +{ + int x, y; + float cx, cy, dx, dy, f, iradius; + unsigned char *d; + cx = (lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius) + lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius)) * 0.5f; + cy = (lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius) + lhrandom(radius + 1, PARTICLETEXTURESIZE - 2 - radius)) * 0.5f; + iradius = 1.0f / radius; + alpha *= (1.0f / 255.0f); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - cx); + dy = (y - cy); + f = (1.0f - sqrt(dx * dx + dy * dy) * iradius) * alpha; + if (f > 0) + { + if (f > 1) + f = 1; + d = data + (y * PARTICLETEXTURESIZE + x) * 4; + d[0] += (int)(f * (blue - d[0])); + d[1] += (int)(f * (green - d[1])); + d[2] += (int)(f * (red - d[2])); + } + } + } +} + +#if 0 +static void particletextureclamp(unsigned char *data, int minr, int ming, int minb, int maxr, int maxg, int maxb) +{ + int i; + for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4) + { + data[0] = bound(minb, data[0], maxb); + data[1] = bound(ming, data[1], maxg); + data[2] = bound(minr, data[2], maxr); + } +} +#endif + +static void particletextureinvert(unsigned char *data) +{ + int i; + for (i = 0;i < PARTICLETEXTURESIZE*PARTICLETEXTURESIZE;i++, data += 4) + { + data[0] = 255 - data[0]; + data[1] = 255 - data[1]; + data[2] = 255 - data[2]; + } +} + +// Those loops are in a separate function to work around an optimization bug in Mac OS X's GCC +static void R_InitBloodTextures (unsigned char *particletexturedata) +{ + int i, j, k, m; + size_t datasize = PARTICLETEXTURESIZE*PARTICLETEXTURESIZE*4; + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, datasize); + + // blood particles + for (i = 0;i < 8;i++) + { + memset(data, 255, datasize); + for (k = 0;k < 24;k++) + particletextureblotch(data, PARTICLETEXTURESIZE/16, 96, 0, 0, 160); + //particletextureclamp(data, 32, 32, 32, 255, 255, 255); + particletextureinvert(data); + setuptex(tex_bloodparticle[i], data, particletexturedata); + } + + // blood decals + for (i = 0;i < 8;i++) + { + memset(data, 255, datasize); + m = 8; + for (j = 1;j < 10;j++) + for (k = min(j, m - 1);k < m;k++) + particletextureblotch(data, (float)j*PARTICLETEXTURESIZE/64.0f, 96, 0, 0, 320 - j * 8); + //particletextureclamp(data, 32, 32, 32, 255, 255, 255); + particletextureinvert(data); + setuptex(tex_blooddecal[i], data, particletexturedata); + } + + Mem_Free(data); +} + +//uncomment this to make engine save out particle font to a tga file when run +//#define DUMPPARTICLEFONT + +static void R_InitParticleTexture (void) +{ + int x, y, d, i, k, m; + int basex, basey, w, h; + float dx, dy, f, s1, t1, s2, t2; + vec3_t light; + char *buf; + fs_offset_t filesize; + char texturename[MAX_QPATH]; + skinframe_t *sf; + + // a note: decals need to modulate (multiply) the background color to + // properly darken it (stain), and they need to be able to alpha fade, + // this is a very difficult challenge because it means fading to white + // (no change to background) rather than black (darkening everything + // behind the whole decal polygon), and to accomplish this the texture is + // inverted (dark red blood on white background becomes brilliant cyan + // and white on black background) so we can alpha fade it to black, then + // we invert it again during the blendfunc to make it work... + +#ifndef DUMPPARTICLEFONT + decalskinframe = R_SkinFrame_LoadExternal("particles/particlefont.tga", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, false); + if (decalskinframe) + { + particlefonttexture = decalskinframe->base; + // TODO maybe allow custom grid size? + particlefontwidth = image_width; + particlefontheight = image_height; + particlefontcellwidth = image_width / 8; + particlefontcellheight = image_height / 8; + particlefontcols = 8; + particlefontrows = 8; + } + else +#endif + { + unsigned char *particletexturedata = (unsigned char *)Mem_Alloc(tempmempool, PARTICLEFONTSIZE*PARTICLEFONTSIZE*4); + size_t datasize = PARTICLETEXTURESIZE*PARTICLETEXTURESIZE*4; + unsigned char *data = (unsigned char *)Mem_Alloc(tempmempool, datasize); + unsigned char *noise1 = (unsigned char *)Mem_Alloc(tempmempool, PARTICLETEXTURESIZE*2*PARTICLETEXTURESIZE*2); + unsigned char *noise2 = (unsigned char *)Mem_Alloc(tempmempool, PARTICLETEXTURESIZE*2*PARTICLETEXTURESIZE*2); + + particlefontwidth = particlefontheight = PARTICLEFONTSIZE; + particlefontcellwidth = particlefontcellheight = PARTICLETEXTURESIZE; + particlefontcols = 8; + particlefontrows = 8; + + memset(particletexturedata, 255, PARTICLEFONTSIZE*PARTICLEFONTSIZE*4); + + // smoke + for (i = 0;i < 8;i++) + { + memset(data, 255, datasize); + do + { + fractalnoise(noise1, PARTICLETEXTURESIZE*2, PARTICLETEXTURESIZE/8); + fractalnoise(noise2, PARTICLETEXTURESIZE*2, PARTICLETEXTURESIZE/4); + m = 0; + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + d = (noise2[y*PARTICLETEXTURESIZE*2+x] - 128) * 3 + 192; + if (d > 0) + d = (int)(d * (1-(dx*dx+dy*dy))); + d = (d * noise1[y*PARTICLETEXTURESIZE*2+x]) >> 7; + d = bound(0, d, 255); + data[(y*PARTICLETEXTURESIZE+x)*4+3] = (unsigned char) d; + if (m < d) + m = d; + } + } + } + while (m < 224); + setuptex(tex_smoke[i], data, particletexturedata); + } + + // rain splash + memset(data, 255, datasize); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + f = 255.0f * (1.0 - 4.0f * fabs(10.0f - sqrt(dx*dx+dy*dy))); + data[(y*PARTICLETEXTURESIZE+x)*4+3] = (int) (bound(0.0f, f, 255.0f)); + } + } + setuptex(tex_rainsplash, data, particletexturedata); + + // normal particle + memset(data, 255, datasize); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + d = (int)(256 * (1 - (dx*dx+dy*dy))); + d = bound(0, d, 255); + data[(y*PARTICLETEXTURESIZE+x)*4+3] = (unsigned char) d; + } + } + setuptex(tex_particle, data, particletexturedata); + + // rain + memset(data, 255, datasize); + light[0] = 1;light[1] = 1;light[2] = 1; + VectorNormalize(light); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + // stretch upper half of bubble by +50% and shrink lower half by -50% + // (this gives an elongated teardrop shape) + if (dy > 0.5f) + dy = (dy - 0.5f) * 2.0f; + else + dy = (dy - 0.5f) / 1.5f; + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + // shrink bubble width to half + dx *= 2.0f; + data[(y*PARTICLETEXTURESIZE+x)*4+3] = shadebubble(dx, dy, light); + } + } + setuptex(tex_raindrop, data, particletexturedata); + + // bubble + memset(data, 255, datasize); + light[0] = 1;light[1] = 1;light[2] = 1; + VectorNormalize(light); + for (y = 0;y < PARTICLETEXTURESIZE;y++) + { + dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + for (x = 0;x < PARTICLETEXTURESIZE;x++) + { + dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1); + data[(y*PARTICLETEXTURESIZE+x)*4+3] = shadebubble(dx, dy, light); + } + } + setuptex(tex_bubble, data, particletexturedata); + + // Blood particles and blood decals + R_InitBloodTextures (particletexturedata); + + // bullet decals + for (i = 0;i < 8;i++) + { + memset(data, 255, datasize); + for (k = 0;k < 12;k++) + particletextureblotch(data, PARTICLETEXTURESIZE/16, 0, 0, 0, 128); + for (k = 0;k < 3;k++) + particletextureblotch(data, PARTICLETEXTURESIZE/2, 0, 0, 0, 160); + //particletextureclamp(data, 64, 64, 64, 255, 255, 255); + particletextureinvert(data); + setuptex(tex_bulletdecal[i], data, particletexturedata); + } + +#ifdef DUMPPARTICLEFONT + Image_WriteTGABGRA ("particles/particlefont.tga", PARTICLEFONTSIZE, PARTICLEFONTSIZE, particletexturedata); +#endif + + decalskinframe = R_SkinFrame_LoadInternalBGRA("particlefont", TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, particletexturedata, PARTICLEFONTSIZE, PARTICLEFONTSIZE, false); + particlefonttexture = decalskinframe->base; + + Mem_Free(particletexturedata); + Mem_Free(data); + Mem_Free(noise1); + Mem_Free(noise2); + } + for (i = 0;i < MAX_PARTICLETEXTURES;i++) + { + CL_Particle_PixelCoordsForTexnum(i, &basex, &basey, &w, &h); + particletexture[i].texture = particlefonttexture; + particletexture[i].s1 = (basex + 1) / (float)particlefontwidth; + particletexture[i].t1 = (basey + 1) / (float)particlefontheight; + particletexture[i].s2 = (basex + w - 1) / (float)particlefontwidth; + particletexture[i].t2 = (basey + h - 1) / (float)particlefontheight; + } + +#ifndef DUMPPARTICLEFONT + particletexture[tex_beam].texture = loadtextureimage(particletexturepool, "particles/nexbeam.tga", false, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true, vid.sRGB3D); + if (!particletexture[tex_beam].texture) +#endif + { + unsigned char noise3[64][64], data2[64][16][4]; + // nexbeam + fractalnoise(&noise3[0][0], 64, 4); + m = 0; + for (y = 0;y < 64;y++) + { + dy = (y - 0.5f*64) / (64*0.5f-1); + for (x = 0;x < 16;x++) + { + dx = (x - 0.5f*16) / (16*0.5f-2); + d = (int)((1 - sqrt(fabs(dx))) * noise3[y][x]); + data2[y][x][0] = data2[y][x][1] = data2[y][x][2] = (unsigned char) bound(0, d, 255); + data2[y][x][3] = 255; + } + } + +#ifdef DUMPPARTICLEFONT + Image_WriteTGABGRA ("particles/nexbeam.tga", 64, 64, &data2[0][0][0]); +#endif + particletexture[tex_beam].texture = R_LoadTexture2D(particletexturepool, "nexbeam", 16, 64, &data2[0][0][0], TEXTYPE_BGRA, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, -1, NULL); + } + particletexture[tex_beam].s1 = 0; + particletexture[tex_beam].t1 = 0; + particletexture[tex_beam].s2 = 1; + particletexture[tex_beam].t2 = 1; + + // now load an texcoord/texture override file + buf = (char *) FS_LoadFile("particles/particlefont.txt", tempmempool, false, &filesize); + if(buf) + { + const char *bufptr; + bufptr = buf; + for(;;) + { + if(!COM_ParseToken_Simple(&bufptr, true, false, true)) + break; + if(!strcmp(com_token, "\n")) + continue; // empty line + i = atoi(com_token); + + texturename[0] = 0; + s1 = 0; + t1 = 0; + s2 = 1; + t2 = 1; + + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) + { + strlcpy(texturename, com_token, sizeof(texturename)); + s1 = atof(com_token); + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) + { + texturename[0] = 0; + t1 = atof(com_token); + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) + { + s2 = atof(com_token); + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) + { + t2 = atof(com_token); + strlcpy(texturename, "particles/particlefont.tga", sizeof(texturename)); + if (COM_ParseToken_Simple(&bufptr, true, false, true) && strcmp(com_token, "\n")) + strlcpy(texturename, com_token, sizeof(texturename)); + } + } + } + else + s1 = 0; + } + if (!texturename[0]) + { + Con_Printf("particles/particlefont.txt: syntax should be texnum x1 y1 x2 y2 texturename or texnum x1 y1 x2 y2 or texnum texturename\n"); + continue; + } + if (i < 0 || i >= MAX_PARTICLETEXTURES) + { + Con_Printf("particles/particlefont.txt: texnum %i outside valid range (0 to %i)\n", i, MAX_PARTICLETEXTURES); + continue; + } + sf = R_SkinFrame_LoadExternal(texturename, TEXF_ALPHA | TEXF_FORCELINEAR | TEXF_RGBMULTIPLYBYALPHA, true); // note: this loads as sRGB if sRGB is active! + if(!sf) + { + // R_SkinFrame_LoadExternal already complained + continue; + } + particletexture[i].texture = sf->base; + particletexture[i].s1 = s1; + particletexture[i].t1 = t1; + particletexture[i].s2 = s2; + particletexture[i].t2 = t2; + } + Mem_Free(buf); + } +} + +static void r_part_start(void) +{ + int i; + // generate particlepalette for convenience from the main one + for (i = 0;i < 256;i++) + particlepalette[i] = palette_rgb[i][0] * 65536 + palette_rgb[i][1] * 256 + palette_rgb[i][2]; + particletexturepool = R_AllocTexturePool(); + R_InitParticleTexture (); + CL_Particles_LoadEffectInfo(NULL); +} + +static void r_part_shutdown(void) +{ + R_FreeTexturePool(&particletexturepool); +} + +static void r_part_newmap(void) +{ + if (decalskinframe) + R_SkinFrame_MarkUsed(decalskinframe); + CL_Particles_LoadEffectInfo(NULL); +} + +unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6]; +float particle_vertex3f[MESHQUEUE_TRANSPARENT_BATCHSIZE*12], particle_texcoord2f[MESHQUEUE_TRANSPARENT_BATCHSIZE*8], particle_color4f[MESHQUEUE_TRANSPARENT_BATCHSIZE*16]; + +void R_Particles_Init (void) +{ + int i; + for (i = 0;i < MESHQUEUE_TRANSPARENT_BATCHSIZE;i++) + { + particle_elements[i*6+0] = i*4+0; + particle_elements[i*6+1] = i*4+1; + particle_elements[i*6+2] = i*4+2; + particle_elements[i*6+3] = i*4+0; + particle_elements[i*6+4] = i*4+2; + particle_elements[i*6+5] = i*4+3; + } + + Cvar_RegisterVariable(&r_drawparticles); + Cvar_RegisterVariable(&r_drawparticles_drawdistance); + Cvar_RegisterVariable(&r_drawparticles_nearclip_min); + Cvar_RegisterVariable(&r_drawparticles_nearclip_max); + Cvar_RegisterVariable(&r_drawdecals); + Cvar_RegisterVariable(&r_drawdecals_drawdistance); + R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap, NULL, NULL); +} + +static void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int surfacelistindex; + const decal_t *d; + float *v3f, *t2f, *c4f; + particletexture_t *tex; + vec_t right[3], up[3], size, ca; + float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value; + + RSurf_ActiveWorldEntity(); + + r_refdef.stats[r_stat_drawndecals] += numsurfaces; +// R_Mesh_ResetTextureState(); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(true); + GL_CullFace(GL_NONE); + + // generate all the vertices at once + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + d = cl.decals + surfacelist[surfacelistindex]; + + // calculate color + c4f = particle_color4f + 16*surfacelistindex; + ca = d->alpha * alphascale; + // ensure alpha multiplier saturates properly + if (ca > 1.0f / 256.0f) + ca = 1.0f / 256.0f; + if (r_refdef.fogenabled) + ca *= RSurf_FogVertex(d->org); + Vector4Set(c4f, d->color[0] * ca, d->color[1] * ca, d->color[2] * ca, 1); + Vector4Copy(c4f, c4f + 4); + Vector4Copy(c4f, c4f + 8); + Vector4Copy(c4f, c4f + 12); + + // calculate vertex positions + size = d->size * cl_particles_size.value; + VectorVectors(d->normal, right, up); + VectorScale(right, size, right); + VectorScale(up, size, up); + v3f = particle_vertex3f + 12*surfacelistindex; + v3f[ 0] = d->org[0] - right[0] - up[0]; + v3f[ 1] = d->org[1] - right[1] - up[1]; + v3f[ 2] = d->org[2] - right[2] - up[2]; + v3f[ 3] = d->org[0] - right[0] + up[0]; + v3f[ 4] = d->org[1] - right[1] + up[1]; + v3f[ 5] = d->org[2] - right[2] + up[2]; + v3f[ 6] = d->org[0] + right[0] + up[0]; + v3f[ 7] = d->org[1] + right[1] + up[1]; + v3f[ 8] = d->org[2] + right[2] + up[2]; + v3f[ 9] = d->org[0] + right[0] - up[0]; + v3f[10] = d->org[1] + right[1] - up[1]; + v3f[11] = d->org[2] + right[2] - up[2]; + + // calculate texcoords + tex = &particletexture[d->texnum]; + t2f = particle_texcoord2f + 8*surfacelistindex; + t2f[0] = tex->s1;t2f[1] = tex->t2; + t2f[2] = tex->s1;t2f[3] = tex->t1; + t2f[4] = tex->s2;t2f[5] = tex->t1; + t2f[6] = tex->s2;t2f[7] = tex->t2; + } + + // now render the decals all at once + // (this assumes they all use one particle font texture!) + GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1, false, false, true); + R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); + R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0); +} + +void R_DrawDecals (void) +{ + int i; + int drawdecals = r_drawdecals.integer; + decal_t *decal; + float frametime; + float decalfade; + float drawdist2; + int killsequence = cl.decalsequence - max(0, cl_decals_max.integer); + + frametime = bound(0, cl.time - cl.decals_updatetime, 1); + cl.decals_updatetime = bound(cl.time - 1, cl.decals_updatetime + frametime, cl.time + 1); + + // LordHavoc: early out conditions + if (!cl.num_decals) + return; + + decalfade = frametime * 256 / cl_decals_fadetime.value; + drawdist2 = r_drawdecals_drawdistance.value * r_refdef.view.quality; + drawdist2 = drawdist2*drawdist2; + + for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++) + { + if (!decal->typeindex) + continue; + + if (killsequence - decal->decalsequence > 0) + goto killdecal; + + if (cl.time > decal->time2 + cl_decals_time.value) + { + decal->alpha -= decalfade; + if (decal->alpha <= 0) + goto killdecal; + } + + if (decal->owner) + { + if (cl.entities[decal->owner].render.model == decal->ownermodel) + { + Matrix4x4_Transform(&cl.entities[decal->owner].render.matrix, decal->relativeorigin, decal->org); + Matrix4x4_Transform3x3(&cl.entities[decal->owner].render.matrix, decal->relativenormal, decal->normal); + } + else + goto killdecal; + } + + if(cl_decals_visculling.integer && decal->clusterindex > -1000 && !CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, decal->clusterindex)) + continue; + + if (!drawdecals) + continue; + + if (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size)) + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL); + continue; +killdecal: + decal->typeindex = 0; + if (cl.free_decal > i) + cl.free_decal = i; + } + + // reduce cl.num_decals if possible + while (cl.num_decals > 0 && cl.decals[cl.num_decals - 1].typeindex == 0) + cl.num_decals--; + + if (cl.num_decals == cl.max_decals && cl.max_decals < MAX_DECALS) + { + decal_t *olddecals = cl.decals; + cl.max_decals = min(cl.max_decals * 2, MAX_DECALS); + cl.decals = (decal_t *) Mem_Alloc(cls.levelmempool, cl.max_decals * sizeof(decal_t)); + memcpy(cl.decals, olddecals, cl.num_decals * sizeof(decal_t)); + Mem_Free(olddecals); + } + + r_refdef.stats[r_stat_totaldecals] = cl.num_decals; +} + +static void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + vec3_t vecorg, vecvel, baseright, baseup; + int surfacelistindex; + int batchstart, batchcount; + const particle_t *p; + pblend_t blendmode; + rtexture_t *texture; + float *v3f, *t2f, *c4f; + particletexture_t *tex; + float up2[3], v[3], right[3], up[3], fog, ifog, size, len, lenfactor, alpha; +// float ambient[3], diffuse[3], diffusenormal[3]; + float palpha, spintime, spinrad, spincos, spinsin, spinm1, spinm2, spinm3, spinm4; + vec4_t colormultiplier; + float minparticledist_start, minparticledist_end; + qboolean dofade; + + RSurf_ActiveWorldEntity(); + + Vector4Set(colormultiplier, r_refdef.view.colorscale * (1.0 / 256.0f), r_refdef.view.colorscale * (1.0 / 256.0f), r_refdef.view.colorscale * (1.0 / 256.0f), cl_particles_alpha.value * (1.0 / 256.0f)); + + r_refdef.stats[r_stat_particles] += numsurfaces; +// R_Mesh_ResetTextureState(); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(true); + GL_CullFace(GL_NONE); + + spintime = r_refdef.scene.time; + + minparticledist_start = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_min.value; + minparticledist_end = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_max.value; + dofade = (minparticledist_start < minparticledist_end); + + // first generate all the vertices at once + for (surfacelistindex = 0, v3f = particle_vertex3f, t2f = particle_texcoord2f, c4f = particle_color4f;surfacelistindex < numsurfaces;surfacelistindex++, v3f += 3*4, t2f += 2*4, c4f += 4*4) + { + p = cl.particles + surfacelist[surfacelistindex]; + + blendmode = (pblend_t)p->blendmode; + palpha = p->alpha; + if(dofade && p->orientation != PARTICLE_VBEAM && p->orientation != PARTICLE_HBEAM) + palpha *= min(1, (DotProduct(p->org, r_refdef.view.forward) - minparticledist_start) / (minparticledist_end - minparticledist_start)); + alpha = palpha * colormultiplier[3]; + // ensure alpha multiplier saturates properly + if (alpha > 1.0f) + alpha = 1.0f; + + switch (blendmode) + { + case PBLEND_INVALID: + case PBLEND_INVMOD: + // additive and modulate can just fade out in fog (this is correct) + if (r_refdef.fogenabled) + alpha *= RSurf_FogVertex(p->org); + // collapse alpha into color for these blends (so that the particlefont does not need alpha on most textures) + alpha *= 1.0f / 256.0f; + c4f[0] = p->color[0] * alpha; + c4f[1] = p->color[1] * alpha; + c4f[2] = p->color[2] * alpha; + c4f[3] = 0; + break; + case PBLEND_ADD: + // additive and modulate can just fade out in fog (this is correct) + if (r_refdef.fogenabled) + alpha *= RSurf_FogVertex(p->org); + // collapse alpha into color for these blends (so that the particlefont does not need alpha on most textures) + c4f[0] = p->color[0] * colormultiplier[0] * alpha; + c4f[1] = p->color[1] * colormultiplier[1] * alpha; + c4f[2] = p->color[2] * colormultiplier[2] * alpha; + c4f[3] = 0; + break; + case PBLEND_ALPHA: + c4f[0] = p->color[0] * colormultiplier[0]; + c4f[1] = p->color[1] * colormultiplier[1]; + c4f[2] = p->color[2] * colormultiplier[2]; + c4f[3] = alpha; + // note: lighting is not cheap! + if (particletype[p->typeindex].lighting) + { + vecorg[0] = p->org[0]; + vecorg[1] = p->org[1]; + vecorg[2] = p->org[2]; + R_LightPoint(c4f, vecorg, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + } + // mix in the fog color + if (r_refdef.fogenabled) + { + fog = RSurf_FogVertex(p->org); + ifog = 1 - fog; + c4f[0] = c4f[0] * fog + r_refdef.fogcolor[0] * ifog; + c4f[1] = c4f[1] * fog + r_refdef.fogcolor[1] * ifog; + c4f[2] = c4f[2] * fog + r_refdef.fogcolor[2] * ifog; + } + // for premultiplied alpha we have to apply the alpha to the color (after fog of course) + VectorScale(c4f, alpha, c4f); + break; + } + // copy the color into the other three vertices + Vector4Copy(c4f, c4f + 4); + Vector4Copy(c4f, c4f + 8); + Vector4Copy(c4f, c4f + 12); + + size = p->size * cl_particles_size.value; + tex = &particletexture[p->texnum]; + switch(p->orientation) + { +// case PARTICLE_INVALID: + case PARTICLE_BILLBOARD: + if (p->angle + p->spin) + { + spinrad = (p->angle + p->spin * (spintime - p->delayedspawn)) * (float)(M_PI / 180.0f); + spinsin = sin(spinrad) * size; + spincos = cos(spinrad) * size; + spinm1 = -p->stretch * spincos; + spinm2 = -spinsin; + spinm3 = spinsin; + spinm4 = -p->stretch * spincos; + VectorMAM(spinm1, r_refdef.view.left, spinm2, r_refdef.view.up, right); + VectorMAM(spinm3, r_refdef.view.left, spinm4, r_refdef.view.up, up); + } + else + { + VectorScale(r_refdef.view.left, -size * p->stretch, right); + VectorScale(r_refdef.view.up, size, up); + } + + v3f[ 0] = p->org[0] - right[0] - up[0]; + v3f[ 1] = p->org[1] - right[1] - up[1]; + v3f[ 2] = p->org[2] - right[2] - up[2]; + v3f[ 3] = p->org[0] - right[0] + up[0]; + v3f[ 4] = p->org[1] - right[1] + up[1]; + v3f[ 5] = p->org[2] - right[2] + up[2]; + v3f[ 6] = p->org[0] + right[0] + up[0]; + v3f[ 7] = p->org[1] + right[1] + up[1]; + v3f[ 8] = p->org[2] + right[2] + up[2]; + v3f[ 9] = p->org[0] + right[0] - up[0]; + v3f[10] = p->org[1] + right[1] - up[1]; + v3f[11] = p->org[2] + right[2] - up[2]; + t2f[0] = tex->s1;t2f[1] = tex->t2; + t2f[2] = tex->s1;t2f[3] = tex->t1; + t2f[4] = tex->s2;t2f[5] = tex->t1; + t2f[6] = tex->s2;t2f[7] = tex->t2; + break; + case PARTICLE_ORIENTED_DOUBLESIDED: + vecvel[0] = p->vel[0]; + vecvel[1] = p->vel[1]; + vecvel[2] = p->vel[2]; + VectorVectors(vecvel, baseright, baseup); + if (p->angle + p->spin) + { + spinrad = (p->angle + p->spin * (spintime - p->delayedspawn)) * (float)(M_PI / 180.0f); + spinsin = sin(spinrad) * size; + spincos = cos(spinrad) * size; + spinm1 = p->stretch * spincos; + spinm2 = -spinsin; + spinm3 = spinsin; + spinm4 = p->stretch * spincos; + VectorMAM(spinm1, baseright, spinm2, baseup, right); + VectorMAM(spinm3, baseright, spinm4, baseup, up); + } + else + { + VectorScale(baseright, size * p->stretch, right); + VectorScale(baseup, size, up); + } + v3f[ 0] = p->org[0] - right[0] - up[0]; + v3f[ 1] = p->org[1] - right[1] - up[1]; + v3f[ 2] = p->org[2] - right[2] - up[2]; + v3f[ 3] = p->org[0] - right[0] + up[0]; + v3f[ 4] = p->org[1] - right[1] + up[1]; + v3f[ 5] = p->org[2] - right[2] + up[2]; + v3f[ 6] = p->org[0] + right[0] + up[0]; + v3f[ 7] = p->org[1] + right[1] + up[1]; + v3f[ 8] = p->org[2] + right[2] + up[2]; + v3f[ 9] = p->org[0] + right[0] - up[0]; + v3f[10] = p->org[1] + right[1] - up[1]; + v3f[11] = p->org[2] + right[2] - up[2]; + t2f[0] = tex->s1;t2f[1] = tex->t2; + t2f[2] = tex->s1;t2f[3] = tex->t1; + t2f[4] = tex->s2;t2f[5] = tex->t1; + t2f[6] = tex->s2;t2f[7] = tex->t2; + break; + case PARTICLE_SPARK: + len = VectorLength(p->vel); + VectorNormalize2(p->vel, up); + lenfactor = p->stretch * 0.04 * len; + if(lenfactor < size * 0.5) + lenfactor = size * 0.5; + VectorMA(p->org, -lenfactor, up, v); + VectorMA(p->org, lenfactor, up, up2); + R_CalcBeam_Vertex3f(v3f, v, up2, size); + t2f[0] = tex->s1;t2f[1] = tex->t2; + t2f[2] = tex->s1;t2f[3] = tex->t1; + t2f[4] = tex->s2;t2f[5] = tex->t1; + t2f[6] = tex->s2;t2f[7] = tex->t2; + break; + case PARTICLE_VBEAM: + R_CalcBeam_Vertex3f(v3f, p->org, p->vel, size); + VectorSubtract(p->vel, p->org, up); + VectorNormalize(up); + v[0] = DotProduct(p->org, up) * (1.0f / 64.0f) * p->stretch; + v[1] = DotProduct(p->vel, up) * (1.0f / 64.0f) * p->stretch; + t2f[0] = tex->s2;t2f[1] = v[0]; + t2f[2] = tex->s1;t2f[3] = v[0]; + t2f[4] = tex->s1;t2f[5] = v[1]; + t2f[6] = tex->s2;t2f[7] = v[1]; + break; + case PARTICLE_HBEAM: + R_CalcBeam_Vertex3f(v3f, p->org, p->vel, size); + VectorSubtract(p->vel, p->org, up); + VectorNormalize(up); + v[0] = DotProduct(p->org, up) * (1.0f / 64.0f) * p->stretch; + v[1] = DotProduct(p->vel, up) * (1.0f / 64.0f) * p->stretch; + t2f[0] = v[0];t2f[1] = tex->t1; + t2f[2] = v[0];t2f[3] = tex->t2; + t2f[4] = v[1];t2f[5] = tex->t2; + t2f[6] = v[1];t2f[7] = tex->t1; + break; + } + } + + // now render batches of particles based on blendmode and texture + blendmode = PBLEND_INVALID; + texture = NULL; + batchstart = 0; + batchcount = 0; + R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;) + { + p = cl.particles + surfacelist[surfacelistindex]; + + if (texture != particletexture[p->texnum].texture) + { + texture = particletexture[p->texnum].texture; + R_SetupShader_Generic(texture, NULL, GL_MODULATE, 1, false, false, false); + } + + if (p->blendmode == PBLEND_INVMOD) + { + // inverse modulate blend - group these + GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + // iterate until we find a change in settings + batchstart = surfacelistindex++; + for (;surfacelistindex < numsurfaces;surfacelistindex++) + { + p = cl.particles + surfacelist[surfacelistindex]; + if (p->blendmode != PBLEND_INVMOD || texture != particletexture[p->texnum].texture) + break; + } + } + else + { + // additive or alpha blend - group these + // (we can group these because we premultiplied the texture alpha) + GL_BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + // iterate until we find a change in settings + batchstart = surfacelistindex++; + for (;surfacelistindex < numsurfaces;surfacelistindex++) + { + p = cl.particles + surfacelist[surfacelistindex]; + if (p->blendmode == PBLEND_INVMOD || texture != particletexture[p->texnum].texture) + break; + } + } + + batchcount = surfacelistindex - batchstart; + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, NULL, 0, particle_elements, NULL, 0); + } +} + +void R_DrawParticles (void) +{ + int i, a; + int drawparticles = r_drawparticles.integer; + float minparticledist_start; + particle_t *p; + float gravity, frametime, f, dist, oldorg[3], decaldir[3]; + float drawdist2; + int hitent; + trace_t trace; + qboolean update; + + frametime = bound(0, cl.time - cl.particles_updatetime, 1); + cl.particles_updatetime = bound(cl.time - 1, cl.particles_updatetime + frametime, cl.time + 1); + + // LordHavoc: early out conditions + if (!cl.num_particles) + return; + + minparticledist_start = DotProduct(r_refdef.view.origin, r_refdef.view.forward) + r_drawparticles_nearclip_min.value; + gravity = frametime * cl.movevars_gravity; + update = frametime > 0; + drawdist2 = r_drawparticles_drawdistance.value * r_refdef.view.quality; + drawdist2 = drawdist2*drawdist2; + + for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++) + { + if (!p->typeindex) + { + if (cl.free_particle > i) + cl.free_particle = i; + continue; + } + + if (update) + { + if (p->delayedspawn > cl.time) + continue; + + p->size += p->sizeincrease * frametime; + p->alpha -= p->alphafade * frametime; + + if (p->alpha <= 0 || p->die <= cl.time) + goto killparticle; + + if (p->orientation != PARTICLE_VBEAM && p->orientation != PARTICLE_HBEAM && frametime > 0) + { + if (p->liquidfriction && cl_particles_collisions.integer && (CL_PointSuperContents(p->org) & SUPERCONTENTS_LIQUIDSMASK)) + { + if (p->typeindex == pt_blood) + p->size += frametime * 8; + else + p->vel[2] -= p->gravity * gravity; + f = 1.0f - min(p->liquidfriction * frametime, 1); + VectorScale(p->vel, f, p->vel); + } + else + { + p->vel[2] -= p->gravity * gravity; + if (p->airfriction) + { + f = 1.0f - min(p->airfriction * frametime, 1); + VectorScale(p->vel, f, p->vel); + } + } + + VectorCopy(p->org, oldorg); + VectorMA(p->org, frametime, p->vel, p->org); +// if (p->bounce && cl.time >= p->delayedcollisions) + if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel)) + { + trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false, false); + // if the trace started in or hit something of SUPERCONTENTS_NODROP + // or if the trace hit something flagged as NOIMPACT + // then remove the particle + if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT || ((trace.startsupercontents | trace.hitsupercontents) & SUPERCONTENTS_NODROP) || (trace.startsupercontents & SUPERCONTENTS_SOLID)) + goto killparticle; + VectorCopy(trace.endpos, p->org); + // react if the particle hit something + if (trace.fraction < 1) + { + VectorCopy(trace.endpos, p->org); + + if (p->staintexnum >= 0) + { + // blood - splash on solid + if (!(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS)) + { + R_Stain(p->org, 16, + p->staincolor[0], p->staincolor[1], p->staincolor[2], (int)(p->stainalpha * p->stainsize * (1.0f / 160.0f)), + p->staincolor[0], p->staincolor[1], p->staincolor[2], (int)(p->stainalpha * p->stainsize * (1.0f / 160.0f))); + if (cl_decals.integer) + { + // create a decal for the blood splat + a = 0xFFFFFF ^ (p->staincolor[0]*65536+p->staincolor[1]*256+p->staincolor[2]); + if (cl_decals_newsystem_bloodsmears.integer) + { + VectorCopy(p->vel, decaldir); + VectorNormalize(decaldir); + } + else + VectorCopy(trace.plane.normal, decaldir); + CL_SpawnDecalParticleForSurface(hitent, p->org, decaldir, a, a, p->staintexnum, p->stainsize, p->stainalpha); // staincolor needs to be inverted for decals! + } + } + } + + if (p->typeindex == pt_blood) + { + // blood - splash on solid + if (trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS) + goto killparticle; + if(p->staintexnum == -1) // staintex < -1 means no stains at all + { + R_Stain(p->org, 16, 64, 16, 16, (int)(p->alpha * p->size * (1.0f / 80.0f)), 64, 32, 32, (int)(p->alpha * p->size * (1.0f / 80.0f))); + if (cl_decals.integer) + { + // create a decal for the blood splat + if (cl_decals_newsystem_bloodsmears.integer) + { + VectorCopy(p->vel, decaldir); + VectorNormalize(decaldir); + } + else + VectorCopy(trace.plane.normal, decaldir); + CL_SpawnDecalParticleForSurface(hitent, p->org, decaldir, p->color[0] * 65536 + p->color[1] * 256 + p->color[2], p->color[0] * 65536 + p->color[1] * 256 + p->color[2], tex_blooddecal[rand()&7], p->size * lhrandom(cl_particles_blood_decal_scalemin.value, cl_particles_blood_decal_scalemax.value), cl_particles_blood_decal_alpha.value * 768); + } + } + goto killparticle; + } + else if (p->bounce < 0) + { + // bounce -1 means remove on impact + goto killparticle; + } + else + { + // anything else - bounce off solid + dist = DotProduct(p->vel, trace.plane.normal) * -p->bounce; + VectorMA(p->vel, dist, trace.plane.normal, p->vel); + } + } + } + + if (VectorLength2(p->vel) < 0.03) + { + if(p->orientation == PARTICLE_SPARK) // sparks are virtually invisible if very slow, so rather let them go off + goto killparticle; + VectorClear(p->vel); + } + } + + if (p->typeindex != pt_static) + { + switch (p->typeindex) + { + case pt_entityparticle: + // particle that removes itself after one rendered frame + if (p->time2) + goto killparticle; + else + p->time2 = 1; + break; + case pt_blood: + a = CL_PointSuperContents(p->org); + if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP)) + goto killparticle; + break; + case pt_bubble: + a = CL_PointSuperContents(p->org); + if (!(a & (SUPERCONTENTS_WATER | SUPERCONTENTS_SLIME))) + goto killparticle; + break; + case pt_rain: + a = CL_PointSuperContents(p->org); + if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) + goto killparticle; + break; + case pt_snow: + if (cl.time > p->time2) + { + // snow flutter + p->time2 = cl.time + (rand() & 3) * 0.1; + p->vel[0] = p->vel[0] * 0.9f + lhrandom(-32, 32); + p->vel[1] = p->vel[0] * 0.9f + lhrandom(-32, 32); + } + a = CL_PointSuperContents(p->org); + if (a & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK)) + goto killparticle; + break; + default: + break; + } + } + } + else if (p->delayedspawn > cl.time) + continue; + if (!drawparticles) + continue; + // don't render particles too close to the view (they chew fillrate) + // also don't render particles behind the view (useless) + // further checks to cull to the frustum would be too slow here + switch(p->typeindex) + { + case pt_beam: + // beams have no culling + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL); + break; + default: + if(cl_particles_visculling.integer) + if (!r_refdef.viewcache.world_novis) + if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf) + { + mleaf_t *leaf = r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, p->org); + if(leaf) + if(!CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, leaf->clusterindex)) + continue; + } + // anything else just has to be in front of the viewer and visible at this distance + if (DotProduct(p->org, r_refdef.view.forward) >= minparticledist_start && VectorDistance2(p->org, r_refdef.view.origin) < drawdist2 * (p->size * p->size)) + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, p->sortorigin, R_DrawParticle_TransparentCallback, NULL, i, NULL); + break; + } + + continue; +killparticle: + p->typeindex = 0; + if (cl.free_particle > i) + cl.free_particle = i; + } + + // reduce cl.num_particles if possible + while (cl.num_particles > 0 && cl.particles[cl.num_particles - 1].typeindex == 0) + cl.num_particles--; + + if (cl.num_particles == cl.max_particles && cl.max_particles < MAX_PARTICLES) + { + particle_t *oldparticles = cl.particles; + cl.max_particles = min(cl.max_particles * 2, MAX_PARTICLES); + cl.particles = (particle_t *) Mem_Alloc(cls.levelmempool, cl.max_particles * sizeof(particle_t)); + memcpy(cl.particles, oldparticles, cl.num_particles * sizeof(particle_t)); + Mem_Free(oldparticles); + } +} diff --git a/app/jni/cl_screen.c b/app/jni/cl_screen.c new file mode 100644 index 0000000..fcda851 --- /dev/null +++ b/app/jni/cl_screen.c @@ -0,0 +1,2788 @@ + +#include "quakedef.h" +#include "cl_video.h" +#include "image.h" +#include "jpeg.h" +#include "image_png.h" +#include "cl_collision.h" +#include "libcurl.h" +#include "csprogs.h" +#include "cap_avi.h" +#include "cap_ogg.h" + +// we have to include snd_main.h here only to get access to snd_renderbuffer->format.speed when writing the AVI headers +#include "snd_main.h" + +cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100", "how large the view should be, 110 disables inventory bar, 120 disables status bar"}; +cvar_t scr_fov = {CVAR_SAVE, "fov","110", "field of vision, 1-170 degrees, default 110, some players use 110-130"}; +cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1", "opacity of console background gfx/conback"}; +cvar_t scr_conalphafactor = {CVAR_SAVE, "scr_conalphafactor", "1", "opacity of console background gfx/conback relative to scr_conalpha; when 0, gfx/conback is not drawn"}; +cvar_t scr_conalpha2factor = {CVAR_SAVE, "scr_conalpha2factor", "0", "opacity of console background gfx/conback2 relative to scr_conalpha; when 0, gfx/conback2 is not drawn"}; +cvar_t scr_conalpha3factor = {CVAR_SAVE, "scr_conalpha3factor", "0", "opacity of console background gfx/conback3 relative to scr_conalpha; when 0, gfx/conback3 is not drawn"}; +cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "1", "brightness of console background (0 = black, 1 = image)"}; +cvar_t scr_conforcewhiledisconnected = {0, "scr_conforcewhiledisconnected", "1", "forces fullscreen console while disconnected"}; +cvar_t scr_conscroll_x = {CVAR_SAVE, "scr_conscroll_x", "0", "scroll speed of gfx/conback in x direction"}; +cvar_t scr_conscroll_y = {CVAR_SAVE, "scr_conscroll_y", "0", "scroll speed of gfx/conback in y direction"}; +cvar_t scr_conscroll2_x = {CVAR_SAVE, "scr_conscroll2_x", "0", "scroll speed of gfx/conback2 in x direction"}; +cvar_t scr_conscroll2_y = {CVAR_SAVE, "scr_conscroll2_y", "0", "scroll speed of gfx/conback2 in y direction"}; +cvar_t scr_conscroll3_x = {CVAR_SAVE, "scr_conscroll3_x", "0", "scroll speed of gfx/conback3 in x direction"}; +cvar_t scr_conscroll3_y = {CVAR_SAVE, "scr_conscroll3_y", "0", "scroll speed of gfx/conback3 in y direction"}; +cvar_t scr_menuforcewhiledisconnected = {0, "scr_menuforcewhiledisconnected", "0", "forces menu while disconnected"}; +cvar_t scr_centertime = {0, "scr_centertime","3", "how long centerprint messages show"}; +cvar_t scr_showram = {CVAR_SAVE, "showram","1", "show ram icon if low on surface cache memory (not used)"}; +cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0", "show turtle icon when framerate is too low"}; +cvar_t scr_showpause = {CVAR_SAVE, "showpause","1", "show pause icon when game is paused"}; +cvar_t scr_showbrand = {0, "showbrand","0", "shows gfx/brand.tga in a corner of the screen (different values select different positions, including centered)"}; +cvar_t scr_printspeed = {0, "scr_printspeed","0", "speed of intermission printing (episode end texts), a value of 0 disables the slow printing"}; +cvar_t scr_loadingscreen_background = {0, "scr_loadingscreen_background","0", "show the last visible background during loading screen (costs one screenful of video memory)"}; +cvar_t scr_loadingscreen_scale = {0, "scr_loadingscreen_scale","1", "scale factor of the background"}; +cvar_t scr_loadingscreen_scale_base = {0, "scr_loadingscreen_scale_base","0", "0 = console pixels, 1 = video pixels"}; +cvar_t scr_loadingscreen_scale_limit = {0, "scr_loadingscreen_scale_limit","0", "0 = no limit, 1 = until first edge hits screen edge, 2 = until last edge hits screen edge, 3 = until width hits screen width, 4 = until height hits screen height"}; +cvar_t scr_loadingscreen_picture = {CVAR_SAVE, "scr_loadingscreen_picture", "gfx/loading", "picture shown during loading"}; +cvar_t scr_loadingscreen_count = {0, "scr_loadingscreen_count","1", "number of loading screen files to use randomly (named loading.tga, loading2.tga, loading3.tga, ...)"}; +cvar_t scr_loadingscreen_firstforstartup = {0, "scr_loadingscreen_firstforstartup","0", "remove loading.tga from random scr_loadingscreen_count selection and only display it on client startup, 0 = normal, 1 = firstforstartup"}; +cvar_t scr_loadingscreen_barcolor = {0, "scr_loadingscreen_barcolor", "0 0 1", "rgb color of loadingscreen progress bar"}; +cvar_t scr_loadingscreen_barheight = {0, "scr_loadingscreen_barheight", "8", "the height of the loadingscreen progress bar"}; +cvar_t scr_loadingscreen_maxfps = {0, "scr_loadingscreen_maxfps", "10", "restrict maximal FPS for loading screen so it will not update very often (this will make lesser loading times on a maps loading large number of models)"}; +cvar_t scr_infobar_height = {0, "scr_infobar_height", "8", "the height of the infobar items"}; +cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640", "virtual width of 2D graphics system"}; +cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480", "virtual height of 2D graphics system"}; +cvar_t vid_pixelheight = {CVAR_SAVE, "vid_pixelheight", "1", "adjusts vertical field of vision to account for non-square pixels (1280x1024 on a CRT monitor for example)"}; +cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"}; +cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"}; +cvar_t scr_screenshot_png = {CVAR_SAVE, "scr_screenshot_png","0", "save png instead of targa"}; +cvar_t scr_screenshot_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"}; +cvar_t scr_screenshot_hwgamma = {CVAR_SAVE, "scr_screenshot_hwgamma","1", "apply the video gamma ramp to saved screenshots and videos"}; +cvar_t scr_screenshot_alpha = {CVAR_SAVE, "scr_screenshot_alpha","0", "try to write an alpha channel to screenshots (debugging feature)"}; +cvar_t scr_screenshot_timestamp = {CVAR_SAVE, "scr_screenshot_timestamp", "1", "use a timestamp based number of the type YYYYMMDDHHMMSSsss instead of sequential numbering"}; +// scr_screenshot_name is defined in fs.c +cvar_t cl_capturevideo = {0, "cl_capturevideo", "0", "enables saving of video to a .avi file using uncompressed I420 colorspace and PCM audio, note that scr_screenshot_gammaboost affects the brightness of the output)"}; +cvar_t cl_capturevideo_demo_stop = {CVAR_SAVE, "cl_capturevideo_demo_stop", "1", "automatically stops video recording when demo ends"}; +cvar_t cl_capturevideo_printfps = {CVAR_SAVE, "cl_capturevideo_printfps", "1", "prints the frames per second captured in capturevideo (is only written to the log file, not to the console, as that would be visible on the video)"}; +cvar_t cl_capturevideo_width = {CVAR_SAVE, "cl_capturevideo_width", "0", "scales all frames to this resolution before saving the video"}; +cvar_t cl_capturevideo_height = {CVAR_SAVE, "cl_capturevideo_height", "0", "scales all frames to this resolution before saving the video"}; +cvar_t cl_capturevideo_realtime = {0, "cl_capturevideo_realtime", "0", "causes video saving to operate in realtime (mostly useful while playing, not while capturing demos), this can produce a much lower quality video due to poor sound/video sync and will abort saving if your machine stalls for over a minute"}; +cvar_t cl_capturevideo_fps = {CVAR_SAVE, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"}; +cvar_t cl_capturevideo_nameformat = {CVAR_SAVE, "cl_capturevideo_nameformat", "dpvideo", "prefix for saved videos (the date is encoded using strftime escapes)"}; +cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"}; +cvar_t cl_capturevideo_ogg = {CVAR_SAVE, "cl_capturevideo_ogg", "1", "save captured video data as Ogg/Vorbis/Theora streams"}; +cvar_t cl_capturevideo_framestep = {CVAR_SAVE, "cl_capturevideo_framestep", "1", "when set to n >= 1, render n frames to capture one (useful for motion blur like effects)"}; +cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"}; +cvar_t r_stereo_angle = {0, "r_stereo_angle", "0", "separation angle of eyes (makes the views look different directions, as an example, 90 gives a 90 degree separation where the views are 45 degrees left and 45 degrees right)"}; +cvar_t scr_stipple = {0, "scr_stipple", "0", "interlacing-like stippling of the display"}; +cvar_t scr_refresh = {0, "scr_refresh", "1", "allows you to completely shut off rendering for benchmarking purposes"}; +cvar_t scr_screenshot_name_in_mapdir = {CVAR_SAVE, "scr_screenshot_name_in_mapdir", "0", "if set to 1, screenshots are placed in a subdirectory named like the map they are from"}; +cvar_t shownetgraph = {CVAR_SAVE, "shownetgraph", "0", "shows a graph of packet sizes and other information, 0 = off, 1 = show client netgraph, 2 = show client and server netgraphs (when hosting a server)"}; +cvar_t cl_demo_mousegrab = {0, "cl_demo_mousegrab", "0", "Allows reading the mouse input while playing demos. Useful for camera mods developed in csqc. (0: never, 1: always)"}; +cvar_t timedemo_screenshotframelist = {0, "timedemo_screenshotframelist", "", "when performing a timedemo, take screenshots of each frame in this space-separated list - example: 1 201 401"}; +cvar_t vid_touchscreen_outlinealpha = {0, "vid_touchscreen_outlinealpha", "0.25", "opacity of touchscreen area outlines"}; +cvar_t vid_touchscreen_overlayalpha = {0, "vid_touchscreen_overlayalpha", "0.25", "opacity of touchscreen area icons"}; +cvar_t r_speeds_graph = {CVAR_SAVE, "r_speeds_graph", "0", "display a graph of renderer statistics "}; +cvar_t r_speeds_graph_filter[8] = +{ + {CVAR_SAVE, "r_speeds_graph_filter_r", "timedelta", "Red - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_g", "batch_batches", "Green - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_b", "batch_triangles", "Blue - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_y", "fast_triangles", "Yellow - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_c", "copytriangles_triangles", "Cyan - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_m", "dynamic_triangles", "Magenta - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_w", "animcache_shade_vertices", "White - display the specified renderer statistic"}, + {CVAR_SAVE, "r_speeds_graph_filter_o", "animcache_shape_vertices", "Orange - display the specified renderer statistic"}, +}; +cvar_t r_speeds_graph_length = {CVAR_SAVE, "r_speeds_graph_length", "1024", "number of frames in statistics graph, can be from 4 to 8192"}; +cvar_t r_speeds_graph_seconds = {CVAR_SAVE, "r_speeds_graph_seconds", "2", "number of seconds in graph, can be from 0.1 to 120"}; +cvar_t r_speeds_graph_x = {CVAR_SAVE, "r_speeds_graph_x", "0", "position of graph"}; +cvar_t r_speeds_graph_y = {CVAR_SAVE, "r_speeds_graph_y", "0", "position of graph"}; +cvar_t r_speeds_graph_width = {CVAR_SAVE, "r_speeds_graph_width", "256", "size of graph"}; +cvar_t r_speeds_graph_height = {CVAR_SAVE, "r_speeds_graph_height", "128", "size of graph"}; + + + +extern cvar_t v_glslgamma; +extern cvar_t sbar_info_pos; +extern cvar_t r_fog_clear; +#define WANT_SCREENSHOT_HWGAMMA (scr_screenshot_hwgamma.integer && vid_usinghwgamma) + +int jpeg_supported = false; + +qboolean scr_initialized; // ready to draw + +float scr_con_current; +int scr_con_margin_bottom; + +extern int con_vislines; + +extern void jni_BigScreenMode(int mode); + + +static void SCR_ScreenShot_f (void); +static void R_Envmap_f (void); + +// backend +void R_ClearScreen(qboolean fogcolor); + +/* +=============================================================================== + +CENTER PRINTING + +=============================================================================== +*/ + +char scr_centerstring[MAX_INPUTLINE]; +float scr_centertime_start; // for slow victory printing +float scr_centertime_off; +int scr_center_lines; +int scr_erase_lines; +int scr_erase_center; +char scr_infobarstring[MAX_INPUTLINE]; +float scr_infobartime_off; + +/* +============== +SCR_CenterPrint + +Called for important messages that should stay in the center of the screen +for a few moments +============== +*/ +void SCR_CenterPrint(const char *str) +{ + //Check to see if this is the shareware message, if so, replace with a more up to date + //relevant one + if (strstr(str, "1-800")) + { + char tempstr[] = "This episode isn't availble in the Shareware version\n" + "You can buy the full game of Quake for $10 on Steam:\n" + "http://store.steampowered.com/app/2310/"; + strlcpy(scr_centerstring, tempstr, sizeof(scr_centerstring)); + } + else { + strlcpy(scr_centerstring, str, sizeof(scr_centerstring)); + } + + scr_centertime_off = scr_centertime.value; + scr_centertime_start = cl.time; + +// count the number of lines for centering + scr_center_lines = 1; + while (*str) + { + if (*str == '\n') + scr_center_lines++; + str++; + } +} + + +static void SCR_DrawCenterString (void) +{ + char *start; + int x, y; + int remaining; + int color; + + if(cl.intermission == 2) // in finale, + if(sb_showscores) // make TAB hide the finale message (sb_showscores overrides finale in sbar.c) + return; + + if(scr_centertime.value <= 0 && !cl.intermission) + return; + +// the finale prints the characters one at a time, except if printspeed is an absurdly high value + if (cl.intermission && scr_printspeed.value > 0 && scr_printspeed.value < 1000000) + remaining = (int)(scr_printspeed.value * (cl.time - scr_centertime_start)); + else + remaining = 9999; + + scr_erase_center = 0; + start = scr_centerstring; + + if (remaining < 1) + return; + + //Lowered to be visible in the GVR + y = (int)(vid_conheight.integer*0.5); + + color = -1; + do + { + // scan the number of characters on the line, not counting color codes + char *newline = strchr(start, '\n'); + int l = newline ? (newline - start) : (int)strlen(start); + float width = DrawQ_TextWidth(start, l, 8, 8, false, FONT_CENTERPRINT); + + x = (int) (vid_conwidth.integer - width)/2 + (r_stereo_side == 0 ? 10 : -10); + if (l > 0) + { + if (remaining < l) + l = remaining; + DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color, false, FONT_CENTERPRINT); + remaining -= l; + if (remaining <= 0) + return; + } + y += 8; + + if (!newline) + break; + start = newline + 1; // skip the \n + } while (1); +} + +static void SCR_CheckDrawCenterString (void) +{ + if (scr_center_lines > scr_erase_lines) + scr_erase_lines = scr_center_lines; + + if (cl.time > cl.oldtime) + scr_centertime_off -= cl.time - cl.oldtime; + + // don't draw if this is a normal stats-screen intermission, + // only if it is not an intermission, or a finale intermission + if (cl.intermission == 1) + return; + if (scr_centertime_off <= 0 && !cl.intermission) + return; + if (key_dest != key_game) + return; + + SCR_DrawCenterString (); +} + +static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int graphheight, float graphscale, const char *label, float textsize, int packetcounter, netgraphitem_t *netgraph) +{ + netgraphitem_t *graph; + int j, x, y, numlines; + int totalbytes = 0; + char bytesstring[128]; + float g[NETGRAPH_PACKETS][6]; + float *a; + float *b; + r_vertexgeneric_t vertex[(NETGRAPH_PACKETS+2)*5*2]; + r_vertexgeneric_t *v; + DrawQ_Fill(graphx, graphy, graphwidth, graphheight + textsize * 2, 0, 0, 0, 0.5, 0); + // draw the bar graph itself + memset(g, 0, sizeof(g)); + for (j = 0;j < NETGRAPH_PACKETS;j++) + { + graph = netgraph + j; + g[j][0] = 1.0f - 0.25f * (realtime - graph->time); + g[j][1] = 1.0f; + g[j][2] = 1.0f; + g[j][3] = 1.0f; + g[j][4] = 1.0f; + g[j][5] = 1.0f; + if (graph->unreliablebytes == NETGRAPH_LOSTPACKET) + g[j][1] = 0.00f; + else if (graph->unreliablebytes == NETGRAPH_CHOKEDPACKET) + g[j][2] = 0.96f; + else + { + g[j][3] = 1.0f - graph->unreliablebytes * graphscale; + g[j][4] = g[j][3] - graph->reliablebytes * graphscale; + g[j][5] = g[j][4] - graph->ackbytes * graphscale; + // count bytes in the last second + if (realtime - graph->time < 1.0f) + totalbytes += graph->unreliablebytes + graph->reliablebytes + graph->ackbytes; + } + g[j][1] = bound(0.0f, g[j][1], 1.0f); + g[j][2] = bound(0.0f, g[j][2], 1.0f); + g[j][3] = bound(0.0f, g[j][3], 1.0f); + g[j][4] = bound(0.0f, g[j][4], 1.0f); + g[j][5] = bound(0.0f, g[j][5], 1.0f); + } + // render the lines for the graph + numlines = 0; + v = vertex; + for (j = 0;j < NETGRAPH_PACKETS;j++) + { + a = g[j]; + b = g[(j+1)%NETGRAPH_PACKETS]; + if (a[0] < 0.0f || b[0] > 1.0f || b[0] < a[0]) + continue; + VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[2], 0.0f);Vector4Set(v->color4f, 1.0f, 1.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[2], 0.0f);Vector4Set(v->color4f, 1.0f, 1.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + + VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[1], 0.0f);Vector4Set(v->color4f, 1.0f, 0.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[1], 0.0f);Vector4Set(v->color4f, 1.0f, 0.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + + VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[5], 0.0f);Vector4Set(v->color4f, 0.0f, 1.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[5], 0.0f);Vector4Set(v->color4f, 0.0f, 1.0f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + + VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[4], 0.0f);Vector4Set(v->color4f, 1.0f, 1.0f, 1.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[4], 0.0f);Vector4Set(v->color4f, 1.0f, 1.0f, 1.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + + VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[3], 0.0f);Vector4Set(v->color4f, 1.0f, 0.5f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[3], 0.0f);Vector4Set(v->color4f, 1.0f, 0.5f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++; + + numlines += 5; + } + if (numlines > 0) + { + R_Mesh_PrepareVertices_Generic(numlines*2, vertex, NULL, 0); + DrawQ_Lines(0.0f, numlines, 0, false); + } + x = graphx; + y = graphy + graphheight; + dpsnprintf(bytesstring, sizeof(bytesstring), "%i", totalbytes); + DrawQ_String(x, y, label , 0, textsize, textsize, 1.0f, 1.0f, 1.0f, 1.0f, 0, NULL, false, FONT_DEFAULT);y += textsize; + DrawQ_String(x, y, bytesstring, 0, textsize, textsize, 1.0f, 1.0f, 1.0f, 1.0f, 0, NULL, false, FONT_DEFAULT);y += textsize; +} + +/* +============== +SCR_DrawNetGraph +============== +*/ +static void SCR_DrawNetGraph (void) +{ + int i, separator1, separator2, graphwidth, graphheight, netgraph_x, netgraph_y, textsize, index, netgraphsperrow; + float graphscale; + netconn_t *c; + char vabuf[1024]; + + if (cls.state != ca_connected) + return; + if (!cls.netcon) + return; + if (!shownetgraph.integer) + return; + + separator1 = 2; + separator2 = 4; + textsize = 8; + graphwidth = 120; + graphheight = 70; + graphscale = 1.0f / 1500.0f; + + netgraphsperrow = (vid_conwidth.integer + separator2) / (graphwidth * 2 + separator1 + separator2); + netgraphsperrow = max(netgraphsperrow, 1); + + index = 0; + netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2); + netgraph_y = (vid_conheight.integer - 48 - sbar_info_pos.integer + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2); + c = cls.netcon; + SCR_DrawNetGraph_DrawGraph(netgraph_x , netgraph_y, graphwidth, graphheight, graphscale, "incoming", textsize, c->incoming_packetcounter, c->incoming_netgraph); + SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, "outgoing", textsize, c->outgoing_packetcounter, c->outgoing_netgraph); + index++; + + if (sv.active && shownetgraph.integer >= 2) + { + for (i = 0;i < svs.maxclients;i++) + { + c = svs.clients[i].netconnection; + if (!c) + continue; + netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2); + netgraph_y = (vid_conheight.integer - 48 + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2); + SCR_DrawNetGraph_DrawGraph(netgraph_x , netgraph_y, graphwidth, graphheight, graphscale, va(vabuf, sizeof(vabuf), "%s", svs.clients[i].name), textsize, c->outgoing_packetcounter, c->outgoing_netgraph); + SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, "" , textsize, c->incoming_packetcounter, c->incoming_netgraph); + index++; + } + } +} + +/* +============== +SCR_DrawTurtle +============== +*/ +static void SCR_DrawTurtle (void) +{ + static int count; + + if (cls.state != ca_connected) + return; + + if (!scr_showturtle.integer) + return; + + if (cl.realframetime < 0.1) + { + count = 0; + return; + } + + count++; + if (count < 3) + return; + + DrawQ_Pic (0, 0, Draw_CachePic ("gfx/turtle"), 0, 0, 1, 1, 1, 1, 0); +} + +/* +============== +SCR_DrawNet +============== +*/ +static void SCR_DrawNet (void) +{ + if (cls.state != ca_connected) + return; + if (realtime - cl.last_received_message < 0.3) + return; + if (cls.demoplayback) + return; + + DrawQ_Pic (64, 0, Draw_CachePic ("gfx/net"), 0, 0, 1, 1, 1, 1, 0); +} + +/* +============== +DrawPause +============== +*/ +static void SCR_DrawPause (void) +{ + cachepic_t *pic; + + if (cls.state != ca_connected) + return; + + if (!scr_showpause.integer) // turn off for screenshots + return; + + if (!cl.paused) + return; + + pic = Draw_CachePic ("gfx/pause"); + DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0); +} + +/* +============== +SCR_DrawBrand +============== +*/ +static void SCR_DrawBrand (void) +{ + cachepic_t *pic; + float x, y; + + if (!scr_showbrand.value) + return; + + pic = Draw_CachePic ("gfx/brand"); + + switch ((int)scr_showbrand.value) + { + case 1: // bottom left + x = 0; + y = vid_conheight.integer - pic->height; + break; + case 2: // bottom centre + x = (vid_conwidth.integer - pic->width) / 2; + y = vid_conheight.integer - pic->height; + break; + case 3: // bottom right + x = vid_conwidth.integer - pic->width; + y = vid_conheight.integer - pic->height; + break; + case 4: // centre right + x = vid_conwidth.integer - pic->width; + y = (vid_conheight.integer - pic->height) / 2; + break; + case 5: // top right + x = vid_conwidth.integer - pic->width; + y = 0; + break; + case 6: // top centre + x = (vid_conwidth.integer - pic->width) / 2; + y = 0; + break; + case 7: // top left + x = 0; + y = 0; + break; + case 8: // centre left + x = 0; + y = (vid_conheight.integer - pic->height) / 2; + break; + default: + return; + } + + DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0); +} + +/* +============== +SCR_DrawQWDownload +============== +*/ +static int SCR_DrawQWDownload(int offset) +{ + // sync with SCR_InfobarHeight + int len; + float x, y; + float size = scr_infobar_height.value; + char temp[256]; + + if (!cls.qw_downloadname[0]) + { + cls.qw_downloadspeedrate = 0; + cls.qw_downloadspeedtime = realtime; + cls.qw_downloadspeedcount = 0; + return 0; + } + if (realtime >= cls.qw_downloadspeedtime + 1) + { + cls.qw_downloadspeedrate = cls.qw_downloadspeedcount; + cls.qw_downloadspeedtime = realtime; + cls.qw_downloadspeedcount = 0; + } + if (cls.protocol == PROTOCOL_QUAKEWORLD) + dpsnprintf(temp, sizeof(temp), "Downloading %s %3i%% (%i) at %i bytes/s", cls.qw_downloadname, cls.qw_downloadpercent, cls.qw_downloadmemorycursize, cls.qw_downloadspeedrate); + else + dpsnprintf(temp, sizeof(temp), "Downloading %s %3i%% (%i/%i) at %i bytes/s", cls.qw_downloadname, cls.qw_downloadpercent, cls.qw_downloadmemorycursize, cls.qw_downloadmemorymaxsize, cls.qw_downloadspeedrate); + len = (int)strlen(temp); + x = (vid_conwidth.integer - DrawQ_TextWidth(temp, len, size, size, true, FONT_INFOBAR)) / 2; + y = vid_conheight.integer - size - offset; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, cls.signon == SIGNONS ? 0.5 : 1, 0); + DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + return size; +} +/* +============== +SCR_DrawInfobarString +============== +*/ +static int SCR_DrawInfobarString(int offset) +{ + int len; + float x, y; + float size = scr_infobar_height.value; + + len = (int)strlen(scr_infobarstring); + x = (vid_conwidth.integer - DrawQ_TextWidth(scr_infobarstring, len, size, size, false, FONT_INFOBAR)) / 2; + y = vid_conheight.integer - size - offset; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, cls.signon == SIGNONS ? 0.5 : 1, 0); + DrawQ_String(x, y, scr_infobarstring, len, size, size, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR); + return size; +} + +/* +============== +SCR_DrawCurlDownload +============== +*/ +static int SCR_DrawCurlDownload(int offset) +{ + // sync with SCR_InfobarHeight + int len; + int nDownloads; + int i; + float x, y; + float size = scr_infobar_height.value; + Curl_downloadinfo_t *downinfo; + char temp[256]; + char addinfobuf[128]; + const char *addinfo; + + downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo, addinfobuf, sizeof(addinfobuf)); + if(!downinfo) + return 0; + + y = vid_conheight.integer - size * nDownloads - offset; + + if(addinfo) + { + len = (int)strlen(addinfo); + x = (vid_conwidth.integer - DrawQ_TextWidth(addinfo, len, size, size, true, FONT_INFOBAR)) / 2; + DrawQ_Fill(0, y - size, vid_conwidth.integer, size, 1, 1, 1, cls.signon == SIGNONS ? 0.8 : 1, 0); + DrawQ_String(x, y - size, addinfo, len, size, size, 0, 0, 0, 1, 0, NULL, true, FONT_INFOBAR); + } + + for(i = 0; i != nDownloads; ++i) + { + if(downinfo[i].queued) + dpsnprintf(temp, sizeof(temp), "Still in queue: %s", downinfo[i].filename); + else if(downinfo[i].progress <= 0) + dpsnprintf(temp, sizeof(temp), "Downloading %s ... ???.?%% @ %.1f KiB/s", downinfo[i].filename, downinfo[i].speed / 1024.0); + else + dpsnprintf(temp, sizeof(temp), "Downloading %s ... %5.1f%% @ %.1f KiB/s", downinfo[i].filename, 100.0 * downinfo[i].progress, downinfo[i].speed / 1024.0); + len = (int)strlen(temp); + x = (vid_conwidth.integer - DrawQ_TextWidth(temp, len, size, size, true, FONT_INFOBAR)) / 2; + DrawQ_Fill(0, y + i * size, vid_conwidth.integer, size, 0, 0, 0, cls.signon == SIGNONS ? 0.5 : 1, 0); + DrawQ_String(x, y + i * size, temp, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + } + + Z_Free(downinfo); + + return size * (nDownloads + (addinfo ? 1 : 0)); +} + +/* +============== +SCR_DrawInfobar +============== +*/ +static void SCR_DrawInfobar(void) +{ + int offset = 0; + offset += SCR_DrawQWDownload(offset); + offset += SCR_DrawCurlDownload(offset); + if(scr_infobartime_off > 0) + offset += SCR_DrawInfobarString(offset); + if(offset != scr_con_margin_bottom) + Con_DPrintf("broken console margin calculation: %d != %d\n", offset, scr_con_margin_bottom); +} + +static int SCR_InfobarHeight(void) +{ + int offset = 0; + Curl_downloadinfo_t *downinfo; + const char *addinfo; + int nDownloads; + char addinfobuf[128]; + + if (cl.time > cl.oldtime) + scr_infobartime_off -= cl.time - cl.oldtime; + if(scr_infobartime_off > 0) + offset += 1; + if(cls.qw_downloadname[0]) + offset += 1; + + downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo, addinfobuf, sizeof(addinfobuf)); + if(downinfo) + { + offset += (nDownloads + (addinfo ? 1 : 0)); + Z_Free(downinfo); + } + offset *= scr_infobar_height.value; + + return offset; +} + +/* +============== +SCR_InfoBar_f +============== +*/ +static void SCR_InfoBar_f(void) +{ + if(Cmd_Argc() == 3) + { + scr_infobartime_off = atof(Cmd_Argv(1)); + strlcpy(scr_infobarstring, Cmd_Argv(2), sizeof(scr_infobarstring)); + } + else + { + Con_Printf("usage:\ninfobar expiretime \"string\"\n"); + } +} +//============================================================================= + +/* +================== +SCR_SetUpToDrawConsole +================== +*/ +static void SCR_SetUpToDrawConsole (void) +{ + // lines of console to display + float conlines; + static int framecounter = 0; + + Con_CheckResize (); + + if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected) + { + if (framecounter >= 2) + MR_ToggleMenu(1); + else + framecounter++; + } + else + framecounter = 0; + + if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS) + key_consoleactive |= KEY_CONSOLEACTIVE_FORCED; + else + key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED; + +// decide on the height of the console + if (key_consoleactive & KEY_CONSOLEACTIVE_USER) + conlines = vid_conheight.integer/2; // half screen + else + conlines = 0; // none visible + + scr_con_current = conlines; +} + +/* +================== +SCR_DrawConsole +================== +*/ +void SCR_DrawConsole (void) +{ + scr_con_margin_bottom = SCR_InfobarHeight(); + if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED) + { + // full screen + Con_DrawConsole (vid_conheight.integer - scr_con_margin_bottom); + jni_BigScreenMode(1); + } + else if (scr_con_current) { + Con_DrawConsole(min((int) scr_con_current, vid_conheight.integer - scr_con_margin_bottom)); + jni_BigScreenMode(1); + } + else { + con_vislines = 0; + } +} + +/* +=============== +SCR_BeginLoadingPlaque + +================ +*/ +void SCR_BeginLoadingPlaque (qboolean startup) +{ + // save console log up to this point to log_file if it was set by configs + Log_Start(); + + Host_StartVideo(); + SCR_UpdateLoadingScreen(false, startup); +} + +//============================================================================= + +const char *r_stat_name[r_stat_count] = +{ + "timedelta", + "quality", + "renders", + "entities", + "entities_surfaces", + "entities_triangles", + "world_leafs", + "world_portals", + "world_surfaces", + "world_triangles", + "lightmapupdates", + "lightmapupdatepixels", + "particles", + "drawndecals", + "totaldecals", + "draws", + "draws_vertices", + "draws_elements", + "lights", + "lights_clears", + "lights_scissored", + "lights_lighttriangles", + "lights_shadowtriangles", + "lights_dynamicshadowtriangles", + "bouncegrid_lights", + "bouncegrid_particles", + "bouncegrid_traces", + "bouncegrid_hits", + "bouncegrid_splats", + "bouncegrid_bounces", + "photoncache_animated", + "photoncache_cached", + "photoncache_traced", + "bloom", + "bloom_copypixels", + "bloom_drawpixels", + "indexbufferuploadcount", + "indexbufferuploadsize", + "vertexbufferuploadcount", + "vertexbufferuploadsize", + "framedatacurrent", + "framedatasize", + "bufferdatacurrent_vertex", // R_BUFFERDATA_ types are added to this index + "bufferdatacurrent_index16", + "bufferdatacurrent_index32", + "bufferdatacurrent_uniform", + "bufferdatasize_vertex", // R_BUFFERDATA_ types are added to this index + "bufferdatasize_index16", + "bufferdatasize_index32", + "bufferdatasize_uniform", + "animcache_vertexmesh_count", + "animcache_vertexmesh_vertices", + "animcache_vertexmesh_maxvertices", + "animcache_skeletal_count", + "animcache_skeletal_bones", + "animcache_skeletal_maxbones", + "animcache_shade_count", + "animcache_shade_vertices", + "animcache_shade_maxvertices", + "animcache_shape_count", + "animcache_shape_vertices", + "animcache_shape_maxvertices", + "batch_batches", + "batch_withgaps", + "batch_surfaces", + "batch_vertices", + "batch_triangles", + "fast_batches", + "fast_surfaces", + "fast_vertices", + "fast_triangles", + "copytriangles_batches", + "copytriangles_surfaces", + "copytriangles_vertices", + "copytriangles_triangles", + "dynamic_batches", + "dynamic_surfaces", + "dynamic_vertices", + "dynamic_triangles", + "dynamicskeletal_batches", + "dynamicskeletal_surfaces", + "dynamicskeletal_vertices", + "dynamicskeletal_triangles", + "dynamic_batches_because_cvar", + "dynamic_surfaces_because_cvar", + "dynamic_vertices_because_cvar", + "dynamic_triangles_because_cvar", + "dynamic_batches_because_lightmapvertex", + "dynamic_surfaces_because_lightmapvertex", + "dynamic_vertices_because_lightmapvertex", + "dynamic_triangles_because_lightmapvertex", + "dynamic_batches_because_deformvertexes_autosprite", + "dynamic_surfaces_because_deformvertexes_autosprite", + "dynamic_vertices_because_deformvertexes_autosprite", + "dynamic_triangles_because_deformvertexes_autosprite", + "dynamic_batches_because_deformvertexes_autosprite2", + "dynamic_surfaces_because_deformvertexes_autosprite2", + "dynamic_vertices_because_deformvertexes_autosprite2", + "dynamic_triangles_because_deformvertexes_autosprite2", + "dynamic_batches_because_deformvertexes_normal", + "dynamic_surfaces_because_deformvertexes_normal", + "dynamic_vertices_because_deformvertexes_normal", + "dynamic_triangles_because_deformvertexes_normal", + "dynamic_batches_because_deformvertexes_wave", + "dynamic_surfaces_because_deformvertexes_wave", + "dynamic_vertices_because_deformvertexes_wave", + "dynamic_triangles_because_deformvertexes_wave", + "dynamic_batches_because_deformvertexes_bulge", + "dynamic_surfaces_because_deformvertexes_bulge", + "dynamic_vertices_because_deformvertexes_bulge", + "dynamic_triangles_because_deformvertexes_bulge", + "dynamic_batches_because_deformvertexes_move", + "dynamic_surfaces_because_deformvertexes_move", + "dynamic_vertices_because_deformvertexes_move", + "dynamic_triangles_because_deformvertexes_move", + "dynamic_batches_because_tcgen_lightmap", + "dynamic_surfaces_because_tcgen_lightmap", + "dynamic_vertices_because_tcgen_lightmap", + "dynamic_triangles_because_tcgen_lightmap", + "dynamic_batches_because_tcgen_vector", + "dynamic_surfaces_because_tcgen_vector", + "dynamic_vertices_because_tcgen_vector", + "dynamic_triangles_because_tcgen_vector", + "dynamic_batches_because_tcgen_environment", + "dynamic_surfaces_because_tcgen_environment", + "dynamic_vertices_because_tcgen_environment", + "dynamic_triangles_because_tcgen_environment", + "dynamic_batches_because_tcmod_turbulent", + "dynamic_surfaces_because_tcmod_turbulent", + "dynamic_vertices_because_tcmod_turbulent", + "dynamic_triangles_because_tcmod_turbulent", + "dynamic_batches_because_interleavedarrays", + "dynamic_surfaces_because_interleavedarrays", + "dynamic_vertices_because_interleavedarrays", + "dynamic_triangles_because_interleavedarrays", + "dynamic_batches_because_nogaps", + "dynamic_surfaces_because_nogaps", + "dynamic_vertices_because_nogaps", + "dynamic_triangles_because_nogaps", + "dynamic_batches_because_derived", + "dynamic_surfaces_because_derived", + "dynamic_vertices_because_derived", + "dynamic_triangles_because_derived", + "entitycache_count", + "entitycache_surfaces", + "entitycache_vertices", + "entitycache_triangles", + "entityanimate_count", + "entityanimate_surfaces", + "entityanimate_vertices", + "entityanimate_triangles", + "entityskeletal_count", + "entityskeletal_surfaces", + "entityskeletal_vertices", + "entityskeletal_triangles", + "entitystatic_count", + "entitystatic_surfaces", + "entitystatic_vertices", + "entitystatic_triangles", + "entitycustom_count", + "entitycustom_surfaces", + "entitycustom_vertices", + "entitycustom_triangles", +}; + +char r_speeds_timestring[4096]; +int speedstringcount, r_timereport_active; +double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0; +int r_speeds_longestitem = 0; + +void R_TimeReport(const char *desc) +{ + char tempbuf[256]; + int length; + int t; + + if (r_speeds.integer < 2 || !r_timereport_active) + return; + + CHECKGLERROR + if (r_speeds.integer == 2) + GL_Finish(); + CHECKGLERROR + r_timereport_temp = r_timereport_current; + r_timereport_current = Sys_DirtyTime(); + t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5); + + length = dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc); + length = min(length, (int)sizeof(tempbuf) - 1); + if (r_speeds_longestitem < length) + r_speeds_longestitem = length; + for (;length < r_speeds_longestitem;length++) + tempbuf[length] = ' '; + tempbuf[length] = 0; + + if (speedstringcount + length > (vid_conwidth.integer / 8)) + { + strlcat(r_speeds_timestring, "\n", sizeof(r_speeds_timestring)); + speedstringcount = 0; + } + strlcat(r_speeds_timestring, tempbuf, sizeof(r_speeds_timestring)); + speedstringcount += length; +} + +static void R_TimeReport_BeginFrame(void) +{ + speedstringcount = 0; + r_speeds_timestring[0] = 0; + r_timereport_active = false; + memset(&r_refdef.stats, 0, sizeof(r_refdef.stats)); + + if (r_speeds.integer >= 2) + { + r_timereport_active = true; + r_timereport_start = r_timereport_current = Sys_DirtyTime(); + } +} + +static int R_CountLeafTriangles(const dp_model_t *model, const mleaf_t *leaf) +{ + int i, triangles = 0; + for (i = 0;i < leaf->numleafsurfaces;i++) + triangles += model->data_surfaces[leaf->firstleafsurface[i]].num_triangles; + return triangles; +} + +#define R_SPEEDS_GRAPH_COLORS 8 +#define R_SPEEDS_GRAPH_TEXTLENGTH 64 +static float r_speeds_graph_colors[R_SPEEDS_GRAPH_COLORS][4] = {{1, 0, 0, 1}, {0, 1, 0, 1}, {0, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 1}, {1, 0, 1, 1}, {1, 1, 1, 1}, {1, 0.5f, 0, 1}}; + +extern cvar_t r_viewscale; +extern float viewscalefpsadjusted; +static void R_TimeReport_EndFrame(void) +{ + int i, j, lines, y; + cl_locnode_t *loc; + char string[1024+4096]; + mleaf_t *viewleaf; + static double oldtime = 0; + + r_refdef.stats[r_stat_timedelta] = (int)((realtime - oldtime) * 1000000.0); + oldtime = realtime; + r_refdef.stats[r_stat_quality] = (int)(100 * r_refdef.view.quality); + + string[0] = 0; + if (r_speeds.integer) + { + // put the location name in the r_speeds display as it greatly helps + // when creating loc files + loc = CL_Locs_FindNearest(cl.movement_origin); + viewleaf = (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf) ? r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, r_refdef.view.origin) : NULL; + dpsnprintf(string, sizeof(string), +"%6ius time delta %s%s %.3f cl.time%2.4f brightness\n" +"%3i renders org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n" +"%5i viewleaf%5i cluster%3i area%4i brushes%4i surfaces(%7i triangles)\n" +"%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n" +"%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n" +"%7i lightmap updates (%7i pixels)%8i/%8i framedata\n" +"%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n" +"bouncegrid:%4i lights%6i particles%6i traces%6i hits%6i splats%6i bounces\n" +"photon cache efficiency:%6i cached%6i traced%6ianimated\n" +"%6i draws%8i vertices%8i triangles bloompixels%8i copied%8i drawn\n" +"updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n" +"animcache%5ib gpuskeletal%7i vertices (%7i with normals)\n" +"fastbatch%5i count%5i surfaces%7i vertices %7i triangles\n" +"copytris%5i count%5i surfaces%7i vertices %7i triangles\n" +"dynamic%5i count%5i surfaces%7i vertices%7i triangles\n" +"%s" +, r_refdef.stats[r_stat_timedelta], loc ? "Location: " : "", loc ? loc->name : "", cl.time, r_refdef.view.colorscale +, r_refdef.stats[r_stat_renders], r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], r_refdef.view.forward[0], r_refdef.view.forward[1], r_refdef.view.forward[2] +, viewleaf ? (int)(viewleaf - r_refdef.scene.worldmodel->brush.data_leafs) : -1, viewleaf ? viewleaf->clusterindex : -1, viewleaf ? viewleaf->areaindex : -1, viewleaf ? viewleaf->numleafbrushes : 0, viewleaf ? viewleaf->numleafsurfaces : 0, viewleaf ? R_CountLeafTriangles(r_refdef.scene.worldmodel, viewleaf) : 0 +, r_refdef.stats[r_stat_world_surfaces], r_refdef.stats[r_stat_world_triangles], r_refdef.stats[r_stat_entities], r_refdef.stats[r_stat_entities_surfaces], r_refdef.stats[r_stat_entities_triangles] +, r_refdef.stats[r_stat_world_leafs], r_refdef.stats[r_stat_world_portals], r_refdef.stats[r_stat_particles], cl.num_particles, r_refdef.stats[r_stat_drawndecals], r_refdef.stats[r_stat_totaldecals], r_refdef.stats[r_stat_quality] +, r_refdef.stats[r_stat_lightmapupdates], r_refdef.stats[r_stat_lightmapupdatepixels], r_refdef.stats[r_stat_framedatacurrent], r_refdef.stats[r_stat_framedatasize] +, r_refdef.stats[r_stat_lights], r_refdef.stats[r_stat_lights_clears], r_refdef.stats[r_stat_lights_scissored], r_refdef.stats[r_stat_lights_lighttriangles], r_refdef.stats[r_stat_lights_shadowtriangles], r_refdef.stats[r_stat_lights_dynamicshadowtriangles] +, r_refdef.stats[r_stat_bouncegrid_lights], r_refdef.stats[r_stat_bouncegrid_particles], r_refdef.stats[r_stat_bouncegrid_traces], r_refdef.stats[r_stat_bouncegrid_hits], r_refdef.stats[r_stat_bouncegrid_splats], r_refdef.stats[r_stat_bouncegrid_bounces] +, r_refdef.stats[r_stat_photoncache_cached], r_refdef.stats[r_stat_photoncache_traced], r_refdef.stats[r_stat_photoncache_animated] +, r_refdef.stats[r_stat_draws], r_refdef.stats[r_stat_draws_vertices], r_refdef.stats[r_stat_draws_elements] / 3, r_refdef.stats[r_stat_bloom_copypixels], r_refdef.stats[r_stat_bloom_drawpixels] +, r_refdef.stats[r_stat_indexbufferuploadcount], r_refdef.stats[r_stat_indexbufferuploadsize], r_refdef.stats[r_stat_vertexbufferuploadcount], r_refdef.stats[r_stat_vertexbufferuploadsize] +, r_refdef.stats[r_stat_animcache_skeletal_bones], r_refdef.stats[r_stat_animcache_shape_vertices], r_refdef.stats[r_stat_animcache_shade_vertices] +, r_refdef.stats[r_stat_batch_fast_batches], r_refdef.stats[r_stat_batch_fast_surfaces], r_refdef.stats[r_stat_batch_fast_vertices], r_refdef.stats[r_stat_batch_fast_triangles] +, r_refdef.stats[r_stat_batch_copytriangles_batches], r_refdef.stats[r_stat_batch_copytriangles_surfaces], r_refdef.stats[r_stat_batch_copytriangles_vertices], r_refdef.stats[r_stat_batch_copytriangles_triangles] +, r_refdef.stats[r_stat_batch_dynamic_batches], r_refdef.stats[r_stat_batch_dynamic_surfaces], r_refdef.stats[r_stat_batch_dynamic_vertices], r_refdef.stats[r_stat_batch_dynamic_triangles] +, r_speeds_timestring); + } + + speedstringcount = 0; + r_speeds_timestring[0] = 0; + r_timereport_active = false; + + if (r_speeds.integer >= 2) + { + r_timereport_active = true; + r_timereport_start = r_timereport_current = Sys_DirtyTime(); + } + + if (string[0]) + { + if (string[strlen(string)-1] == '\n') + string[strlen(string)-1] = 0; + lines = 1; + for (i = 0;string[i];i++) + if (string[i] == '\n') + lines++; + y = vid_conheight.integer - sb_lines - lines * 8; + i = j = 0; + r_draw2d_force = true; + DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0); + while (string[i]) + { + j = i; + while (string[i] && string[i] != '\n') + i++; + if (i - j > 0) + DrawQ_String(0, y, string + j, i - j, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT); + if (string[i] == '\n') + i++; + y += 8; + } + r_draw2d_force = false; + } + + if (r_speeds_graph_length.integer != bound(4, r_speeds_graph_length.integer, 8192)) + Cvar_SetValueQuick(&r_speeds_graph_length, bound(4, r_speeds_graph_length.integer, 8192)); + if (fabs(r_speeds_graph_seconds.value - bound(0.1f, r_speeds_graph_seconds.value, 120.0f)) > 0.01f) + Cvar_SetValueQuick(&r_speeds_graph_seconds, bound(0.1f, r_speeds_graph_seconds.value, 120.0f)); + if (r_speeds_graph.integer) + { + // if we currently have no graph data, reset the graph data entirely + if (!cls.r_speeds_graph_data) + for (i = 0;i < r_stat_count;i++) + cls.r_speeds_graph_datamin[i] = cls.r_speeds_graph_datamax[i] = r_refdef.stats[i]; + if (cls.r_speeds_graph_length != r_speeds_graph_length.integer) + { + int i, stat, index, d, graph_length, *graph_data; + cls.r_speeds_graph_length = r_speeds_graph_length.integer; + cls.r_speeds_graph_current = 0; + if (cls.r_speeds_graph_data) + Mem_Free(cls.r_speeds_graph_data); + cls.r_speeds_graph_data = (int *)Mem_Alloc(cls.permanentmempool, cls.r_speeds_graph_length * sizeof(r_refdef.stats)); + // initialize the graph to have the current values throughout history + graph_data = cls.r_speeds_graph_data; + graph_length = cls.r_speeds_graph_length; + index = 0; + for (stat = 0;stat < r_stat_count;stat++) + { + d = r_refdef.stats[stat]; + if (stat == r_stat_timedelta) + d = 0; + for (i = 0;i < graph_length;i++) + graph_data[index++] = d; + } + } + } + else + { + if (cls.r_speeds_graph_length) + { + cls.r_speeds_graph_length = 0; + Mem_Free(cls.r_speeds_graph_data); + cls.r_speeds_graph_data = NULL; + cls.r_speeds_graph_current = 0; + } + } + + if (cls.r_speeds_graph_length) + { + char legend[128]; + r_vertexgeneric_t *v; + int numlines; + const int *data; + float x, y, width, height, scalex, scaley; + int color, stat, stats, index, range_min, range_max; + int graph_current, graph_length, *graph_data; + int statindex[R_SPEEDS_GRAPH_COLORS]; + int sum; + + // add current stats to the graph_data + cls.r_speeds_graph_current++; + if (cls.r_speeds_graph_current >= cls.r_speeds_graph_length) + cls.r_speeds_graph_current = 0; + // poke each new stat into the current offset of its graph + graph_data = cls.r_speeds_graph_data; + graph_current = cls.r_speeds_graph_current; + graph_length = cls.r_speeds_graph_length; + for (stat = 0;stat < r_stat_count;stat++) + graph_data[stat * graph_length + graph_current] = r_refdef.stats[stat]; + + // update the graph ranges + for (stat = 0;stat < r_stat_count;stat++) + { + if (cls.r_speeds_graph_datamin[stat] > r_refdef.stats[stat]) + cls.r_speeds_graph_datamin[stat] = r_refdef.stats[stat]; + if (cls.r_speeds_graph_datamax[stat] < r_refdef.stats[stat]) + cls.r_speeds_graph_datamax[stat] = r_refdef.stats[stat]; + } + + // force 2D drawing to occur even if r_render is 0 + r_draw2d_force = true; + + // position the graph + width = r_speeds_graph_width.value; + height = r_speeds_graph_height.value; + x = bound(0, r_speeds_graph_x.value, vid_conwidth.value - width); + y = bound(0, r_speeds_graph_y.value, vid_conheight.value - height); + + // fill background with a pattern of gray and black at one second intervals + scalex = (float)width / (float)r_speeds_graph_seconds.value; + for (i = 0;i < r_speeds_graph_seconds.integer + 1;i++) + { + float x1 = x + width - (i + 1) * scalex; + float x2 = x + width - i * scalex; + if (x1 < x) + x1 = x; + if (i & 1) + DrawQ_Fill(x1, y, x2 - x1, height, 0.0f, 0.0f, 0.0f, 0.5f, 0); + else + DrawQ_Fill(x1, y, x2 - x1, height, 0.2f, 0.2f, 0.2f, 0.5f, 0); + } + + // count how many stats match our pattern + stats = 0; + color = 0; + for (color = 0;color < R_SPEEDS_GRAPH_COLORS;color++) + { + // look at all stat names and find ones matching the filter + statindex[color] = -1; + if (!r_speeds_graph_filter[color].string) + continue; + for (stat = 0;stat < r_stat_count;stat++) + if (!strcmp(r_stat_name[stat], r_speeds_graph_filter[color].string)) + break; + if (stat >= r_stat_count) + continue; + // record that this color is this stat for the line drawing loop + statindex[color] = stat; + // draw the legend text in the background of the graph + dpsnprintf(legend, sizeof(legend), "%10i :%s", graph_data[stat * graph_length + graph_current], r_stat_name[stat]); + DrawQ_String(x, y + stats * 8, legend, 0, 8, 8, r_speeds_graph_colors[color][0], r_speeds_graph_colors[color][1], r_speeds_graph_colors[color][2], r_speeds_graph_colors[color][3] * 1.00f, 0, NULL, true, FONT_DEFAULT); + // count how many stats we need to graph in vertex buffer + stats++; + } + + if (stats) + { + // legend text is drawn after the graphs + // render the graph lines, we'll go back and render the legend text later + scalex = (float)width / (1000000.0 * r_speeds_graph_seconds.value); + // get space in a vertex buffer to draw this + numlines = stats * (graph_length - 1); + v = R_Mesh_PrepareVertices_Generic_Lock(numlines * 2); + stats = 0; + for (color = 0;color < R_SPEEDS_GRAPH_COLORS;color++) + { + // look at all stat names and find ones matching the filter + stat = statindex[color]; + if (stat < 0) + continue; + // prefer to graph stats with 0 base, but if they are + // negative we have no choice + range_min = min(cls.r_speeds_graph_datamin[stat], 0); + range_max = cls.r_speeds_graph_datamax[stat]; + // some stats we specifically override the graph scale on + if (stat == r_stat_timedelta) + range_max = 100000; + if (range_max == range_min) + range_max++; + scaley = height / (range_max - range_min); + // generate lines (2 vertices each) + // to deal with incomplete data we walk right to left + data = graph_data + stat * graph_length; + index = graph_current; + sum = 0; + for (i = 0;i < graph_length - 1;) + { + v->vertex3f[0] = x + width - sum * scalex; + if (v->vertex3f[0] < x) + v->vertex3f[0] = x; + v->vertex3f[1] = y + height - (data[index] - range_min) * scaley; + v->vertex3f[2] = 0; + v->color4f[0] = r_speeds_graph_colors[color][0]; + v->color4f[1] = r_speeds_graph_colors[color][1]; + v->color4f[2] = r_speeds_graph_colors[color][2]; + v->color4f[3] = r_speeds_graph_colors[color][3]; + v->texcoord2f[0] = 0; + v->texcoord2f[1] = 0; + v++; + sum += graph_data[r_stat_timedelta * graph_length + index]; + index--; + if (index < 0) + index = graph_length - 1; + i++; + v->vertex3f[0] = x + width - sum * scalex; + if (v->vertex3f[0] < x) + v->vertex3f[0] = x; + v->vertex3f[1] = y + height - (data[index] - range_min) * scaley; + v->vertex3f[2] = 0; + v->color4f[0] = r_speeds_graph_colors[color][0]; + v->color4f[1] = r_speeds_graph_colors[color][1]; + v->color4f[2] = r_speeds_graph_colors[color][2]; + v->color4f[3] = r_speeds_graph_colors[color][3]; + v->texcoord2f[0] = 0; + v->texcoord2f[1] = 0; + v++; + } + } + R_Mesh_PrepareVertices_Generic_Unlock(); + DrawQ_Lines(0.0f, numlines, 0, false); + } + + // return to not drawing anything if r_render is 0 + r_draw2d_force = false; + } + + memset(&r_refdef.stats, 0, sizeof(r_refdef.stats)); +} + +/* +================= +SCR_SizeUp_f + +Keybinding command +================= +*/ +static void SCR_SizeUp_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value+10); +} + + +/* +================= +SCR_SizeDown_f + +Keybinding command +================= +*/ +static void SCR_SizeDown_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value-10); +} + +void SCR_CaptureVideo_EndVideo(void); +void CL_Screen_Shutdown(void) +{ + SCR_CaptureVideo_EndVideo(); +} + +void CL_Screen_Init(void) +{ + int i; + Cvar_RegisterVariable (&scr_fov); + Cvar_RegisterVariable (&scr_viewsize); + Cvar_RegisterVariable (&scr_conalpha); + Cvar_RegisterVariable (&scr_conalphafactor); + Cvar_RegisterVariable (&scr_conalpha2factor); + Cvar_RegisterVariable (&scr_conalpha3factor); + Cvar_RegisterVariable (&scr_conscroll_x); + Cvar_RegisterVariable (&scr_conscroll_y); + Cvar_RegisterVariable (&scr_conscroll2_x); + Cvar_RegisterVariable (&scr_conscroll2_y); + Cvar_RegisterVariable (&scr_conscroll3_x); + Cvar_RegisterVariable (&scr_conscroll3_y); + Cvar_RegisterVariable (&scr_conbrightness); + Cvar_RegisterVariable (&scr_conforcewhiledisconnected); + Cvar_RegisterVariable (&scr_menuforcewhiledisconnected); + Cvar_RegisterVariable (&scr_loadingscreen_background); + Cvar_RegisterVariable (&scr_loadingscreen_scale); + Cvar_RegisterVariable (&scr_loadingscreen_scale_base); + Cvar_RegisterVariable (&scr_loadingscreen_scale_limit); + Cvar_RegisterVariable (&scr_loadingscreen_picture); + Cvar_RegisterVariable (&scr_loadingscreen_count); + Cvar_RegisterVariable (&scr_loadingscreen_firstforstartup); + Cvar_RegisterVariable (&scr_loadingscreen_barcolor); + Cvar_RegisterVariable (&scr_loadingscreen_barheight); + Cvar_RegisterVariable (&scr_loadingscreen_maxfps); + Cvar_RegisterVariable (&scr_infobar_height); + Cvar_RegisterVariable (&scr_showram); + Cvar_RegisterVariable (&scr_showturtle); + Cvar_RegisterVariable (&scr_showpause); + Cvar_RegisterVariable (&scr_showbrand); + Cvar_RegisterVariable (&scr_centertime); + Cvar_RegisterVariable (&scr_printspeed); + Cvar_RegisterVariable (&vid_conwidth); + Cvar_RegisterVariable (&vid_conheight); + Cvar_RegisterVariable (&vid_pixelheight); + Cvar_RegisterVariable (&scr_screenshot_jpeg); + Cvar_RegisterVariable (&scr_screenshot_jpeg_quality); + Cvar_RegisterVariable (&scr_screenshot_png); + Cvar_RegisterVariable (&scr_screenshot_gammaboost); + Cvar_RegisterVariable (&scr_screenshot_hwgamma); + Cvar_RegisterVariable (&scr_screenshot_name_in_mapdir); + Cvar_RegisterVariable (&scr_screenshot_alpha); + Cvar_RegisterVariable (&scr_screenshot_timestamp); + Cvar_RegisterVariable (&cl_capturevideo); + Cvar_RegisterVariable (&cl_capturevideo_demo_stop); + Cvar_RegisterVariable (&cl_capturevideo_printfps); + Cvar_RegisterVariable (&cl_capturevideo_width); + Cvar_RegisterVariable (&cl_capturevideo_height); + Cvar_RegisterVariable (&cl_capturevideo_realtime); + Cvar_RegisterVariable (&cl_capturevideo_fps); + Cvar_RegisterVariable (&cl_capturevideo_nameformat); + Cvar_RegisterVariable (&cl_capturevideo_number); + Cvar_RegisterVariable (&cl_capturevideo_ogg); + Cvar_RegisterVariable (&cl_capturevideo_framestep); + Cvar_RegisterVariable (&r_letterbox); + Cvar_RegisterVariable(&r_stereo_angle); + Cvar_RegisterVariable(&scr_stipple); + Cvar_RegisterVariable(&scr_refresh); + Cvar_RegisterVariable(&shownetgraph); + Cvar_RegisterVariable(&cl_demo_mousegrab); + Cvar_RegisterVariable(&timedemo_screenshotframelist); + Cvar_RegisterVariable(&vid_touchscreen_outlinealpha); + Cvar_RegisterVariable(&vid_touchscreen_overlayalpha); + Cvar_RegisterVariable(&r_speeds_graph); + for (i = 0;i < (int)(sizeof(r_speeds_graph_filter)/sizeof(r_speeds_graph_filter[0]));i++) + Cvar_RegisterVariable(&r_speeds_graph_filter[i]); + Cvar_RegisterVariable(&r_speeds_graph_length); + Cvar_RegisterVariable(&r_speeds_graph_seconds); + Cvar_RegisterVariable(&r_speeds_graph_x); + Cvar_RegisterVariable(&r_speeds_graph_y); + Cvar_RegisterVariable(&r_speeds_graph_width); + Cvar_RegisterVariable(&r_speeds_graph_height); + + // if we want no console, turn it off here too + if (COM_CheckParm ("-noconsole")) + Cvar_SetQuick(&scr_conforcewhiledisconnected, "0"); + + Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)"); + Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)"); + Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame"); + Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene"); + Cmd_AddCommand ("infobar", SCR_InfoBar_f, "display a text in the infobar (usage: infobar expiretime string)"); + + SCR_CaptureVideo_Ogg_Init(); + + scr_initialized = true; +} + +/* +================== +SCR_ScreenShot_f +================== +*/ +void SCR_ScreenShot_f (void) +{ + static int shotnumber; + static char old_prefix_name[MAX_QPATH]; + char prefix_name[MAX_QPATH]; + char filename[MAX_QPATH]; + unsigned char *buffer1; + unsigned char *buffer2; + qboolean jpeg = (scr_screenshot_jpeg.integer != 0); + qboolean png = (scr_screenshot_png.integer != 0) && !jpeg; + char vabuf[1024]; + + if (Cmd_Argc() == 2) + { + const char *ext; + strlcpy(filename, Cmd_Argv(1), sizeof(filename)); + ext = FS_FileExtension(filename); + if (!strcasecmp(ext, "jpg")) + { + jpeg = true; + png = false; + } + else if (!strcasecmp(ext, "tga")) + { + jpeg = false; + png = false; + } + else if (!strcasecmp(ext, "png")) + { + jpeg = false; + png = true; + } + else + { + Con_Printf("screenshot: supplied filename must end in .jpg or .tga or .png\n"); + return; + } + } + else if (scr_screenshot_timestamp.integer) + { + int shotnumber100; + + // TODO maybe make capturevideo and screenshot use similar name patterns? + if (scr_screenshot_name_in_mapdir.integer && cl.worldbasename[0]) + dpsnprintf(prefix_name, sizeof(prefix_name), "%s/%s%s", cl.worldbasename, scr_screenshot_name.string, Sys_TimeString("%Y%m%d%H%M%S")); + else + dpsnprintf(prefix_name, sizeof(prefix_name), "%s%s", scr_screenshot_name.string, Sys_TimeString("%Y%m%d%H%M%S")); + + // find a file name to save it to + for (shotnumber100 = 0;shotnumber100 < 100;shotnumber100++) + if (!FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s-%02d.tga", fs_gamedir, prefix_name, shotnumber100)) + && !FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s-%02d.jpg", fs_gamedir, prefix_name, shotnumber100)) + && !FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s-%02d.png", fs_gamedir, prefix_name, shotnumber100))) + break; + if (shotnumber100 >= 100) + { + Con_Print("Couldn't create the image file - already 100 shots taken this second!\n"); + return; + } + + dpsnprintf(filename, sizeof(filename), "screenshots/%s-%02d.%s", prefix_name, shotnumber100, jpeg ? "jpg" : png ? "png" : "tga"); + } + else + { + // TODO maybe make capturevideo and screenshot use similar name patterns? + if (scr_screenshot_name_in_mapdir.integer && cl.worldbasename[0]) + dpsnprintf(prefix_name, sizeof(prefix_name), "%s/%s", cl.worldbasename, Sys_TimeString(scr_screenshot_name.string)); + else + dpsnprintf(prefix_name, sizeof(prefix_name), "%s", Sys_TimeString(scr_screenshot_name.string)); + + // if prefix changed, gamedir or map changed, reset the shotnumber so + // we scan again + // FIXME: should probably do this whenever FS_Rescan or something like that occurs? + if (strcmp(old_prefix_name, prefix_name)) + { + dpsnprintf(old_prefix_name, sizeof(old_prefix_name), "%s", prefix_name ); + shotnumber = 0; + } + + // find a file name to save it to + for (;shotnumber < 1000000;shotnumber++) + if (!FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s%06d.tga", fs_gamedir, prefix_name, shotnumber)) + && !FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s%06d.jpg", fs_gamedir, prefix_name, shotnumber)) + && !FS_SysFileExists(va(vabuf, sizeof(vabuf), "%s/screenshots/%s%06d.png", fs_gamedir, prefix_name, shotnumber))) + break; + if (shotnumber >= 1000000) + { + Con_Print("Couldn't create the image file - you already have 1000000 screenshots!\n"); + return; + } + + dpsnprintf(filename, sizeof(filename), "screenshots/%s%06d.%s", prefix_name, shotnumber, jpeg ? "jpg" : png ? "png" : "tga"); + + shotnumber++; + } + + buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4); + buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (scr_screenshot_alpha.integer ? 4 : 3)); + + if (SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, jpeg, png, true, scr_screenshot_alpha.integer != 0)) + Con_Printf("Wrote %s\n", filename); + else + { + Con_Printf("Unable to write %s\n", filename); + if(jpeg || png) + { + if(SCR_ScreenShot (filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, false, false, true, scr_screenshot_alpha.integer != 0)) + { + strlcpy(filename + strlen(filename) - 3, "tga", 4); + Con_Printf("Wrote %s\n", filename); + } + } + } + + Mem_Free (buffer1); + Mem_Free (buffer2); +} + +static void SCR_CaptureVideo_BeginVideo(void) +{ + double r, g, b; + unsigned int i; + int width = cl_capturevideo_width.integer, height = cl_capturevideo_height.integer; + if (cls.capturevideo.active) + return; + memset(&cls.capturevideo, 0, sizeof(cls.capturevideo)); + // soundrate is figured out on the first SoundFrame + + if(width == 0 && height != 0) + width = (int) (height * (double)vid.width / ((double)vid.height * vid_pixelheight.value)); // keep aspect + if(width != 0 && height == 0) + height = (int) (width * ((double)vid.height * vid_pixelheight.value) / (double)vid.width); // keep aspect + + if(width < 2 || width > vid.width) // can't scale up + width = vid.width; + if(height < 2 || height > vid.height) // can't scale up + height = vid.height; + + // ensure it's all even; if not, scale down a little + if(width % 1) + --width; + if(height % 1) + --height; + + cls.capturevideo.width = width; + cls.capturevideo.height = height; + cls.capturevideo.active = true; + cls.capturevideo.framerate = bound(1, cl_capturevideo_fps.value, 1001) * bound(1, cl_capturevideo_framestep.integer, 64); + cls.capturevideo.framestep = cl_capturevideo_framestep.integer; + cls.capturevideo.soundrate = S_GetSoundRate(); + cls.capturevideo.soundchannels = S_GetSoundChannels(); + cls.capturevideo.startrealtime = realtime; + cls.capturevideo.frame = cls.capturevideo.lastfpsframe = 0; + cls.capturevideo.starttime = cls.capturevideo.lastfpstime = realtime; + cls.capturevideo.soundsampleframe = 0; + cls.capturevideo.realtime = cl_capturevideo_realtime.integer != 0; + cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4); + cls.capturevideo.outbuffer = (unsigned char *)Mem_Alloc(tempmempool, width * height * (4+4) + 18); + dpsnprintf(cls.capturevideo.basename, sizeof(cls.capturevideo.basename), "video/%s%03i", Sys_TimeString(cl_capturevideo_nameformat.string), cl_capturevideo_number.integer); + Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1); + + /* + for (i = 0;i < 256;i++) + { + unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255); + cls.capturevideo.rgbgammatable[0][i] = j; + cls.capturevideo.rgbgammatable[1][i] = j; + cls.capturevideo.rgbgammatable[2][i] = j; + } + */ +/* +R = Y + 1.4075 * (Cr - 128); +G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128); +B = Y + 1.7790 * (Cb - 128); +Y = R * .299 + G * .587 + B * .114; +Cb = R * -.169 + G * -.332 + B * .500 + 128.; +Cr = R * .500 + G * -.419 + B * -.0813 + 128.; +*/ + + if(WANT_SCREENSHOT_HWGAMMA) + { + VID_BuildGammaTables(&cls.capturevideo.vidramp[0], 256); + } + else + { + // identity gamma table + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256*2, 256); + } + if(scr_screenshot_gammaboost.value != 1) + { + double igamma = 1 / scr_screenshot_gammaboost.value; + for (i = 0;i < 256 * 3;i++) + cls.capturevideo.vidramp[i] = (unsigned short) (0.5 + pow(cls.capturevideo.vidramp[i] * (1.0 / 65535.0), igamma) * 65535.0); + } + + for (i = 0;i < 256;i++) + { + r = 255*cls.capturevideo.vidramp[i]/65535.0; + g = 255*cls.capturevideo.vidramp[i+256]/65535.0; + b = 255*cls.capturevideo.vidramp[i+512]/65535.0; + // NOTE: we have to round DOWN here, or integer overflows happen. Sorry for slightly wrong looking colors sometimes... + // Y weights from RGB + cls.capturevideo.rgbtoyuvscaletable[0][0][i] = (short)(r * 0.299); + cls.capturevideo.rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587); + cls.capturevideo.rgbtoyuvscaletable[0][2][i] = (short)(b * 0.114); + // Cb weights from RGB + cls.capturevideo.rgbtoyuvscaletable[1][0][i] = (short)(r * -0.169); + cls.capturevideo.rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332); + cls.capturevideo.rgbtoyuvscaletable[1][2][i] = (short)(b * 0.500); + // Cr weights from RGB + cls.capturevideo.rgbtoyuvscaletable[2][0][i] = (short)(r * 0.500); + cls.capturevideo.rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419); + cls.capturevideo.rgbtoyuvscaletable[2][2][i] = (short)(b * -0.0813); + // range reduction of YCbCr to valid signal range + cls.capturevideo.yuvnormalizetable[0][i] = 16 + i * (236-16) / 256; + cls.capturevideo.yuvnormalizetable[1][i] = 16 + i * (240-16) / 256; + cls.capturevideo.yuvnormalizetable[2][i] = 16 + i * (240-16) / 256; + } + + if (cl_capturevideo_ogg.integer) + { + if(SCR_CaptureVideo_Ogg_Available()) + { + SCR_CaptureVideo_Ogg_BeginVideo(); + return; + } + else + Con_Print("cl_capturevideo_ogg: libraries not available. Capturing in AVI instead.\n"); + } + + SCR_CaptureVideo_Avi_BeginVideo(); +} + +void SCR_CaptureVideo_EndVideo(void) +{ + if (!cls.capturevideo.active) + return; + cls.capturevideo.active = false; + + Con_Printf("Finishing capture of %s.%s (%d frames, %d audio frames)\n", cls.capturevideo.basename, cls.capturevideo.formatextension, cls.capturevideo.frame, cls.capturevideo.soundsampleframe); + + if (cls.capturevideo.videofile) + { + cls.capturevideo.endvideo(); + } + + if (cls.capturevideo.screenbuffer) + { + Mem_Free (cls.capturevideo.screenbuffer); + cls.capturevideo.screenbuffer = NULL; + } + + if (cls.capturevideo.outbuffer) + { + Mem_Free (cls.capturevideo.outbuffer); + cls.capturevideo.outbuffer = NULL; + } + + memset(&cls.capturevideo, 0, sizeof(cls.capturevideo)); +} + +static void SCR_ScaleDownBGRA(unsigned char *in, int inw, int inh, unsigned char *out, int outw, int outh) +{ + // TODO optimize this function + + int x, y; + float area; + + // memcpy is faster than me + if(inw == outw && inh == outh) + { + memcpy(out, in, 4 * inw * inh); + return; + } + + // otherwise: a box filter + area = (float)outw * (float)outh / (float)inw / (float)inh; + for(y = 0; y < outh; ++y) + { + float iny0 = y / (float)outh * inh; int iny0_i = (int) floor(iny0); + float iny1 = (y+1) / (float)outh * inh; int iny1_i = (int) ceil(iny1); + for(x = 0; x < outw; ++x) + { + float inx0 = x / (float)outw * inw; int inx0_i = (int) floor(inx0); + float inx1 = (x+1) / (float)outw * inw; int inx1_i = (int) ceil(inx1); + float r = 0, g = 0, b = 0, alpha = 0; + int xx, yy; + + for(yy = iny0_i; yy < iny1_i; ++yy) + { + float ya = min(yy+1, iny1) - max(iny0, yy); + for(xx = inx0_i; xx < inx1_i; ++xx) + { + float a = ya * (min(xx+1, inx1) - max(inx0, xx)); + r += a * in[4*(xx + inw * yy)+0]; + g += a * in[4*(xx + inw * yy)+1]; + b += a * in[4*(xx + inw * yy)+2]; + alpha += a * in[4*(xx + inw * yy)+3]; + } + } + + out[4*(x + outw * y)+0] = (unsigned char) (r * area); + out[4*(x + outw * y)+1] = (unsigned char) (g * area); + out[4*(x + outw * y)+2] = (unsigned char) (b * area); + out[4*(x + outw * y)+3] = (unsigned char) (alpha * area); + } + } +} + +static void SCR_CaptureVideo_VideoFrame(int newframestepframenum) +{ + int x = 0, y = 0; + int width = cls.capturevideo.width, height = cls.capturevideo.height; + + if(newframestepframenum == cls.capturevideo.framestepframe) + return; + + CHECKGLERROR + // speed is critical here, so do saving as directly as possible + + GL_ReadPixelsBGRA(x, y, vid.width, vid.height, cls.capturevideo.screenbuffer); + + SCR_ScaleDownBGRA (cls.capturevideo.screenbuffer, vid.width, vid.height, cls.capturevideo.outbuffer, width, height); + + cls.capturevideo.videoframes(newframestepframenum - cls.capturevideo.framestepframe); + cls.capturevideo.framestepframe = newframestepframenum; + + if(cl_capturevideo_printfps.integer) + { + char buf[80]; + double t = realtime; + if(t > cls.capturevideo.lastfpstime + 1) + { + double fps1 = (cls.capturevideo.frame - cls.capturevideo.lastfpsframe) / (t - cls.capturevideo.lastfpstime + 0.0000001); + double fps = (cls.capturevideo.frame ) / (t - cls.capturevideo.starttime + 0.0000001); + dpsnprintf(buf, sizeof(buf), "capturevideo: (%.1fs) last second %.3ffps, total %.3ffps\n", cls.capturevideo.frame / cls.capturevideo.framerate, fps1, fps); + Sys_PrintToTerminal(buf); + cls.capturevideo.lastfpstime = t; + cls.capturevideo.lastfpsframe = cls.capturevideo.frame; + } + } +} + +void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) +{ + cls.capturevideo.soundsampleframe += length; + cls.capturevideo.soundframe(paintbuffer, length); +} + +static void SCR_CaptureVideo(void) +{ + int newframenum; + if (cl_capturevideo.integer) + { + if (!cls.capturevideo.active) + SCR_CaptureVideo_BeginVideo(); + if (cls.capturevideo.framerate != cl_capturevideo_fps.value * cl_capturevideo_framestep.integer) + { + Con_Printf("You can not change the video framerate while recording a video.\n"); + Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo.framerate / (double) cl_capturevideo_framestep.integer); + } + // for AVI saving we have to make sure that sound is saved before video + if (cls.capturevideo.soundrate && !cls.capturevideo.soundsampleframe) + return; + if (cls.capturevideo.realtime) + { + // preserve sound sync by duplicating frames when running slow + newframenum = (int)((realtime - cls.capturevideo.startrealtime) * cls.capturevideo.framerate); + } + else + newframenum = cls.capturevideo.frame + 1; + // if falling behind more than one second, stop + if (newframenum - cls.capturevideo.frame > 60 * (int)ceil(cls.capturevideo.framerate)) + { + Cvar_SetValueQuick(&cl_capturevideo, 0); + Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo.frame); + SCR_CaptureVideo_EndVideo(); + return; + } + // write frames + SCR_CaptureVideo_VideoFrame(newframenum / cls.capturevideo.framestep); + cls.capturevideo.frame = newframenum; + if (cls.capturevideo.error) + { + Cvar_SetValueQuick(&cl_capturevideo, 0); + Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo.frame); + SCR_CaptureVideo_EndVideo(); + } + } + else if (cls.capturevideo.active) + SCR_CaptureVideo_EndVideo(); +} + +/* +=============== +R_Envmap_f + +Grab six views for environment mapping tests +=============== +*/ +struct envmapinfo_s +{ + float angles[3]; + const char *name; + qboolean flipx, flipy, flipdiagonaly; +} +envmapinfo[12] = +{ + {{ 0, 0, 0}, "rt", false, false, false}, + {{ 0, 270, 0}, "ft", false, false, false}, + {{ 0, 180, 0}, "lf", false, false, false}, + {{ 0, 90, 0}, "bk", false, false, false}, + {{-90, 180, 0}, "up", true, true, false}, + {{ 90, 180, 0}, "dn", true, true, false}, + + {{ 0, 0, 0}, "px", true, true, true}, + {{ 0, 90, 0}, "py", false, true, false}, + {{ 0, 180, 0}, "nx", false, false, true}, + {{ 0, 270, 0}, "ny", true, false, false}, + {{-90, 180, 0}, "pz", false, false, true}, + {{ 90, 180, 0}, "nz", false, false, true} +}; + +static void R_Envmap_f (void) +{ + int j, size; + char filename[MAX_QPATH], basename[MAX_QPATH]; + unsigned char *buffer1; + unsigned char *buffer2; + + if (Cmd_Argc() != 3) + { + Con_Print("envmap : save out 6 cubic environment map images, usable with loadsky, note that size must one of 128, 256, 512, or 1024 and can't be bigger than your current resolution\n"); + return; + } + + strlcpy (basename, Cmd_Argv(1), sizeof (basename)); + size = atoi(Cmd_Argv(2)); + if (size != 128 && size != 256 && size != 512 && size != 1024) + { + Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n"); + return; + } + if (size > vid.width || size > vid.height) + { + Con_Print("envmap: your resolution is not big enough to render that size\n"); + return; + } + + r_refdef.envmap = true; + + R_UpdateVariables(); + + r_refdef.view.x = 0; + r_refdef.view.y = 0; + r_refdef.view.z = 0; + r_refdef.view.width = size; + r_refdef.view.height = size; + r_refdef.view.depth = 1; + r_refdef.view.useperspective = true; + r_refdef.view.isoverlay = false; + + r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView + r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView + + buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 4); + buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3); + + for (j = 0;j < 12;j++) + { + dpsnprintf(filename, sizeof(filename), "env/%s%s.tga", basename, envmapinfo[j].name); + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], envmapinfo[j].angles[0], envmapinfo[j].angles[1], envmapinfo[j].angles[2], 1); + r_refdef.view.quality = 1; + r_refdef.view.clear = true; + R_Mesh_Start(); + R_RenderView(0.0); + R_Mesh_Finish(); + SCR_ScreenShot(filename, buffer1, buffer2, 0, vid.height - (r_refdef.view.y + r_refdef.view.height), size, size, envmapinfo[j].flipx, envmapinfo[j].flipy, envmapinfo[j].flipdiagonaly, false, false, false, false); + } + + Mem_Free (buffer1); + Mem_Free (buffer2); + + r_refdef.envmap = false; +} + +//============================================================================= + +void SHOWLMP_decodehide(void) +{ + int i; + char *lmplabel; + lmplabel = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + for (i = 0;i < cl.num_showlmps;i++) + if (cl.showlmps[i].isactive && strcmp(cl.showlmps[i].label, lmplabel) == 0) + { + cl.showlmps[i].isactive = false; + return; + } +} + +void SHOWLMP_decodeshow(void) +{ + int k; + char lmplabel[256], picname[256]; + float x, y; + strlcpy (lmplabel,MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (lmplabel)); + strlcpy (picname, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof (picname)); + if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk + { + x = MSG_ReadByte(&cl_message); + y = MSG_ReadByte(&cl_message); + } + else + { + x = MSG_ReadShort(&cl_message); + y = MSG_ReadShort(&cl_message); + } + if (!cl.showlmps || cl.num_showlmps >= cl.max_showlmps) + { + showlmp_t *oldshowlmps = cl.showlmps; + cl.max_showlmps += 16; + cl.showlmps = (showlmp_t *) Mem_Alloc(cls.levelmempool, cl.max_showlmps * sizeof(showlmp_t)); + if (cl.num_showlmps) + memcpy(cl.showlmps, oldshowlmps, cl.num_showlmps * sizeof(showlmp_t)); + if (oldshowlmps) + Mem_Free(oldshowlmps); + } + for (k = 0;k < cl.max_showlmps;k++) + if (cl.showlmps[k].isactive && !strcmp(cl.showlmps[k].label, lmplabel)) + break; + if (k == cl.max_showlmps) + for (k = 0;k < cl.max_showlmps;k++) + if (!cl.showlmps[k].isactive) + break; + cl.showlmps[k].isactive = true; + strlcpy (cl.showlmps[k].label, lmplabel, sizeof (cl.showlmps[k].label)); + strlcpy (cl.showlmps[k].pic, picname, sizeof (cl.showlmps[k].pic)); + cl.showlmps[k].x = x; + cl.showlmps[k].y = y; + cl.num_showlmps = max(cl.num_showlmps, k + 1); +} + +void SHOWLMP_drawall(void) +{ + int i; + for (i = 0;i < cl.num_showlmps;i++) + if (cl.showlmps[i].isactive) + DrawQ_Pic(cl.showlmps[i].x, cl.showlmps[i].y, Draw_CachePic_Flags (cl.showlmps[i].pic, CACHEPICFLAG_NOTPERSISTENT), 0, 0, 1, 1, 1, 1, 0); +} + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + +// buffer1: 4*w*h +// buffer2: 3*w*h (or 4*w*h if screenshotting alpha too) +qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *buffer2, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg, qboolean png, qboolean gammacorrect, qboolean keep_alpha) +{ + int indices[4] = {0,1,2,3}; // BGRA + qboolean ret; + + GL_ReadPixelsBGRA(x, y, width, height, buffer1); + + if(gammacorrect && (scr_screenshot_gammaboost.value != 1 || WANT_SCREENSHOT_HWGAMMA)) + { + int i; + double igamma = 1.0 / scr_screenshot_gammaboost.value; + unsigned short vidramp[256 * 3]; + if(WANT_SCREENSHOT_HWGAMMA) + { + VID_BuildGammaTables(&vidramp[0], 256); + } + else + { + // identity gamma table + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256*2, 256); + } + if(scr_screenshot_gammaboost.value != 1) + { + for (i = 0;i < 256 * 3;i++) + vidramp[i] = (unsigned short) (0.5 + pow(vidramp[i] * (1.0 / 65535.0), igamma) * 65535.0); + } + for (i = 0;i < width*height*4;i += 4) + { + buffer1[i] = (unsigned char) (vidramp[buffer1[i] + 512] * 255.0 / 65535.0 + 0.5); // B + buffer1[i+1] = (unsigned char) (vidramp[buffer1[i+1] + 256] * 255.0 / 65535.0 + 0.5); // G + buffer1[i+2] = (unsigned char) (vidramp[buffer1[i+2]] * 255.0 / 65535.0 + 0.5); // R + // A + } + } + + if(keep_alpha && !jpeg) + { + if(!png) + flipy = !flipy; // TGA: not preflipped + Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 4, 4, indices); + if (png) + ret = PNG_SaveImage_preflipped (filename, width, height, true, buffer2); + else + ret = Image_WriteTGABGRA(filename, width, height, buffer2); + } + else + { + if(jpeg) + { + indices[0] = 2; + indices[2] = 0; // RGB + } + Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 4, indices); + if (jpeg) + ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2); + else if (png) + ret = PNG_SaveImage_preflipped (filename, width, height, false, buffer2); + else + ret = Image_WriteTGABGR_preflipped (filename, width, height, buffer2); + } + + return ret; +} + +//============================================================================= + +int scr_numtouchscreenareas; +scr_touchscreenarea_t scr_touchscreenareas[16]; + +static void SCR_DrawTouchscreenOverlay(void) +{ + int i; + scr_touchscreenarea_t *a; + cachepic_t *pic; + for (i = 0, a = scr_touchscreenareas;i < scr_numtouchscreenareas;i++, a++) + { + if (vid_touchscreen_outlinealpha.value > 0 && a->rect[0] >= 0 && a->rect[1] >= 0 && a->rect[2] >= 4 && a->rect[3] >= 4) + { + DrawQ_Fill(a->rect[0] + 2, a->rect[1] , a->rect[2] - 4, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 1, a->rect[1] + 1, a->rect[2] - 2, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] , a->rect[1] + 2, 2 , a->rect[3] - 2, 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + a->rect[2] - 2, a->rect[1] + 2, 2 , a->rect[3] - 2, 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 1, a->rect[1] + a->rect[3] - 2, a->rect[2] - 2, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 2, a->rect[1] + a->rect[3] - 1, a->rect[2] - 4, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + } + pic = a->pic ? Draw_CachePic(a->pic) : NULL; + if (pic && pic->tex != r_texture_notexture) + DrawQ_Pic(a->rect[0], a->rect[1], Draw_CachePic(a->pic), a->rect[2], a->rect[3], 1, 1, 1, vid_touchscreen_overlayalpha.value * (0.5f + 0.5f * a->active), 0); + } +} + +void R_ClearScreen(qboolean fogcolor) +{ + float clearcolor[4]; + // clear to black + Vector4Clear(clearcolor); + if (fogcolor && r_fog_clear.integer) + { + R_UpdateFog(); + VectorCopy(r_refdef.fogcolor, clearcolor); + } + // clear depth is 1.0 + // LordHavoc: we use a stencil centered around 128 instead of 0, + // to avoid clamping interfering with strange shadow volume + // drawing orders + // clear the screen + GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (vid.stencil ? GL_STENCIL_BUFFER_BIT : 0), clearcolor, 1.0f, 128); +} + +extern int r_stereo_side; + +/*static*/ void SCR_DrawScreen (int x, int y) +{ + Draw_Frame(); + + R_Mesh_Start(); + + R_UpdateVariables(); + + // Quake uses clockwise winding, so these are swapped + r_refdef.view.cullface_front = GL_BACK; + r_refdef.view.cullface_back = GL_FRONT; + + if (cls.signon == SIGNONS) + { + float size; + + size = scr_viewsize.value * (1.0 / 100.0); + size = min(size, 1); + + r_refdef.view.width = (int)(vid.width * size); + r_refdef.view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100)); + r_refdef.view.depth = 1; + r_refdef.view.x = (int)((vid.width - r_refdef.view.width)/2) + x; + r_refdef.view.y = (int)((vid.height - r_refdef.view.height)/2) + y; + r_refdef.view.z = 0; + + // LordHavoc: viewzoom (zoom in for sniper rifles, etc) + // LordHavoc: this is designed to produce widescreen fov values + // when the screen is wider than 4/3 width/height aspect, to do + // this it simply assumes the requested fov is the vertical fov + // for a 4x3 display, if the ratio is not 4x3 this makes the fov + // higher/lower according to the ratio + r_refdef.view.useperspective = true; + r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom; + r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value; + + r_refdef.view.frustum_x *= r_refdef.frustumscale_x; + r_refdef.view.frustum_y *= r_refdef.frustumscale_y; + r_refdef.view.ortho_x = atan(r_refdef.view.frustum_x) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView + r_refdef.view.ortho_y = atan(r_refdef.view.frustum_y) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView + + if(!CL_VM_UpdateView(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime))) + R_RenderView(); + } + + r_refdef.view.width = vid.width; + r_refdef.view.height = vid.height; + r_refdef.view.depth = 1; + r_refdef.view.x = x; + r_refdef.view.y = y; + r_refdef.view.z = 0; + r_refdef.view.useperspective = false; + + if (cls.timedemo && cls.td_frames > 0 && timedemo_screenshotframelist.string && timedemo_screenshotframelist.string[0]) + { + const char *t; + int framenum; + t = timedemo_screenshotframelist.string; + while (*t) + { + while (*t == ' ') + t++; + if (!*t) + break; + framenum = atof(t); + if (framenum == cls.td_frames) + break; + while (*t && *t != ' ') + t++; + } + if (*t) + { + // we need to take a screenshot of this frame... + char filename[MAX_QPATH]; + unsigned char *buffer1; + unsigned char *buffer2; + dpsnprintf(filename, sizeof(filename), "timedemoscreenshots/%s%06d.tga", cls.demoname, cls.td_frames); + buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4); + buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3); + SCR_ScreenShot(filename, buffer1, buffer2, 0, 0, vid.width, vid.height, false, false, false, false, false, true, false); + Mem_Free(buffer1); + Mem_Free(buffer2); + } + } + + // draw 2D stuff + if(!scr_con_current && !(key_consoleactive & KEY_CONSOLEACTIVE_FORCED)) + if ((key_dest == key_game || key_dest == key_message) && !r_letterbox.value) + Con_DrawNotify (); // only draw notify in game + + if (cls.signon == SIGNONS) + { + SCR_DrawNet (); + SCR_DrawTurtle (); + SCR_DrawPause (); + if (!r_letterbox.value) + Sbar_Draw(); + SHOWLMP_drawall(); + SCR_CheckDrawCenterString(); + } + SCR_DrawNetGraph (); + MR_Draw(); + CL_DrawVideo(); + R_Shadow_EditLights_DrawSelectedLightProperties(); + + SCR_DrawConsole(); + + SCR_DrawBrand(); + + SCR_DrawInfobar(); + + // No need for this + //SCR_DrawTouchscreenOverlay(); + + if (r_timereport_active) + R_TimeReport("2d"); + + R_TimeReport_EndFrame(); + R_TimeReport_BeginFrame(); + Sbar_ShowFPS(); + + DrawQ_Finish(); + + R_DrawGamma(); + + R_Mesh_Finish(); +} + +typedef struct loadingscreenstack_s +{ + struct loadingscreenstack_s *prev; + char msg[MAX_QPATH]; + float absolute_loading_amount_min; // this corresponds to relative completion 0 of this item + float absolute_loading_amount_len; // this corresponds to relative completion 1 of this item + float relative_completion; // 0 .. 1 +} +loadingscreenstack_t; +static loadingscreenstack_t *loadingscreenstack = NULL; +static qboolean loadingscreendone = false; +static qboolean loadingscreencleared = false; +static float loadingscreenheight = 0; +rtexture_t *loadingscreentexture = NULL; +static float loadingscreentexture_vertex3f[12]; +static float loadingscreentexture_texcoord2f[8]; +static int loadingscreenpic_number = 0; + +static void SCR_ClearLoadingScreenTexture(void) +{ + if(loadingscreentexture) + R_FreeTexture(loadingscreentexture); + loadingscreentexture = NULL; +} + +extern rtexturepool_t *r_main_texturepool; +static void SCR_SetLoadingScreenTexture(void) +{ + int w, h; + float loadingscreentexture_w; + float loadingscreentexture_h; + + SCR_ClearLoadingScreenTexture(); + + if (vid.support.arb_texture_non_power_of_two) + { + w = vid.width; h = vid.height; + loadingscreentexture_w = loadingscreentexture_h = 1; + } + else + { + w = CeilPowerOf2(vid.width); h = CeilPowerOf2(vid.height); + loadingscreentexture_w = vid.width / (float) w; + loadingscreentexture_h = vid.height / (float) h; + } + + loadingscreentexture = R_LoadTexture2D(r_main_texturepool, "loadingscreentexture", w, h, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP, -1, NULL); + R_Mesh_CopyToTexture(loadingscreentexture, 0, 0, 0, 0, vid.width, vid.height); + + loadingscreentexture_vertex3f[2] = loadingscreentexture_vertex3f[5] = loadingscreentexture_vertex3f[8] = loadingscreentexture_vertex3f[11] = 0; + loadingscreentexture_vertex3f[0] = loadingscreentexture_vertex3f[9] = 0; + loadingscreentexture_vertex3f[1] = loadingscreentexture_vertex3f[4] = 0; + loadingscreentexture_vertex3f[3] = loadingscreentexture_vertex3f[6] = vid_conwidth.integer; + loadingscreentexture_vertex3f[7] = loadingscreentexture_vertex3f[10] = vid_conheight.integer; + loadingscreentexture_texcoord2f[0] = 0;loadingscreentexture_texcoord2f[1] = loadingscreentexture_h; + loadingscreentexture_texcoord2f[2] = loadingscreentexture_w;loadingscreentexture_texcoord2f[3] = loadingscreentexture_h; + loadingscreentexture_texcoord2f[4] = loadingscreentexture_w;loadingscreentexture_texcoord2f[5] = 0; + loadingscreentexture_texcoord2f[6] = 0;loadingscreentexture_texcoord2f[7] = 0; +} + +void SCR_UpdateLoadingScreenIfShown(void) +{ + if(loadingscreendone) + SCR_UpdateLoadingScreen(loadingscreencleared, false); +} + +void SCR_PushLoadingScreen (qboolean redraw, const char *msg, float len_in_parent) +{ + loadingscreenstack_t *s = (loadingscreenstack_t *) Z_Malloc(sizeof(loadingscreenstack_t)); + s->prev = loadingscreenstack; + loadingscreenstack = s; + + strlcpy(s->msg, msg, sizeof(s->msg)); + s->relative_completion = 0; + + if(s->prev) + { + s->absolute_loading_amount_min = s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len * s->prev->relative_completion; + s->absolute_loading_amount_len = s->prev->absolute_loading_amount_len * len_in_parent; + if(s->absolute_loading_amount_len > s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len - s->absolute_loading_amount_min) + s->absolute_loading_amount_len = s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len - s->absolute_loading_amount_min; + } + else + { + s->absolute_loading_amount_min = 0; + s->absolute_loading_amount_len = 1; + } + + if(redraw) + SCR_UpdateLoadingScreenIfShown(); +} + +void SCR_PopLoadingScreen (qboolean redraw) +{ + loadingscreenstack_t *s = loadingscreenstack; + + if(!s) + { + Con_DPrintf("Popping a loading screen item from an empty stack!\n"); + return; + } + + loadingscreenstack = s->prev; + if(s->prev) + s->prev->relative_completion = (s->absolute_loading_amount_min + s->absolute_loading_amount_len - s->prev->absolute_loading_amount_min) / s->prev->absolute_loading_amount_len; + Z_Free(s); + + if(redraw) + SCR_UpdateLoadingScreenIfShown(); +} + +void SCR_ClearLoadingScreen (qboolean redraw) +{ + while(loadingscreenstack) + SCR_PopLoadingScreen(redraw && !loadingscreenstack->prev); +} + +static float SCR_DrawLoadingStack_r(loadingscreenstack_t *s, float y, float size) +{ + float x; + size_t len; + float total; + + total = 0; +#if 0 + if(s) + { + total += SCR_DrawLoadingStack_r(s->prev, y, 8); + y -= total; + if(!s->prev || strcmp(s->msg, s->prev->msg)) + { + len = strlen(s->msg); + x = (vid_conwidth.integer - DrawQ_TextWidth(s->msg, len, size, size, true, FONT_INFOBAR)) / 2; + y -= size; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, 1, 0); + DrawQ_String(x, y, s->msg, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + total += size; + } + } +#else + if(s) + { + len = strlen(s->msg); + x = (vid_conwidth.integer - DrawQ_TextWidth(s->msg, len, size, size, true, FONT_INFOBAR)) / 2; + y -= size; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, 1, 0); + DrawQ_String(x, y, s->msg, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + total += size; + } +#endif + return total; +} + +static void SCR_DrawLoadingStack(void) +{ + float verts[12]; + float colors[16]; + + loadingscreenheight = SCR_DrawLoadingStack_r(loadingscreenstack, vid_conheight.integer, scr_loadingscreen_barheight.value); + if(loadingscreenstack) + { + // height = 32; // sorry, using the actual one is ugly + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(false); +// R_Mesh_ResetTextureState(); + verts[2] = verts[5] = verts[8] = verts[11] = 0; + verts[0] = verts[9] = 0; + verts[1] = verts[4] = vid_conheight.integer - scr_loadingscreen_barheight.value; + verts[3] = verts[6] = vid_conwidth.integer * loadingscreenstack->absolute_loading_amount_min; + verts[7] = verts[10] = vid_conheight.integer; + +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + // ^^^^^^^^^^ blue component + // ^^^^^^ bottom row + // ^^^^^^^^^^^^ alpha is always on + colors[0] = 0; colors[1] = 0; colors[2] = 0; colors[3] = 1; + colors[4] = 0; colors[5] = 0; colors[6] = 0; colors[7] = 1; + sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[8], &colors[9], &colors[10]); colors[11] = 1; + sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[12], &colors[13], &colors[14]); colors[15] = 1; + + R_Mesh_PrepareVertices_Generic_Arrays(4, verts, colors, NULL); + R_SetupShader_Generic_NoTexture(true, true); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + + // make sure everything is cleared, including the progress indicator + if(loadingscreenheight < 8) + loadingscreenheight = 8; + } +} + +static cachepic_t *loadingscreenpic; +static float loadingscreenpic_vertex3f[12]; +static float loadingscreenpic_texcoord2f[8]; + +static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear) +{ + r_viewport_t viewport; + float x, y, w, h, sw, sh, f; + char vabuf[1024]; + // release mouse grab while loading + if (!vid.fullscreen) + VID_SetMouse(false, false, false); +// CHECKGLERROR + r_refdef.draw2dstage = true; + R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL); + R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL); + R_SetViewport(&viewport); + GL_ColorMask(1,1,1,1); + // when starting up a new video mode, make sure the screen is cleared to black + if (clear || loadingscreentexture) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0); + R_Textures_Frame(); + R_Mesh_Start(); + R_EntityMatrix(&identitymatrix); + // draw the loading plaque + loadingscreenpic = Draw_CachePic_Flags (loadingscreenpic_number ? va(vabuf, sizeof(vabuf), "%s%d", scr_loadingscreen_picture.string, loadingscreenpic_number+1) : scr_loadingscreen_picture.string, loadingscreenpic_number ? CACHEPICFLAG_NOTPERSISTENT : 0); + + w = loadingscreenpic->width; + h = loadingscreenpic->height; + + // apply scale + w *= scr_loadingscreen_scale.value; + h *= scr_loadingscreen_scale.value; + + // apply scale base + if(scr_loadingscreen_scale_base.integer) + { + w *= vid_conwidth.integer / (float) vid.width; + h *= vid_conheight.integer / (float) vid.height; + } + + // apply scale limit + sw = w / vid_conwidth.integer; + sh = h / vid_conheight.integer; + f = 1; + switch(scr_loadingscreen_scale_limit.integer) + { + case 1: + f = max(sw, sh); + break; + case 2: + f = min(sw, sh); + break; + case 3: + f = sw; + break; + case 4: + f = sh; + break; + } + if(f > 1) + { + w /= f; + h /= f; + } + + x = (vid_conwidth.integer - w)/2; + y = (vid_conheight.integer - h)/2; + loadingscreenpic_vertex3f[2] = loadingscreenpic_vertex3f[5] = loadingscreenpic_vertex3f[8] = loadingscreenpic_vertex3f[11] = 0; + loadingscreenpic_vertex3f[0] = loadingscreenpic_vertex3f[9] = x; + loadingscreenpic_vertex3f[1] = loadingscreenpic_vertex3f[4] = y; + loadingscreenpic_vertex3f[3] = loadingscreenpic_vertex3f[6] = x + w; + loadingscreenpic_vertex3f[7] = loadingscreenpic_vertex3f[10] = y + h; + loadingscreenpic_texcoord2f[0] = 0;loadingscreenpic_texcoord2f[1] = 0; + loadingscreenpic_texcoord2f[2] = 1;loadingscreenpic_texcoord2f[3] = 0; + loadingscreenpic_texcoord2f[4] = 1;loadingscreenpic_texcoord2f[5] = 1; + loadingscreenpic_texcoord2f[6] = 0;loadingscreenpic_texcoord2f[7] = 1; +} + +static void SCR_DrawLoadingScreen (qboolean clear) +{ + // we only need to draw the image if it isn't already there + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(false); +// R_Mesh_ResetTextureState(); + GL_Color(1,1,1,1); + if(loadingscreentexture) + { + R_Mesh_PrepareVertices_Generic_Arrays(4, loadingscreentexture_vertex3f, NULL, loadingscreentexture_texcoord2f); + R_SetupShader_Generic(loadingscreentexture, NULL, GL_MODULATE, 1, true, true, true); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + } + R_Mesh_PrepareVertices_Generic_Arrays(4, loadingscreenpic_vertex3f, NULL, loadingscreenpic_texcoord2f); + R_SetupShader_Generic(Draw_GetPicTexture(loadingscreenpic), NULL, GL_MODULATE, 1, true, true, false); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + SCR_DrawLoadingStack(); +} + +static void SCR_DrawLoadingScreen_SharedFinish (qboolean clear) +{ + R_Mesh_Finish(); + // refresh + VID_Finish(); +} + +static double loadingscreen_lastupdate; + +void SCR_UpdateLoadingScreen (qboolean clear, qboolean startup) +{ + keydest_t old_key_dest; + int old_key_consoleactive; + + // don't do anything if not initialized yet + if (vid_hidden || cls.state == ca_dedicated) + return; + + // limit update rate + if (scr_loadingscreen_maxfps.value) + { + double t = Sys_DirtyTime(); + if ((t - loadingscreen_lastupdate) < 1.0f/scr_loadingscreen_maxfps.value) + return; + loadingscreen_lastupdate = t; + } + + if(!scr_loadingscreen_background.integer) + clear = true; + + if(loadingscreendone) + clear |= loadingscreencleared; + + if(!loadingscreendone) + { + if(startup && scr_loadingscreen_firstforstartup.integer) + loadingscreenpic_number = 0; + else if(scr_loadingscreen_firstforstartup.integer) + if(scr_loadingscreen_count.integer > 1) + loadingscreenpic_number = rand() % (scr_loadingscreen_count.integer - 1) + 1; + else + loadingscreenpic_number = 0; + else + loadingscreenpic_number = rand() % (scr_loadingscreen_count.integer > 1 ? scr_loadingscreen_count.integer : 1); + } + + if(clear) + SCR_ClearLoadingScreenTexture(); + else if(!loadingscreendone) + SCR_SetLoadingScreenTexture(); + + if(!loadingscreendone) + { + loadingscreendone = true; + loadingscreenheight = 0; + } + loadingscreencleared = clear; + +#ifdef USE_GLES2 + SCR_DrawLoadingScreen_SharedSetup(clear); + SCR_DrawLoadingScreen(clear); +#else + if (qglDrawBuffer) + qglDrawBuffer(GL_BACK); + SCR_DrawLoadingScreen_SharedSetup(clear); + if (vid.stereobuffer && qglDrawBuffer) + { + qglDrawBuffer(GL_BACK_LEFT); + SCR_DrawLoadingScreen(clear); + qglDrawBuffer(GL_BACK_RIGHT); + SCR_DrawLoadingScreen(clear); + } + else + { + if (qglDrawBuffer) + qglDrawBuffer(GL_BACK); + SCR_DrawLoadingScreen(clear); + } +#endif + SCR_DrawLoadingScreen_SharedFinish(clear); + + // this goes into the event loop, and should prevent unresponsive cursor on vista + old_key_dest = key_dest; + old_key_consoleactive = key_consoleactive; + key_dest = key_void; + key_consoleactive = false; + Key_EventQueue_Block(); Sys_SendKeyEvents(); + key_dest = old_key_dest; + key_consoleactive = old_key_consoleactive; +} + +extern cvar_t cl_minfps; +extern cvar_t cl_minfps_fade; +extern cvar_t cl_minfps_qualitymax; +extern cvar_t cl_minfps_qualitymin; +extern cvar_t cl_minfps_qualitymultiply; +extern cvar_t cl_minfps_qualityhysteresis; +extern cvar_t cl_minfps_qualitystepmax; +extern cvar_t cl_minfps_force; +static double cl_updatescreen_quality = 1; +void CL_BeginUpdateScreen() +{ + vec3_t vieworigin; + static double drawscreenstart = 0.0; + double drawscreendelta; + float conwidth, conheight; + r_viewport_t viewport; + + if(drawscreenstart) + { + drawscreendelta = Sys_DirtyTime() - drawscreenstart; + if (cl_minfps.value > 0 && (cl_minfps_force.integer || !(cls.timedemo || (cls.capturevideo.active && !cls.capturevideo.realtime))) && drawscreendelta >= 0 && drawscreendelta < 60) + { + // quality adjustment according to render time + double actualframetime; + double targetframetime; + double adjust; + double f; + double h; + + // fade lastdrawscreentime + r_refdef.lastdrawscreentime += (drawscreendelta - r_refdef.lastdrawscreentime) * cl_minfps_fade.value; + + // find actual and target frame times + actualframetime = r_refdef.lastdrawscreentime; + targetframetime = (1.0 / cl_minfps.value); + + // we scale hysteresis by quality + h = cl_updatescreen_quality * cl_minfps_qualityhysteresis.value; + + // calculate adjustment assuming linearity + f = cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value; + adjust = (targetframetime - actualframetime) * f; + + // one sided hysteresis + if(adjust > 0) + adjust = max(0, adjust - h); + + // adjust > 0 if: + // (targetframetime - actualframetime) * f > h + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value) > (cl_updatescreen_quality * cl_minfps_qualityhysteresis.value) + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_minfps_qualitymultiply.value / actualframetime) > cl_minfps_qualityhysteresis.value + // (1.0 / cl_minfps.value) * (cl_minfps_qualitymultiply.value / actualframetime) - cl_minfps_qualitymultiply.value > cl_minfps_qualityhysteresis.value + // (1.0 / cl_minfps.value) * (cl_minfps_qualitymultiply.value / actualframetime) > cl_minfps_qualityhysteresis.value + cl_minfps_qualitymultiply.value + // (1.0 / cl_minfps.value) / actualframetime > (cl_minfps_qualityhysteresis.value + cl_minfps_qualitymultiply.value) / cl_minfps_qualitymultiply.value + // (1.0 / cl_minfps.value) / actualframetime > 1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value + // cl_minfps.value * actualframetime < 1.0 / (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + // actualframetime < 1.0 / cl_minfps.value / (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + // actualfps > cl_minfps.value * (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value) + + // adjust < 0 if: + // (targetframetime - actualframetime) * f < 0 + // ((1.0 / cl_minfps.value) - actualframetime) * (cl_updatescreen_quality / actualframetime * cl_minfps_qualitymultiply.value) < 0 + // ((1.0 / cl_minfps.value) - actualframetime) < 0 + // -actualframetime) < -(1.0 / cl_minfps.value) + // actualfps < cl_minfps.value + + /* + Con_Printf("adjust UP if fps > %f, adjust DOWN if fps < %f\n", + cl_minfps.value * (1.0 + cl_minfps_qualityhysteresis.value / cl_minfps_qualitymultiply.value), + cl_minfps.value); + */ + + // don't adjust too much at once + adjust = bound(-cl_minfps_qualitystepmax.value, adjust, cl_minfps_qualitystepmax.value); + + // adjust! + cl_updatescreen_quality += adjust; + cl_updatescreen_quality = bound(max(0.01, cl_minfps_qualitymin.value), cl_updatescreen_quality, cl_minfps_qualitymax.value); + } + else + { + cl_updatescreen_quality = 1; + r_refdef.lastdrawscreentime = 0; + } + } + + drawscreenstart = Sys_DirtyTime(); + + Sbar_ShowFPS_Update(); + + if (!scr_initialized || !con_initialized || !scr_refresh.integer) + return; // not initialized yet + + loadingscreendone = false; + + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + // play a bit with the palette (experimental) + palette_rgb_pantscolormap[15][0] = (unsigned char) (128 + 127 * sin(cl.time / exp(1.0f) + 0.0f*M_PI/3.0f)); + palette_rgb_pantscolormap[15][1] = (unsigned char) (128 + 127 * sin(cl.time / exp(1.0f) + 2.0f*M_PI/3.0f)); + palette_rgb_pantscolormap[15][2] = (unsigned char) (128 + 127 * sin(cl.time / exp(1.0f) + 4.0f*M_PI/3.0f)); + palette_rgb_shirtcolormap[15][0] = (unsigned char) (128 + 127 * sin(cl.time / M_PI + 5.0f*M_PI/3.0f)); + palette_rgb_shirtcolormap[15][1] = (unsigned char) (128 + 127 * sin(cl.time / M_PI + 3.0f*M_PI/3.0f)); + palette_rgb_shirtcolormap[15][2] = (unsigned char) (128 + 127 * sin(cl.time / M_PI + 1.0f*M_PI/3.0f)); + memcpy(palette_rgb_pantsscoreboard[15], palette_rgb_pantscolormap[15], sizeof(*palette_rgb_pantscolormap)); + memcpy(palette_rgb_shirtscoreboard[15], palette_rgb_shirtcolormap[15], sizeof(*palette_rgb_shirtcolormap)); + } + + if (vid_hidden) + { + VID_Finish(); + return; + } + + conwidth = bound(160, vid_conwidth.value, 32768); + conheight = bound(90, vid_conheight.value, 24576); + if (vid_conwidth.value != conwidth) + Cvar_SetValue("vid_conwidth", conwidth); + if (vid_conheight.value != conheight) + Cvar_SetValue("vid_conheight", conheight); + + // 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 < 1) + Cvar_Set ("fov","1"); + if (scr_fov.value > 170) + Cvar_Set ("fov","170"); + + // intermission is always full screen + if (cl.intermission) + sb_lines = 0; + else + { + if (scr_viewsize.value >= 120) + sb_lines = 0; // no status bar at all + else if (scr_viewsize.value >= 110) + sb_lines = 24; // no inventory + else + sb_lines = 24+16+8; + } + + R_FrameData_NewFrame(); + R_BufferData_NewFrame(); + + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin); + R_HDR_UpdateIrisAdaptation(vieworigin); + + r_refdef.view.colormask[0] = 1; + r_refdef.view.colormask[1] = 1; + r_refdef.view.colormask[2] = 1; + + SCR_SetUpToDrawConsole(); + + R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL); + R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL); + R_SetViewport(&viewport); + GL_ScissorTest(false); + GL_ColorMask(1,1,1,1); + GL_DepthMask(true); + + R_ClearScreen(false); + r_refdef.view.clear = false; + r_refdef.view.isoverlay = false; + + // calculate r_refdef.view.quality + r_refdef.view.quality = cl_updatescreen_quality; +} + + +void CL_EndUpdateScreen() +{ + SCR_CaptureVideo(); + +// if (qglFlush) +// qglFlush(); // FIXME: should we really be using qglFlush here? + + if (!vid_activewindow) + VID_SetMouse(false, false, false); + else if (key_consoleactive) + VID_SetMouse(vid.fullscreen, false, false); + else if (key_dest == key_menu_grabbed) + VID_SetMouse(true, vid_mouse.integer && !in_client_mouse && !vid_touchscreen.integer, !vid_touchscreen.integer); + else if (key_dest == key_menu) + VID_SetMouse(vid.fullscreen, vid_mouse.integer && !in_client_mouse && !vid_touchscreen.integer, !vid_touchscreen.integer); + else + VID_SetMouse(vid.fullscreen, vid_mouse.integer && !cl.csqc_wantsmousemove && cl_prydoncursor.integer <= 0 && (!cls.demoplayback || cl_demo_mousegrab.integer) && !vid_touchscreen.integer, !vid_touchscreen.integer); + + VID_Finish(); +} + +void CL_Screen_NewMap(void) +{ +} diff --git a/app/jni/cl_screen.h b/app/jni/cl_screen.h new file mode 100644 index 0000000..ddf611f --- /dev/null +++ b/app/jni/cl_screen.h @@ -0,0 +1,30 @@ + +#ifndef CL_SCREEN_H +#define CL_SCREEN_H + +void SHOWLMP_decodehide(void); +void SHOWLMP_decodeshow(void); +void SHOWLMP_drawall(void); + +extern cvar_t vid_conwidth; +extern cvar_t vid_conheight; +extern cvar_t vid_pixelheight; +extern cvar_t scr_screenshot_jpeg; +extern cvar_t scr_screenshot_jpeg_quality; +extern cvar_t scr_screenshot_png; +extern cvar_t scr_screenshot_gammaboost; +extern cvar_t scr_screenshot_name; + +void CL_Screen_NewMap(void); +void CL_Screen_Init(void); +void CL_Screen_Shutdown(void); +void CL_BeginUpdateScreen(); +void CL_EndUpdateScreen(); + +void SCR_DrawScreen (); + +qboolean R_Stereo_Active(void); +qboolean R_Stereo_ColorMasking(void); + +#endif + diff --git a/app/jni/cl_video.c b/app/jni/cl_video.c new file mode 100644 index 0000000..1089b75 --- /dev/null +++ b/app/jni/cl_video.c @@ -0,0 +1,743 @@ + +#include "quakedef.h" +#include "cl_dyntexture.h" +#include "cl_video.h" + +// cvars +cvar_t cl_video_subtitles = {CVAR_SAVE, "cl_video_subtitles", "0", "show subtitles for videos (if they are present)"}; +cvar_t cl_video_subtitles_lines = {CVAR_SAVE, "cl_video_subtitles_lines", "4", "how many lines to occupy for subtitles"}; +cvar_t cl_video_subtitles_textsize = {CVAR_SAVE, "cl_video_subtitles_textsize", "16", "textsize for subtitles"}; +cvar_t cl_video_scale = {CVAR_SAVE, "cl_video_scale", "1", "scale of video, 1 = fullscreen, 0.75 - 3/4 of screen etc."}; +cvar_t cl_video_scale_vpos = {CVAR_SAVE, "cl_video_scale_vpos", "0", "vertical align of scaled video, -1 is top, 1 is bottom"}; +cvar_t cl_video_stipple = {CVAR_SAVE, "cl_video_stipple", "0", "draw interlacing-like effect on videos, similar to scr_stipple but static and used only with video playing."}; +cvar_t cl_video_brightness = {CVAR_SAVE, "cl_video_brightness", "1", "brightness of video, 1 = fullbright, 0.75 - 3/4 etc."}; +cvar_t cl_video_keepaspectratio = {CVAR_SAVE, "cl_video_keepaspectratio", "0", "keeps aspect ratio of fullscreen videos, leaving black color on unfilled areas, a value of 2 let video to be stretched horizontally with top & bottom being sliced out"}; +cvar_t cl_video_fadein = {CVAR_SAVE, "cl_video_fadein", "0", "fading-from-black effect once video is started, in seconds"}; +cvar_t cl_video_fadeout = {CVAR_SAVE, "cl_video_fadeout", "0", "fading-to-black effect once video is ended, in seconds"}; + +cvar_t v_glslgamma_video = {CVAR_SAVE, "v_glslgamma_video", "1", "applies GLSL gamma to played video, could be a fraction, requires r_glslgamma_2d 1."}; + +// DPV stream decoder +#include "dpvsimpledecode.h" + +// VorteX: libavcodec implementation +#include "cl_video_libavw.c" + +// JAM video decoder used by Blood Omnicide +#ifdef JAMVIDEO +#include "cl_video_jamdecode.c" +#endif + +// constants (and semi-constants) +static int cl_videormask; +static int cl_videobmask; +static int cl_videogmask; +static int cl_videobytesperpixel; + +static int cl_num_videos; +static clvideo_t cl_videos[ MAXCLVIDEOS ]; +static rtexturepool_t *cl_videotexturepool; + +static clvideo_t *FindUnusedVid( void ) +{ + int i; + for( i = 1 ; i < MAXCLVIDEOS ; i++ ) + if( cl_videos[ i ].state == CLVIDEO_UNUSED ) + return &cl_videos[ i ]; + return NULL; +} + +static qboolean OpenStream( clvideo_t * video ) +{ + const char *errorstring; + + video->stream = dpvsimpledecode_open( video, video->filename, &errorstring); + if (video->stream) + return true; + +#ifdef JAMVIDEO + video->stream = jam_open( video, video->filename, &errorstring); + if (video->stream) + return true; +#endif + + video->stream = LibAvW_OpenVideo( video, video->filename, &errorstring); + if (video->stream) + return true; + + Con_Printf("unable to open \"%s\", error: %s\n", video->filename, errorstring); + return false; +} + +static void VideoUpdateCallback(rtexture_t *rt, void *data) +{ + clvideo_t *video = (clvideo_t *) data; + R_UpdateTexture( video->cpif.tex, (unsigned char *)video->imagedata, 0, 0, 0, video->cpif.width, video->cpif.height, 1 ); +} + +static void LinkVideoTexture( clvideo_t *video ) +{ + video->cpif.tex = R_LoadTexture2D( cl_videotexturepool, video->cpif.name, video->cpif.width, video->cpif.height, NULL, TEXTYPE_BGRA, TEXF_PERSISTENT | TEXF_CLAMP, -1, NULL ); + R_MakeTextureDynamic( video->cpif.tex, VideoUpdateCallback, video ); + CL_LinkDynTexture( video->cpif.name, video->cpif.tex ); +} + +static void UnlinkVideoTexture( clvideo_t *video ) +{ + CL_UnlinkDynTexture( video->cpif.name ); + // free the texture + R_FreeTexture( video->cpif.tex ); + video->cpif.tex = NULL; + // free the image data + Mem_Free( video->imagedata ); +} + +static void SuspendVideo( clvideo_t * video ) +{ + if (video->suspended) + return; + video->suspended = true; + UnlinkVideoTexture(video); + // if we are in firstframe mode, also close the stream + if (video->state == CLVIDEO_FIRSTFRAME) + { + if (video->stream) + video->close(video->stream); + video->stream = NULL; + } +} + +static qboolean WakeVideo( clvideo_t * video ) +{ + if( !video->suspended ) + return true; + video->suspended = false; + + if( video->state == CLVIDEO_FIRSTFRAME ) + if( !OpenStream( video ) ) { + video->state = CLVIDEO_UNUSED; + return false; + } + + video->imagedata = Mem_Alloc( cls.permanentmempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel ); + LinkVideoTexture( video ); + + // update starttime + video->starttime += realtime - video->lasttime; + + return true; +} + +static void LoadSubtitles( clvideo_t *video, const char *subtitlesfile ) +{ + char *subtitle_text; + const char *data; + float subtime, sublen; + int numsubs = 0; + + if (gamemode == GAME_BLOODOMNICIDE) + { + char overridename[MAX_QPATH]; + cvar_t *langcvar; + + langcvar = Cvar_FindVar("language"); + subtitle_text = NULL; + if (langcvar) + { + dpsnprintf(overridename, sizeof(overridename), "locale/%s/%s", langcvar->string, subtitlesfile); + subtitle_text = (char *)FS_LoadFile(overridename, cls.permanentmempool, false, NULL); + } + if (!subtitle_text) + subtitle_text = (char *)FS_LoadFile(subtitlesfile, cls.permanentmempool, false, NULL); + } + else + { + subtitle_text = (char *)FS_LoadFile(subtitlesfile, cls.permanentmempool, false, NULL); + } + if (!subtitle_text) + { + Con_DPrintf( "LoadSubtitles: can't open subtitle file '%s'!\n", subtitlesfile ); + return; + } + + // parse subtitle_text + // line is: x y "text" where + // x - start time + // y - seconds last (if 0 - last thru next sub, if negative - last to next sub - this amount of seconds) + + data = subtitle_text; + for (;;) + { + if (!COM_ParseToken_QuakeC(&data, false)) + break; + subtime = atof( com_token ); + if (!COM_ParseToken_QuakeC(&data, false)) + break; + sublen = atof( com_token ); + if (!COM_ParseToken_QuakeC(&data, false)) + break; + if (!com_token[0]) + continue; + // check limits + if (video->subtitles == CLVIDEO_MAX_SUBTITLES) + { + Con_Printf("WARNING: CLVIDEO_MAX_SUBTITLES = %i reached when reading subtitles from '%s'\n", CLVIDEO_MAX_SUBTITLES, subtitlesfile); + break; + } + // add a sub + video->subtitle_text[numsubs] = (char *) Mem_Alloc(cls.permanentmempool, strlen(com_token) + 1); + memcpy(video->subtitle_text[numsubs], com_token, strlen(com_token) + 1); + video->subtitle_start[numsubs] = subtime; + video->subtitle_end[numsubs] = sublen; + if (numsubs > 0) // make true len for prev sub, autofix overlapping subtitles + { + if (video->subtitle_end[numsubs-1] <= 0) + video->subtitle_end[numsubs-1] = max(video->subtitle_start[numsubs-1], video->subtitle_start[numsubs] + video->subtitle_end[numsubs-1]); + else + video->subtitle_end[numsubs-1] = min(video->subtitle_start[numsubs-1] + video->subtitle_end[numsubs-1], video->subtitle_start[numsubs]); + } + numsubs++; + // todo: check timing for consistency? + } + if (numsubs > 0) // make true len for prev sub, autofix overlapping subtitles + { + if (video->subtitle_end[numsubs-1] <= 0) + video->subtitle_end[numsubs-1] = 99999999; // fixme: make it end when video ends? + else + video->subtitle_end[numsubs-1] = video->subtitle_start[numsubs-1] + video->subtitle_end[numsubs-1]; + } + Z_Free( subtitle_text ); + video->subtitles = numsubs; +/* + Con_Printf( "video->subtitles: %i\n", video->subtitles ); + for (numsubs = 0; numsubs < video->subtitles; numsubs++) + Con_Printf( " %03.2f %03.2f : %s\n", video->subtitle_start[numsubs], video->subtitle_end[numsubs], video->subtitle_text[numsubs] ); +*/ +} + +static clvideo_t* OpenVideo( clvideo_t *video, const char *filename, const char *name, int owner, const char *subtitlesfile ) +{ + strlcpy( video->filename, filename, sizeof(video->filename) ); + video->ownertag = owner; + if( strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) ) + return NULL; + strlcpy( video->cpif.name, name, sizeof(video->cpif.name) ); + + if( !OpenStream( video ) ) + return NULL; + + video->state = CLVIDEO_FIRSTFRAME; + video->framenum = -1; + video->framerate = video->getframerate( video->stream ); + video->lasttime = realtime; + video->subtitles = 0; + + video->cpif.width = video->getwidth( video->stream ); + video->cpif.height = video->getheight( video->stream ); + video->imagedata = Mem_Alloc( cls.permanentmempool, video->cpif.width * video->cpif.height * cl_videobytesperpixel ); + LinkVideoTexture( video ); + + // VorteX: load simple subtitle_text file + if (subtitlesfile[0]) + LoadSubtitles( video, subtitlesfile ); + + return video; +} + +clvideo_t* CL_OpenVideo( const char *filename, const char *name, int owner, const char *subtitlesfile ) +{ + clvideo_t *video; + // sanity check + if( !name || !*name || strncmp( name, CLVIDEOPREFIX, sizeof( CLVIDEOPREFIX ) - 1 ) != 0 ) { + Con_DPrintf( "CL_OpenVideo: Bad video texture name '%s'!\n", name ); + return NULL; + } + + video = FindUnusedVid(); + if( !video ) { + Con_Printf( "CL_OpenVideo: unable to open video \"%s\" - video limit reached\n", filename ); + return NULL; + } + video = OpenVideo( video, filename, name, owner, subtitlesfile ); + // expand the active range to include the new entry + if (video) { + cl_num_videos = max(cl_num_videos, (int)(video - cl_videos) + 1); + } + return video; +} + +static clvideo_t* CL_GetVideoBySlot( int slot ) +{ + clvideo_t *video = &cl_videos[ slot ]; + + if( video->suspended ) + { + if( !WakeVideo( video ) ) + return NULL; + else if( video->state == CLVIDEO_RESETONWAKEUP ) + video->framenum = -1; + } + + video->lasttime = realtime; + + return video; +} + +clvideo_t *CL_GetVideoByName( const char *name ) +{ + int i; + + for( i = 0 ; i < cl_num_videos ; i++ ) + if( cl_videos[ i ].state != CLVIDEO_UNUSED + && !strcmp( cl_videos[ i ].cpif.name , name ) ) + break; + if( i != cl_num_videos ) + return CL_GetVideoBySlot( i ); + else + return NULL; +} + +void CL_SetVideoState(clvideo_t *video, clvideostate_t state) +{ + if (!video) + return; + + video->lasttime = realtime; + video->state = state; + if (state == CLVIDEO_FIRSTFRAME) + CL_RestartVideo(video); +} + +void CL_RestartVideo(clvideo_t *video) +{ + if (!video) + return; + + // reset time + video->starttime = video->lasttime = realtime; + video->framenum = -1; + + // reopen stream + if (video->stream) + video->close(video->stream); + video->stream = NULL; + if (!OpenStream(video)) + video->state = CLVIDEO_UNUSED; +} + +// close video +void CL_CloseVideo(clvideo_t * video) +{ + int i; + + if (!video || video->state == CLVIDEO_UNUSED) + return; + + // close stream + if (!video->suspended || video->state != CLVIDEO_FIRSTFRAME) + { + if (video->stream) + video->close(video->stream); + video->stream = NULL; + } + // unlink texture + if (!video->suspended) + UnlinkVideoTexture(video); + // purge subtitles + if (video->subtitles) + { + for (i = 0; i < video->subtitles; i++) + Z_Free( video->subtitle_text[i] ); + video->subtitles = 0; + } + video->state = CLVIDEO_UNUSED; +} + +// update all videos +void CL_Video_Frame(void) +{ + clvideo_t *video; + int destframe; + int i; + + if (!cl_num_videos) + return; + for (video = cl_videos, i = 0 ; i < cl_num_videos ; video++, i++) + { + if (video->state != CLVIDEO_UNUSED && !video->suspended) + { + if (realtime - video->lasttime > CLTHRESHOLD) + { + SuspendVideo(video); + continue; + } + if (video->state == CLVIDEO_PAUSE) + { + video->starttime = realtime - video->framenum * video->framerate; + continue; + } + // read video frame from stream if time has come + if (video->state == CLVIDEO_FIRSTFRAME ) + destframe = 0; + else + destframe = (int)((realtime - video->starttime) * video->framerate); + if (destframe < 0) + destframe = 0; + if (video->framenum < destframe) + { + do { + video->framenum++; + if (video->decodeframe(video->stream, video->imagedata, cl_videormask, cl_videogmask, cl_videobmask, cl_videobytesperpixel, cl_videobytesperpixel * video->cpif.width)) + { + // finished? + CL_RestartVideo(video); + if (video->state == CLVIDEO_PLAY) + video->state = CLVIDEO_FIRSTFRAME; + return; + } + } while(video->framenum < destframe); + R_MarkDirtyTexture(video->cpif.tex); + } + } + } + + // stop main video + if (cl_videos->state == CLVIDEO_FIRSTFRAME) + CL_VideoStop(); + + // reduce range to exclude unnecessary entries + while(cl_num_videos > 0 && cl_videos[cl_num_videos-1].state == CLVIDEO_UNUSED) + cl_num_videos--; +} + +void CL_PurgeOwner( int owner ) +{ + int i; + + for (i = 0 ; i < cl_num_videos ; i++) + if (cl_videos[i].ownertag == owner) + CL_CloseVideo(&cl_videos[i]); +} + +typedef struct +{ + dp_font_t *font; + float x; + float y; + float width; + float height; + float alignment; // 0 = left, 0.5 = center, 1 = right + float fontsize; + float textalpha; +} +cl_video_subtitle_info_t; + +static float CL_DrawVideo_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth) +{ + cl_video_subtitle_info_t *si = (cl_video_subtitle_info_t *) passthrough; + + if(w == NULL) + return si->fontsize * si->font->maxwidth; + if(maxWidth >= 0) + return DrawQ_TextWidth_UntilWidth(w, length, si->fontsize, si->fontsize, false, si->font, -maxWidth); // -maxWidth: we want at least one char + else if(maxWidth == -1) + return DrawQ_TextWidth(w, *length, si->fontsize, si->fontsize, false, si->font); + else + return 0; +} + +static int CL_DrawVideo_DisplaySubtitleLine(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation) +{ + cl_video_subtitle_info_t *si = (cl_video_subtitle_info_t *) passthrough; + + int x = (int) (si->x + (si->width - width) * si->alignment); + if (length > 0) + DrawQ_String(x, si->y, line, length, si->fontsize, si->fontsize, 1.0, 1.0, 1.0, si->textalpha, 0, NULL, false, si->font); + si->y += si->fontsize; + return 1; +} + +int cl_videoplaying = false; // old, but still supported + +void CL_DrawVideo(void) +{ + clvideo_t *video; + float videotime, px, py, sx, sy, st[8], b; + cl_video_subtitle_info_t si; + int i; + + if (!cl_videoplaying) + return; + + video = CL_GetVideoBySlot( 0 ); + + // fix cvars + if (cl_video_scale.value <= 0 || cl_video_scale.value > 1) + Cvar_SetValueQuick( &cl_video_scale, 1); + if (cl_video_brightness.value <= 0 || cl_video_brightness.value > 10) + Cvar_SetValueQuick( &cl_video_brightness, 1); + + // calc video proportions + px = 0; + py = 0; + sx = vid_conwidth.integer; + sy = vid_conheight.integer; + st[0] = 0.0; st[1] = 0.0; + st[2] = 1.0; st[3] = 0.0; + st[4] = 0.0; st[5] = 1.0; + st[6] = 1.0; st[7] = 1.0; + if (cl_video_keepaspectratio.integer) + { + float a = video->getaspectratio(video->stream) / ((float)vid.width / (float)vid.height); + if (cl_video_keepaspectratio.integer >= 2) + { + // clip instead of scale + if (a < 1.0) // clip horizontally + { + st[1] = st[3] = (1 - a)*0.5; + st[5] = st[7] = 1 - (1 - a)*0.5; + } + else if (a > 1.0) // clip vertically + { + st[0] = st[4] = (1 - 1/a)*0.5; + st[2] = st[6] = (1/a)*0.5; + } + } + else if (a < 1.0) // scale horizontally + { + px += sx * (1 - a) * 0.5; + sx *= a; + } + else if (a > 1.0) // scale vertically + { + a = 1 / a; + py += sy * (1 - a); + sy *= a; + } + } + + if (cl_video_scale.value != 1) + { + px += sx * (1 - cl_video_scale.value) * 0.5; + py += sy * (1 - cl_video_scale.value) * ((bound(-1, cl_video_scale_vpos.value, 1) + 1) / 2); + sx *= cl_video_scale.value; + sy *= cl_video_scale.value; + } + + // calc brightness for fadein and fadeout effects + b = cl_video_brightness.value; + if (cl_video_fadein.value && (realtime - video->starttime) < cl_video_fadein.value) + b = pow((realtime - video->starttime)/cl_video_fadein.value, 2); + else if (cl_video_fadeout.value && ((video->starttime + video->framenum * video->framerate) - realtime) < cl_video_fadeout.value) + b = pow(((video->starttime + video->framenum * video->framerate) - realtime)/cl_video_fadeout.value, 2); + + // draw black bg in case stipple is active or video is scaled + if (cl_video_stipple.integer || px != 0 || py != 0 || sx != vid_conwidth.integer || sy != vid_conheight.integer) + DrawQ_Fill(0, 0, vid_conwidth.integer, vid_conheight.integer, 0, 0, 0, 1, 0); + +#ifndef USE_GLES2 + // enable video-only polygon stipple (of global stipple is not active) + if (qglPolygonStipple && !scr_stipple.integer && cl_video_stipple.integer) + { + GLubyte stipple[128]; + int i, s, width, parts; + + s = cl_video_stipple.integer; + parts = (s & 007); + width = (s & 070) >> 3; + qglEnable(GL_POLYGON_STIPPLE);CHECKGLERROR // 0x0B42 + for(i = 0; i < 128; ++i) + { + int line = i/4; + stipple[i] = ((line >> width) & ((1 << parts) - 1)) ? 0x00 : 0xFF; + } + qglPolygonStipple(stipple);CHECKGLERROR + } +#endif + + // draw video + if (v_glslgamma_video.value >= 1) + DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, 0); + else + { + DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, 1, st[2], st[3], b, b, b, 1, st[4], st[5], b, b, b, 1, st[6], st[7], b, b, b, 1, DRAWFLAG_NOGAMMA); + if (v_glslgamma_video.value > 0.0) + DrawQ_SuperPic(px, py, &video->cpif, sx, sy, st[0], st[1], b, b, b, v_glslgamma_video.value, st[2], st[3], b, b, b, v_glslgamma_video.value, st[4], st[5], b, b, b, v_glslgamma_video.value, st[6], st[7], b, b, b, v_glslgamma_video.value, 0); + } + +#ifndef USE_GLES2 + // disable video-only stipple + if (qglPolygonStipple && !scr_stipple.integer && cl_video_stipple.integer) + qglDisable(GL_POLYGON_STIPPLE);CHECKGLERROR +#endif + + // VorteX: draw subtitle_text + if (!video->subtitles || !cl_video_subtitles.integer) + return; + + // find current subtitle + videotime = realtime - video->starttime; + for (i = 0; i < video->subtitles; i++) + { + if (videotime >= video->subtitle_start[i] && videotime <= video->subtitle_end[i]) + { + // found, draw it + si.font = FONT_NOTIFY; + si.x = vid_conwidth.integer * 0.1; + si.y = vid_conheight.integer - (max(1, cl_video_subtitles_lines.value) * cl_video_subtitles_textsize.value); + si.width = vid_conwidth.integer * 0.8; + si.height = max(1, cl_video_subtitles_lines.integer) * cl_video_subtitles_textsize.value; + si.alignment = 0.5; + si.fontsize = cl_video_subtitles_textsize.value; + si.textalpha = min(1, (videotime - video->subtitle_start[i])/0.5) * min(1, ((video->subtitle_end[i] - videotime)/0.3)); // fade in and fade out + COM_Wordwrap(video->subtitle_text[i], strlen(video->subtitle_text[i]), 0, si.width, CL_DrawVideo_WordWidthFunc, &si, CL_DrawVideo_DisplaySubtitleLine, &si); + break; + } + } +} + +void CL_VideoStart(char *filename, const char *subtitlesfile) +{ + char vabuf[1024]; + Host_StartVideo(); + + if( cl_videos->state != CLVIDEO_UNUSED ) + CL_CloseVideo( cl_videos ); + // already contains video/ + if( !OpenVideo( cl_videos, filename, va(vabuf, sizeof(vabuf), CLDYNTEXTUREPREFIX "%s", filename ), 0, subtitlesfile ) ) + return; + // expand the active range to include the new entry + cl_num_videos = max(cl_num_videos, 1); + + cl_videoplaying = true; + + CL_SetVideoState( cl_videos, CLVIDEO_PLAY ); + CL_RestartVideo( cl_videos ); +} + +void CL_Video_KeyEvent( int key, int ascii, qboolean down ) +{ + // only react to up events, to allow the user to delay the abortion point if it suddenly becomes interesting.. + if( !down ) { + if( key == K_ESCAPE || key == K_ENTER || key == K_MOUSE1 || key == K_SPACE ) { + CL_VideoStop(); + } + } +} + +void CL_VideoStop(void) +{ + cl_videoplaying = false; + + CL_CloseVideo( cl_videos ); +} + +static void CL_PlayVideo_f(void) +{ + char name[MAX_QPATH], subtitlesfile[MAX_QPATH]; + const char *extension; + + Host_StartVideo(); + + if (COM_CheckParm("-benchmark")) + return; + + if (Cmd_Argc() < 2) + { + Con_Print("usage: playvideo [custom_subtitles_file]\nplays video named video/.dpv\nif custom subtitles file is not presented\nit tries video/.sub"); + return; + } + + extension = FS_FileExtension(Cmd_Argv(1)); + if (extension[0]) + dpsnprintf(name, sizeof(name), "video/%s", Cmd_Argv(1)); + else + dpsnprintf(name, sizeof(name), "video/%s.dpv", Cmd_Argv(1)); + if ( Cmd_Argc() > 2) + CL_VideoStart(name, Cmd_Argv(2)); + else + { + dpsnprintf(subtitlesfile, sizeof(subtitlesfile), "video/%s.dpsubs", Cmd_Argv(1)); + CL_VideoStart(name, subtitlesfile); + } +} + +static void CL_StopVideo_f(void) +{ + CL_VideoStop(); +} + +static void cl_video_start( void ) +{ + int i; + clvideo_t *video; + + cl_videotexturepool = R_AllocTexturePool(); + + for( video = cl_videos, i = 0 ; i < cl_num_videos ; i++, video++ ) + if( video->state != CLVIDEO_UNUSED && !video->suspended ) + LinkVideoTexture( video ); +} + +static void cl_video_shutdown( void ) +{ + int i; + clvideo_t *video; + + for( video = cl_videos, i = 0 ; i < cl_num_videos ; i++, video++ ) + if( video->state != CLVIDEO_UNUSED && !video->suspended ) + SuspendVideo( video ); + R_FreeTexturePool( &cl_videotexturepool ); +} + +static void cl_video_newmap( void ) +{ +} + +void CL_Video_Init( void ) +{ + union + { + unsigned char b[4]; + unsigned int i; + } + bgra; + + cl_num_videos = 0; + cl_videobytesperpixel = 4; + + // set masks in an endian-independent way (as they really represent bytes) + bgra.i = 0;bgra.b[0] = 0xFF;cl_videobmask = bgra.i; + bgra.i = 0;bgra.b[1] = 0xFF;cl_videogmask = bgra.i; + bgra.i = 0;bgra.b[2] = 0xFF;cl_videormask = bgra.i; + + Cmd_AddCommand( "playvideo", CL_PlayVideo_f, "play a .dpv video file" ); + Cmd_AddCommand( "stopvideo", CL_StopVideo_f, "stop playing a .dpv video file" ); + + Cvar_RegisterVariable(&cl_video_subtitles); + Cvar_RegisterVariable(&cl_video_subtitles_lines); + Cvar_RegisterVariable(&cl_video_subtitles_textsize); + Cvar_RegisterVariable(&cl_video_scale); + Cvar_RegisterVariable(&cl_video_scale_vpos); + Cvar_RegisterVariable(&cl_video_brightness); + Cvar_RegisterVariable(&cl_video_stipple); + Cvar_RegisterVariable(&cl_video_keepaspectratio); + Cvar_RegisterVariable(&cl_video_fadein); + Cvar_RegisterVariable(&cl_video_fadeout); + + Cvar_RegisterVariable(&v_glslgamma_video); + + R_RegisterModule( "CL_Video", cl_video_start, cl_video_shutdown, cl_video_newmap, NULL, NULL ); + + LibAvW_OpenLibrary(); +} + +void CL_Video_Shutdown( void ) +{ + int i; + + for (i = 0 ; i < cl_num_videos ; i++) + CL_CloseVideo(&cl_videos[ i ]); + + LibAvW_CloseLibrary(); +} diff --git a/app/jni/cl_video.h b/app/jni/cl_video.h new file mode 100644 index 0000000..97960b8 --- /dev/null +++ b/app/jni/cl_video.h @@ -0,0 +1,97 @@ + +#ifndef CL_VIDEO_H +#define CL_VIDEO_H + +#include "cl_dyntexture.h" + +// yields DYNAMIC_TEXTURE_PATH_PREFIX CLVIDEOPREFIX video name for a path +#define CLVIDEOPREFIX CLDYNTEXTUREPREFIX "video/" +#define CLTHRESHOLD 2.0 + +#define MENUOWNER 1 + +typedef enum clvideostate_e +{ + CLVIDEO_UNUSED, + CLVIDEO_PLAY, + CLVIDEO_LOOP, + CLVIDEO_PAUSE, + CLVIDEO_FIRSTFRAME, + CLVIDEO_RESETONWAKEUP, + CLVIDEO_STATECOUNT +} clvideostate_t; + +#define CLVIDEO_MAX_SUBTITLES 512 + +extern cvar_t cl_video_subtitles; +extern cvar_t cl_video_subtitles_lines; +extern cvar_t cl_video_subtitles_textsize; +extern cvar_t cl_video_scale; +extern cvar_t cl_video_scale_vpos; +extern cvar_t cl_video_stipple; +extern cvar_t cl_video_brightness; +extern cvar_t cl_video_keepaspectratio; + +typedef struct clvideo_s +{ + int ownertag; + clvideostate_t state; + + // private stuff + void *stream; + + double starttime; + int framenum; + double framerate; + + void *imagedata; + + cachepic_t cpif; + + // VorteX: subtitles array + int subtitles; + char *subtitle_text[CLVIDEO_MAX_SUBTITLES]; + float subtitle_start[CLVIDEO_MAX_SUBTITLES]; + float subtitle_end[CLVIDEO_MAX_SUBTITLES]; + + // this functions gets filled by video format module + void (*close) (void *stream); + unsigned int (*getwidth) (void *stream); + unsigned int (*getheight) (void *stream); + double (*getframerate) (void *stream); + double (*getaspectratio) (void *stream); + int (*decodeframe) (void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow); + + // if a video is suspended, it is automatically paused (else we'd still have to process the frames) + // used to determine whether the video's resources should be freed or not + double lasttime; + // when lasttime - realtime > THRESHOLD, all but the stream is freed + qboolean suspended; + + char filename[MAX_QPATH]; +} clvideo_t; + +clvideo_t* CL_OpenVideo( const char *filename, const char *name, int owner, const char *subtitlesfile ); +clvideo_t* CL_GetVideoByName( const char *name ); +void CL_SetVideoState( clvideo_t *video, clvideostate_t state ); +void CL_RestartVideo( clvideo_t *video ); + +void CL_CloseVideo( clvideo_t * video ); +void CL_PurgeOwner( int owner ); + +void CL_Video_Frame( void ); // update all videos +void CL_Video_Init( void ); +void CL_Video_Shutdown( void ); + +// old interface +extern int cl_videoplaying; + +void CL_DrawVideo( void ); +void CL_VideoStart( char *filename, const char *subtitlesfile ); +void CL_VideoStop( void ); + +// new function used for fullscreen videos +// TODO: Andreas Kirsch: move this subsystem somewhere else (preferably host) since the cl_video system shouldnt do such work like managing key events.. +void CL_Video_KeyEvent( int key, int ascii, qboolean down ); + +#endif diff --git a/app/jni/cl_video_libavw.c b/app/jni/cl_video_libavw.c new file mode 100644 index 0000000..7924127 --- /dev/null +++ b/app/jni/cl_video_libavw.c @@ -0,0 +1,386 @@ +/* + Libavcodec integration for Darkplaces by Timofeyev Pavel + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +// LordHavoc: for some reason this is being #include'd rather than treated as its own file... +// LordHavoc: adapted to not require stdint.h as this is not available on MSVC++, using unsigned char instead of uint8_t and fs_offset_t instead of int64_t. + +// scaler type +#define LIBAVW_SCALER_BILINEAR 0 +#define LIBAVW_SCALER_BICUBIC 1 +#define LIBAVW_SCALER_X 2 +#define LIBAVW_SCALER_POINT 3 +#define LIBAVW_SCALER_AREA 4 +#define LIBAVW_SCALER_BICUBLIN 5 +#define LIBAVW_SCALER_GAUSS 6 +#define LIBAVW_SCALER_SINC 7 +#define LIBAVW_SCALER_LANCZOS 8 +#define LIBAVW_SCALER_SPLINE 9 +// output format +#define LIBAVW_PIXEL_FORMAT_BGR 0 +#define LIBAVW_PIXEL_FORMAT_BGRA 1 +// print levels +#define LIBAVW_PRINT_WARNING 1 +#define LIBAVW_PRINT_ERROR 2 +#define LIBAVW_PRINT_FATAL 3 +#define LIBAVW_PRINT_PANIC 4 +// exported callback functions: +typedef void avwCallbackPrint(int, const char *); +typedef int avwCallbackIoRead(void *, unsigned char *, int); +typedef fs_offset_t avwCallbackIoSeek(void *, fs_offset_t, int); +typedef fs_offset_t avwCallbackIoSeekSize(void *); +// exported functions: +int (*qLibAvW_Init)(avwCallbackPrint *printfunction); // init library, returns error code +const char *(*qLibAvW_ErrorString)(int errorcode); // get string for error code +const char *(*qLibAvW_AvcVersion)(void); // get a string containing libavcodec version wrapper was built for +float (*qLibAvW_Version)(void); // get wrapper version +int (*qLibAvW_CreateStream)(void **stream); // create stream, returns error code +void (*qLibAvW_RemoveStream)(void *stream); // flush and remove stream +int (*qLibAvW_StreamGetVideoWidth)(void *stream); // get video parameters of stream +int (*qLibAvW_StreamGetVideoHeight)(void *stream); +double (*qLibAvW_StreamGetFramerate)(void *stream); +int (*qLibAvW_StreamGetError)(void *stream); // get last function errorcode from stream +// simple API to play video +int (*qLibAvW_PlayVideo)(void *stream, void *file, avwCallbackIoRead *IoRead, avwCallbackIoSeek *IoSeek, avwCallbackIoSeekSize *IoSeekSize); +int (*qLibAvW_PlaySeekNextFrame)(void *stream); +int (*qLibAvW_PlayGetFrameImage)(void *stream, int pixel_format, void *imagedata, int imagewidth, int imageheight, int scaler); + +static dllfunction_t libavwfuncs[] = +{ + {"LibAvW_Init", (void **) &qLibAvW_Init }, + {"LibAvW_ErrorString", (void **) &qLibAvW_ErrorString }, + {"LibAvW_AvcVersion", (void **) &qLibAvW_AvcVersion }, + {"LibAvW_Version", (void **) &qLibAvW_Version }, + {"LibAvW_CreateStream", (void **) &qLibAvW_CreateStream }, + {"LibAvW_RemoveStream", (void **) &qLibAvW_RemoveStream }, + {"LibAvW_StreamGetVideoWidth", (void **) &qLibAvW_StreamGetVideoWidth }, + {"LibAvW_StreamGetVideoHeight",(void **) &qLibAvW_StreamGetVideoHeight }, + {"LibAvW_StreamGetFramerate", (void **) &qLibAvW_StreamGetFramerate }, + {"LibAvW_StreamGetError", (void **) &qLibAvW_StreamGetError }, + {"LibAvW_PlayVideo", (void **) &qLibAvW_PlayVideo }, + {"LibAvW_PlaySeekNextFrame", (void **) &qLibAvW_PlaySeekNextFrame }, + {"LibAvW_PlayGetFrameImage", (void **) &qLibAvW_PlayGetFrameImage }, + {NULL, NULL} +}; + +const char* dllnames_libavw[] = +{ +#if defined(WIN32) + "libavw.dll", +#elif defined(MACOSX) + "libavw.dylib", +#else + "libavw.so.1", + "libavw.so", +#endif + NULL +}; + +static dllhandle_t libavw_dll = NULL; + +// DP videostream +typedef struct libavwstream_s +{ + qfile_t *file; + double info_framerate; + unsigned int info_imagewidth; + unsigned int info_imageheight; + double info_aspectratio; + void *stream; + + // channel the sound file is being played on + sfx_t *sfx; + int sndchan; + int sndstarted; +} +libavwstream_t; + +cvar_t cl_video_libavw_minwidth = {CVAR_SAVE, "cl_video_libavw_minwidth", "0", "if videos width is lesser than minimal, thay will be upscaled"}; +cvar_t cl_video_libavw_minheight = {CVAR_SAVE, "cl_video_libavw_minheight", "0", "if videos height is lesser than minimal, thay will be upscaled"}; +cvar_t cl_video_libavw_scaler = {CVAR_SAVE, "cl_video_libavw_scaler", "1", "selects a scaler for libavcode played videos. Scalers are: 0 - bilinear, 1 - bicubic, 2 - x, 3 - point, 4 - area, 5 - bicublin, 6 - gauss, 7 - sinc, 8 - lanczos, 9 - spline."}; + +// video extensions +const char* libavw_extensions[] = +{ + "ogv", + "avi", + "mpg", + "mp4", + "mkv", + "webm", + "bik", + "roq", + "flv", + "wmv", + "mpeg", + "mjpeg", + "mpeg4", + NULL +}; + +/* +================================================================= + + Video decoding + a features that is not supported yet and likely to be done + - streaming audio from videofiles + - streaming subtitles + +================================================================= +*/ + +unsigned int libavw_getwidth(void *stream); +unsigned int libavw_getheight(void *stream); +double libavw_getframerate(void *stream); +double libavw_getaspectratio(void *stream); +void libavw_close(void *stream); + +static int libavw_decodeframe(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow) +{ + int pixel_format = LIBAVW_PIXEL_FORMAT_BGR; + int errorcode; + + libavwstream_t *s = (libavwstream_t *)stream; + + // start sound + if (!s->sndstarted) + { + if (s->sfx != NULL) + s->sndchan = S_StartSound(-1, 0, s->sfx, vec3_origin, 1.0f, 0); + s->sndstarted = 1; + } + + // read frame + if (!qLibAvW_PlaySeekNextFrame(s->stream)) + { + // got error or file end + errorcode = qLibAvW_StreamGetError(s->stream); + if (errorcode) + Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(errorcode)); + return 1; + } + + // decode into bgr texture + if (bytesperpixel == 4) + pixel_format = LIBAVW_PIXEL_FORMAT_BGRA; + else if (bytesperpixel == 3) + pixel_format = LIBAVW_PIXEL_FORMAT_BGR; + else + { + Con_Printf("LibAvW: cannot determine pixel format for bpp %i\n", bytesperpixel); + return 1; + } + if (!qLibAvW_PlayGetFrameImage(s->stream, pixel_format, imagedata, s->info_imagewidth, s->info_imageheight, min(9, max(0, cl_video_libavw_scaler.integer)))) + Con_Printf("LibAvW: %s\n", qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream))); + return 0; +} + +// get stream info +unsigned int libavw_getwidth(void *stream) +{ + return ((libavwstream_t *)stream)->info_imagewidth; +} + +unsigned int libavw_getheight(void *stream) +{ + return ((libavwstream_t *)stream)->info_imageheight; +} + +double libavw_getframerate(void *stream) +{ + return ((libavwstream_t *)stream)->info_framerate; +} + +double libavw_getaspectratio(void *stream) +{ + return ((libavwstream_t *)stream)->info_aspectratio; +} + +// close stream +void libavw_close(void *stream) +{ + libavwstream_t *s = (libavwstream_t *)stream; + + if (s->stream) + qLibAvW_RemoveStream(s->stream); + s->stream = NULL; + if (s->file) + FS_Close(s->file); + s->file = NULL; + if (s->sndchan >= 0) + S_StopChannel(s->sndchan, true, true); + s->sndchan = -1; +} + +// IO wrapper +static int LibAvW_FS_Read(void *opaque, unsigned char *buf, int buf_size) +{ + return FS_Read((qfile_t *)opaque, buf, buf_size); +} +static fs_offset_t LibAvW_FS_Seek(void *opaque, fs_offset_t pos, int whence) +{ + return (fs_offset_t)FS_Seek((qfile_t *)opaque, pos, whence); +} +static fs_offset_t LibAvW_FS_SeekSize(void *opaque) +{ + return (fs_offset_t)FS_FileSize((qfile_t *)opaque); +} + +// open as DP video stream +static void *LibAvW_OpenVideo(clvideo_t *video, char *filename, const char **errorstring) +{ + libavwstream_t *s; + char filebase[MAX_OSPATH], check[MAX_OSPATH]; + unsigned int i; + int errorcode; + char *wavename; + size_t len; + + if (!libavw_dll) + return NULL; + + // allocate stream + s = (libavwstream_t *)Z_Malloc(sizeof(libavwstream_t)); + if (s == NULL) + { + *errorstring = "unable to allocate memory for stream info structure"; + return NULL; + } + memset(s, 0, sizeof(libavwstream_t)); + s->sndchan = -1; + + // open file + s->file = FS_OpenVirtualFile(filename, true); + if (!s->file) + { + FS_StripExtension(filename, filebase, sizeof(filebase)); + // we tried .dpv, try another extensions + for (i = 0; libavw_extensions[i] != NULL; i++) + { + dpsnprintf(check, sizeof(check), "%s.%s", filebase, libavw_extensions[i]); + s->file = FS_OpenVirtualFile(check, true); + if (s->file) + break; + } + if (!s->file) + { + *errorstring = "unable to open videofile"; + libavw_close(s); + Z_Free(s); + return NULL; + } + } + + // allocate libavw stream + if ((errorcode = qLibAvW_CreateStream(&s->stream))) + { + *errorstring = qLibAvW_ErrorString(errorcode); + libavw_close(s); + Z_Free(s); + return NULL; + } + + // open video for playing + if (!qLibAvW_PlayVideo(s->stream, s->file, &LibAvW_FS_Read, &LibAvW_FS_Seek, &LibAvW_FS_SeekSize)) + { + *errorstring = qLibAvW_ErrorString(qLibAvW_StreamGetError(s->stream)); + libavw_close(s); + Z_Free(s); + return NULL; + } + + // all right, start codec + s->info_imagewidth = qLibAvW_StreamGetVideoWidth(s->stream); + s->info_imageheight = qLibAvW_StreamGetVideoHeight(s->stream); + s->info_framerate = qLibAvW_StreamGetFramerate(s->stream); + s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight; + video->close = libavw_close; + video->getwidth = libavw_getwidth; + video->getheight = libavw_getheight; + video->getframerate = libavw_getframerate; + video->decodeframe = libavw_decodeframe; + video->getaspectratio = libavw_getaspectratio; + + // apply min-width, min-height, keep aspect rate + if (cl_video_libavw_minwidth.integer > 0) + s->info_imagewidth = max(s->info_imagewidth, (unsigned int)cl_video_libavw_minwidth.integer); + if (cl_video_libavw_minheight.integer > 0) + s->info_imageheight = max(s->info_imageheight, (unsigned int)cl_video_libavw_minheight.integer); + + // provide sound in separate .wav + len = strlen(filename) + 10; + wavename = (char *)Z_Malloc(len); + if (wavename) + { + FS_StripExtension(filename, wavename, len-1); + strlcat(wavename, ".wav", len); + s->sfx = S_PrecacheSound(wavename, false, false); + s->sndchan = -1; + Z_Free(wavename); + } + return s; +} + +static void libavw_message(int level, const char *message) +{ + if (level == LIBAVW_PRINT_WARNING) + Con_Printf("LibAvcodec warning: %s\n", message); + else if (level == LIBAVW_PRINT_ERROR) + Con_Printf("LibAvcodec error: %s\n", message); + else if (level == LIBAVW_PRINT_FATAL) + Con_Printf("LibAvcodec fatal error: %s\n", message); + else + Con_Printf("LibAvcodec panic: %s\n", message); +} + +static qboolean LibAvW_OpenLibrary(void) +{ + int errorcode; + + // COMMANDLINEOPTION: Video: -nolibavw disables libavcodec wrapper support + if (COM_CheckParm("-nolibavw")) + return false; + + // load DLL's + Sys_LoadLibrary(dllnames_libavw, &libavw_dll, libavwfuncs); + if (!libavw_dll) + return false; + + // initialize libav wrapper + if ((errorcode = qLibAvW_Init(&libavw_message))) + { + Con_Printf("LibAvW failed to initialize: %s\n", qLibAvW_ErrorString(errorcode)); + Sys_UnloadLibrary(&libavw_dll); + } + + Cvar_RegisterVariable(&cl_video_libavw_minwidth); + Cvar_RegisterVariable(&cl_video_libavw_minheight); + Cvar_RegisterVariable(&cl_video_libavw_scaler); + + return true; +} + +static void LibAvW_CloseLibrary(void) +{ + Sys_UnloadLibrary(&libavw_dll); +} + diff --git a/app/jni/client.h b/app/jni/client.h new file mode 100644 index 0000000..8e4e74c --- /dev/null +++ b/app/jni/client.h @@ -0,0 +1,2052 @@ +/* +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 + +#ifndef CLIENT_H +#define CLIENT_H + +#include "matrixlib.h" +#include "snd_main.h" + +// NOTE: r_stat_name[] must match this indexing +typedef enum r_stat_e +{ + r_stat_timedelta, + r_stat_quality, + r_stat_renders, + r_stat_entities, + r_stat_entities_surfaces, + r_stat_entities_triangles, + r_stat_world_leafs, + r_stat_world_portals, + r_stat_world_surfaces, + r_stat_world_triangles, + r_stat_lightmapupdates, + r_stat_lightmapupdatepixels, + r_stat_particles, + r_stat_drawndecals, + r_stat_totaldecals, + r_stat_draws, + r_stat_draws_vertices, + r_stat_draws_elements, + r_stat_lights, + r_stat_lights_clears, + r_stat_lights_scissored, + r_stat_lights_lighttriangles, + r_stat_lights_shadowtriangles, + r_stat_lights_dynamicshadowtriangles, + r_stat_bouncegrid_lights, + r_stat_bouncegrid_particles, + r_stat_bouncegrid_traces, + r_stat_bouncegrid_hits, + r_stat_bouncegrid_splats, + r_stat_bouncegrid_bounces, + r_stat_photoncache_animated, + r_stat_photoncache_cached, + r_stat_photoncache_traced, + r_stat_bloom, + r_stat_bloom_copypixels, + r_stat_bloom_drawpixels, + r_stat_indexbufferuploadcount, + r_stat_indexbufferuploadsize, + r_stat_vertexbufferuploadcount, + r_stat_vertexbufferuploadsize, + r_stat_framedatacurrent, + r_stat_framedatasize, + r_stat_bufferdatacurrent_vertex, // R_BUFFERDATA_ types are added to this index + r_stat_bufferdatacurrent_index16, + r_stat_bufferdatacurrent_index32, + r_stat_bufferdatacurrent_uniform, + r_stat_bufferdatasize_vertex, // R_BUFFERDATA_ types are added to this index + r_stat_bufferdatasize_index16, + r_stat_bufferdatasize_index32, + r_stat_bufferdatasize_uniform, + r_stat_animcache_vertexmesh_count, + r_stat_animcache_vertexmesh_vertices, + r_stat_animcache_vertexmesh_maxvertices, + r_stat_animcache_skeletal_count, + r_stat_animcache_skeletal_bones, + r_stat_animcache_skeletal_maxbones, + r_stat_animcache_shade_count, + r_stat_animcache_shade_vertices, + r_stat_animcache_shade_maxvertices, + r_stat_animcache_shape_count, + r_stat_animcache_shape_vertices, + r_stat_animcache_shape_maxvertices, + r_stat_batch_batches, + r_stat_batch_withgaps, + r_stat_batch_surfaces, + r_stat_batch_vertices, + r_stat_batch_triangles, + r_stat_batch_fast_batches, + r_stat_batch_fast_surfaces, + r_stat_batch_fast_vertices, + r_stat_batch_fast_triangles, + r_stat_batch_copytriangles_batches, + r_stat_batch_copytriangles_surfaces, + r_stat_batch_copytriangles_vertices, + r_stat_batch_copytriangles_triangles, + r_stat_batch_dynamic_batches, + r_stat_batch_dynamic_surfaces, + r_stat_batch_dynamic_vertices, + r_stat_batch_dynamic_triangles, + r_stat_batch_dynamicskeletal_batches, + r_stat_batch_dynamicskeletal_surfaces, + r_stat_batch_dynamicskeletal_vertices, + r_stat_batch_dynamicskeletal_triangles, + r_stat_batch_dynamic_batches_because_cvar, + r_stat_batch_dynamic_surfaces_because_cvar, + r_stat_batch_dynamic_vertices_because_cvar, + r_stat_batch_dynamic_triangles_because_cvar, + r_stat_batch_dynamic_batches_because_lightmapvertex, + r_stat_batch_dynamic_surfaces_because_lightmapvertex, + r_stat_batch_dynamic_vertices_because_lightmapvertex, + r_stat_batch_dynamic_triangles_because_lightmapvertex, + r_stat_batch_dynamic_batches_because_deformvertexes_autosprite, + r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite, + r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite, + r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite, + r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2, + r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2, + r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2, + r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2, + r_stat_batch_dynamic_batches_because_deformvertexes_normal, + r_stat_batch_dynamic_surfaces_because_deformvertexes_normal, + r_stat_batch_dynamic_vertices_because_deformvertexes_normal, + r_stat_batch_dynamic_triangles_because_deformvertexes_normal, + r_stat_batch_dynamic_batches_because_deformvertexes_wave, + r_stat_batch_dynamic_surfaces_because_deformvertexes_wave, + r_stat_batch_dynamic_vertices_because_deformvertexes_wave, + r_stat_batch_dynamic_triangles_because_deformvertexes_wave, + r_stat_batch_dynamic_batches_because_deformvertexes_bulge, + r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge, + r_stat_batch_dynamic_vertices_because_deformvertexes_bulge, + r_stat_batch_dynamic_triangles_because_deformvertexes_bulge, + r_stat_batch_dynamic_batches_because_deformvertexes_move, + r_stat_batch_dynamic_surfaces_because_deformvertexes_move, + r_stat_batch_dynamic_vertices_because_deformvertexes_move, + r_stat_batch_dynamic_triangles_because_deformvertexes_move, + r_stat_batch_dynamic_batches_because_tcgen_lightmap, + r_stat_batch_dynamic_surfaces_because_tcgen_lightmap, + r_stat_batch_dynamic_vertices_because_tcgen_lightmap, + r_stat_batch_dynamic_triangles_because_tcgen_lightmap, + r_stat_batch_dynamic_batches_because_tcgen_vector, + r_stat_batch_dynamic_surfaces_because_tcgen_vector, + r_stat_batch_dynamic_vertices_because_tcgen_vector, + r_stat_batch_dynamic_triangles_because_tcgen_vector, + r_stat_batch_dynamic_batches_because_tcgen_environment, + r_stat_batch_dynamic_surfaces_because_tcgen_environment, + r_stat_batch_dynamic_vertices_because_tcgen_environment, + r_stat_batch_dynamic_triangles_because_tcgen_environment, + r_stat_batch_dynamic_batches_because_tcmod_turbulent, + r_stat_batch_dynamic_surfaces_because_tcmod_turbulent, + r_stat_batch_dynamic_vertices_because_tcmod_turbulent, + r_stat_batch_dynamic_triangles_because_tcmod_turbulent, + r_stat_batch_dynamic_batches_because_interleavedarrays, + r_stat_batch_dynamic_surfaces_because_interleavedarrays, + r_stat_batch_dynamic_vertices_because_interleavedarrays, + r_stat_batch_dynamic_triangles_because_interleavedarrays, + r_stat_batch_dynamic_batches_because_nogaps, + r_stat_batch_dynamic_surfaces_because_nogaps, + r_stat_batch_dynamic_vertices_because_nogaps, + r_stat_batch_dynamic_triangles_because_nogaps, + r_stat_batch_dynamic_batches_because_derived, + r_stat_batch_dynamic_surfaces_because_derived, + r_stat_batch_dynamic_vertices_because_derived, + r_stat_batch_dynamic_triangles_because_derived, + r_stat_batch_entitycache_count, + r_stat_batch_entitycache_surfaces, + r_stat_batch_entitycache_vertices, + r_stat_batch_entitycache_triangles, + r_stat_batch_entityanimate_count, + r_stat_batch_entityanimate_surfaces, + r_stat_batch_entityanimate_vertices, + r_stat_batch_entityanimate_triangles, + r_stat_batch_entityskeletal_count, + r_stat_batch_entityskeletal_surfaces, + r_stat_batch_entityskeletal_vertices, + r_stat_batch_entityskeletal_triangles, + r_stat_batch_entitystatic_count, + r_stat_batch_entitystatic_surfaces, + r_stat_batch_entitystatic_vertices, + r_stat_batch_entitystatic_triangles, + r_stat_batch_entitycustom_count, + r_stat_batch_entitycustom_surfaces, + r_stat_batch_entitycustom_vertices, + r_stat_batch_entitycustom_triangles, + r_stat_count // size of array +} +r_stat_t; + +// flags for rtlight rendering +#define LIGHTFLAG_NORMALMODE 1 +#define LIGHTFLAG_REALTIMEMODE 2 + +typedef struct tridecal_s +{ + // color and initial alpha value + float texcoord2f[3][2]; + float vertex3f[3][3]; + float color4f[3][4]; + float plane[4]; // backface culling + // how long this decal has lived so far (the actual fade begins at cl_decals_time) + float lived; + // if >= 0 this indicates the decal should follow an animated triangle + int triangleindex; + // for visibility culling + int surfaceindex; + // old decals are killed to obey cl_decals_max + int decalsequence; +} +tridecal_t; + +typedef struct decalsystem_s +{ + dp_model_t *model; + double lastupdatetime; + int maxdecals; + int freedecal; + int numdecals; + tridecal_t *decals; + float *vertex3f; + float *texcoord2f; + float *color4f; + int *element3i; + unsigned short *element3s; +} +decalsystem_t; + +typedef struct effect_s +{ + int active; + vec3_t origin; + double starttime; + float framerate; + int modelindex; + int startframe; + int endframe; + // these are for interpolation + int frame; + double frame1time; + double frame2time; +} +cl_effect_t; + +typedef struct beam_s +{ + int entity; + // draw this as lightning polygons, or a model? + int lightning; + struct model_s *model; + float endtime; + vec3_t start, end; +} +beam_t; + +typedef struct rtlight_particle_s +{ + float origin[3]; + float color[3]; +} +rtlight_particle_t; + +typedef struct rtlight_s +{ + // shadow volumes are done entirely in model space, so there are no matrices for dealing with them... they just use the origin + + // note that the world to light matrices are inversely scaled (divided) by lightradius + + // core properties + /// matrix for transforming light filter coordinates to world coordinates + matrix4x4_t matrix_lighttoworld; + /// matrix for transforming world coordinates to light filter coordinates + matrix4x4_t matrix_worldtolight; + /// typically 1 1 1, can be lower (dim) or higher (overbright) + vec3_t color; + /// size of the light (remove?) + vec_t radius; + /// light filter + char cubemapname[64]; + /// light style to monitor for brightness + int style; + /// whether light should render shadows + int shadow; + /// intensity of corona to render + vec_t corona; + /// radius scale of corona to render (1.0 means same as light radius) + vec_t coronasizescale; + /// ambient intensity to render + vec_t ambientscale; + /// diffuse intensity to render + vec_t diffusescale; + /// specular intensity to render + vec_t specularscale; + /// LIGHTFLAG_* flags + int flags; + + // generated properties + /// used only for shadow volumes + vec3_t shadoworigin; + /// culling + vec3_t cullmins; + vec3_t cullmaxs; + // culling + //vec_t cullradius; + // squared cullradius + //vec_t cullradius2; + + // rendering properties, updated each time a light is rendered + // this is rtlight->color * d_lightstylevalue + vec3_t currentcolor; + /// used by corona updates, due to occlusion query + float corona_visibility; + unsigned int corona_queryindex_visiblepixels; + unsigned int corona_queryindex_allpixels; + /// this is R_GetCubemap(rtlight->cubemapname) + rtexture_t *currentcubemap; + /// set by R_Shadow_PrepareLight to decide whether R_Shadow_DrawLight should draw it + qboolean draw; + /// these fields are set by R_Shadow_PrepareLight for later drawing + int cached_numlightentities; + int cached_numlightentities_noselfshadow; + int cached_numshadowentities; + int cached_numshadowentities_noselfshadow; + int cached_numsurfaces; + struct entity_render_s **cached_lightentities; + struct entity_render_s **cached_lightentities_noselfshadow; + struct entity_render_s **cached_shadowentities; + struct entity_render_s **cached_shadowentities_noselfshadow; + unsigned char *cached_shadowtrispvs; + unsigned char *cached_lighttrispvs; + int *cached_surfacelist; + // reduced light cullbox from GetLightInfo + vec3_t cached_cullmins; + vec3_t cached_cullmaxs; + // current shadow-caster culling planes based on view + // (any geometry outside these planes can not contribute to the visible + // shadows in any way, and thus can be culled safely) + int cached_numfrustumplanes; + mplane_t cached_frustumplanes[5]; // see R_Shadow_ComputeShadowCasterCullingPlanes + + /// static light info + /// true if this light should be compiled as a static light + int isstatic; + /// true if this is a compiled world light, cleared if the light changes + int compiled; + /// the shadowing mode used to compile this light + int shadowmode; + /// premade shadow volumes to render for world entity + shadowmesh_t *static_meshchain_shadow_zpass; + shadowmesh_t *static_meshchain_shadow_zfail; + shadowmesh_t *static_meshchain_shadow_shadowmap; + /// used for visibility testing (more exact than bbox) + int static_numleafs; + int static_numleafpvsbytes; + int *static_leaflist; + unsigned char *static_leafpvs; + /// surfaces seen by light + int static_numsurfaces; + int *static_surfacelist; + /// flag bits indicating which triangles of the world model should cast + /// shadows, and which ones should be lit + /// + /// this avoids redundantly scanning the triangles in each surface twice + /// for whether they should cast shadows, once in culling and once in the + /// actual shadowmarklist production. + int static_numshadowtrispvsbytes; + unsigned char *static_shadowtrispvs; + /// this allows the lighting batch code to skip backfaces andother culled + /// triangles not relevant for lighting + /// (important on big surfaces such as terrain) + int static_numlighttrispvsbytes; + unsigned char *static_lighttrispvs; + /// masks of all shadowmap sides that have any potential static receivers or casters + int static_shadowmap_receivers; + int static_shadowmap_casters; + /// particle-tracing cache for global illumination + int particlecache_numparticles; + int particlecache_maxparticles; + int particlecache_updateparticle; + rtlight_particle_t *particlecache_particles; + + /// bouncegrid light info + float photoncolor[3]; + float photons; +} +rtlight_t; + +typedef struct dlight_s +{ + // destroy light after this time + // (dlight only) + vec_t die; + // the entity that owns this light (can be NULL) + // (dlight only) + struct entity_render_s *ent; + // location + // (worldlight: saved to .rtlights file) + vec3_t origin; + // worldlight orientation + // (worldlight only) + // (worldlight: saved to .rtlights file) + vec3_t angles; + // dlight orientation/scaling/location + // (dlight only) + matrix4x4_t matrix; + // color of light + // (worldlight: saved to .rtlights file) + vec3_t color; + // cubemap name to use on this light + // (worldlight: saved to .rtlights file) + char cubemapname[64]; + // make light flash while selected + // (worldlight only) + int selected; + // brightness (not really radius anymore) + // (worldlight: saved to .rtlights file) + vec_t radius; + // drop intensity this much each second + // (dlight only) + vec_t decay; + // intensity value which is dropped over time + // (dlight only) + vec_t intensity; + // initial values for intensity to modify + // (dlight only) + vec_t initialradius; + vec3_t initialcolor; + // light style which controls intensity of this light + // (worldlight: saved to .rtlights file) + int style; + // cast shadows + // (worldlight: saved to .rtlights file) + int shadow; + // corona intensity + // (worldlight: saved to .rtlights file) + vec_t corona; + // radius scale of corona to render (1.0 means same as light radius) + // (worldlight: saved to .rtlights file) + vec_t coronasizescale; + // ambient intensity to render + // (worldlight: saved to .rtlights file) + vec_t ambientscale; + // diffuse intensity to render + // (worldlight: saved to .rtlights file) + vec_t diffusescale; + // specular intensity to render + // (worldlight: saved to .rtlights file) + vec_t specularscale; + // LIGHTFLAG_* flags + // (worldlight: saved to .rtlights file) + int flags; + // linked list of world lights + // (worldlight only) + struct dlight_s *next; + // embedded rtlight struct for renderer + // (worldlight only) + rtlight_t rtlight; +} +dlight_t; + +// this is derived from processing of the framegroupblend array +// note: technically each framegroupblend can produce two of these, but that +// never happens in practice because no one blends between more than 2 +// framegroups at once +#define MAX_FRAMEBLENDS (MAX_FRAMEGROUPBLENDS * 2) +typedef struct frameblend_s +{ + int subframe; + float lerp; +} +frameblend_t; + +// LordHavoc: this struct is intended for the renderer but some fields are +// used by the client. +// +// The renderer should not rely on any changes to this struct to be persistent +// across multiple frames because temp entities are wiped every frame, but it +// is acceptable to cache things in this struct that are not critical. +// +// For example the r_cullentities_trace code does such caching. +typedef struct entity_render_s +{ + // location + //vec3_t origin; + // orientation + //vec3_t angles; + // transform matrix for model to world + matrix4x4_t matrix; + // transform matrix for world to model + matrix4x4_t inversematrix; + // opacity (alpha) of the model + float alpha; + // size the model is shown + float scale; + // transparent sorting offset + float transparent_offset; + + // NULL = no model + dp_model_t *model; + // number of the entity represents, or 0 for non-network entities + int entitynumber; + // literal colormap colors for renderer, if both are 0 0 0 it is not colormapped + vec3_t colormap_pantscolor; + vec3_t colormap_shirtcolor; + // light, particles, etc + int effects; + // qw CTF flags and other internal-use-only effect bits + int internaleffects; + // for Alias models + int skinnum; + // render flags + int flags; + + // colormod tinting of models + float colormod[3]; + float glowmod[3]; + + // interpolated animation - active framegroups and blend factors + framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS]; + + // time of last model change (for shader animations) + double shadertime; + + // calculated by the renderer (but not persistent) + + // calculated during R_AddModelEntities + vec3_t mins, maxs; + // subframe numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use subframeblend[0].subframe + frameblend_t frameblend[MAX_FRAMEBLENDS]; + // skeletal animation data (if skeleton.relativetransforms is not NULL, it overrides frameblend) + skeleton_t *skeleton; + + // animation cache (pointers allocated using R_FrameData_Alloc) + // ONLY valid during R_RenderView! may be NULL (not cached) + float *animcache_vertex3f; + r_meshbuffer_t *animcache_vertex3f_vertexbuffer; + int animcache_vertex3f_bufferoffset; + float *animcache_normal3f; + r_meshbuffer_t *animcache_normal3f_vertexbuffer; + int animcache_normal3f_bufferoffset; + float *animcache_svector3f; + r_meshbuffer_t *animcache_svector3f_vertexbuffer; + int animcache_svector3f_bufferoffset; + float *animcache_tvector3f; + r_meshbuffer_t *animcache_tvector3f_vertexbuffer; + int animcache_tvector3f_bufferoffset; + // interleaved arrays for rendering and dynamic vertex buffers for them + r_vertexmesh_t *animcache_vertexmesh; + r_meshbuffer_t *animcache_vertexmesh_vertexbuffer; + int animcache_vertexmesh_bufferoffset; + // gpu-skinning shader needs transforms in a certain format, we have to + // upload this to a uniform buffer for the shader to use, and also keep a + // backup copy in system memory for the dynamic batch fallback code + // if this is not NULL, the other animcache variables are NULL + float *animcache_skeletaltransform3x4; + r_meshbuffer_t *animcache_skeletaltransform3x4buffer; + int animcache_skeletaltransform3x4offset; + int animcache_skeletaltransform3x4size; + + // current lighting from map (updated ONLY by client code, not renderer) + vec3_t modellight_ambient; + vec3_t modellight_diffuse; // q3bsp + vec3_t modellight_lightdir; // q3bsp + + // storage of decals on this entity + // (note: if allowdecals is set, be sure to call R_DecalSystem_Reset on removal!) + int allowdecals; + decalsystem_t decalsystem; + + // FIELDS UPDATED BY RENDERER: + // last time visible during trace culling + double last_trace_visibility; + + // user wavefunc parameters (from csqc) + vec_t userwavefunc_param[Q3WAVEFUNC_USER_COUNT]; +} +entity_render_t; + +typedef struct entity_persistent_s +{ + vec3_t trail_origin; // previous position for particle trail spawning + vec3_t oldorigin; // lerp + vec3_t oldangles; // lerp + vec3_t neworigin; // lerp + vec3_t newangles; // lerp + vec_t lerpstarttime; // lerp + vec_t lerpdeltatime; // lerp + float muzzleflash; // muzzleflash intensity, fades over time + float trail_time; // residual error accumulation for particle trail spawning (to keep spacing across frames) + qboolean trail_allowed; // set to false by teleports, true by update code, prevents bad lerps +} +entity_persistent_t; + +typedef struct entity_s +{ + // baseline state (default values) + entity_state_t state_baseline; + // previous state (interpolating from this) + entity_state_t state_previous; + // current state (interpolating to this) + entity_state_t state_current; + + // used for regenerating parts of render + entity_persistent_t persistent; + + // the only data the renderer should know about + entity_render_t render; +} +entity_t; + +typedef struct usercmd_s +{ + vec3_t viewangles; + +// intended velocities + float forwardmove; + float sidemove; + float upmove; + + vec3_t cursor_screen; + vec3_t cursor_start; + vec3_t cursor_end; + vec3_t cursor_impact; + vec3_t cursor_normal; + vec_t cursor_fraction; + int cursor_entitynumber; + + double time; // time the move is executed for (cl_movement: clienttime, non-cl_movement: receivetime) + double receivetime; // time the move was received at + double clienttime; // time to which server state the move corresponds to + int msec; // for predicted moves + int buttons; + int impulse; + int sequence; + qboolean applied; // if false we're still accumulating a move + qboolean predicted; // if true the sequence should be sent as 0 + + // derived properties + double frametime; + qboolean canjump; + qboolean jump; + qboolean crouch; +} usercmd_t; + +typedef struct lightstyle_s +{ + int length; + char map[MAX_STYLESTRING]; +} lightstyle_t; + +typedef struct scoreboard_s +{ + char name[MAX_SCOREBOARDNAME]; + int frags; + int colors; // two 4 bit fields + // QW fields: + int qw_userid; + char qw_userinfo[MAX_USERINFO_STRING]; + float qw_entertime; + int qw_ping; + int qw_packetloss; + int qw_movementloss; + int qw_spectator; + char qw_team[8]; + char qw_skin[MAX_QPATH]; +} scoreboard_t; + +typedef struct cshift_s +{ + float destcolor[3]; + float percent; // 0-255 + float alphafade; // (any speed) +} cshift_t; + +#define CSHIFT_CONTENTS 0 +#define CSHIFT_DAMAGE 1 +#define CSHIFT_BONUS 2 +#define CSHIFT_POWERUP 3 +#define CSHIFT_VCSHIFT 4 +#define NUM_CSHIFTS 5 + +#define NAME_LENGTH 64 + + +// +// client_state_t should hold all pieces of the client state +// + +#define SIGNONS 4 // signon messages to receive before connected + +typedef enum cactive_e +{ + ca_uninitialized, // during early startup + 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; + +typedef enum qw_downloadtype_e +{ + dl_none, + dl_single, + dl_skin, + dl_model, + dl_sound +} +qw_downloadtype_t; + +typedef enum capturevideoformat_e +{ + CAPTUREVIDEOFORMAT_AVI_I420, + CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA +} +capturevideoformat_t; + +typedef struct capturevideostate_s +{ + double startrealtime; + double framerate; + int framestep; + int framestepframe; + qboolean active; + qboolean realtime; + qboolean error; + int soundrate; + int soundchannels; + int frame; + double starttime; + double lastfpstime; + int lastfpsframe; + int soundsampleframe; + unsigned char *screenbuffer; + unsigned char *outbuffer; + char basename[MAX_QPATH]; + int width, height; + + // precomputed RGB to YUV tables + // converts the RGB values to YUV (see cap_avi.c for how to use them) + short rgbtoyuvscaletable[3][3][256]; + unsigned char yuvnormalizetable[3][256]; + + // precomputed gamma ramp (only needed if the capturevideo module uses RGB output) + // note: to map from these values to RGB24, you have to multiply by 255.0/65535.0, then add 0.5, then cast to integer + unsigned short vidramp[256 * 3]; + + // stuff to be filled in by the video format module + capturevideoformat_t format; + const char *formatextension; + qfile_t *videofile; + // always use this: + // cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false); + void (*endvideo) (void); + void (*videoframes) (int num); + void (*soundframe) (const portable_sampleframe_t *paintbuffer, size_t length); + + // format specific data + void *formatspecific; +} +capturevideostate_t; + +#define CL_MAX_DOWNLOADACKS 4 + +typedef struct cl_downloadack_s +{ + int start, size; +} +cl_downloadack_t; + +typedef struct cl_soundstats_s +{ + int mixedsounds; + int totalsounds; + int latency_milliseconds; +} +cl_soundstats_t; + +// +// the client_static_t structure is persistent through an arbitrary number +// of server connections +// +typedef struct client_static_s +{ + cactive_t state; + + // all client memory allocations go in these pools + mempool_t *levelmempool; + mempool_t *permanentmempool; + +// demo loop control + // -1 = don't play demos + int demonum; + // list of demos in loop + char demos[MAX_DEMOS][MAX_DEMONAME]; + // the actively playing demo (set by CL_PlayDemo_f) + char demoname[MAX_QPATH]; + +// demo recording info must be here, because record is started before +// entering a map (and clearing client_state_t) + qboolean demorecording; + fs_offset_t demo_lastcsprogssize; + int demo_lastcsprogscrc; + qboolean demoplayback; + qboolean demostarting; // set if currently starting a demo, to stop -demo from quitting when switching to another demo + qboolean timedemo; + // -1 = use normal cd track + int forcetrack; + qfile_t *demofile; + // realtime at second frame of timedemo (LordHavoc: changed to double) + double td_starttime; + int td_frames; // total frames parsed + double td_onesecondnexttime; + double td_onesecondframes; + double td_onesecondrealtime; + double td_onesecondminfps; + double td_onesecondmaxfps; + double td_onesecondavgfps; + int td_onesecondavgcount; + // LordHavoc: pausedemo + qboolean demopaused; + + // sound mixer statistics for showsound display + cl_soundstats_t soundstats; + + qboolean connect_trying; + int connect_remainingtries; + double connect_nextsendtime; + lhnetsocket_t *connect_mysocket; + lhnetaddress_t connect_address; + // protocol version of the server we're connected to + // (kept outside client_state_t because it's used between levels) + protocolversion_t protocol; + +#define MAX_RCONS 16 + int rcon_trying; + lhnetaddress_t rcon_addresses[MAX_RCONS]; + char rcon_commands[MAX_RCONS][MAX_INPUTLINE]; + double rcon_timeout[MAX_RCONS]; + int rcon_ringpos; + +// connection information + // 0 to SIGNONS + int signon; + // network connection + netconn_t *netcon; + + // download information + // (note: qw_download variables are also used) + cl_downloadack_t dp_downloadack[CL_MAX_DOWNLOADACKS]; + + // input sequence numbers are not reset on level change, only connect + int movesequence; + int servermovesequence; + + // quakeworld stuff below + + // value of "qport" cvar at time of connection + int qw_qport; + // copied from cls.netcon->qw. variables every time they change, or set by demos (which have no cls.netcon) + int qw_incoming_sequence; + int qw_outgoing_sequence; + + // current file download buffer (only saved when file is completed) + char qw_downloadname[MAX_QPATH]; + unsigned char *qw_downloadmemory; + int qw_downloadmemorycursize; + int qw_downloadmemorymaxsize; + int qw_downloadnumber; + int qw_downloadpercent; + qw_downloadtype_t qw_downloadtype; + // transfer rate display + double qw_downloadspeedtime; + int qw_downloadspeedcount; + int qw_downloadspeedrate; + qboolean qw_download_deflate; + + // current file upload buffer (for uploading screenshots to server) + unsigned char *qw_uploaddata; + int qw_uploadsize; + int qw_uploadpos; + + // user infostring + // this normally contains the following keys in quakeworld: + // password spectator name team skin topcolor bottomcolor rate noaim msg *ver *ip + char userinfo[MAX_USERINFO_STRING]; + + // extra user info for the "connect" command + char connect_userinfo[MAX_USERINFO_STRING]; + + // video capture stuff + capturevideostate_t capturevideo; + + // crypto channel + crypto_t crypto; + + // ProQuake compatibility stuff + int proquake_servermod; // 0 = not proquake, 1 = proquake + int proquake_serverversion; // actual proquake server version * 10 (3.40 = 34, etc) + int proquake_serverflags; // 0 (PQF_CHEATFREE not supported) + + // don't write-then-read csprogs.dat (useful for demo playback) + unsigned char *caughtcsprogsdata; + fs_offset_t caughtcsprogsdatasize; + + int r_speeds_graph_length; + int r_speeds_graph_current; + int *r_speeds_graph_data; + + // graph scales + int r_speeds_graph_datamin[r_stat_count]; + int r_speeds_graph_datamax[r_stat_count]; +} +client_static_t; + +extern client_static_t cls; + +typedef struct client_movementqueue_s +{ + double time; + float frametime; + int sequence; + float viewangles[3]; + float move[3]; + qboolean jump; + qboolean crouch; + qboolean canjump; +} +client_movementqueue_t; + +//[515]: csqc +typedef struct +{ + qboolean drawworld; + qboolean drawenginesbar; + qboolean drawcrosshair; +}csqc_vidvars_t; + +typedef enum +{ + PARTICLE_BILLBOARD = 0, + PARTICLE_SPARK = 1, + PARTICLE_ORIENTED_DOUBLESIDED = 2, + PARTICLE_VBEAM = 3, + PARTICLE_HBEAM = 4, + PARTICLE_INVALID = -1 +} +porientation_t; + +typedef enum +{ + PBLEND_ALPHA = 0, + PBLEND_ADD = 1, + PBLEND_INVMOD = 2, + PBLEND_INVALID = -1 +} +pblend_t; + +typedef struct particletype_s +{ + pblend_t blendmode; + porientation_t orientation; + qboolean lighting; +} +particletype_t; + +typedef enum ptype_e +{ + pt_dead, pt_alphastatic, pt_static, pt_spark, pt_beam, pt_rain, pt_raindecal, pt_snow, pt_bubble, pt_blood, pt_smoke, pt_decal, pt_entityparticle, pt_total +} +ptype_t; + +typedef struct decal_s +{ + // fields used by rendering: (44 bytes) + unsigned short typeindex; + unsigned short texnum; + int decalsequence; + vec3_t org; + vec3_t normal; + float size; + float alpha; // 0-255 + unsigned char color[3]; + unsigned char unused1; + int clusterindex; // cheap culling by pvs + + // fields not used by rendering: (36 bytes in 32bit, 40 bytes in 64bit) + float time2; // used for decal fade + unsigned int owner; // decal stuck to this entity + dp_model_t *ownermodel; // model the decal is stuck to (used to make sure the entity is still alive) + vec3_t relativeorigin; // decal at this location in entity's coordinate space + vec3_t relativenormal; // decal oriented this way relative to entity's coordinate space +} +decal_t; + +typedef struct particle_s +{ + // for faster batch rendering, particles are rendered in groups by effect (resulting in less perfect sorting but far less state changes) + + // fields used by rendering: (48 bytes) + vec3_t sortorigin; // sort by this group origin, not particle org + vec3_t org; + vec3_t vel; // velocity of particle, or orientation of decal, or end point of beam + float size; + float alpha; // 0-255 + float stretch; // only for sparks + + // fields not used by rendering: (44 bytes) + float stainsize; + float stainalpha; + float sizeincrease; // rate of size change per second + float alphafade; // how much alpha reduces per second + float time2; // used for snow fluttering and decal fade + float bounce; // how much bounce-back from a surface the particle hits (0 = no physics, 1 = stop and slide, 2 = keep bouncing forever, 1.5 is typical) + float gravity; // how much gravity affects this particle (1.0 = normal gravity, 0.0 = none) + float airfriction; // how much air friction affects this object (objects with a low mass/size ratio tend to get more air friction) + float liquidfriction; // how much liquid friction affects this object (objects with a low mass/size ratio tend to get more liquid friction) +// float delayedcollisions; // time that p->bounce becomes active + float delayedspawn; // time that particle appears and begins moving + float die; // time when this particle should be removed, regardless of alpha + + // short variables grouped to save memory (4 bytes) + short angle; // base rotation of particle + short spin; // geometry rotation speed around the particle center normal + + // byte variables grouped to save memory (12 bytes) + unsigned char color[3]; + unsigned char qualityreduction; // enables skipping of this particle according to r_refdef.view.qualityreduction + unsigned char typeindex; + unsigned char blendmode; + unsigned char orientation; + unsigned char texnum; + unsigned char staincolor[3]; + signed char staintexnum; +} +particle_t; + +typedef enum cl_parsingtextmode_e +{ + CL_PARSETEXTMODE_NONE, + CL_PARSETEXTMODE_PING, + CL_PARSETEXTMODE_STATUS, + CL_PARSETEXTMODE_STATUS_PLAYERID, + CL_PARSETEXTMODE_STATUS_PLAYERIP +} +cl_parsingtextmode_t; + +typedef struct cl_locnode_s +{ + struct cl_locnode_s *next; + char *name; + vec3_t mins, maxs; +} +cl_locnode_t; + +typedef struct showlmp_s +{ + qboolean isactive; + float x; + float y; + char label[32]; + char pic[128]; +} +showlmp_t; + +// +// the client_state_t structure is wiped completely at every +// server signon +// +typedef struct client_state_s +{ + // true if playing in a local game and no one else is connected + int islocalgame; + + // send a clc_nop periodically until connected + float sendnoptime; + + // current input being accumulated by mouse/joystick/etc input + usercmd_t cmd; + // latest moves sent to the server that have not been confirmed yet + usercmd_t movecmd[CL_MAX_USERCMDS]; + +// information for local display + // health, etc + int stats[MAX_CL_STATS]; + float *statsf; // points to stats[] array + // last known inventory bit flags, for blinking + int olditems; + // cl.time of acquiring item, for blinking + float item_gettime[32]; + // last known STAT_ACTIVEWEAPON + int activeweapon; + // cl.time of changing STAT_ACTIVEWEAPON + float weapontime; + // use pain anim frame if cl.time < this + float faceanimtime; + // for stair smoothing + float stairsmoothz; + double stairsmoothtime; + + // color shifts for damage, powerups + cshift_t cshifts[NUM_CSHIFTS]; + // and content types + cshift_t prev_cshifts[NUM_CSHIFTS]; + +// 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 temporarily offset, and an angle reset commands at the start +// of each level and after teleporting. + + //The increments for comfort mode + int comfortInc; + + // mviewangles is read from demo + // viewangles is either client controlled or lerped from mviewangles + vec3_t mviewangles[2], viewangles; + // update by server, used by qc to do weapon recoil + vec3_t mpunchangle[2], punchangle; + // update by server, can be used by mods to kick view around + vec3_t mpunchvector[2], punchvector; + // update by server, used for lean+bob (0 is newest) + vec3_t mvelocity[2], velocity; + // update by server, can be used by mods for zooming + vec_t mviewzoom[2], viewzoom; + // if true interpolation the mviewangles and other interpolation of the + // player is disabled until the next network packet + // this is used primarily by teleporters, and when spectating players + // special checking of the old fixangle[1] is used to differentiate + // between teleporting and spectating + qboolean fixangle[2]; + + // client movement simulation + // these fields are only updated by CL_ClientMovement (called by CL_SendMove after parsing each network packet) + // set by CL_ClientMovement_Replay functions + qboolean movement_predicted; + // if true the CL_ClientMovement_Replay function will update origin, etc + qboolean movement_replay; + // simulated data (this is valid even if cl.movement is false) + vec3_t movement_origin; + vec3_t movement_velocity; + // whether the replay should allow a jump at the first sequence + qboolean movement_replay_canjump; + + // previous gun angles (for leaning effects) + vec3_t gunangles_prev; + vec3_t gunangles_highpass; + vec3_t gunangles_adjustment_lowpass; + vec3_t gunangles_adjustment_highpass; + // previous gun angles (for leaning effects) + vec3_t gunorg_prev; + vec3_t gunorg_highpass; + vec3_t gunorg_adjustment_lowpass; + vec3_t gunorg_adjustment_highpass; + +// pitch drifting vars + float idealpitch; + float pitchvel; + qboolean nodrift; + float driftmove; + double laststop; + +//[515]: added for csqc purposes + float sensitivityscale; + csqc_vidvars_t csqc_vidvars; //[515]: these parms must be set to true by default + qboolean csqc_wantsmousemove; + qboolean csqc_paused; // vortex: int because could be flags + struct model_s *csqc_model_precache[MAX_MODELS]; + + // local amount for smoothing stepups + //float crouch; + + // sent by server + qboolean paused; + qboolean onground; + qboolean inwater; + + // used by bob + qboolean oldonground; + double lastongroundtime; + double hitgroundtime; + float bob2_smooth; + float bobfall_speed; + float bobfall_swing; + double calcrefdef_prevtime; + + // don't change view angle, full screen, etc + int intermission; + // latched at intermission start + double completed_time; + + // the timestamp of the last two messages + double mtime[2]; + + // clients view of time, time should be between mtime[0] and mtime[1] to + // generate a lerp point for other data, oldtime is the previous frame's + // value of time, frametime is the difference between time and oldtime + // note: cl.time may be beyond cl.mtime[0] if packet loss is occuring, it + // is only forcefully limited when a packet is received + double time, oldtime; + // how long it has been since the previous client frame in real time + // (not game time, for that use cl.time - cl.oldtime) + double realframetime; + + // fade var for fading while dead + float deathfade; + + // motionblur alpha level variable + float motionbluralpha; + + // copy of realtime from last recieved message, for net trouble icon + float last_received_message; + +// 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]; + + // FIXME: this is a lot of memory to be keeping around, this really should be dynamically allocated and freed somehow + char model_name[MAX_MODELS][MAX_QPATH]; + char sound_name[MAX_SOUNDS][MAX_QPATH]; + + // for display on solo scoreboard + char worldmessage[40]; // map title (not related to filename) + // variants of map name + char worldbasename[MAX_QPATH]; // %s + char worldname[MAX_QPATH]; // maps/%s.bsp + char worldnamenoextension[MAX_QPATH]; // maps/%s + // cl_entitites[cl.viewentity] = player + int viewentity; + // the real player entity (normally same as viewentity, + // different than viewentity if mod uses chasecam or other tricks) + int realplayerentity; + // this is updated to match cl.viewentity whenever it is in the clients + // range, basically this is used in preference to cl.realplayerentity for + // most purposes because when spectating another player it should show + // their information rather than yours + int playerentity; + // max players that can be in this game + int maxclients; + // type of game (deathmatch, coop, singleplayer) + int gametype; + + // models and sounds used by engine code (particularly cl_parse.c) + dp_model_t *model_bolt; + dp_model_t *model_bolt2; + dp_model_t *model_bolt3; + dp_model_t *model_beam; + sfx_t *sfx_wizhit; + sfx_t *sfx_knighthit; + sfx_t *sfx_tink1; + sfx_t *sfx_ric1; + sfx_t *sfx_ric2; + sfx_t *sfx_ric3; + sfx_t *sfx_r_exp3; + // indicates that the file "sound/misc/talk2.wav" was found (for use by team chat messages) + qboolean foundtalk2wav; + +// refresh related state + + // cl_entitites[0].model + struct model_s *worldmodel; + + // the gun model + entity_t viewent; + + // cd audio + int cdtrack, looptrack; + +// frag scoreboard + + // [cl.maxclients] + scoreboard_t *scores; + + // keep track of svc_print parsing state (analyzes ping reports and status reports) + cl_parsingtextmode_t parsingtextmode; + int parsingtextplayerindex; + // set by scoreboard code when sending ping command, this causes the next ping results to be hidden + // (which could eat the wrong ping report if the player issues one + // manually, but they would still see a ping report, just a later one + // caused by the scoreboard code rather than the one they intentionally + // issued) + int parsingtextexpectingpingforscores; + + // entity database stuff + // latest received entity frame numbers +#define LATESTFRAMENUMS 32 + int latestframenumsposition; + int latestframenums[LATESTFRAMENUMS]; + int latestsendnums[LATESTFRAMENUMS]; + entityframe_database_t *entitydatabase; + entityframe4_database_t *entitydatabase4; + entityframeqw_database_t *entitydatabaseqw; + + // keep track of quake entities because they need to be killed if they get stale + int lastquakeentity; + unsigned char isquakeentity[MAX_EDICTS]; + + // bounding boxes for clientside movement + vec3_t playerstandmins; + vec3_t playerstandmaxs; + vec3_t playercrouchmins; + vec3_t playercrouchmaxs; + + // old decals are killed based on this + int decalsequence; + + int max_entities; + int max_csqcrenderentities; + int max_static_entities; + int max_effects; + int max_beams; + int max_dlights; + int max_lightstyle; + int max_brushmodel_entities; + int max_particles; + int max_decals; + int max_showlmps; + + entity_t *entities; + entity_render_t *csqcrenderentities; + unsigned char *entities_active; + entity_t *static_entities; + cl_effect_t *effects; + beam_t *beams; + dlight_t *dlights; + lightstyle_t *lightstyle; + int *brushmodel_entities; + particle_t *particles; + decal_t *decals; + showlmp_t *showlmps; + + int num_entities; + int num_static_entities; + int num_brushmodel_entities; + int num_effects; + int num_beams; + int num_dlights; + int num_particles; + int num_decals; + int num_showlmps; + + double particles_updatetime; + double decals_updatetime; + int free_particle; + int free_decal; + + // cl_serverextension_download feature + int loadmodel_current; + int downloadmodel_current; + int loadmodel_total; + int loadsound_current; + int downloadsound_current; + int loadsound_total; + qboolean downloadcsqc; + qboolean loadcsqc; + qboolean loadbegun; + qboolean loadfinished; + + // quakeworld stuff + + // local copy of the server infostring + char qw_serverinfo[MAX_SERVERINFO_STRING]; + + // time of last qw "pings" command sent to server while showing scores + double last_ping_request; + + // used during connect + int qw_servercount; + + // updated from serverinfo + int qw_teamplay; + + // unused: indicates whether the player is spectating + // use cl.scores[cl.playerentity-1].qw_spectator instead + //qboolean qw_spectator; + + // last time an input packet was sent + double lastpackettime; + + // movement parameters for client prediction + unsigned int moveflags; + float movevars_wallfriction; + float movevars_waterfriction; + float movevars_friction; + float movevars_timescale; + float movevars_gravity; + float movevars_stopspeed; + float movevars_maxspeed; + float movevars_spectatormaxspeed; + float movevars_accelerate; + float movevars_airaccelerate; + float movevars_wateraccelerate; + float movevars_entgravity; + float movevars_jumpvelocity; + float movevars_edgefriction; + float movevars_maxairspeed; + float movevars_stepheight; + float movevars_airaccel_qw; + float movevars_airaccel_qw_stretchfactor; + float movevars_airaccel_sideways_friction; + float movevars_airstopaccelerate; + float movevars_airstrafeaccelerate; + float movevars_maxairstrafespeed; + float movevars_airstrafeaccel_qw; + float movevars_aircontrol; + float movevars_aircontrol_power; + float movevars_aircontrol_penalty; + float movevars_warsowbunny_airforwardaccel; + float movevars_warsowbunny_accel; + float movevars_warsowbunny_topspeed; + float movevars_warsowbunny_turnaccel; + float movevars_warsowbunny_backtosideratio; + float movevars_ticrate; + float movevars_airspeedlimit_nonqw; + + // models used by qw protocol + int qw_modelindex_spike; + int qw_modelindex_player; + int qw_modelindex_flag; + int qw_modelindex_s_explod; + + vec3_t qw_intermission_origin; + vec3_t qw_intermission_angles; + + // 255 is the most nails the QW protocol could send + int qw_num_nails; + vec_t qw_nails[255][6]; + + float qw_weaponkick; + + int qw_validsequence; + + int qw_deltasequence[QW_UPDATE_BACKUP]; + + // csqc stuff: + // server entity number corresponding to a clientside entity + unsigned short csqc_server2csqcentitynumber[MAX_EDICTS]; + qboolean csqc_loaded; + vec3_t csqc_vieworigin; + vec3_t csqc_viewangles; + vec3_t csqc_vieworiginfromengine; + vec3_t csqc_viewanglesfromengine; + matrix4x4_t csqc_viewmodelmatrixfromengine; + qboolean csqc_usecsqclistener; + matrix4x4_t csqc_listenermatrix; + char csqc_printtextbuf[MAX_INPUTLINE]; + + // collision culling data + world_t world; + + // loc file stuff (points and boxes describing locations in the level) + cl_locnode_t *locnodes; + // this is updated to cl.movement_origin whenever health is < 1 + // used by %d print in say/say_team messages if cl_locs_enable is on + vec3_t lastdeathorigin; + + // processing buffer used by R_BuildLightMap, reallocated as needed, + // freed on each level change + size_t buildlightmapmemorysize; + unsigned char *buildlightmapmemory; + + // used by EntityState5_ReadUpdate + skeleton_t *engineskeletonobjects; +} +client_state_t; + +// +// cvars +// +extern cvar_t cl_name; +extern cvar_t cl_color; +extern cvar_t cl_rate; +extern cvar_t cl_pmodel; +extern cvar_t cl_playermodel; +extern cvar_t cl_playerskin; + +extern cvar_t rcon_password; +extern cvar_t rcon_address; + +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_yawmode; +extern cvar_t cl_pitchmode; +extern cvar_t cl_comfort; +extern cvar_t cl_yawspeed; +extern cvar_t cl_pitchspeed; +extern cvar_t cl_yawmult; +extern cvar_t cl_pitchmult; +extern qboolean headtracking; + +extern cvar_t cl_anglespeedkey; + +extern cvar_t cl_autofire; + +extern cvar_t cl_shownet; +extern cvar_t cl_nolerp; +extern cvar_t cl_nettimesyncfactor; +extern cvar_t cl_nettimesyncboundmode; +extern cvar_t cl_nettimesyncboundtolerance; + +extern cvar_t cl_pitchdriftspeed; +extern cvar_t lookspring; +extern cvar_t lookstrafe; +extern cvar_t sensitivity; + +extern cvar_t freelook; + +extern cvar_t m_pitch; +extern cvar_t m_yaw; +extern cvar_t m_forward; +extern cvar_t m_side; + +extern cvar_t cl_autodemo; +extern cvar_t cl_autodemo_nameformat; +extern cvar_t cl_autodemo_delete; + +extern cvar_t r_draweffects; + +extern cvar_t cl_explosions_alpha_start; +extern cvar_t cl_explosions_alpha_end; +extern cvar_t cl_explosions_size_start; +extern cvar_t cl_explosions_size_end; +extern cvar_t cl_explosions_lifetime; +extern cvar_t cl_stainmaps; +extern cvar_t cl_stainmaps_clearonload; + +extern cvar_t cl_prydoncursor; +extern cvar_t cl_prydoncursor_notrace; + +extern cvar_t cl_locs_enable; + +extern client_state_t cl; + +extern void CL_AllocLightFlash (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags); + +cl_locnode_t *CL_Locs_FindNearest(const vec3_t point); +void CL_Locs_FindLocationName(char *buffer, size_t buffersize, vec3_t point); + +//============================================================================= + +// +// cl_main +// + +void CL_Shutdown (void); +void CL_Init (void); + +void CL_EstablishConnection(const char *host, int firstarg); + +void CL_Disconnect (void); +void CL_Disconnect_f (void); + +void CL_UpdateRenderEntity(entity_render_t *ent); +void CL_SetEntityColormapColors(entity_render_t *ent, int colormap); +void CL_UpdateViewEntities(void); + +// +// cl_input +// +typedef struct kbutton_s +{ + 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_SendMove (void); + +void CL_ValidateState(entity_state_t *s); +void CL_MoveLerpEntityStates(entity_t *ent); +void CL_LerpUpdate(entity_t *e); +void CL_ParseTEnt (void); +void CL_NewBeam (int ent, vec3_t start, vec3_t end, dp_model_t *m, int lightning); +void CL_RelinkBeams (void); +void CL_Beam_CalculatePositions (const beam_t *b, vec3_t start, vec3_t end); +void CL_ClientMovement_Replay(void); + +void CL_ClearTempEntities (void); +entity_render_t *CL_NewTempEntity (double shadertime); + +void CL_Effect(vec3_t org, int modelindex, int startframe, int framecount, float framerate); + +void CL_ClearState (void); +void CL_ExpandEntities(int num); +void CL_ExpandCSQCRenderEntities(int num); +void CL_SetInfo(const char *key, const char *value, qboolean send, qboolean allowstarkey, qboolean allowmodel, qboolean quiet); + + +void CL_UpdateWorld (void); +void CL_WriteToServer (void); +void CL_Input (void); +extern int cl_ignoremousemoves; + + +float CL_KeyState (kbutton_t *key); +const char *Key_KeynumToString (int keynum, char *buf, size_t buflength); +int Key_StringToKeynum (const char *str); + +// +// cl_demo.c +// +void CL_StopPlayback(void); +void CL_ReadDemoMessage(void); +void CL_WriteDemoMessage(sizebuf_t *mesage); + +void CL_CutDemo(unsigned char **buf, fs_offset_t *filesize); +void CL_PasteDemo(unsigned char **buf, fs_offset_t *filesize); + +void CL_NextDemo(void); +void CL_Stop_f(void); +void CL_Record_f(void); +void CL_PlayDemo_f(void); +void CL_TimeDemo_f(void); + +// +// cl_parse.c +// +void CL_Parse_Init(void); +void CL_Parse_Shutdown(void); +void CL_ParseServerMessage(void); +void CL_Parse_DumpPacket(void); +void CL_Parse_ErrorCleanUp(void); +void QW_CL_StartUpload(unsigned char *data, int size); +extern cvar_t qport; +void CL_KeepaliveMessage(qboolean readmessages); // call this during loading of large content + +// +// view +// +void V_StartPitchDrift (void); +void V_StopPitchDrift (void); + +void V_Init (void); +float V_CalcRoll (const vec3_t angles, const vec3_t velocity); +void V_UpdateBlends (void); +void V_ParseDamage (void); + +// +// cl_part +// + +extern cvar_t cl_particles; +extern cvar_t cl_particles_quality; +extern cvar_t cl_particles_size; +extern cvar_t cl_particles_quake; +extern cvar_t cl_particles_blood; +extern cvar_t cl_particles_blood_alpha; +extern cvar_t cl_particles_blood_decal_alpha; +extern cvar_t cl_particles_blood_decal_scalemin; +extern cvar_t cl_particles_blood_decal_scalemax; +extern cvar_t cl_particles_blood_bloodhack; +extern cvar_t cl_particles_bulletimpacts; +extern cvar_t cl_particles_explosions_sparks; +extern cvar_t cl_particles_explosions_shell; +extern cvar_t cl_particles_rain; +extern cvar_t cl_particles_snow; +extern cvar_t cl_particles_smoke; +extern cvar_t cl_particles_smoke_alpha; +extern cvar_t cl_particles_smoke_alphafade; +extern cvar_t cl_particles_sparks; +extern cvar_t cl_particles_bubbles; +extern cvar_t cl_decals; +extern cvar_t cl_decals_time; +extern cvar_t cl_decals_fadetime; + +void CL_Particles_Clear(void); +void CL_Particles_Init(void); +void CL_Particles_Shutdown(void); +particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, int pcolor1, int pcolor2, int ptex, float psize, float psizeincrease, float palpha, float palphafade, float pgravity, float pbounce, float px, float py, float pz, float pvx, float pvy, float pvz, float pairfriction, float pliquidfriction, float originjitter, float velocityjitter, qboolean pqualityreduction, float lifetime, float stretch, pblend_t blendmode, porientation_t orientation, int staincolor1, int staincolor2, int staintex, float stainalpha, float stainsize, float angle, float spin, float tint[4]); + +typedef enum effectnameindex_s +{ + EFFECT_NONE, + EFFECT_TE_GUNSHOT, + EFFECT_TE_GUNSHOTQUAD, + EFFECT_TE_SPIKE, + EFFECT_TE_SPIKEQUAD, + EFFECT_TE_SUPERSPIKE, + EFFECT_TE_SUPERSPIKEQUAD, + EFFECT_TE_WIZSPIKE, + EFFECT_TE_KNIGHTSPIKE, + EFFECT_TE_EXPLOSION, + EFFECT_TE_EXPLOSIONQUAD, + EFFECT_TE_TAREXPLOSION, + EFFECT_TE_TELEPORT, + EFFECT_TE_LAVASPLASH, + EFFECT_TE_SMALLFLASH, + EFFECT_TE_FLAMEJET, + EFFECT_EF_FLAME, + EFFECT_TE_BLOOD, + EFFECT_TE_SPARK, + EFFECT_TE_PLASMABURN, + EFFECT_TE_TEI_G3, + EFFECT_TE_TEI_SMOKE, + EFFECT_TE_TEI_BIGEXPLOSION, + EFFECT_TE_TEI_PLASMAHIT, + EFFECT_EF_STARDUST, + EFFECT_TR_ROCKET, + EFFECT_TR_GRENADE, + EFFECT_TR_BLOOD, + EFFECT_TR_WIZSPIKE, + EFFECT_TR_SLIGHTBLOOD, + EFFECT_TR_KNIGHTSPIKE, + EFFECT_TR_VORESPIKE, + EFFECT_TR_NEHAHRASMOKE, + EFFECT_TR_NEXUIZPLASMA, + EFFECT_TR_GLOWTRAIL, + EFFECT_SVC_PARTICLE, + EFFECT_TOTAL +} +effectnameindex_t; + +int CL_ParticleEffectIndexForName(const char *name); +const char *CL_ParticleEffectNameForIndex(int i); +void CL_ParticleEffect(int effectindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor); +void CL_ParticleTrail(int effectindex, float pcount, const vec3_t originmins, const vec3_t originmaxs, const vec3_t velocitymins, const vec3_t velocitymaxs, entity_t *ent, int palettecolor, qboolean spawndlight, qboolean spawnparticles, float tintmins[4], float tintmaxs[4]); +void CL_ParseParticleEffect (void); +void CL_ParticleCube (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, vec_t gravity, vec_t randomvel); +void CL_ParticleRain (const vec3_t mins, const vec3_t maxs, const vec3_t dir, int count, int colorbase, int type); +void CL_EntityParticles (const entity_t *ent); +void CL_ParticleExplosion (const vec3_t org); +void CL_ParticleExplosion2 (const vec3_t org, int colorStart, int colorLength); +void R_NewExplosion(const vec3_t org); + +void Debug_PolygonBegin(const char *picname, int flags); +void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a); +void Debug_PolygonEnd(void); + +#include "cl_screen.h" + +extern qboolean sb_showscores; + +float RSurf_FogVertex(const vec3_t p); +float RSurf_FogPoint(const vec3_t p); + +typedef enum r_viewport_type_e +{ + R_VIEWPORTTYPE_ORTHO, + R_VIEWPORTTYPE_PERSPECTIVE, + R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP, + R_VIEWPORTTYPE_PERSPECTIVECUBESIDE, + R_VIEWPORTTYPE_TOTAL +} +r_viewport_type_t; + +typedef struct r_viewport_s +{ + matrix4x4_t cameramatrix; // from entity (transforms from camera entity to world) + matrix4x4_t viewmatrix; // actual matrix for rendering (transforms to viewspace) + matrix4x4_t projectmatrix; // actual projection matrix (transforms from viewspace to screen) + int x; + int y; + int z; + int width; + int height; + int depth; + r_viewport_type_t type; + float screentodepth[2]; // used by deferred renderer to calculate linear depth from device depth coordinates +} +r_viewport_t; + +typedef struct r_refdef_view_s +{ + // view information (changes multiple times per frame) + // if any of these variables change then r_refdef.viewcache must be regenerated + // by calling R_View_Update + // (which also updates viewport, scissor, colormask) + + // it is safe and expected to copy this into a structure on the stack and + // call the renderer recursively, then restore from the stack afterward + // (as long as R_View_Update is called) + + // eye position information + matrix4x4_t matrix, inverse_matrix; + vec3_t origin; + vec3_t forward; + vec3_t left; + vec3_t right; + vec3_t up; + int numfrustumplanes; + mplane_t frustum[6]; + qboolean useclipplane; + qboolean usecustompvs; // uses r_refdef.viewcache.pvsbits as-is rather than computing it + mplane_t clipplane; + float frustum_x, frustum_y; + vec3_t frustumcorner[4]; + // if turned off it renders an ortho view + int useperspective; + float ortho_x, ortho_y; + + // screen area to render in + int x; + int y; + int z; + int width; + int height; + int depth; + r_viewport_t viewport; // note: if r_viewscale is used, the viewport.width and viewport.height may be less than width and height + + // which color components to allow (for anaglyph glasses) + int colormask[4]; + + // global RGB color multiplier for rendering + float colorscale; + + // whether to call R_ClearScreen before rendering stuff + qboolean clear; + // if true, don't clear or do any post process effects (bloom, etc) + qboolean isoverlay; + // if true, this is the MAIN view (which is, after CSQC, copied into the scene for use e.g. by r_speeds 1, showtex, prydon cursor) + qboolean ismain; + + // whether to draw r_showtris and such, this is only true for the main + // view render, all secondary renders (mirrors, portals, cameras, + // distortion effects, etc) omit such debugging information + qboolean showdebug; + + // these define which values to use in GL_CullFace calls to request frontface or backface culling + int cullface_front; + int cullface_back; + + // render quality (0 to 1) - affects r_drawparticles_drawdistance and others + float quality; +} +r_refdef_view_t; + +typedef struct r_refdef_viewcache_s +{ + // updated by gl_main_newmap() + int maxentities; + int world_numclusters; + int world_numclusterbytes; + int world_numleafs; + int world_numsurfaces; + + // these properties are generated by R_View_Update() + + // which entities are currently visible for this viewpoint + // (the used range is 0...r_refdef.scene.numentities) + unsigned char *entityvisible; + + // flag arrays used for visibility checking on world model + // (all other entities have no per-surface/per-leaf visibility checks) + unsigned char *world_pvsbits; + unsigned char *world_leafvisible; + unsigned char *world_surfacevisible; + // if true, the view is currently in a leaf without pvs data + qboolean world_novis; +} +r_refdef_viewcache_t; + +// TODO: really think about which fields should go into scene and which one should stay in refdef [1/7/2008 Black] +// maybe also refactor some of the functions to support different setting sources (ie. fogenabled, etc.) for different scenes +typedef struct r_refdef_scene_s { + // whether to call S_ExtraUpdate during render to reduce sound chop + qboolean extraupdate; + + // (client gameworld) time for rendering time based effects + double time; + + // the world + entity_render_t *worldentity; + + // same as worldentity->model + dp_model_t *worldmodel; + + // renderable entities (excluding world) + entity_render_t **entities; + int numentities; + int maxentities; + + // field of temporary entities that is reset each (client) frame + entity_render_t *tempentities; + int numtempentities; + int maxtempentities; + qboolean expandtempentities; + + // renderable dynamic lights + rtlight_t *lights[MAX_DLIGHTS]; + rtlight_t templights[MAX_DLIGHTS]; + int numlights; + + // intensities for light styles right now, controls rtlights + float rtlightstylevalue[MAX_LIGHTSTYLES]; // float fraction of base light value + // 8.8bit fixed point intensities for light styles + // controls intensity lightmap layers + unsigned short lightstylevalue[MAX_LIGHTSTYLES]; // 8.8 fraction of base light value + + float ambient; + + qboolean rtworld; + qboolean rtworldshadows; + qboolean rtdlight; + qboolean rtdlightshadows; +} r_refdef_scene_t; + +typedef struct r_refdef_s +{ + // these fields define the basic rendering information for the world + // but not the view, which could change multiple times in one rendered + // frame (for example when rendering textures for certain effects) + + // these are set for water warping before + // frustum_x/frustum_y are calculated + float frustumscale_x, frustumscale_y; + + // current view settings (these get reset a few times during rendering because of water rendering, reflections, etc) + r_refdef_view_t view; + r_refdef_viewcache_t viewcache; + + // minimum visible distance (pixels closer than this disappear) + double nearclip; + // maximum visible distance (pixels further than this disappear in 16bpp modes, + // in 32bpp an infinite-farclip matrix is used instead) + double farclip; + + // fullscreen color blend + float viewblend[4]; + + r_refdef_scene_t scene; + + float fogplane[4]; + float fogplaneviewdist; + qboolean fogplaneviewabove; + float fogheightfade; + float fogcolor[3]; + float fogrange; + float fograngerecip; + float fogmasktabledistmultiplier; +#define FOGMASKTABLEWIDTH 1024 + float fogmasktable[FOGMASKTABLEWIDTH]; + float fogmasktable_start, fogmasktable_alpha, fogmasktable_range, fogmasktable_density; + float fog_density; + float fog_red; + float fog_green; + float fog_blue; + float fog_alpha; + float fog_start; + float fog_end; + float fog_height; + float fog_fadedepth; + qboolean fogenabled; + qboolean oldgl_fogenable; + + // new flexible texture height fog (overrides normal fog) + char fog_height_texturename[64]; // note: must be 64 for the sscanf code + unsigned char *fog_height_table1d; + unsigned char *fog_height_table2d; + int fog_height_tablesize; // enable + float fog_height_tablescale; + float fog_height_texcoordscale; + char fogheighttexturename[64]; // detects changes to active fog height texture + + int draw2dstage; // 0 = no, 1 = yes, other value = needs setting up again + + // true during envmap command capture + qboolean envmap; + + // brightness of world lightmaps and related lighting + // (often reduced when world rtlights are enabled) + float lightmapintensity; + // whether to draw world lights realtime, dlights realtime, and their shadows + float polygonfactor; + float polygonoffset; + float shadowpolygonfactor; + float shadowpolygonoffset; + + // how long R_RenderView took on the previous frame + double lastdrawscreentime; + + // rendering stats for r_speeds display + // (these are incremented in many places) + int stats[r_stat_count]; +} +r_refdef_t; + +extern r_refdef_t r_refdef; + +typedef enum waterlevel_e +{ + WATERLEVEL_NONE, + WATERLEVEL_WETFEET, + WATERLEVEL_SWIMMING, + WATERLEVEL_SUBMERGED +} +waterlevel_t; + +typedef struct cl_clientmovement_state_s +{ + // entity to be ignored for movement + struct prvm_edict_s *self; + // position + vec3_t origin; + vec3_t velocity; + // current bounding box (different if crouched vs standing) + vec3_t mins; + vec3_t maxs; + // currently on the ground + qboolean onground; + // currently crouching + qboolean crouched; + // what kind of water (SUPERCONTENTS_LAVA for instance) + int watertype; + // how deep + waterlevel_t waterlevel; + // weird hacks when jumping out of water + // (this is in seconds and counts down to 0) + float waterjumptime; + + // user command + usercmd_t cmd; +} +cl_clientmovement_state_t; +void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s); + +// warpzone prediction hack (CSQC builtin) +void CL_RotateMoves(const matrix4x4_t *m); + +void CL_NewFrameReceived(int num); +void CL_ParseEntityLump(char *entitystring); +void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius); +void CL_RelinkLightFlashes(void); +void Sbar_ShowFPS(void); +void Sbar_ShowFPS_Update(void); +void Host_SaveConfig(void); +void Host_LoadConfig_f(void); +void CL_UpdateMoveVars(void); +void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length); +void V_DriftPitch(void); +void V_FadeViewFlashs(void); +void V_CalcViewBlend(void); +void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump, float clstatsviewheight, qboolean cldead, qboolean clintermission, const vec3_t clvelocity); +void V_CalcRefdef(void); +void CL_Locs_Reload_f(void); + +#endif + diff --git a/app/jni/clprogdefs.h b/app/jni/clprogdefs.h new file mode 100644 index 0000000..bee62ab --- /dev/null +++ b/app/jni/clprogdefs.h @@ -0,0 +1,98 @@ +/* file generated by qcc, do not modify */ + + +#ifndef CLPROGDEFS_H +#define CLPROGDEFS_H + +/* +typedef struct cl_globalvars_s +{ + int pad[28]; + int self; + int other; + int world; + float time; + float frametime; + float player_localentnum; + float player_localnum; + float maxclients; + float clientcommandframe; + float servercommandframe; + string_t mapname; + 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; + func_t CSQC_Init; + func_t CSQC_Shutdown; + func_t CSQC_InputEvent; + func_t CSQC_UpdateView; + func_t CSQC_ConsoleCommand; + vec3_t pmove_org; + vec3_t pmove_vel; + vec3_t pmove_mins; + vec3_t pmove_maxs; + float input_timelength; + vec3_t input_angles; + vec3_t input_movevalues; + float input_buttons; + float movevar_gravity; + float movevar_stopspeed; + float movevar_maxspeed; + float movevar_spectatormaxspeed; + float movevar_accelerate; + float movevar_airaccelerate; + float movevar_wateraccelerate; + float movevar_friction; + float movevar_waterfriction; + float movevar_entgravity; +} cl_globalvars_t; + +typedef struct cl_entvars_s +{ + float modelindex; + vec3_t absmin; + vec3_t absmax; + float entnum; + float drawmask; + func_t predraw; + float movetype; + float solid; + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t angles; + vec3_t avelocity; + 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 chain; + string_t netname; + int enemy; + float flags; + float colormap; + int owner; +} cl_entvars_t; + +#define CL_PROGHEADER_CRC 52195 +*/ + +#endif diff --git a/app/jni/clvm_cmds.c b/app/jni/clvm_cmds.c new file mode 100644 index 0000000..6ca2749 --- /dev/null +++ b/app/jni/clvm_cmds.c @@ -0,0 +1,5007 @@ +#include "quakedef.h" + +#include "prvm_cmds.h" +#include "csprogs.h" +#include "cl_collision.h" +#include "r_shadow.h" +#include "jpeg.h" +#include "image.h" + +//============================================================================ +// Client +//[515]: unsolved PROBLEMS +//- finish player physics code (cs_runplayerphysics) +//- EntWasFreed ? +//- RF_DEPTHHACK is not like it should be +//- add builtin that sets cl.viewangles instead of reading "input_angles" global +//- finish lines support for R_Polygon*** +//- insert selecttraceline into traceline somehow + +//4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh) +//4 feature darkplaces csqc: add builtins to clientside qc for gl calls + +extern cvar_t v_flipped; +extern cvar_t r_equalize_entities_fullbright; + +r_refdef_view_t csqc_original_r_refdef_view; +r_refdef_view_t csqc_main_r_refdef_view; + +// #1 void(vector ang) makevectors +static void VM_CL_makevectors (prvm_prog_t *prog) +{ + vec3_t angles, forward, right, up; + VM_SAFEPARMCOUNT(1, VM_CL_makevectors); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), angles); + AngleVectors(angles, forward, right, up); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorCopy(right, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); +} + +// #2 void(entity e, vector o) setorigin +static void VM_CL_setorigin (prvm_prog_t *prog) +{ + prvm_edict_t *e; + prvm_vec_t *org; + VM_SAFEPARMCOUNT(2, VM_CL_setorigin); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setorigin: can not modify world entity\n"); + return; + } + if (e->priv.required->free) + { + VM_Warning(prog, "setorigin: can not modify free entity\n"); + return; + } + org = PRVM_G_VECTOR(OFS_PARM1); + VectorCopy (org, PRVM_clientedictvector(e, origin)); + if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN) + e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT; + CL_LinkEdict(e); +} + +static void SetMinMaxSizePRVM (prvm_prog_t *prog, prvm_edict_t *e, prvm_vec_t *min, prvm_vec_t *max) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (min[i] > max[i]) + prog->error_cmd("SetMinMaxSize: backwards mins/maxs"); + + // set derived values + VectorCopy (min, PRVM_clientedictvector(e, mins)); + VectorCopy (max, PRVM_clientedictvector(e, maxs)); + VectorSubtract (max, min, PRVM_clientedictvector(e, size)); + + CL_LinkEdict (e); +} + +static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, const vec_t *min, const vec_t *max) +{ + prvm_vec3_t mins, maxs; + VectorCopy(min, mins); + VectorCopy(max, maxs); + SetMinMaxSizePRVM(prog, e, mins, maxs); +} + +// #3 void(entity e, string m) setmodel +static void VM_CL_setmodel (prvm_prog_t *prog) +{ + prvm_edict_t *e; + const char *m; + dp_model_t *mod; + int i; + + VM_SAFEPARMCOUNT(2, VM_CL_setmodel); + + e = PRVM_G_EDICT(OFS_PARM0); + PRVM_clientedictfloat(e, modelindex) = 0; + PRVM_clientedictstring(e, model) = 0; + + m = PRVM_G_STRING(OFS_PARM1); + mod = NULL; + for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++) + { + if (!strcmp(cl.csqc_model_precache[i]->name, m)) + { + mod = cl.csqc_model_precache[i]; + PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name); + PRVM_clientedictfloat(e, modelindex) = -(i+1); + break; + } + } + + if( !mod ) { + for (i = 0;i < MAX_MODELS;i++) + { + mod = cl.model_precache[i]; + if (mod && !strcmp(mod->name, m)) + { + PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name); + PRVM_clientedictfloat(e, modelindex) = i; + break; + } + } + } + + if( mod ) { + // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black] + // LordHavoc: erm you broke it by commenting this out - setmodel must do setsize or else the qc can't find out the model size, and ssqc does this by necessity, consistency. + SetMinMaxSize (prog, e, mod->normalmins, mod->normalmaxs); + } + else + { + SetMinMaxSize (prog, e, vec3_origin, vec3_origin); + VM_Warning(prog, "setmodel: model '%s' not precached\n", m); + } +} + +// #4 void(entity e, vector min, vector max) setsize +static void VM_CL_setsize (prvm_prog_t *prog) +{ + prvm_edict_t *e; + vec3_t mins, maxs; + VM_SAFEPARMCOUNT(3, VM_CL_setsize); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setsize: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setsize: can not modify free entity\n"); + return; + } + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs); + + SetMinMaxSize( prog, e, mins, maxs ); + + CL_LinkEdict(e); +} + +// #8 void(entity e, float chan, string samp, float volume, float atten[, float pitchchange[, float flags]]) sound +static void VM_CL_sound (prvm_prog_t *prog) +{ + const char *sample; + int channel; + prvm_edict_t *entity; + float volume; + float attenuation; + float pitchchange; + float startposition; + int flags; + vec3_t org; + + VM_SAFEPARMCOUNTRANGE(5, 7, VM_CL_sound); + + entity = PRVM_G_EDICT(OFS_PARM0); + channel = (int)PRVM_G_FLOAT(OFS_PARM1); + sample = PRVM_G_STRING(OFS_PARM2); + volume = PRVM_G_FLOAT(OFS_PARM3); + attenuation = PRVM_G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 1) + { + VM_Warning(prog, "VM_CL_sound: volume must be in range 0-1\n"); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + VM_Warning(prog, "VM_CL_sound: attenuation must be in range 0-4\n"); + return; + } + + if (prog->argc < 6) + pitchchange = 0; + else + pitchchange = PRVM_G_FLOAT(OFS_PARM5); + + if (prog->argc < 7) + flags = 0; + else + { + // LordHavoc: we only let the qc set certain flags, others are off-limits + flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED); + } + + // sound_starttime exists instead of sound_startposition because in a + // networking sense you might not know when something is being received, + // so making sounds match up in sync would be impossible if relative + // position was sent + if (PRVM_clientglobalfloat(sound_starttime)) + startposition = cl.time - PRVM_clientglobalfloat(sound_starttime); + else + startposition = 0; + + channel = CHAN_USER2ENGINE(channel); + + if (!IS_CHAN(channel)) + { + VM_Warning(prog, "VM_CL_sound: channel must be in range 0-127\n"); + return; + } + + CL_VM_GetEntitySoundOrigin(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), org); + S_StartSound_StartPosition_Flags(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), org, volume, attenuation, startposition, flags, pitchchange > 0.0f ? pitchchange * 0.01f : 1.0f); +} + +// #483 void(vector origin, string sample, float volume, float attenuation) pointsound +static void VM_CL_pointsound(prvm_prog_t *prog) +{ + const char *sample; + float volume; + float attenuation; + vec3_t org; + + VM_SAFEPARMCOUNT(4, VM_CL_pointsound); + + VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org); + sample = PRVM_G_STRING(OFS_PARM1); + volume = PRVM_G_FLOAT(OFS_PARM2); + attenuation = PRVM_G_FLOAT(OFS_PARM3); + + if (volume < 0 || volume > 1) + { + VM_Warning(prog, "VM_CL_pointsound: volume must be in range 0-1\n"); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + VM_Warning(prog, "VM_CL_pointsound: attenuation must be in range 0-4\n"); + return; + } + + // Send World Entity as Entity to Play Sound (for CSQC, that is MAX_EDICTS) + S_StartSound(MAX_EDICTS, 0, S_FindName(sample), org, volume, attenuation); +} + +// #14 entity() spawn +static void VM_CL_spawn (prvm_prog_t *prog) +{ + prvm_edict_t *ed; + ed = PRVM_ED_Alloc(prog); + VM_RETURN_EDICT(ed); +} + +static void CL_VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace, int svent) +{ + VM_SetTraceGlobals(prog, trace); + PRVM_clientglobalfloat(trace_networkentity) = svent; +} + +#define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY) +#define CL_HitNetworkPlayers(move) !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS) + +// #16 void(vector v1, vector v2, float movetype, entity ignore) traceline +static void VM_CL_traceline (prvm_prog_t *prog) +{ + vec3_t v1, v2; + trace_t trace; + int move, svent; + prvm_edict_t *ent; + +// R_TimeReport("pretraceline"); + + VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline); + + prog->xfunction->builtinsprofile += 30; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2); + move = (int)PRVM_G_FLOAT(OFS_PARM2); + ent = PRVM_G_EDICT(OFS_PARM3); + + if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2])) + prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); + + trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false); + + CL_VM_SetTraceGlobals(prog, &trace, svent); +// R_TimeReport("traceline"); +} + +/* +================= +VM_CL_tracebox + +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. + +tracebox (vector1, vector mins, vector maxs, vector2, tryents) +================= +*/ +// LordHavoc: added this for my own use, VERY useful, similar to traceline +static void VM_CL_tracebox (prvm_prog_t *prog) +{ + vec3_t v1, v2, m1, m2; + trace_t trace; + int move, svent; + prvm_edict_t *ent; + +// R_TimeReport("pretracebox"); + VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion + + prog->xfunction->builtinsprofile += 30; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2); + move = (int)PRVM_G_FLOAT(OFS_PARM4); + ent = PRVM_G_EDICT(OFS_PARM5); + + if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2])) + prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); + + trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true); + + CL_VM_SetTraceGlobals(prog, &trace, svent); +// R_TimeReport("tracebox"); +} + +static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent) +{ + int i; + float gravity; + vec3_t start, end, mins, maxs, move; + vec3_t original_origin; + vec3_t original_velocity; + vec3_t original_angles; + vec3_t original_avelocity; + trace_t trace; + + VectorCopy(PRVM_clientedictvector(tossent, origin) , original_origin ); + VectorCopy(PRVM_clientedictvector(tossent, velocity) , original_velocity ); + VectorCopy(PRVM_clientedictvector(tossent, angles) , original_angles ); + VectorCopy(PRVM_clientedictvector(tossent, avelocity), original_avelocity); + + gravity = PRVM_clientedictfloat(tossent, gravity); + if (!gravity) + gravity = 1.0f; + gravity *= cl.movevars_gravity * 0.05; + + for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds + { + PRVM_clientedictvector(tossent, velocity)[2] -= gravity; + VectorMA (PRVM_clientedictvector(tossent, angles), 0.05, PRVM_clientedictvector(tossent, avelocity), PRVM_clientedictvector(tossent, angles)); + VectorScale (PRVM_clientedictvector(tossent, velocity), 0.05, move); + VectorAdd (PRVM_clientedictvector(tossent, origin), move, end); + VectorCopy(PRVM_clientedictvector(tossent, origin), start); + VectorCopy(PRVM_clientedictvector(tossent, mins), mins); + VectorCopy(PRVM_clientedictvector(tossent, maxs), maxs); + trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true); + VectorCopy (trace.endpos, PRVM_clientedictvector(tossent, origin)); + + if (trace.fraction < 1) + break; + } + + VectorCopy(original_origin , PRVM_clientedictvector(tossent, origin) ); + VectorCopy(original_velocity , PRVM_clientedictvector(tossent, velocity) ); + VectorCopy(original_angles , PRVM_clientedictvector(tossent, angles) ); + VectorCopy(original_avelocity, PRVM_clientedictvector(tossent, avelocity)); + + return trace; +} + +static void VM_CL_tracetoss (prvm_prog_t *prog) +{ + trace_t trace; + prvm_edict_t *ent; + prvm_edict_t *ignore; + int svent = 0; + + prog->xfunction->builtinsprofile += 600; + + VM_SAFEPARMCOUNT(2, VM_CL_tracetoss); + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning(prog, "tracetoss: can not use world entity\n"); + return; + } + ignore = PRVM_G_EDICT(OFS_PARM1); + + trace = CL_Trace_Toss (prog, ent, ignore, &svent); + + CL_VM_SetTraceGlobals(prog, &trace, svent); +} + + +// #20 void(string s) precache_model +static void VM_CL_precache_model (prvm_prog_t *prog) +{ + const char *name; + int i; + dp_model_t *m; + + VM_SAFEPARMCOUNT(1, VM_CL_precache_model); + + name = PRVM_G_STRING(OFS_PARM0); + for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++) + { + if(!strcmp(cl.csqc_model_precache[i]->name, name)) + { + PRVM_G_FLOAT(OFS_RETURN) = -(i+1); + return; + } + } + PRVM_G_FLOAT(OFS_RETURN) = 0; + m = Mod_ForName(name, false, false, name[0] == '*' ? cl.model_name[1] : NULL); + if(m && m->loaded) + { + for (i = 0;i < MAX_MODELS;i++) + { + if (!cl.csqc_model_precache[i]) + { + cl.csqc_model_precache[i] = (dp_model_t*)m; + PRVM_G_FLOAT(OFS_RETURN) = -(i+1); + return; + } + } + VM_Warning(prog, "VM_CL_precache_model: no free models\n"); + return; + } + VM_Warning(prog, "VM_CL_precache_model: model \"%s\" not found\n", name); +} + +// #22 entity(vector org, float rad) findradius +static void VM_CL_findradius (prvm_prog_t *prog) +{ + prvm_edict_t *ent, *chain; + vec_t radius, radius2; + vec3_t org, eorg, mins, maxs; + int i, numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + int chainfield; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_findradius); + + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if(chainfield < 0) + prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name); + + chain = (prvm_edict_t *)prog->edicts; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + radius = PRVM_G_FLOAT(OFS_PARM1); + radius2 = radius * radius; + + mins[0] = org[0] - (radius + 1); + mins[1] = org[1] - (radius + 1); + mins[2] = org[2] - (radius + 1); + maxs[0] = org[0] + (radius + 1); + maxs[1] = org[1] + (radius + 1); + maxs[2] = org[2] + (radius + 1); + numtouchedicts = World_EntitiesInBox(&cl.world, mins, maxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens //[515]: for what then ? + Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + ent = touchedicts[i]; + // Quake did not return non-solid entities but darkplaces does + // (note: this is the reason you can't blow up fallen zombies) + if (PRVM_clientedictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer) + continue; + // LordHavoc: compare against bounding box rather than center so it + // doesn't miss large objects, and use DotProduct instead of Length + // for a major speedup + VectorSubtract(org, PRVM_clientedictvector(ent, origin), eorg); + if (sv_gameplayfix_findradiusdistancetobox.integer) + { + eorg[0] -= bound(PRVM_clientedictvector(ent, mins)[0], eorg[0], PRVM_clientedictvector(ent, maxs)[0]); + eorg[1] -= bound(PRVM_clientedictvector(ent, mins)[1], eorg[1], PRVM_clientedictvector(ent, maxs)[1]); + eorg[2] -= bound(PRVM_clientedictvector(ent, mins)[2], eorg[2], PRVM_clientedictvector(ent, maxs)[2]); + } + else + VectorMAMAM(1, eorg, -0.5f, PRVM_clientedictvector(ent, mins), -0.5f, PRVM_clientedictvector(ent, maxs), eorg); + if (DotProduct(eorg, eorg) < radius2) + { + PRVM_EDICTFIELDEDICT(ent, chainfield) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + } + + VM_RETURN_EDICT(chain); +} + +// #34 float() droptofloor +static void VM_CL_droptofloor (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + vec3_t start, end, mins, maxs; + trace_t trace; + + VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "droptofloor: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "droptofloor: can not modify free entity\n"); + return; + } + + VectorCopy(PRVM_clientedictvector(ent, origin), start); + VectorCopy(PRVM_clientedictvector(ent, mins), mins); + VectorCopy(PRVM_clientedictvector(ent, maxs), maxs); + VectorCopy(PRVM_clientedictvector(ent, origin), end); + end[2] -= 256; + + trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true); + + if (trace.fraction != 1) + { + VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin)); + PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) | FL_ONGROUND; + PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_G_FLOAT(OFS_RETURN) = 1; + // if support is destroyed, keep suspended (gross hack for floating items in various maps) +// ent->priv.server->suspendedinairflag = true; + } +} + +// #35 void(float style, string value) lightstyle +static void VM_CL_lightstyle (prvm_prog_t *prog) +{ + int i; + const char *c; + + VM_SAFEPARMCOUNT(2, VM_CL_lightstyle); + + i = (int)PRVM_G_FLOAT(OFS_PARM0); + c = PRVM_G_STRING(OFS_PARM1); + if (i >= cl.max_lightstyle) + { + VM_Warning(prog, "VM_CL_lightstyle >= MAX_LIGHTSTYLES\n"); + return; + } + strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map)); + cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0; + cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map); +} + +// #40 float(entity e) checkbottom +static void VM_CL_checkbottom (prvm_prog_t *prog) +{ + static int cs_yes, cs_no; + prvm_edict_t *ent; + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VM_SAFEPARMCOUNT(1, VM_CL_checkbottom); + ent = PRVM_G_EDICT(OFS_PARM0); + PRVM_G_FLOAT(OFS_RETURN) = 0; + + VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins); + VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, 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 (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY))) + goto realcheck; + } + + cs_yes++; + PRVM_G_FLOAT(OFS_RETURN) = true; + return; // we got out easy + +realcheck: + cs_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*sv_stepheight.value; + trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false); + + if (trace.fraction == 1.0) + return; + + 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 = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value) + return; + } + + cs_yes++; + PRVM_G_FLOAT(OFS_RETURN) = true; +} + +// #41 float(vector v) pointcontents +static void VM_CL_pointcontents (prvm_prog_t *prog) +{ + vec3_t point; + VM_SAFEPARMCOUNT(1, VM_CL_pointcontents); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point); + PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(point)); +} + +// #48 void(vector o, vector d, float color, float count) particle +static void VM_CL_particle (prvm_prog_t *prog) +{ + vec3_t org, dir; + int count; + unsigned char color; + VM_SAFEPARMCOUNT(4, VM_CL_particle); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir); + color = (int)PRVM_G_FLOAT(OFS_PARM2); + count = (int)PRVM_G_FLOAT(OFS_PARM3); + CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color); +} + +// #74 void(vector pos, string samp, float vol, float atten) ambientsound +static void VM_CL_ambientsound (prvm_prog_t *prog) +{ + vec3_t f; + sfx_t *s; + VM_SAFEPARMCOUNT(4, VM_CL_ambientsound); + s = S_FindName(PRVM_G_STRING(OFS_PARM0)); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f); + S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64); +} + +// #92 vector(vector org[, float lpflag]) getlight (DP_QC_GETLIGHT) +static void VM_CL_getlight (prvm_prog_t *prog) +{ + vec3_t ambientcolor, diffusecolor, diffusenormal; + vec3_t p; + + VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getlight); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p); + VectorClear(ambientcolor); + VectorClear(diffusecolor); + VectorClear(diffusenormal); + if (prog->argc >= 2) + R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, PRVM_G_FLOAT(OFS_PARM1)); + else if (cl.worldmodel && cl.worldmodel->brush.LightPoint) + cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal); + VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN)); + if (PRVM_clientglobalvector(getlight_ambient)) + VectorCopy(ambientcolor, PRVM_clientglobalvector(getlight_ambient)); + if (PRVM_clientglobalvector(getlight_diffuse)) + VectorCopy(diffusecolor, PRVM_clientglobalvector(getlight_diffuse)); + if (PRVM_clientglobalvector(getlight_dir)) + VectorCopy(diffusenormal, PRVM_clientglobalvector(getlight_dir)); +} + +//============================================================================ +//[515]: SCENE MANAGER builtins + +void CSQC_R_RecalcView (void) +{ + extern matrix4x4_t viewmodelmatrix_nobob; + extern matrix4x4_t viewmodelmatrix_withbob; + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1); + Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix); + Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value); + Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine); +} + +//#300 void() clearscene (EXT_CSQC) +static void VM_CL_R_ClearScene (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene); + // clear renderable entity and light lists + r_refdef.scene.numentities = 0; + r_refdef.scene.numlights = 0; + // restore the view settings to the values that VM_CL_UpdateView received from the client code + r_refdef.view = csqc_original_r_refdef_view; + VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); + VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); + cl.csqc_vidvars.drawworld = r_drawworld.integer != 0; + cl.csqc_vidvars.drawenginesbar = false; + cl.csqc_vidvars.drawcrosshair = false; + CSQC_R_RecalcView(); +} + +//#301 void(float mask) addentities (EXT_CSQC) +static void VM_CL_R_AddEntities (prvm_prog_t *prog) +{ + double t = Sys_DirtyTime(); + int i, drawmask; + prvm_edict_t *ed; + VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities); + drawmask = (int)PRVM_G_FLOAT(OFS_PARM0); + CSQC_RelinkAllEntities(drawmask); + CL_RelinkLightFlashes(); + + PRVM_clientglobalfloat(time) = cl.time; + for(i=1;inum_edicts;i++) + { + // so we can easily check if CSQC entity #edictnum is currently drawn + cl.csqcrenderentities[i].entitynumber = 0; + ed = &prog->edicts[i]; + if(ed->priv.required->free) + continue; + CSQC_Think(ed); + if(ed->priv.required->free) + continue; + // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict + CSQC_Predraw(ed); + if(ed->priv.required->free) + continue; + if(!((int)PRVM_clientedictfloat(ed, drawmask) & drawmask)) + continue; + CSQC_AddRenderEdict(ed, i); + } + + // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView + t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0; + prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t; +} + +//#302 void(entity ent) addentity (EXT_CSQC) +static void VM_CL_R_AddEntity (prvm_prog_t *prog) +{ + double t = Sys_DirtyTime(); + VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity); + CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0), 0); + t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0; + prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t; +} + +//#303 float(float property, ...) setproperty (EXT_CSQC) +//#303 float(float property) getproperty +//#303 vector(float property) getpropertyvec +//#309 float(float property) getproperty +//#309 vector(float property) getpropertyvec +// VorteX: make this function be able to return previously set property if new value is not given +static void VM_CL_R_SetView (prvm_prog_t *prog) +{ + int c; + prvm_vec_t *f; + float k; + + VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_R_SetView); + + c = (int)PRVM_G_FLOAT(OFS_PARM0); + + // return value? + if (prog->argc < 2) + { + switch(c) + { + case VF_MIN: + VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x, r_refdef.view.y, 0); + break; + case VF_MIN_X: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.x; + break; + case VF_MIN_Y: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.y; + break; + case VF_SIZE: + VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.width, r_refdef.view.height, 0); + break; + case VF_SIZE_X: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.width; + break; + case VF_SIZE_Y: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.height; + break; + case VF_VIEWPORT: + VM_Warning(prog, "VM_CL_R_GetView : VF_VIEWPORT can't be retrieved, use VF_MIN/VF_SIZE instead\n"); + break; + case VF_FOV: + VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.ortho_x, r_refdef.view.ortho_y, 0); + break; + case VF_FOVX: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_x; + break; + case VF_FOVY: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y; + break; + case VF_ORIGIN: + VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN)); + break; + case VF_ORIGIN_X: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0]; + break; + case VF_ORIGIN_Y: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1]; + break; + case VF_ORIGIN_Z: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2]; + break; + case VF_ANGLES: + VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN)); + break; + case VF_ANGLES_X: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0]; + break; + case VF_ANGLES_Y: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1]; + break; + case VF_ANGLES_Z: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2]; + break; + case VF_DRAWWORLD: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld; + break; + case VF_DRAWENGINESBAR: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawenginesbar; + break; + case VF_DRAWCROSSHAIR: + PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawcrosshair; + break; + case VF_CL_VIEWANGLES: + VectorCopy(cl.viewangles, PRVM_G_VECTOR(OFS_RETURN));; + break; + case VF_CL_VIEWANGLES_X: + PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[0]; + break; + case VF_CL_VIEWANGLES_Y: + PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[1]; + break; + case VF_CL_VIEWANGLES_Z: + PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[2]; + break; + case VF_PERSPECTIVE: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.useperspective; + break; + case VF_CLEARSCREEN: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.isoverlay; + break; + case VF_MAINVIEW: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain; + break; + case VF_FOG_DENSITY: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_density; + break; + case VF_FOG_COLOR: + PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red; + PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green; + PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue; + break; + case VF_FOG_COLOR_R: + PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red; + break; + case VF_FOG_COLOR_G: + PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green; + break; + case VF_FOG_COLOR_B: + PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue; + break; + case VF_FOG_ALPHA: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_alpha; + break; + case VF_FOG_START: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_start; + break; + case VF_FOG_END: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_end; + break; + case VF_FOG_HEIGHT: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_height; + break; + case VF_FOG_FADEDEPTH: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_fadedepth; + break; + case VF_MINFPS_QUALITY: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.quality; + break; + default: + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_CL_R_GetView : unknown parm %i\n", c); + return; + } + return; + } + + f = PRVM_G_VECTOR(OFS_PARM1); + k = PRVM_G_FLOAT(OFS_PARM1); + switch(c) + { + case VF_MIN: + r_refdef.view.x = (int)(f[0]); + r_refdef.view.y = (int)(f[1]); + DrawQ_RecalcView(); + break; + case VF_MIN_X: + r_refdef.view.x = (int)(k); + DrawQ_RecalcView(); + break; + case VF_MIN_Y: + r_refdef.view.y = (int)(k); + DrawQ_RecalcView(); + break; + case VF_SIZE: + r_refdef.view.width = (int)(f[0]); + r_refdef.view.height = (int)(f[1]); + DrawQ_RecalcView(); + break; + case VF_SIZE_X: + r_refdef.view.width = (int)(k); + DrawQ_RecalcView(); + break; + case VF_SIZE_Y: + r_refdef.view.height = (int)(k); + DrawQ_RecalcView(); + break; + case VF_VIEWPORT: + r_refdef.view.x = (int)(f[0]); + r_refdef.view.y = (int)(f[1]); + f = PRVM_G_VECTOR(OFS_PARM2); + r_refdef.view.width = (int)(f[0]); + r_refdef.view.height = (int)(f[1]); + DrawQ_RecalcView(); + break; + case VF_FOV: + r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0]; + r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1]; + break; + case VF_FOVX: + r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k; + break; + case VF_FOVY: + r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k; + break; + case VF_ORIGIN: + VectorCopy(f, cl.csqc_vieworigin); + CSQC_R_RecalcView(); + break; + case VF_ORIGIN_X: + cl.csqc_vieworigin[0] = k; + CSQC_R_RecalcView(); + break; + case VF_ORIGIN_Y: + cl.csqc_vieworigin[1] = k; + CSQC_R_RecalcView(); + break; + case VF_ORIGIN_Z: + cl.csqc_vieworigin[2] = k; + CSQC_R_RecalcView(); + break; + case VF_ANGLES: + VectorCopy(f, cl.csqc_viewangles); + CSQC_R_RecalcView(); + break; + case VF_ANGLES_X: + cl.csqc_viewangles[0] = k; + CSQC_R_RecalcView(); + break; + case VF_ANGLES_Y: + cl.csqc_viewangles[1] = k; + CSQC_R_RecalcView(); + break; + case VF_ANGLES_Z: + cl.csqc_viewangles[2] = k; + CSQC_R_RecalcView(); + break; + case VF_DRAWWORLD: + cl.csqc_vidvars.drawworld = ((k != 0) && r_drawworld.integer); + break; + case VF_DRAWENGINESBAR: + cl.csqc_vidvars.drawenginesbar = k != 0; + break; + case VF_DRAWCROSSHAIR: + cl.csqc_vidvars.drawcrosshair = k != 0; + break; + case VF_CL_VIEWANGLES: + VectorCopy(f, cl.viewangles); + break; + case VF_CL_VIEWANGLES_X: + cl.viewangles[0] = k; + break; + case VF_CL_VIEWANGLES_Y: + cl.viewangles[1] = k; + break; + case VF_CL_VIEWANGLES_Z: + cl.viewangles[2] = k; + break; + case VF_PERSPECTIVE: + r_refdef.view.useperspective = k != 0; + break; + case VF_CLEARSCREEN: + r_refdef.view.isoverlay = !k; + break; + case VF_MAINVIEW: + PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain; + break; + case VF_FOG_DENSITY: + r_refdef.fog_density = k; + break; + case VF_FOG_COLOR: + r_refdef.fog_red = f[0]; + r_refdef.fog_green = f[1]; + r_refdef.fog_blue = f[2]; + break; + case VF_FOG_COLOR_R: + r_refdef.fog_red = k; + break; + case VF_FOG_COLOR_G: + r_refdef.fog_green = k; + break; + case VF_FOG_COLOR_B: + r_refdef.fog_blue = k; + break; + case VF_FOG_ALPHA: + r_refdef.fog_alpha = k; + break; + case VF_FOG_START: + r_refdef.fog_start = k; + break; + case VF_FOG_END: + r_refdef.fog_end = k; + break; + case VF_FOG_HEIGHT: + r_refdef.fog_height = k; + break; + case VF_FOG_FADEDEPTH: + r_refdef.fog_fadedepth = k; + break; + case VF_MINFPS_QUALITY: + r_refdef.view.quality = k; + break; + default: + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_CL_R_SetView : unknown parm %i\n", c); + return; + } + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +//#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC) +static void VM_CL_R_AddDynamicLight (prvm_prog_t *prog) +{ + double t = Sys_DirtyTime(); + vec3_t org; + float radius = 300; + vec3_t col; + int style = -1; + const char *cubemapname = NULL; + int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC; + float coronaintensity = 1; + float coronasizescale = 0.25; + qboolean castshadow = true; + float ambientscale = 0; + float diffusescale = 1; + float specularscale = 1; + matrix4x4_t matrix; + vec3_t forward, left, up; + VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); + + // if we've run out of dlights, just return + if (r_refdef.scene.numlights >= MAX_DLIGHTS) + return; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + radius = PRVM_G_FLOAT(OFS_PARM1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), col); + if (prog->argc >= 4) + { + style = (int)PRVM_G_FLOAT(OFS_PARM3); + if (style >= MAX_LIGHTSTYLES) + { + Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style); + style = -1; + } + } + if (prog->argc >= 5) + cubemapname = PRVM_G_STRING(OFS_PARM4); + if (prog->argc >= 6) + pflags = (int)PRVM_G_FLOAT(OFS_PARM5); + coronaintensity = (pflags & PFLAGS_CORONA) != 0; + castshadow = (pflags & PFLAGS_NOSHADOW) == 0; + + VectorScale(PRVM_clientglobalvector(v_forward), radius, forward); + VectorScale(PRVM_clientglobalvector(v_right), -radius, left); + VectorScale(PRVM_clientglobalvector(v_up), radius, up); + Matrix4x4_FromVectors(&matrix, forward, left, up, org); + + R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++; + t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0; + prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t; +} + +//============================================================================ + +//#310 vector (vector v) cs_unproject (EXT_CSQC) +static void VM_CL_unproject (prvm_prog_t *prog) +{ + vec3_t f; + vec3_t temp; + vec3_t result; + + VM_SAFEPARMCOUNT(1, VM_CL_unproject); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f); + VectorSet(temp, + f[2], + (-1.0 + 2.0 * (f[0] / vid_conwidth.integer)) * f[2] * -r_refdef.view.frustum_x, + (-1.0 + 2.0 * (f[1] / vid_conheight.integer)) * f[2] * -r_refdef.view.frustum_y); + if(v_flipped.integer) + temp[1] = -temp[1]; + Matrix4x4_Transform(&r_refdef.view.matrix, temp, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); +} + +//#311 vector (vector v) cs_project (EXT_CSQC) +static void VM_CL_project (prvm_prog_t *prog) +{ + vec3_t f; + vec3_t v; + matrix4x4_t m; + + VM_SAFEPARMCOUNT(1, VM_CL_project); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f); + Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix); + Matrix4x4_Transform(&m, f, v); + if(v_flipped.integer) + v[1] = -v[1]; + VectorSet(PRVM_G_VECTOR(OFS_RETURN), + vid_conwidth.integer * (0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)), + vid_conheight.integer * (0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)), + v[0]); + // explanation: + // after transforming, relative position to viewport (0..1) = 0.5 * (1 + v[2]/v[0]/-frustum_{x \or y}) + // as 2D drawing honors the viewport too, to get the same pixel, we simply multiply this by conwidth/height +} + +//#330 float(float stnum) getstatf (EXT_CSQC) +static void VM_CL_getstatf (prvm_prog_t *prog) +{ + int i; + union + { + float f; + int l; + }dat; + VM_SAFEPARMCOUNT(1, VM_CL_getstatf); + i = (int)PRVM_G_FLOAT(OFS_PARM0); + if(i < 0 || i >= MAX_CL_STATS) + { + VM_Warning(prog, "VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n"); + return; + } + dat.l = cl.stats[i]; + PRVM_G_FLOAT(OFS_RETURN) = dat.f; +} + +//#331 float(float stnum) getstati (EXT_CSQC) +static void VM_CL_getstati (prvm_prog_t *prog) +{ + int i, index; + int firstbit, bitcount; + + VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati); + + index = (int)PRVM_G_FLOAT(OFS_PARM0); + if (prog->argc > 1) + { + firstbit = (int)PRVM_G_FLOAT(OFS_PARM1); + if (prog->argc > 2) + bitcount = (int)PRVM_G_FLOAT(OFS_PARM2); + else + bitcount = 1; + } + else + { + firstbit = 0; + bitcount = 32; + } + + if(index < 0 || index >= MAX_CL_STATS) + { + VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n"); + return; + } + i = cl.stats[index]; + if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from. + i = (((unsigned int)i)&(((1<>firstbit; + PRVM_G_FLOAT(OFS_RETURN) = i; +} + +//#332 string(float firststnum) getstats (EXT_CSQC) +static void VM_CL_getstats (prvm_prog_t *prog) +{ + int i; + char t[17]; + VM_SAFEPARMCOUNT(1, VM_CL_getstats); + i = (int)PRVM_G_FLOAT(OFS_PARM0); + if(i < 0 || i > MAX_CL_STATS-4) + { + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + VM_Warning(prog, "VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n"); + return; + } + strlcpy(t, (char*)&cl.stats[i], sizeof(t)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t); +} + +//#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) +static void VM_CL_setmodelindex (prvm_prog_t *prog) +{ + int i; + prvm_edict_t *t; + struct model_s *model; + + VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex); + + t = PRVM_G_EDICT(OFS_PARM0); + + i = (int)PRVM_G_FLOAT(OFS_PARM1); + + PRVM_clientedictstring(t, model) = 0; + PRVM_clientedictfloat(t, modelindex) = 0; + + if (!i) + return; + + model = CL_GetModelByIndex(i); + if (!model) + { + VM_Warning(prog, "VM_CL_setmodelindex: null model\n"); + return; + } + PRVM_clientedictstring(t, model) = PRVM_SetEngineString(prog, model->name); + PRVM_clientedictfloat(t, modelindex) = i; + + // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black] + if (model) + { + SetMinMaxSize (prog, t, model->normalmins, model->normalmaxs); + } + else + SetMinMaxSize (prog, t, vec3_origin, vec3_origin); +} + +//#334 string(float mdlindex) modelnameforindex (EXT_CSQC) +static void VM_CL_modelnameforindex (prvm_prog_t *prog) +{ + dp_model_t *model; + + VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex); + + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(prog, model->name) : 0; +} + +//#335 float(string effectname) particleeffectnum (EXT_CSQC) +static void VM_CL_particleeffectnum (prvm_prog_t *prog) +{ + int i; + VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum); + i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0)); + if (i == 0) + i = -1; + PRVM_G_FLOAT(OFS_RETURN) = i; +} + +// #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC) +static void VM_CL_trailparticles (prvm_prog_t *prog) +{ + int i; + vec3_t start, end, velocity; + prvm_edict_t *t; + VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles); + + t = PRVM_G_EDICT(OFS_PARM0); + i = (int)PRVM_G_FLOAT(OFS_PARM1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end); + VectorCopy(PRVM_clientedictvector(t, velocity), velocity); + + if (i < 0) + return; + CL_ParticleEffect(i, 1, start, end, velocity, velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0); +} + +//#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC) +static void VM_CL_pointparticles (prvm_prog_t *prog) +{ + int i; + float n; + vec3_t f, v; + VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles); + i = (int)PRVM_G_FLOAT(OFS_PARM0); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), v); + n = PRVM_G_FLOAT(OFS_PARM3); + if (i < 0) + return; + CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0); +} + +//#502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count, float extflags) boxparticles (DP_CSQC_BOXPARTICLES) +static void VM_CL_boxparticles (prvm_prog_t *prog) +{ + int effectnum; + // prvm_edict_t *own; + vec3_t origin_from, origin_to, dir_from, dir_to; + float count; + int flags; + float tintmins[4], tintmaxs[4]; + VM_SAFEPARMCOUNTRANGE(7, 8, VM_CL_boxparticles); + + effectnum = (int)PRVM_G_FLOAT(OFS_PARM0); + // own = PRVM_G_EDICT(OFS_PARM1); // TODO find use for this + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin_from); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin_to ); + VectorCopy(PRVM_G_VECTOR(OFS_PARM4), dir_from ); + VectorCopy(PRVM_G_VECTOR(OFS_PARM5), dir_to ); + count = PRVM_G_FLOAT(OFS_PARM6); + if(prog->argc >= 8) + flags = PRVM_G_FLOAT(OFS_PARM7); + else + flags = 0; + Vector4Set(tintmins, 1, 1, 1, 1); + Vector4Set(tintmaxs, 1, 1, 1, 1); + if(flags & 1) // read alpha + { + tintmins[3] = PRVM_clientglobalfloat(particles_alphamin); + tintmaxs[3] = PRVM_clientglobalfloat(particles_alphamax); + } + if(flags & 2) // read color + { + VectorCopy(PRVM_clientglobalvector(particles_colormin), tintmins); + VectorCopy(PRVM_clientglobalvector(particles_colormax), tintmaxs); + } + if (effectnum < 0) + return; + CL_ParticleTrail(effectnum, count, origin_from, origin_to, dir_from, dir_to, NULL, 0, true, true, tintmins, tintmaxs); +} + +//#531 void(float pause) setpause +static void VM_CL_setpause(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_CL_setpause); + if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0) + cl.csqc_paused = true; + else + cl.csqc_paused = false; +} + +//#343 void(float usecursor) setcursormode (DP_CSQC) +static void VM_CL_setcursormode (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_CL_setcursormode); + cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0) != 0; + cl_ignoremousemoves = 2; +} + +//#344 vector() getmousepos (DP_CSQC) +static void VM_CL_getmousepos(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_CL_getmousepos); + + if (key_consoleactive || key_dest != key_game) + VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0); + else if (cl.csqc_wantsmousemove) + VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0); + else + VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0); +} + +//#345 float(float framenum) getinputstate (EXT_CSQC) +static void VM_CL_getinputstate (prvm_prog_t *prog) +{ + int i, frame; + VM_SAFEPARMCOUNT(1, VM_CL_getinputstate); + frame = (int)PRVM_G_FLOAT(OFS_PARM0); + PRVM_G_FLOAT(OFS_RETURN) = false; + for (i = 0;i < CL_MAX_USERCMDS;i++) + { + if (cl.movecmd[i].sequence == frame) + { + VectorCopy(cl.movecmd[i].viewangles, PRVM_clientglobalvector(input_angles)); + PRVM_clientglobalfloat(input_buttons) = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?) + PRVM_clientglobalvector(input_movevalues)[0] = cl.movecmd[i].forwardmove; + PRVM_clientglobalvector(input_movevalues)[1] = cl.movecmd[i].sidemove; + PRVM_clientglobalvector(input_movevalues)[2] = cl.movecmd[i].upmove; + PRVM_clientglobalfloat(input_timelength) = cl.movecmd[i].frametime; + // this probably shouldn't be here + if(cl.movecmd[i].crouch) + { + VectorCopy(cl.playercrouchmins, PRVM_clientglobalvector(pmove_mins)); + VectorCopy(cl.playercrouchmaxs, PRVM_clientglobalvector(pmove_maxs)); + } + else + { + VectorCopy(cl.playerstandmins, PRVM_clientglobalvector(pmove_mins)); + VectorCopy(cl.playerstandmaxs, PRVM_clientglobalvector(pmove_maxs)); + } + PRVM_G_FLOAT(OFS_RETURN) = true; + } + } +} + +//#346 void(float sens) setsensitivityscaler (EXT_CSQC) +static void VM_CL_setsensitivityscale (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale); + cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0); +} + +//#347 void() runstandardplayerphysics (EXT_CSQC) +#define PMF_JUMP_HELD 1 // matches FTEQW +#define PMF_LADDER 2 // not used by DP, FTEQW sets this in runplayerphysics but does not read it +#define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement because Q1 cannot crouch +#define PMF_ONGROUND 8 // FIXME FTEQW doesn't have this for Q1 like movement and expects CSQC code to do its own trace, this is stupid CPU waste +static void VM_CL_runplayerphysics (prvm_prog_t *prog) +{ + cl_clientmovement_state_t s; + prvm_edict_t *ent; + + memset(&s, 0, sizeof(s)); + + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_runplayerphysics); + + ent = (prog->argc == 1 ? PRVM_G_EDICT(OFS_PARM0) : prog->edicts); + if(ent == prog->edicts) + { + // deprecated use + s.self = NULL; + VectorCopy(PRVM_clientglobalvector(pmove_org), s.origin); + VectorCopy(PRVM_clientglobalvector(pmove_vel), s.velocity); + VectorCopy(PRVM_clientglobalvector(pmove_mins), s.mins); + VectorCopy(PRVM_clientglobalvector(pmove_maxs), s.maxs); + s.crouched = 0; + s.waterjumptime = PRVM_clientglobalfloat(pmove_waterjumptime); + s.cmd.canjump = (int)PRVM_clientglobalfloat(pmove_jump_held) == 0; + } + else + { + // new use + s.self = ent; + VectorCopy(PRVM_clientedictvector(ent, origin), s.origin); + VectorCopy(PRVM_clientedictvector(ent, velocity), s.velocity); + VectorCopy(PRVM_clientedictvector(ent, mins), s.mins); + VectorCopy(PRVM_clientedictvector(ent, maxs), s.maxs); + s.crouched = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_DUCKED) != 0; + s.waterjumptime = 0; // FIXME where do we get this from? FTEQW lacks support for this too + s.cmd.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0; + } + + VectorCopy(PRVM_clientglobalvector(input_angles), s.cmd.viewangles); + s.cmd.forwardmove = PRVM_clientglobalvector(input_movevalues)[0]; + s.cmd.sidemove = PRVM_clientglobalvector(input_movevalues)[1]; + s.cmd.upmove = PRVM_clientglobalvector(input_movevalues)[2]; + s.cmd.buttons = PRVM_clientglobalfloat(input_buttons); + s.cmd.frametime = PRVM_clientglobalfloat(input_timelength); + s.cmd.jump = (s.cmd.buttons & 2) != 0; + s.cmd.crouch = (s.cmd.buttons & 16) != 0; + + CL_ClientMovement_PlayerMove_Frame(&s); + + if(ent == prog->edicts) + { + // deprecated use + VectorCopy(s.origin, PRVM_clientglobalvector(pmove_org)); + VectorCopy(s.velocity, PRVM_clientglobalvector(pmove_vel)); + PRVM_clientglobalfloat(pmove_jump_held) = !s.cmd.canjump; + PRVM_clientglobalfloat(pmove_waterjumptime) = s.waterjumptime; + } + else + { + // new use + VectorCopy(s.origin, PRVM_clientedictvector(ent, origin)); + VectorCopy(s.velocity, PRVM_clientedictvector(ent, velocity)); + PRVM_clientedictfloat(ent, pmove_flags) = + (s.crouched ? PMF_DUCKED : 0) | + (s.cmd.canjump ? 0 : PMF_JUMP_HELD) | + (s.onground ? PMF_ONGROUND : 0); + } +} + +//#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC) +static void VM_CL_getplayerkey (prvm_prog_t *prog) +{ + int i; + char t[128]; + const char *c; + + VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey); + + i = (int)PRVM_G_FLOAT(OFS_PARM0); + c = PRVM_G_STRING(OFS_PARM1); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + Sbar_SortFrags(); + + if (i < 0) + i = Sbar_GetSortedPlayerIndex(-1-i); + if(i < 0 || i >= cl.maxclients) + return; + + t[0] = 0; + + if(!strcasecmp(c, "name")) + strlcpy(t, cl.scores[i].name, sizeof(t)); + else + if(!strcasecmp(c, "frags")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].frags); + else + if(!strcasecmp(c, "ping")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_ping); + else + if(!strcasecmp(c, "pl")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_packetloss); + else + if(!strcasecmp(c, "movementloss")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_movementloss); + else + if(!strcasecmp(c, "entertime")) + dpsnprintf(t, sizeof(t), "%f", cl.scores[i].qw_entertime); + else + if(!strcasecmp(c, "colors")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors); + else + if(!strcasecmp(c, "topcolor")) + dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors & 0xf0); + else + if(!strcasecmp(c, "bottomcolor")) + dpsnprintf(t, sizeof(t), "%i", (cl.scores[i].colors &15)<<4); + else + if(!strcasecmp(c, "viewentity")) + dpsnprintf(t, sizeof(t), "%i", i+1); + else + if(gamemode == GAME_XONOTIC && !strcasecmp(c, "TEMPHACK_origin")) + { + // PLEASE REMOVE THIS once deltalisten() of EXT_CSQC_1 + // is implemented, or Xonotic uses CSQC-networked + // players, whichever comes first + entity_t *e = cl.entities + (i+1); + if(e->state_current.active) + { + vec3_t origin; + Matrix4x4_OriginFromMatrix(&e->render.matrix, origin); + dpsnprintf(t, sizeof(t), VECTOR_LOSSLESS_FORMAT, origin[0], origin[1], origin[2]); + } + } + if(!t[0]) + return; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t); +} + +//#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC) +static void VM_CL_setlistener (prvm_prog_t *prog) +{ + vec3_t origin, forward, left, up; + VM_SAFEPARMCOUNT(4, VM_CL_setlistener); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), origin); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), forward); + VectorNegate(PRVM_G_VECTOR(OFS_PARM2), left); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), up); + Matrix4x4_FromVectors(&cl.csqc_listenermatrix, forward, left, up, origin); + cl.csqc_usecsqclistener = true; //use csqc listener at this frame +} + +//#352 void(string cmdname) registercommand (EXT_CSQC) +static void VM_CL_registercmd (prvm_prog_t *prog) +{ + char *t; + VM_SAFEPARMCOUNT(1, VM_CL_registercmd); + if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0))) + { + size_t alloclen; + + alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1; + t = (char *)Z_Malloc(alloclen); + memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen); + Cmd_AddCommand(t, NULL, "console command created by QuakeC"); + } + else + Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC"); + +} + +//#360 float() readbyte (EXT_CSQC) +static void VM_CL_ReadByte (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadByte); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte(&cl_message); +} + +//#361 float() readchar (EXT_CSQC) +static void VM_CL_ReadChar (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadChar); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar(&cl_message); +} + +//#362 float() readshort (EXT_CSQC) +static void VM_CL_ReadShort (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadShort); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort(&cl_message); +} + +//#363 float() readlong (EXT_CSQC) +static void VM_CL_ReadLong (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadLong); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong(&cl_message); +} + +//#364 float() readcoord (EXT_CSQC) +static void VM_CL_ReadCoord (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(&cl_message, cls.protocol); +} + +//#365 float() readangle (EXT_CSQC) +static void VM_CL_ReadAngle (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(&cl_message, cls.protocol); +} + +//#366 string() readstring (EXT_CSQC) +static void VM_CL_ReadString (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadString); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); +} + +//#367 float() readfloat (EXT_CSQC) +static void VM_CL_ReadFloat (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat); + PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat(&cl_message); +} + +//#501 string() readpicture (DP_CSQC_READWRITEPICTURE) +extern cvar_t cl_readpicture_force; +static void VM_CL_ReadPicture (prvm_prog_t *prog) +{ + const char *name; + unsigned char *data; + unsigned char *buf; + unsigned short size; + int i; + cachepic_t *pic; + + VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture); + + name = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + size = (unsigned short) MSG_ReadShort(&cl_message); + + // check if a texture of that name exists + // if yes, it is used and the data is discarded + // if not, the (low quality) data is used to build a new texture, whose name will get returned + + pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT); + + if(size) + { + if(pic->tex == r_texture_notexture) + pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic + if(pic->tex && !cl_readpicture_force.integer) + { + // texture found and loaded + // skip over the jpeg as we don't need it + for(i = 0; i < size; ++i) + (void) MSG_ReadByte(&cl_message); + } + else + { + // texture not found + // use the attached jpeg as texture + buf = (unsigned char *) Mem_Alloc(tempmempool, size); + MSG_ReadBytes(&cl_message, size, buf); + data = JPEG_LoadImage_BGRA(buf, size, NULL); + Mem_Free(buf); + Draw_NewPic(name, image_width, image_height, false, data); + Mem_Free(data); + } + } + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, name); +} + +////////////////////////////////////////////////////////// + +static void VM_CL_makestatic (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + + VM_SAFEPARMCOUNT(1, VM_CL_makestatic); + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning(prog, "makestatic: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "makestatic: can not modify free entity\n"); + return; + } + + if (cl.num_static_entities < cl.max_static_entities) + { + int renderflags; + entity_t *staticent = &cl.static_entities[cl.num_static_entities++]; + + // copy it to the current state + memset(staticent, 0, sizeof(*staticent)); + staticent->render.model = CL_GetModelByIndex((int)PRVM_clientedictfloat(ent, modelindex)); + staticent->render.framegroupblend[0].frame = (int)PRVM_clientedictfloat(ent, frame); + staticent->render.framegroupblend[0].lerp = 1; + // make torchs play out of sync + staticent->render.framegroupblend[0].start = lhrandom(-10, -1); + staticent->render.skinnum = (int)PRVM_clientedictfloat(ent, skin); + staticent->render.effects = (int)PRVM_clientedictfloat(ent, effects); + staticent->render.alpha = PRVM_clientedictfloat(ent, alpha); + staticent->render.scale = PRVM_clientedictfloat(ent, scale); + VectorCopy(PRVM_clientedictvector(ent, colormod), staticent->render.colormod); + VectorCopy(PRVM_clientedictvector(ent, glowmod), staticent->render.glowmod); + + // sanitize values + if (!staticent->render.alpha) + staticent->render.alpha = 1.0f; + if (!staticent->render.scale) + staticent->render.scale = 1.0f; + if (!VectorLength2(staticent->render.colormod)) + VectorSet(staticent->render.colormod, 1, 1, 1); + if (!VectorLength2(staticent->render.glowmod)) + VectorSet(staticent->render.glowmod, 1, 1, 1); + + renderflags = (int)PRVM_clientedictfloat(ent, renderflags); + if (renderflags & RF_USEAXIS) + { + vec3_t forward, left, up, origin; + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + VectorCopy(PRVM_clientedictvector(ent, origin), origin); + Matrix4x4_FromVectors(&staticent->render.matrix, forward, left, up, origin); + Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1); + } + else + Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], staticent->render.scale); + + // either fullbright or lit + if(!r_fullbright.integer) + { + if (!(staticent->render.effects & EF_FULLBRIGHT)) + staticent->render.flags |= RENDER_LIGHT; + else if(r_equalize_entities_fullbright.integer) + staticent->render.flags |= RENDER_LIGHT | RENDER_EQUALIZE; + } + // turn off shadows from transparent objects + if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1)) + staticent->render.flags |= RENDER_SHADOW; + if (staticent->render.effects & EF_NODEPTHTEST) + staticent->render.flags |= RENDER_NODEPTHTEST; + if (staticent->render.effects & EF_ADDITIVE) + staticent->render.flags |= RENDER_ADDITIVE; + if (staticent->render.effects & EF_DOUBLESIDED) + staticent->render.flags |= RENDER_DOUBLESIDED; + + staticent->render.allowdecals = true; + CL_UpdateRenderEntity(&staticent->render); + } + else + Con_Printf("Too many static entities"); + +// throw the entity away now + PRVM_ED_Free(prog, ent); +} + +//=================================================================// + +/* +================= +VM_CL_copyentity + +copies data from one entity to another + +copyentity(src, dst) +================= +*/ +static void VM_CL_copyentity (prvm_prog_t *prog) +{ + prvm_edict_t *in, *out; + VM_SAFEPARMCOUNT(2, VM_CL_copyentity); + in = PRVM_G_EDICT(OFS_PARM0); + if (in == prog->edicts) + { + VM_Warning(prog, "copyentity: can not read world entity\n"); + return; + } + if (in->priv.server->free) + { + VM_Warning(prog, "copyentity: can not read free entity\n"); + return; + } + out = PRVM_G_EDICT(OFS_PARM1); + if (out == prog->edicts) + { + VM_Warning(prog, "copyentity: can not modify world entity\n"); + return; + } + if (out->priv.server->free) + { + VM_Warning(prog, "copyentity: can not modify free entity\n"); + return; + } + memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t)); + CL_LinkEdict(out); +} + +//=================================================================// + +// #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT) +static void VM_CL_effect (prvm_prog_t *prog) +{ +#if 1 + Con_Printf("WARNING: VM_CL_effect not implemented\n"); // FIXME: this needs to take modelname not modelindex, the csqc defs has it as string and so it shall be +#else + vec3_t org; + VM_SAFEPARMCOUNT(5, VM_CL_effect); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + CL_Effect(org, (int)PRVM_G_FLOAT(OFS_PARM1), (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4)); +#endif +} + +// #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD) +static void VM_CL_te_blood (prvm_prog_t *prog) +{ + vec3_t pos, vel, pos2; + VM_SAFEPARMCOUNT(3, VM_CL_te_blood); + if (PRVM_G_FLOAT(OFS_PARM2) < 1) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0); +} + +// #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER) +static void VM_CL_te_bloodshower (prvm_prog_t *prog) +{ + vec_t speed; + vec3_t mincorner, maxcorner, vel1, vel2; + VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower); + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + return; + speed = PRVM_G_FLOAT(OFS_PARM2); + vel1[0] = -speed; + vel1[1] = -speed; + vel1[2] = -speed; + vel2[0] = speed; + vel2[1] = speed; + vel2[2] = speed; + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner); + CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), mincorner, maxcorner, vel1, vel2, NULL, 0); +} + +// #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB) +static void VM_CL_te_explosionrgb (prvm_prog_t *prog) +{ + vec3_t pos; + vec3_t pos2; + matrix4x4_t tempmatrix; + VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleExplosion(pos2); + Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); + CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); +} + +// #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE) +static void VM_CL_te_particlecube (prvm_prog_t *prog) +{ + vec3_t mincorner, maxcorner, vel; + VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel); + CL_ParticleCube(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6)); +} + +// #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN) +static void VM_CL_te_particlerain (prvm_prog_t *prog) +{ + vec3_t mincorner, maxcorner, vel; + VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel); + CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 0); +} + +// #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW) +static void VM_CL_te_particlesnow (prvm_prog_t *prog) +{ + vec3_t mincorner, maxcorner, vel; + VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel); + CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 1); +} + +// #411 void(vector org, vector vel, float howmany) te_spark +static void VM_CL_te_spark (prvm_prog_t *prog) +{ + vec3_t pos, pos2, vel; + VM_SAFEPARMCOUNT(3, VM_CL_te_spark); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0); +} + +extern cvar_t cl_sound_ric_gunshot; +// #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1) +static void VM_CL_te_gunshotquad (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + if(cl_sound_ric_gunshot.integer >= 2) + { + if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } + } +} + +// #413 void(vector org) te_spikequad (DP_QUADEFFECTS1) +static void VM_CL_te_spikequad (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } +} + +// #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1) +static void VM_CL_te_superspikequad (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + 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, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } +} + +// #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1) +static void VM_CL_te_explosionquad (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1); +} + +// #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH) +static void VM_CL_te_smallflash (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); +} + +// #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH) +static void VM_CL_te_customflash (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + matrix4x4_t tempmatrix; + VM_SAFEPARMCOUNT(4, VM_CL_te_customflash); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); + CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); +} + +// #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_gunshot (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3) + { + if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } + } +} + +// #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_spike (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_spike); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } +} + +// #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_superspike (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + int rnd; + VM_SAFEPARMCOUNT(1, VM_CL_te_superspike); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1); + else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1); + else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1); + } +} + +// #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_explosion (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_explosion); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1); +} + +// #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_tarexplosion (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1); +} + +// #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_wizspike (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1); +} + +// #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_knightspike (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); + S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1); +} + +// #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_lavasplash (prvm_prog_t *prog) +{ + vec3_t pos; + VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); +} + +// #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_teleport (prvm_prog_t *prog) +{ + vec3_t pos; + VM_SAFEPARMCOUNT(1, VM_CL_te_teleport); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0); +} + +// #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_explosion2 (prvm_prog_t *prog) +{ + vec3_t pos, pos2, color; + matrix4x4_t tempmatrix; + int colorStart, colorLength; + unsigned char *tempcolor; + VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + colorStart = (int)PRVM_G_FLOAT(OFS_PARM1); + colorLength = (int)PRVM_G_FLOAT(OFS_PARM2); + CL_FindNonSolidLocation(pos, pos2, 10); + CL_ParticleExplosion2(pos2, colorStart, colorLength); + tempcolor = palette_rgb[(rand()%colorLength) + colorStart]; + color[0] = tempcolor[0] * (2.0f / 255.0f); + color[1] = tempcolor[1] * (2.0f / 255.0f); + color[2] = tempcolor[2] * (2.0f / 255.0f); + Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]); + CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE); + S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1); +} + + +// #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_lightning1 (prvm_prog_t *prog) +{ + vec3_t start, end; + VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end); + CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt, true); +} + +// #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_lightning2 (prvm_prog_t *prog) +{ + vec3_t start, end; + VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end); + CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt2, true); +} + +// #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_lightning3 (prvm_prog_t *prog) +{ + vec3_t start, end; + VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end); + CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt3, false); +} + +// #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) +static void VM_CL_te_beam (prvm_prog_t *prog) +{ + vec3_t start, end; + VM_SAFEPARMCOUNT(3, VM_CL_te_beam); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end); + CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_beam, false); +} + +// #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) +static void VM_CL_te_plasmaburn (prvm_prog_t *prog) +{ + vec3_t pos, pos2; + VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0); +} + +// #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET) +static void VM_CL_te_flamejet (prvm_prog_t *prog) +{ + vec3_t pos, pos2, vel; + VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet); + if (PRVM_G_FLOAT(OFS_PARM2) < 1) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel); + CL_FindNonSolidLocation(pos, pos2, 4); + CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0); +} + + +// #443 void(entity e, entity tagentity, string tagname) setattachment +static void VM_CL_setattachment (prvm_prog_t *prog) +{ + prvm_edict_t *e; + prvm_edict_t *tagentity; + const char *tagname; + int modelindex; + int tagindex; + dp_model_t *model; + VM_SAFEPARMCOUNT(3, VM_CL_setattachment); + + e = PRVM_G_EDICT(OFS_PARM0); + tagentity = PRVM_G_EDICT(OFS_PARM1); + tagname = PRVM_G_STRING(OFS_PARM2); + + if (e == prog->edicts) + { + VM_Warning(prog, "setattachment: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setattachment: can not modify free entity\n"); + return; + } + + if (tagentity == NULL) + tagentity = prog->edicts; + + tagindex = 0; + if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) + { + modelindex = (int)PRVM_clientedictfloat(tagentity, modelindex); + model = CL_GetModelByIndex(modelindex); + if (model) + { + tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(tagentity, skin), tagname); + if (tagindex == 0) + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name); + } + else + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); + } + + PRVM_clientedictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity); + PRVM_clientedictfloat(e, tag_index) = tagindex; +} + +///////////////////////////////////////// +// DP_MD3_TAGINFO extension coded by VorteX + +static int CL_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname) +{ + dp_model_t *model = CL_GetModelFromEdict(e); + if (model) + return Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(e, skin), tagname); + else + return -1; +} + +static int CL_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix) +{ + int r; + dp_model_t *model; + + *tagname = NULL; + *parentindex = 0; + Matrix4x4_CreateIdentity(tag_localmatrix); + + if (tagindex >= 0 + && (model = CL_GetModelFromEdict(e)) + && model->animscenes) + { + r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_clientedictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix); + + if(!r) // success? + *parentindex += 1; + + return r; + } + + return 1; +} + +int CL_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent) +{ + dp_model_t *model; + if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias) + return -1; + return 1; +} + +void CL_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix) +{ + float scale; + float pitchsign = 1; + + scale = PRVM_clientedictfloat(ent, scale); + if (!scale) + scale = 1.0f; + + if(viewmatrix) + *out = r_refdef.view.matrix; + else if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_USEAXIS) + { + vec3_t forward; + vec3_t left; + vec3_t up; + vec3_t origin; + VectorScale(PRVM_clientglobalvector(v_forward), scale, forward); + VectorScale(PRVM_clientglobalvector(v_right), -scale, left); + VectorScale(PRVM_clientglobalvector(v_up), scale, up); + VectorCopy(PRVM_clientedictvector(ent, origin), origin); + Matrix4x4_FromVectors(out, forward, left, up, origin); + } + else + { + pitchsign = CL_GetPitchSign(prog, ent); + Matrix4x4_CreateFromQuakeEntity(out, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], pitchsign * PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], scale); + } +} + +static int CL_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out) +{ + dp_model_t *model; + if (tagindex >= 0 + && (model = CL_GetModelFromEdict(ent)) + && model->animscenes) + { + VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent); + VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, cl.time); + VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend); + return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out); + } + *out = identitymatrix; + return 0; +} + +// Warnings/errors code: +// 0 - normal (everything all-right) +// 1 - world entity +// 2 - free entity +// 3 - null or non-precached model +// 4 - no tags with requested index +// 5 - runaway loop at attachment chain +extern cvar_t cl_bob; +extern cvar_t cl_bobcycle; +extern cvar_t cl_bobup; +int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex) +{ + int ret; + int attachloop; + matrix4x4_t entitymatrix, tagmatrix, attachmatrix; + dp_model_t *model; + + *out = identitymatrix; // warnings and errors return identical matrix + + if (ent == prog->edicts) + return 1; + if (ent->priv.server->free) + return 2; + + model = CL_GetModelFromEdict(ent); + if(!model) + return 3; + + tagmatrix = identitymatrix; + attachloop = 0; + for(;;) + { + if(attachloop >= 256) + return 5; + // apply transformation by child's tagindex on parent entity and then + // by parent entity itself + ret = CL_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix); + if(ret && attachloop == 0) + return ret; + CL_GetEntityMatrix(prog, ent, &entitymatrix, false); + Matrix4x4_Concat(&tagmatrix, &attachmatrix, out); + Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); + // next iteration we process the parent entity + if (PRVM_clientedictedict(ent, tag_entity)) + { + tagindex = (int)PRVM_clientedictfloat(ent, tag_index); + ent = PRVM_EDICT_NUM(PRVM_clientedictedict(ent, tag_entity)); + } + else + break; + attachloop++; + } + + // RENDER_VIEWMODEL magic + if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_VIEWMODEL) + { + Matrix4x4_Copy(&tagmatrix, out); + + CL_GetEntityMatrix(prog, prog->edicts, &entitymatrix, true); + Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); + + /* + // Cl_bob, ported from rendering code + if (PRVM_clientedictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value) + { + double bob, cycle; + // LordHavoc: this code is *weird*, but not replacable (I think it + // should be done in QC on the server, but oh well, quake is quake) + // LordHavoc: figured out bobup: the time at which the sin is at 180 + // degrees (which allows lengthening or squishing the peak or valley) + cycle = cl.time/cl_bobcycle.value; + cycle -= (int)cycle; + if (cycle < cl_bobup.value) + cycle = sin(M_PI * cycle / cl_bobup.value); + else + cycle = sin(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 = sqrt(PRVM_clientedictvector(ent, velocity)[0]*PRVM_clientedictvector(ent, velocity)[0] + PRVM_clientedictvector(ent, velocity)[1]*PRVM_clientedictvector(ent, velocity)[1])*cl_bob.value; + bob = bob*0.3 + bob*0.7*cycle; + Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4)); + } + */ + } + return 0; +} + +// #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO) +static void VM_CL_gettagindex (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + const char *tag_name; + int tag_index; + + VM_SAFEPARMCOUNT(2, VM_CL_gettagindex); + + ent = PRVM_G_EDICT(OFS_PARM0); + tag_name = PRVM_G_STRING(OFS_PARM1); + if (ent == prog->edicts) + { + VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent)); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent)); + return; + } + + tag_index = 0; + if (!CL_GetModelFromEdict(ent)) + Con_DPrintf("VM_CL_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent)); + else + { + tag_index = CL_GetTagIndex(prog, ent, tag_name); + if (tag_index == 0) + if(developer_extra.integer) + Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name); + } + PRVM_G_FLOAT(OFS_RETURN) = tag_index; +} + +// #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO) +static void VM_CL_gettaginfo (prvm_prog_t *prog) +{ + prvm_edict_t *e; + int tagindex; + matrix4x4_t tag_matrix; + matrix4x4_t tag_localmatrix; + int parentindex; + const char *tagname; + int returncode; + vec3_t forward, left, up, origin; + const dp_model_t *model; + + VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo); + + e = PRVM_G_EDICT(OFS_PARM0); + tagindex = (int)PRVM_G_FLOAT(OFS_PARM1); + returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex); + Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorScale(left, -1, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); + model = CL_GetModelFromEdict(e); + VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e); + VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, cl.time); + VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend); + CL_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix); + Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin); + + PRVM_clientglobalfloat(gettaginfo_parent) = parentindex; + PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0; + VectorCopy(forward, PRVM_clientglobalvector(gettaginfo_forward)); + VectorScale(left, -1, PRVM_clientglobalvector(gettaginfo_right)); + VectorCopy(up, PRVM_clientglobalvector(gettaginfo_up)); + VectorCopy(origin, PRVM_clientglobalvector(gettaginfo_offset)); + + switch(returncode) + { + case 1: + VM_Warning(prog, "gettagindex: can't affect world entity\n"); + break; + case 2: + VM_Warning(prog, "gettagindex: can't affect free entity\n"); + break; + case 3: + Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e)); + break; + case 4: + Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex); + break; + case 5: + Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e)); + break; + } +} + +//============================================================================ + +//==================== +// DP_CSQC_SPAWNPARTICLE +// a QC hook to engine's CL_NewParticle +//==================== + +// particle theme struct +typedef struct vmparticletheme_s +{ + unsigned short typeindex; + qboolean initialized; + pblend_t blendmode; + porientation_t orientation; + int color1; + int color2; + int tex; + float size; + float sizeincrease; + float alpha; + float alphafade; + float gravity; + float bounce; + float airfriction; + float liquidfriction; + float originjitter; + float velocityjitter; + qboolean qualityreduction; + float lifetime; + float stretch; + int staincolor1; + int staincolor2; + int staintex; + float stainalpha; + float stainsize; + float delayspawn; + float delaycollision; + float angle; + float spin; +}vmparticletheme_t; + +// particle spawner +typedef struct vmparticlespawner_s +{ + mempool_t *pool; + qboolean initialized; + qboolean verified; + vmparticletheme_t *themes; + int max_themes; +}vmparticlespawner_t; + +vmparticlespawner_t vmpartspawner; + +// TODO: automatic max_themes grow +static void VM_InitParticleSpawner (prvm_prog_t *prog, int maxthemes) +{ + // bound max themes to not be an insane value + if (maxthemes < 4) + maxthemes = 4; + if (maxthemes > 2048) + maxthemes = 2048; + // allocate and set up structure + if (vmpartspawner.initialized) // reallocate + { + Mem_FreePool(&vmpartspawner.pool); + memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t)); + } + vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL); + vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes); + vmpartspawner.max_themes = maxthemes; + vmpartspawner.initialized = true; + vmpartspawner.verified = true; +} + +// reset particle theme to default values +static void VM_ResetParticleTheme (vmparticletheme_t *theme) +{ + theme->initialized = true; + theme->typeindex = pt_static; + theme->blendmode = PBLEND_ADD; + theme->orientation = PARTICLE_BILLBOARD; + theme->color1 = 0x808080; + theme->color2 = 0xFFFFFF; + theme->tex = 63; + theme->size = 2; + theme->sizeincrease = 0; + theme->alpha = 256; + theme->alphafade = 512; + theme->gravity = 0.0f; + theme->bounce = 0.0f; + theme->airfriction = 1.0f; + theme->liquidfriction = 4.0f; + theme->originjitter = 0.0f; + theme->velocityjitter = 0.0f; + theme->qualityreduction = false; + theme->lifetime = 4; + theme->stretch = 1; + theme->staincolor1 = -1; + theme->staincolor2 = -1; + theme->staintex = -1; + theme->delayspawn = 0.0f; + theme->delaycollision = 0.0f; + theme->angle = 0.0f; + theme->spin = 0.0f; +} + +// particle theme -> QC globals +static void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme, prvm_prog_t *prog) +{ + PRVM_clientglobalfloat(particle_type) = theme->typeindex; + PRVM_clientglobalfloat(particle_blendmode) = theme->blendmode; + PRVM_clientglobalfloat(particle_orientation) = theme->orientation; + // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375... + VectorSet(PRVM_clientglobalvector(particle_color1), (theme->color1 >> 16) & 0xFF, (theme->color1 >> 8) & 0xFF, (theme->color1 >> 0) & 0xFF); + VectorSet(PRVM_clientglobalvector(particle_color2), (theme->color2 >> 16) & 0xFF, (theme->color2 >> 8) & 0xFF, (theme->color2 >> 0) & 0xFF); + PRVM_clientglobalfloat(particle_tex) = (prvm_vec_t)theme->tex; + PRVM_clientglobalfloat(particle_size) = theme->size; + PRVM_clientglobalfloat(particle_sizeincrease) = theme->sizeincrease; + PRVM_clientglobalfloat(particle_alpha) = theme->alpha/256; + PRVM_clientglobalfloat(particle_alphafade) = theme->alphafade/256; + PRVM_clientglobalfloat(particle_time) = theme->lifetime; + PRVM_clientglobalfloat(particle_gravity) = theme->gravity; + PRVM_clientglobalfloat(particle_bounce) = theme->bounce; + PRVM_clientglobalfloat(particle_airfriction) = theme->airfriction; + PRVM_clientglobalfloat(particle_liquidfriction) = theme->liquidfriction; + PRVM_clientglobalfloat(particle_originjitter) = theme->originjitter; + PRVM_clientglobalfloat(particle_velocityjitter) = theme->velocityjitter; + PRVM_clientglobalfloat(particle_qualityreduction) = theme->qualityreduction; + PRVM_clientglobalfloat(particle_stretch) = theme->stretch; + VectorSet(PRVM_clientglobalvector(particle_staincolor1), ((int)theme->staincolor1 >> 16) & 0xFF, ((int)theme->staincolor1 >> 8) & 0xFF, ((int)theme->staincolor1 >> 0) & 0xFF); + VectorSet(PRVM_clientglobalvector(particle_staincolor2), ((int)theme->staincolor2 >> 16) & 0xFF, ((int)theme->staincolor2 >> 8) & 0xFF, ((int)theme->staincolor2 >> 0) & 0xFF); + PRVM_clientglobalfloat(particle_staintex) = (prvm_vec_t)theme->staintex; + PRVM_clientglobalfloat(particle_stainalpha) = (prvm_vec_t)theme->stainalpha/256; + PRVM_clientglobalfloat(particle_stainsize) = (prvm_vec_t)theme->stainsize; + PRVM_clientglobalfloat(particle_delayspawn) = theme->delayspawn; + PRVM_clientglobalfloat(particle_delaycollision) = theme->delaycollision; + PRVM_clientglobalfloat(particle_angle) = theme->angle; + PRVM_clientglobalfloat(particle_spin) = theme->spin; +} + +// QC globals -> particle theme +static void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme, prvm_prog_t *prog) +{ + theme->typeindex = (unsigned short)PRVM_clientglobalfloat(particle_type); + theme->blendmode = (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode); + theme->orientation = (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation); + theme->color1 = ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]); + theme->color2 = ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]); + theme->tex = (int)PRVM_clientglobalfloat(particle_tex); + theme->size = PRVM_clientglobalfloat(particle_size); + theme->sizeincrease = PRVM_clientglobalfloat(particle_sizeincrease); + theme->alpha = PRVM_clientglobalfloat(particle_alpha)*256; + theme->alphafade = PRVM_clientglobalfloat(particle_alphafade)*256; + theme->lifetime = PRVM_clientglobalfloat(particle_time); + theme->gravity = PRVM_clientglobalfloat(particle_gravity); + theme->bounce = PRVM_clientglobalfloat(particle_bounce); + theme->airfriction = PRVM_clientglobalfloat(particle_airfriction); + theme->liquidfriction = PRVM_clientglobalfloat(particle_liquidfriction); + theme->originjitter = PRVM_clientglobalfloat(particle_originjitter); + theme->velocityjitter = PRVM_clientglobalfloat(particle_velocityjitter); + theme->qualityreduction = PRVM_clientglobalfloat(particle_qualityreduction) != 0 ? true : false; + theme->stretch = PRVM_clientglobalfloat(particle_stretch); + theme->staincolor1 = ((int)PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]); + theme->staincolor2 = (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]); + theme->staintex =(int)PRVM_clientglobalfloat(particle_staintex); + theme->stainalpha = PRVM_clientglobalfloat(particle_stainalpha)*256; + theme->stainsize = PRVM_clientglobalfloat(particle_stainsize); + theme->delayspawn = PRVM_clientglobalfloat(particle_delayspawn); + theme->delaycollision = PRVM_clientglobalfloat(particle_delaycollision); + theme->angle = PRVM_clientglobalfloat(particle_angle); + theme->spin = PRVM_clientglobalfloat(particle_spin); +} + +// init particle spawner interface +// # float(float max_themes) initparticlespawner +static void VM_CL_InitParticleSpawner (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner); + VM_InitParticleSpawner(prog, (int)PRVM_G_FLOAT(OFS_PARM0)); + vmpartspawner.themes[0].initialized = true; + VM_ResetParticleTheme(&vmpartspawner.themes[0]); + PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0; +} + +// void() resetparticle +static void VM_CL_ResetParticle (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_ResetParticle: particle spawner not initialized\n"); + return; + } + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog); +} + +// void(float themenum) particletheme +static void VM_CL_ParticleTheme (prvm_prog_t *prog) +{ + int themenum; + + VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_ParticleTheme: particle spawner not initialized\n"); + return; + } + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (themenum < 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning(prog, "VM_CL_ParticleTheme: bad theme number %i\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog); + return; + } + if (vmpartspawner.themes[themenum].initialized == false) + { + VM_Warning(prog, "VM_CL_ParticleTheme: theme #%i not exists\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog); + return; + } + // load particle theme into globals + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum], prog); +} + +// float() saveparticletheme +// void(float themenum) updateparticletheme +static void VM_CL_ParticleThemeSave (prvm_prog_t *prog) +{ + int themenum; + + VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_ParticleThemeSave: particle spawner not initialized\n"); + return; + } + // allocate new theme, save it and return + if (prog->argc < 1) + { + for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++) + if (vmpartspawner.themes[themenum].initialized == false) + break; + if (themenum >= vmpartspawner.max_themes) + { + if (vmpartspawner.max_themes == 2048) + VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots\n"); + else + VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n"); + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + vmpartspawner.themes[themenum].initialized = true; + VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog); + PRVM_G_FLOAT(OFS_RETURN) = themenum; + return; + } + // update existing theme + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (themenum < 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning(prog, "VM_CL_ParticleThemeSave: bad theme number %i\n", themenum); + return; + } + vmpartspawner.themes[themenum].initialized = true; + VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog); +} + +// void(float themenum) freeparticletheme +static void VM_CL_ParticleThemeFree (prvm_prog_t *prog) +{ + int themenum; + + VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_ParticleThemeFree: particle spawner not initialized\n"); + return; + } + themenum = (int)PRVM_G_FLOAT(OFS_PARM0); + // check parms + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning(prog, "VM_CL_ParticleThemeFree: bad theme number %i\n", themenum); + return; + } + if (vmpartspawner.themes[themenum].initialized == false) + { + VM_Warning(prog, "VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum); + VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog); + return; + } + // free theme + VM_ResetParticleTheme(&vmpartspawner.themes[themenum]); + vmpartspawner.themes[themenum].initialized = false; +} + +// float(vector org, vector dir, [float theme]) particle +// returns 0 if failed, 1 if succesful +static void VM_CL_SpawnParticle (prvm_prog_t *prog) +{ + vec3_t org, dir; + vmparticletheme_t *theme; + particle_t *part; + int themenum; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle2); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n"); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir); + + if (prog->argc < 3) // global-set particle + { + part = CL_NewParticle(org, + (unsigned short)PRVM_clientglobalfloat(particle_type), + ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]), + ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]), + (int)PRVM_clientglobalfloat(particle_tex), + PRVM_clientglobalfloat(particle_size), + PRVM_clientglobalfloat(particle_sizeincrease), + PRVM_clientglobalfloat(particle_alpha)*256, + PRVM_clientglobalfloat(particle_alphafade)*256, + PRVM_clientglobalfloat(particle_gravity), + PRVM_clientglobalfloat(particle_bounce), + org[0], + org[1], + org[2], + dir[0], + dir[1], + dir[2], + PRVM_clientglobalfloat(particle_airfriction), + PRVM_clientglobalfloat(particle_liquidfriction), + PRVM_clientglobalfloat(particle_originjitter), + PRVM_clientglobalfloat(particle_velocityjitter), + (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false, + PRVM_clientglobalfloat(particle_time), + PRVM_clientglobalfloat(particle_stretch), + (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode), + (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation), + (int)(PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]), + (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]), + (int)PRVM_clientglobalfloat(particle_staintex), + PRVM_clientglobalfloat(particle_stainalpha)*256, + PRVM_clientglobalfloat(particle_stainsize), + PRVM_clientglobalfloat(particle_angle), + PRVM_clientglobalfloat(particle_spin), + NULL); + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + if (PRVM_clientglobalfloat(particle_delayspawn)) + part->delayedspawn = cl.time + PRVM_clientglobalfloat(particle_delayspawn); + //if (PRVM_clientglobalfloat(particle_delaycollision)) + // part->delayedcollisions = cl.time + PRVM_clientglobalfloat(particle_delaycollision); + } + else // quick themed particle + { + themenum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + theme = &vmpartspawner.themes[themenum]; + part = CL_NewParticle(org, + theme->typeindex, + theme->color1, + theme->color2, + theme->tex, + theme->size, + theme->sizeincrease, + theme->alpha, + theme->alphafade, + theme->gravity, + theme->bounce, + org[0], + org[1], + org[2], + dir[0], + dir[1], + dir[2], + theme->airfriction, + theme->liquidfriction, + theme->originjitter, + theme->velocityjitter, + theme->qualityreduction, + theme->lifetime, + theme->stretch, + theme->blendmode, + theme->orientation, + theme->staincolor1, + theme->staincolor2, + theme->staintex, + theme->stainalpha, + theme->stainsize, + theme->angle, + theme->spin, + NULL); + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + if (theme->delayspawn) + part->delayedspawn = cl.time + theme->delayspawn; + //if (theme->delaycollision) + // part->delayedcollisions = cl.time + theme->delaycollision; + } + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +// float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle +// returns 0 if failed, 1 if success +static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog) +{ + vec3_t org, dir; + vmparticletheme_t *theme; + particle_t *part; + int themenum; + + VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticle2); + if (vmpartspawner.verified == false) + { + VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n"); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir); + if (prog->argc < 5) // global-set particle + part = CL_NewParticle(org, + (unsigned short)PRVM_clientglobalfloat(particle_type), + ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]), + ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]), + (int)PRVM_clientglobalfloat(particle_tex), + PRVM_clientglobalfloat(particle_size), + PRVM_clientglobalfloat(particle_sizeincrease), + PRVM_clientglobalfloat(particle_alpha)*256, + PRVM_clientglobalfloat(particle_alphafade)*256, + PRVM_clientglobalfloat(particle_gravity), + PRVM_clientglobalfloat(particle_bounce), + org[0], + org[1], + org[2], + dir[0], + dir[1], + dir[2], + PRVM_clientglobalfloat(particle_airfriction), + PRVM_clientglobalfloat(particle_liquidfriction), + PRVM_clientglobalfloat(particle_originjitter), + PRVM_clientglobalfloat(particle_velocityjitter), + (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false, + PRVM_clientglobalfloat(particle_time), + PRVM_clientglobalfloat(particle_stretch), + (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode), + (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation), + ((int)PRVM_clientglobalvector(particle_staincolor1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor1)[2]), + ((int)PRVM_clientglobalvector(particle_staincolor2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor2)[2]), + (int)PRVM_clientglobalfloat(particle_staintex), + PRVM_clientglobalfloat(particle_stainalpha)*256, + PRVM_clientglobalfloat(particle_stainsize), + PRVM_clientglobalfloat(particle_angle), + PRVM_clientglobalfloat(particle_spin), + NULL); + else // themed particle + { + themenum = (int)PRVM_G_FLOAT(OFS_PARM4); + if (themenum <= 0 || themenum >= vmpartspawner.max_themes) + { + VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + theme = &vmpartspawner.themes[themenum]; + part = CL_NewParticle(org, + theme->typeindex, + theme->color1, + theme->color2, + theme->tex, + theme->size, + theme->sizeincrease, + theme->alpha, + theme->alphafade, + theme->gravity, + theme->bounce, + org[0], + org[1], + org[2], + dir[0], + dir[1], + dir[2], + theme->airfriction, + theme->liquidfriction, + theme->originjitter, + theme->velocityjitter, + theme->qualityreduction, + theme->lifetime, + theme->stretch, + theme->blendmode, + theme->orientation, + theme->staincolor1, + theme->staincolor2, + theme->staintex, + theme->stainalpha, + theme->stainsize, + theme->angle, + theme->spin, + NULL); + } + if (!part) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2); + //part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3); + PRVM_G_FLOAT(OFS_RETURN) = 0; +} + +//==================== +//CSQC engine entities query +//==================== + +// float(float entitynum, float whatfld) getentity; +// vector(float entitynum, float whatfld) getentityvec; +// querying engine-drawn entity +// VorteX: currently it's only tested with whatfld = 1..7 +static void VM_CL_GetEntity (prvm_prog_t *prog) +{ + int entnum, fieldnum; + vec3_t forward, left, up, org; + VM_SAFEPARMCOUNT(2, VM_CL_GetEntityVec); + + entnum = PRVM_G_FLOAT(OFS_PARM0); + if (entnum < 0 || entnum >= cl.num_entities) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + fieldnum = PRVM_G_FLOAT(OFS_PARM1); + switch(fieldnum) + { + case 0: // active state + PRVM_G_FLOAT(OFS_RETURN) = cl.entities_active[entnum]; + break; + case 1: // origin + Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org); + VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 2: // forward + Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org); + VectorCopy(forward, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 3: // right + Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org); + VectorNegate(left, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 4: // up + Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org); + VectorCopy(up, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 5: // scale + PRVM_G_FLOAT(OFS_RETURN) = Matrix4x4_ScaleFromMatrix(&cl.entities[entnum].render.matrix); + break; + case 6: // origin + v_forward, v_right, v_up + Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorNegate(left, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 7: // alpha + PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.alpha; + break; + case 8: // colormor + VectorCopy(cl.entities[entnum].render.colormod, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 9: // pants colormod + VectorCopy(cl.entities[entnum].render.colormap_pantscolor, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 10: // shirt colormod + VectorCopy(cl.entities[entnum].render.colormap_shirtcolor, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 11: // skinnum + PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.skinnum; + break; + case 12: // mins + VectorCopy(cl.entities[entnum].render.mins, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 13: // maxs + VectorCopy(cl.entities[entnum].render.maxs, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 14: // absmin + Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org); + VectorAdd(cl.entities[entnum].render.mins, org, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 15: // absmax + Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org); + VectorAdd(cl.entities[entnum].render.maxs, org, PRVM_G_VECTOR(OFS_RETURN)); + break; + case 16: // light + VectorMA(cl.entities[entnum].render.modellight_ambient, 0.5, cl.entities[entnum].render.modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN)); + break; + default: + PRVM_G_FLOAT(OFS_RETURN) = 0; + break; + } +} + +//==================== +//QC POLYGON functions +//==================== + +//#304 void() renderscene (EXT_CSQC) +// moved that here to reset the polygons, +// resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0 +// --blub +static void VM_CL_R_RenderScene (prvm_prog_t *prog) +{ + double t = Sys_DirtyTime(); + vmpolygons_t *polys = &prog->vmpolygons; + VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene); + + // update the views + if(r_refdef.view.ismain) + { + // set the main view + csqc_main_r_refdef_view = r_refdef.view; + + // clear the flags so no other view becomes "main" unless CSQC sets VF_MAINVIEW + r_refdef.view.ismain = false; + csqc_original_r_refdef_view.ismain = false; + } + + // we need to update any RENDER_VIEWMODEL entities at this point because + // csqc supplies its own view matrix + CL_UpdateViewEntities(); + + // now draw stuff! + R_RenderView(); + + polys->num_vertices = polys->num_triangles = 0; + + // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView + t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0; + prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t; +} + +static void VM_ResizePolygons(vmpolygons_t *polys) +{ + float *oldvertex3f = polys->data_vertex3f; + float *oldcolor4f = polys->data_color4f; + float *oldtexcoord2f = polys->data_texcoord2f; + vmpolygons_triangle_t *oldtriangles = polys->data_triangles; + unsigned short *oldsortedelement3s = polys->data_sortedelement3s; + polys->max_vertices = min(polys->max_triangles*3, 65536); + polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3])); + polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4])); + polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2])); + polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t)); + polys->data_sortedelement3s = (unsigned short *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(unsigned short[3])); + if (polys->num_vertices) + { + memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3])); + memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4])); + memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2])); + } + if (polys->num_triangles) + { + memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t)); + memcpy(polys->data_sortedelement3s, oldsortedelement3s, polys->num_triangles*sizeof(unsigned short[3])); + } + if (oldvertex3f) + Mem_Free(oldvertex3f); + if (oldcolor4f) + Mem_Free(oldcolor4f); + if (oldtexcoord2f) + Mem_Free(oldtexcoord2f); + if (oldtriangles) + Mem_Free(oldtriangles); + if (oldsortedelement3s) + Mem_Free(oldsortedelement3s); +} + +static void VM_InitPolygons (vmpolygons_t* polys) +{ + memset(polys, 0, sizeof(*polys)); + polys->pool = Mem_AllocPool("VMPOLY", 0, NULL); + polys->max_triangles = 1024; + VM_ResizePolygons(polys); + polys->initialized = true; +} + +static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int surfacelistindex; + vmpolygons_t *polys = (vmpolygons_t *)ent; +// R_Mesh_ResetTextureState(); + R_EntityMatrix(&identitymatrix); + GL_CullFace(GL_NONE); + GL_DepthTest(true); // polys in 3D space shall always have depth test + GL_DepthRange(0, 1); + R_Mesh_PrepareVertices_Generic_Arrays(polys->num_vertices, polys->data_vertex3f, polys->data_color4f, polys->data_texcoord2f); + + for (surfacelistindex = 0;surfacelistindex < numsurfaces;) + { + int numtriangles = 0; + rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture; + int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag; + DrawQ_ProcessDrawFlag(drawflag, polys->data_triangles[surfacelist[surfacelistindex]].hasalpha); + R_SetupShader_Generic(tex, NULL, GL_MODULATE, 1, false, false, false); + numtriangles = 0; + for (;surfacelistindex < numsurfaces;surfacelistindex++) + { + if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag) + break; + VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles); + numtriangles++; + } + R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, NULL, 0, polys->data_sortedelement3s, NULL, 0); + } +} + +static void VMPolygons_Store(vmpolygons_t *polys) +{ + qboolean hasalpha; + int i; + + // detect if we have alpha + hasalpha = polys->begin_texture_hasalpha; + for(i = 0; !hasalpha && (i < polys->begin_vertices); ++i) + if(polys->begin_color[i][3] < 1) + hasalpha = true; + + if (polys->begin_draw2d) + { + // draw the polygon as 2D immediately + drawqueuemesh_t mesh; + mesh.texture = polys->begin_texture; + mesh.num_vertices = polys->begin_vertices; + mesh.num_triangles = polys->begin_vertices-2; + mesh.data_element3i = polygonelement3i; + mesh.data_element3s = polygonelement3s; + mesh.data_vertex3f = polys->begin_vertex[0]; + mesh.data_color4f = polys->begin_color[0]; + mesh.data_texcoord2f = polys->begin_texcoord[0]; + DrawQ_Mesh(&mesh, polys->begin_drawflag, hasalpha); + } + else + { + // queue the polygon as 3D for sorted transparent rendering later + int i; + if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2) + { + while (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2) + polys->max_triangles *= 2; + VM_ResizePolygons(polys); + } + if (polys->num_vertices + polys->begin_vertices <= polys->max_vertices) + { + // needle in a haystack! + // polys->num_vertices was used for copying where we actually want to copy begin_vertices + // that also caused it to not render the first polygon that is added + // --blub + memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->begin_vertices * sizeof(float[3])); + memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->begin_vertices * sizeof(float[4])); + memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->begin_vertices * sizeof(float[2])); + for (i = 0;i < polys->begin_vertices-2;i++) + { + polys->data_triangles[polys->num_triangles].texture = polys->begin_texture; + polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag; + polys->data_triangles[polys->num_triangles].elements[0] = polys->num_vertices; + polys->data_triangles[polys->num_triangles].elements[1] = polys->num_vertices + i+1; + polys->data_triangles[polys->num_triangles].elements[2] = polys->num_vertices + i+2; + polys->data_triangles[polys->num_triangles].hasalpha = hasalpha; + polys->num_triangles++; + } + polys->num_vertices += polys->begin_vertices; + } + } + polys->begin_active = false; +} + +// TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black] +// LordHavoc: agreed, this is a mess +void VM_CL_AddPolygonsToMeshQueue (prvm_prog_t *prog) +{ + int i; + vmpolygons_t *polys = &prog->vmpolygons; + vec3_t center; + + // only add polygons of the currently active prog to the queue - if there is none, we're done + if( !prog ) + return; + + if (!polys->num_triangles) + return; + + for (i = 0;i < polys->num_triangles;i++) + { + VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].elements[2], center); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, VM_DrawPolygonCallback, (entity_render_t *)polys, i, NULL); + } + + /*polys->num_triangles = 0; // now done after rendering the scene, + polys->num_vertices = 0; // otherwise it's not rendered at all and prints an error message --blub */ +} + +//void(string texturename, float flag[, float is2d]) R_BeginPolygon +static void VM_CL_R_PolygonBegin (prvm_prog_t *prog) +{ + const char *picname; + skinframe_t *sf; + vmpolygons_t *polys = &prog->vmpolygons; + int tf; + + // TODO instead of using skinframes here (which provides the benefit of + // better management of flags, and is more suited for 3D rendering), what + // about supporting Q3 shaders? + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_PolygonBegin); + + if (!polys->initialized) + VM_InitPolygons(polys); + if (polys->begin_active) + { + VM_Warning(prog, "VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n"); + return; + } + picname = PRVM_G_STRING(OFS_PARM0); + + sf = NULL; + if(*picname) + { + tf = TEXF_ALPHA; + if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP) + tf |= TEXF_MIPMAP; + + do + { + sf = R_SkinFrame_FindNextByName(sf, picname); + } + while(sf && sf->textureflags != tf); + + if(!sf || !sf->base) + sf = R_SkinFrame_LoadExternal(picname, tf, true); + + if(sf) + R_SkinFrame_MarkUsed(sf); + } + + polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white; + polys->begin_texture_hasalpha = (sf && sf->base) ? sf->hasalpha : false; + polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK; + polys->begin_vertices = 0; + polys->begin_active = true; + polys->begin_draw2d = (prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : r_refdef.draw2dstage); +} + +//void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex +static void VM_CL_R_PolygonVertex (prvm_prog_t *prog) +{ + vmpolygons_t *polys = &prog->vmpolygons; + + VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex); + + if (!polys->begin_active) + { + VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n"); + return; + } + + if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS) + { + VM_Warning(prog, "VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS); + return; + } + + polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0]; + polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1]; + polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2]; + polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0]; + polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1]; + polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0]; + polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1]; + polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2]; + polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3); + polys->begin_vertices++; +} + +//void() R_EndPolygon +static void VM_CL_R_PolygonEnd (prvm_prog_t *prog) +{ + vmpolygons_t *polys = &prog->vmpolygons; + + VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd); + if (!polys->begin_active) + { + VM_Warning(prog, "VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n"); + return; + } + polys->begin_active = false; + if (polys->begin_vertices >= 3) + VMPolygons_Store(polys); + else + VM_Warning(prog, "VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices); +} + +static vmpolygons_t debugPolys; + +void Debug_PolygonBegin(const char *picname, int drawflag) +{ + if(!debugPolys.initialized) + VM_InitPolygons(&debugPolys); + if(debugPolys.begin_active) + { + Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n"); + return; + } + debugPolys.begin_texture = picname[0] ? Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT)->tex : r_texture_white; + debugPolys.begin_drawflag = drawflag; + debugPolys.begin_vertices = 0; + debugPolys.begin_active = true; +} + +void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a) +{ + if(!debugPolys.begin_active) + { + Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n"); + return; + } + + if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS) + { + Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS); + return; + } + + debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x; + debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y; + debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z; + debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s; + debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t; + debugPolys.begin_color[debugPolys.begin_vertices][0] = r; + debugPolys.begin_color[debugPolys.begin_vertices][1] = g; + debugPolys.begin_color[debugPolys.begin_vertices][2] = b; + debugPolys.begin_color[debugPolys.begin_vertices][3] = a; + debugPolys.begin_vertices++; +} + +void Debug_PolygonEnd(void) +{ + if (!debugPolys.begin_active) + { + Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n"); + return; + } + debugPolys.begin_active = false; + if (debugPolys.begin_vertices >= 3) + VMPolygons_Store(&debugPolys); + else + Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices); +} + +/* +============= +CL_CheckBottom + +Returns false if any part of the bottom of the entity is off an edge that +is not a staircase. + +============= +*/ +static qboolean CL_CheckBottom (prvm_edict_t *ent) +{ + prvm_prog_t *prog = CLVM_prog; + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins); + VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, 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 (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY))) + goto realcheck; + } + + return true; // we got out easy + +realcheck: +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*sv_stepheight.value; + trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false); + + 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 = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value) + return false; + } + + return true; +} + +/* +============= +CL_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 and false is returned +============= +*/ +static qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace) +{ + prvm_prog_t *prog = CLVM_prog; + float dz; + vec3_t oldorg, neworg, end, traceendpos; + vec3_t mins, maxs, start; + trace_t trace; + int i, svent; + prvm_edict_t *enemy; + +// try the move + VectorCopy(PRVM_clientedictvector(ent, mins), mins); + VectorCopy(PRVM_clientedictvector(ent, maxs), maxs); + VectorCopy (PRVM_clientedictvector(ent, origin), oldorg); + VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg); + +// flying monsters don't step up + if ( (int)PRVM_clientedictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg); + enemy = PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy)); + if (i == 0 && enemy != prog->edicts) + { + dz = PRVM_clientedictvector(ent, origin)[2] - PRVM_clientedictvector(PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy)), origin)[2]; + if (dz > 40) + neworg[2] -= 8; + if (dz < 30) + neworg[2] += 8; + } + VectorCopy(PRVM_clientedictvector(ent, origin), start); + trace = CL_TraceBox(start, mins, maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true); + if (settrace) + CL_VM_SetTraceGlobals(prog, &trace, svent); + + if (trace.fraction == 1) + { + VectorCopy(trace.endpos, traceendpos); + if (((int)PRVM_clientedictfloat(ent, flags) & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK)) + return false; // swim monster left water + + VectorCopy (traceendpos, PRVM_clientedictvector(ent, origin)); + if (relink) + CL_LinkEdict(ent); + return true; + } + + if (enemy == prog->edicts) + break; + } + + return false; + } + +// push down from a step height above the wished position + neworg[2] += sv_stepheight.value; + VectorCopy (neworg, end); + end[2] -= sv_stepheight.value*2; + + trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true); + if (settrace) + CL_VM_SetTraceGlobals(prog, &trace, svent); + + if (trace.startsolid) + { + neworg[2] -= sv_stepheight.value; + trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true); + if (settrace) + CL_VM_SetTraceGlobals(prog, &trace, svent); + if (trace.startsolid) + return false; + } + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND ) + { + VectorAdd (PRVM_clientedictvector(ent, origin), move, PRVM_clientedictvector(ent, origin)); + if (relink) + CL_LinkEdict(ent); + PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_ONGROUND; + return true; + } + + return false; // walked off an edge + } + +// check point traces down for dangling corners + VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin)); + + if (!CL_CheckBottom (ent)) + { + if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + CL_LinkEdict(ent); + return true; + } + VectorCopy (oldorg, PRVM_clientedictvector(ent, origin)); + return false; + } + + if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND ) + PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_PARTIALGROUND; + + PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + +// the move is ok + if (relink) + CL_LinkEdict(ent); + return true; +} + +/* +=============== +VM_CL_walkmove + +float(float yaw, float dist[, settrace]) walkmove +=============== +*/ +static void VM_CL_walkmove (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + float yaw, dist; + vec3_t move; + mfunction_t *oldf; + int oldself; + qboolean settrace; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove); + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "walkmove: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "walkmove: can not modify free entity\n"); + return; + } + yaw = PRVM_G_FLOAT(OFS_PARM0); + dist = PRVM_G_FLOAT(OFS_PARM1); + settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2); + + if ( !( (int)PRVM_clientedictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + return; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + +// save program state, because CL_movestep may call other progs + oldf = prog->xfunction; + oldself = PRVM_clientglobaledict(self); + + PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace); + + +// restore program state + prog->xfunction = oldf; + PRVM_clientglobaledict(self) = oldself; +} + +/* +=============== +VM_CL_serverkey + +string(string key) serverkey +=============== +*/ +static void VM_CL_serverkey(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNT(1, VM_CL_serverkey); + InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +/* +================= +VM_CL_checkpvs + +Checks if an entity is in a point's PVS. +Should be fast but can be inexact. + +float checkpvs(vector viewpos, entity viewee) = #240; +================= +*/ +static void VM_CL_checkpvs (prvm_prog_t *prog) +{ + vec3_t viewpos; + prvm_edict_t *viewee; + vec3_t mi, ma; +#if 1 + unsigned char *pvs; +#else + int fatpvsbytes; + unsigned char fatpvs[MAX_MAP_LEAFS/8]; +#endif + + VM_SAFEPARMCOUNT(2, VM_SV_checkpvs); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos); + viewee = PRVM_G_EDICT(OFS_PARM1); + + if(viewee->priv.required->free) + { + VM_Warning(prog, "checkpvs: can not check free entity\n"); + PRVM_G_FLOAT(OFS_RETURN) = 4; + return; + } + + VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, mins), mi); + VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, maxs), ma); + +#if 1 + if(!cl.worldmodel || !cl.worldmodel->brush.GetPVS || !cl.worldmodel->brush.BoxTouchingPVS) + { + // no PVS support on this worldmodel... darn + PRVM_G_FLOAT(OFS_RETURN) = 3; + return; + } + pvs = cl.worldmodel->brush.GetPVS(cl.worldmodel, viewpos); + if(!pvs) + { + // viewpos isn't in any PVS... darn + PRVM_G_FLOAT(OFS_RETURN) = 2; + return; + } + PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, pvs, mi, ma); +#else + // using fat PVS like FTEQW does (slow) + if(!cl.worldmodel || !cl.worldmodel->brush.FatPVS || !cl.worldmodel->brush.BoxTouchingPVS) + { + // no PVS support on this worldmodel... darn + PRVM_G_FLOAT(OFS_RETURN) = 3; + return; + } + fatpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false); + if(!fatpvsbytes) + { + // viewpos isn't in any PVS... darn + PRVM_G_FLOAT(OFS_RETURN) = 2; + return; + } + PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, fatpvs, mi, ma); +#endif +} + +// #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex. +static void VM_CL_skel_create(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = CL_GetModelByIndex(modelindex); + skeleton_t *skeleton; + int i; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (!model || !model->num_bones) + return; + for (i = 0;i < MAX_EDICTS;i++) + if (!prog->skeletons[i]) + break; + if (i == MAX_EDICTS) + return; + prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t)); + PRVM_G_FLOAT(OFS_RETURN) = i + 1; + skeleton->model = model; + skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1); + // initialize to identity matrices + for (i = 0;i < skeleton->model->num_bones;i++) + skeleton->relativetransforms[i] = identitymatrix; +} + +// #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure +static void VM_CL_skel_build(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1); + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2); + float retainfrac = PRVM_G_FLOAT(OFS_PARM3); + int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1; + dp_model_t *model = CL_GetModelByIndex(modelindex); + int numblends; + int bonenum; + int blendindex; + framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS]; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + matrix4x4_t bonematrix; + matrix4x4_t matrix; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + firstbone = max(0, firstbone); + lastbone = min(lastbone, model->num_bones - 1); + lastbone = min(lastbone, skeleton->model->num_bones - 1); + VM_GenerateFrameGroupBlend(prog, framegroupblend, ed); + VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, cl.time); + for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++) + ; + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + { + memset(&bonematrix, 0, sizeof(bonematrix)); + for (blendindex = 0;blendindex < numblends;blendindex++) + { + Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); + Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp); + } + Matrix4x4_Normalize3(&bonematrix, &bonematrix); + Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac); + } + PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1; +} + +// #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton +static void VM_CL_skel_get_numbones(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones; +} + +// #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring) +static void VM_CL_skel_get_bonename(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + PRVM_G_INT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name); +} + +// #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +static void VM_CL_skel_get_boneparent(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1; +} + +// #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex +static void VM_CL_skel_find_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + const char *tagname = PRVM_G_STRING(OFS_PARM1); + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname); +} + +// #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) +static void VM_CL_skel_get_bonerel(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + matrix4x4_t matrix; + vec3_t forward, left, up, origin; + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + VectorClear(PRVM_clientglobalvector(v_forward)); + VectorClear(PRVM_clientglobalvector(v_right)); + VectorClear(PRVM_clientglobalvector(v_up)); + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + matrix = skeleton->relativetransforms[bonenum]; + Matrix4x4_ToVectors(&matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorNegate(left, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); +} + +// #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) +static void VM_CL_skel_get_boneabs(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + vec3_t forward, left, up, origin; + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + VectorClear(PRVM_clientglobalvector(v_forward)); + VectorClear(PRVM_clientglobalvector(v_right)); + VectorClear(PRVM_clientglobalvector(v_up)); + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + matrix = skeleton->relativetransforms[bonenum]; + // convert to absolute + while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0) + { + temp = matrix; + Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp); + } + Matrix4x4_ToVectors(&matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorNegate(left, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); +} + +// #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +static void VM_CL_skel_set_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + skeleton->relativetransforms[bonenum] = matrix; +} + +// #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +static void VM_CL_skel_mul_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin); + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + temp = skeleton->relativetransforms[bonenum]; + Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp); +} + +// #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) +static void VM_CL_skel_mul_bones(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1; + int bonenum; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin); + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + firstbone = max(0, firstbone); + lastbone = min(lastbone, skeleton->model->num_bones - 1); + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + { + temp = skeleton->relativetransforms[bonenum]; + Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp); + } +} + +// #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse +static void VM_CL_skel_copybones(prvm_prog_t *prog) +{ + int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1; + int bonenum; + skeleton_t *skeletondst; + skeleton_t *skeletonsrc; + if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst])) + return; + if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc])) + return; + firstbone = max(0, firstbone); + lastbone = min(lastbone, skeletondst->model->num_bones - 1); + lastbone = min(lastbone, skeletonsrc->model->num_bones - 1); + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum]; +} + +// #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) +static void VM_CL_skel_delete(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + Mem_Free(skeleton); + prog->skeletons[skeletonindex] = NULL; +} + +// #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found +static void VM_CL_frameforname(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = CL_GetModelByIndex(modelindex); + const char *name = PRVM_G_STRING(OFS_PARM1); + int i; + PRVM_G_FLOAT(OFS_RETURN) = -1; + if (!model || !model->animscenes) + return; + for (i = 0;i < model->numframes;i++) + { + if (!strcasecmp(model->animscenes[i].name, name)) + { + PRVM_G_FLOAT(OFS_RETURN) = i; + break; + } + } +} + +// #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. +static void VM_CL_frameduration(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = CL_GetModelByIndex(modelindex); + int framenum = (int)PRVM_G_FLOAT(OFS_PARM1); + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes) + return; + if (model->animscenes[framenum].framerate) + PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate; +} + +static void VM_CL_RotateMoves(prvm_prog_t *prog) +{ + /* + * Obscure builtin used by GAME_XONOTIC. + * + * Edits the input history of cl_movement by rotating all move commands + * currently in the queue using the given transform. + * + * The vector passed is an "angles transform" as used by warpzonelib, i.e. + * v_angle-like (non-inverted) euler angles that perform the rotation + * of the space that is to be done. + * + * This is meant to be used as a fixangle replacement after passing + * through a warpzone/portal: the client is told about the warp transform, + * and calls this function in the same frame as the one on which the + * client's origin got changed by the serverside teleport. Then this code + * transforms the pre-warp input (which matches the empty space behind + * the warp plane) into post-warp input (which matches the target area + * of the warp). Also, at the same time, the client has to use + * R_SetView to adjust VF_CL_VIEWANGLES according to the same transform. + * + * This together allows warpzone motion to be perfectly predicted by + * the client! + * + * Furthermore, for perfect warpzone behaviour, the server side also + * has to detect input the client sent before it received the origin + * update, but after the warp occurred on the server, and has to adjust + * input appropriately. + */ + matrix4x4_t m; + vec3_t v = {0, 0, 0}; + vec3_t a, x, y, z; + VM_SAFEPARMCOUNT(1, VM_CL_RotateMoves); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), a); + AngleVectorsFLU(a, x, y, z); + Matrix4x4_FromVectors(&m, x, y, z, v); + CL_RotateMoves(&m); +} + +// #358 void(string cubemapname) loadcubemap +static void VM_CL_loadcubemap(prvm_prog_t *prog) +{ + const char *name; + + VM_SAFEPARMCOUNT(1, VM_CL_loadcubemap); + name = PRVM_G_STRING(OFS_PARM0); + R_GetCubemap(name); +} + +#define REFDEFFLAG_TELEPORTED 1 +#define REFDEFFLAG_JUMPING 2 +#define REFDEFFLAG_DEAD 4 +#define REFDEFFLAG_INTERMISSION 8 +static void VM_CL_V_CalcRefdef(prvm_prog_t *prog) +{ + matrix4x4_t entrendermatrix; + vec3_t clviewangles; + vec3_t clvelocity; + qboolean teleported; + qboolean clonground; + qboolean clcmdjump; + qboolean cldead; + qboolean clintermission; + float clstatsviewheight; + prvm_edict_t *ent; + int flags; + + VM_SAFEPARMCOUNT(2, VM_CL_V_CalcRefdef); + ent = PRVM_G_EDICT(OFS_PARM0); + flags = PRVM_G_FLOAT(OFS_PARM1); + + // use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad) + CL_GetTagMatrix(prog, &entrendermatrix, ent, 0); + + VectorCopy(cl.csqc_viewangles, clviewangles); + teleported = (flags & REFDEFFLAG_TELEPORTED) != 0; + clonground = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_ONGROUND) != 0; + clcmdjump = (flags & REFDEFFLAG_JUMPING) != 0; + clstatsviewheight = PRVM_clientedictvector(ent, view_ofs)[2]; + cldead = (flags & REFDEFFLAG_DEAD) != 0; + clintermission = (flags & REFDEFFLAG_INTERMISSION) != 0; + VectorCopy(PRVM_clientedictvector(ent, velocity), clvelocity); + + V_CalcRefdefUsing(&entrendermatrix, clviewangles, teleported, clonground, clcmdjump, clstatsviewheight, cldead, clintermission, clvelocity); + + VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); + VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); + CSQC_R_RecalcView(); +} + +//============================================================================ + +// To create a almost working builtin file from this replace: +// "^NULL.*" with "" +// "^{.*//.*}:Wh\(.*\)" with "\1" +// "\:" with "//" +// "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;" +// "\n\n+" with "\n\n" + +prvm_builtin_t vm_cl_builtins[] = { +NULL, // #0 NULL function (not callable) (QUAKE) +VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE) +VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE) +VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE) +VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE) +NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE) +VM_break, // #6 void() break (QUAKE) +VM_random, // #7 float() random (QUAKE) +VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE) +VM_normalize, // #9 vector(vector v) normalize (QUAKE) +VM_error, // #10 void(string e) error (QUAKE) +VM_objerror, // #11 void(string e) objerror (QUAKE) +VM_vlen, // #12 float(vector v) vlen (QUAKE) +VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE) +VM_CL_spawn, // #14 entity() spawn (QUAKE) +VM_remove, // #15 void(entity e) remove (QUAKE) +VM_CL_traceline, // #16 void(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE) +NULL, // #17 entity() checkclient (QUAKE) +VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE) +VM_precache_sound, // #19 void(string s) precache_sound (QUAKE) +VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE) +NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE) +VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE) +NULL, // #23 void(string s, ...) bprint (QUAKE) +NULL, // #24 void(entity client, string s, ...) sprint (QUAKE) +VM_dprint, // #25 void(string s, ...) dprint (QUAKE) +VM_ftos, // #26 string(float f) ftos (QUAKE) +VM_vtos, // #27 string(vector v) vtos (QUAKE) +VM_coredump, // #28 void() coredump (QUAKE) +VM_traceon, // #29 void() traceon (QUAKE) +VM_traceoff, // #30 void() traceoff (QUAKE) +VM_eprint, // #31 void(entity e) eprint (QUAKE) +VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE) +NULL, // #33 (QUAKE) +VM_CL_droptofloor, // #34 float() droptofloor (QUAKE) +VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE) +VM_rint, // #36 float(float v) rint (QUAKE) +VM_floor, // #37 float(float v) floor (QUAKE) +VM_ceil, // #38 float(float v) ceil (QUAKE) +NULL, // #39 (QUAKE) +VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE) +VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE) +NULL, // #42 (QUAKE) +VM_fabs, // #43 float(float f) fabs (QUAKE) +NULL, // #44 vector(entity e, float speed) aim (QUAKE) +VM_cvar, // #45 float(string s) cvar (QUAKE) +VM_localcmd, // #46 void(string s) localcmd (QUAKE) +VM_nextent, // #47 entity(entity e) nextent (QUAKE) +VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE) +VM_changeyaw, // #49 void() ChangeYaw (QUAKE) +NULL, // #50 (QUAKE) +VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE) +NULL, // #52 void(float to, float f) WriteByte (QUAKE) +NULL, // #53 void(float to, float f) WriteChar (QUAKE) +NULL, // #54 void(float to, float f) WriteShort (QUAKE) +NULL, // #55 void(float to, float f) WriteLong (QUAKE) +NULL, // #56 void(float to, float f) WriteCoord (QUAKE) +NULL, // #57 void(float to, float f) WriteAngle (QUAKE) +NULL, // #58 void(float to, string s) WriteString (QUAKE) +NULL, // #59 (QUAKE) +VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) +VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) +VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) +VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) +VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) +VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) +NULL, // #66 (QUAKE) +NULL, // #67 void(float step) movetogoal (QUAKE) +VM_precache_file, // #68 string(string s) precache_file (QUAKE) +VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE) +NULL, // #70 void(string s) changelevel (QUAKE) +NULL, // #71 (QUAKE) +VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE) +NULL, // #73 void(entity client, strings) centerprint (QUAKE) +VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE) +VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE) +VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE) +VM_precache_file, // #77 string(string s) precache_file2 (QUAKE) +NULL, // #78 void(entity e) setspawnparms (QUAKE) +NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD) +NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD) +VM_stof, // #81 float(string s) stof (FRIK_FILE) +NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD) +NULL, // #83 (QUAKE) +NULL, // #84 (QUAKE) +NULL, // #85 (QUAKE) +NULL, // #86 (QUAKE) +NULL, // #87 (QUAKE) +NULL, // #88 (QUAKE) +NULL, // #89 (QUAKE) +VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX) +VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC) +VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT) +VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR) +VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND) +VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND) +VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND) +VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW) +VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT) +VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system) +// FrikaC and Telejano range #100-#199 +NULL, // #100 +NULL, // #101 +NULL, // #102 +NULL, // #103 +NULL, // #104 +NULL, // #105 +NULL, // #106 +NULL, // #107 +NULL, // #108 +NULL, // #109 +VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE) +VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE) +VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE) +VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE) +VM_strlen, // #114 float(string s) strlen (FRIK_FILE) +VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE) +VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE) +VM_stov, // #117 vector(string) stov (FRIK_FILE) +VM_strzone, // #118 string(string s) strzone (FRIK_FILE) +VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE) +NULL, // #120 +NULL, // #121 +NULL, // #122 +NULL, // #123 +NULL, // #124 +NULL, // #125 +NULL, // #126 +NULL, // #127 +NULL, // #128 +NULL, // #129 +NULL, // #130 +NULL, // #131 +NULL, // #132 +NULL, // #133 +NULL, // #134 +NULL, // #135 +NULL, // #136 +NULL, // #137 +NULL, // #138 +NULL, // #139 +NULL, // #140 +NULL, // #141 +NULL, // #142 +NULL, // #143 +NULL, // #144 +NULL, // #145 +NULL, // #146 +NULL, // #147 +NULL, // #148 +NULL, // #149 +NULL, // #150 +NULL, // #151 +NULL, // #152 +NULL, // #153 +NULL, // #154 +NULL, // #155 +NULL, // #156 +NULL, // #157 +NULL, // #158 +NULL, // #159 +NULL, // #160 +NULL, // #161 +NULL, // #162 +NULL, // #163 +NULL, // #164 +NULL, // #165 +NULL, // #166 +NULL, // #167 +NULL, // #168 +NULL, // #169 +NULL, // #170 +NULL, // #171 +NULL, // #172 +NULL, // #173 +NULL, // #174 +NULL, // #175 +NULL, // #176 +NULL, // #177 +NULL, // #178 +NULL, // #179 +NULL, // #180 +NULL, // #181 +NULL, // #182 +NULL, // #183 +NULL, // #184 +NULL, // #185 +NULL, // #186 +NULL, // #187 +NULL, // #188 +NULL, // #189 +NULL, // #190 +NULL, // #191 +NULL, // #192 +NULL, // #193 +NULL, // #194 +NULL, // #195 +NULL, // #196 +NULL, // #197 +NULL, // #198 +NULL, // #199 +// FTEQW range #200-#299 +NULL, // #200 +NULL, // #201 +NULL, // #202 +NULL, // #203 +NULL, // #204 +NULL, // #205 +NULL, // #206 +NULL, // #207 +NULL, // #208 +NULL, // #209 +NULL, // #210 +NULL, // #211 +NULL, // #212 +NULL, // #213 +NULL, // #214 +NULL, // #215 +NULL, // #216 +NULL, // #217 +VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT) +NULL, // #219 +NULL, // #220 +VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS) +VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS) +VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS) +VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS) +VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS) +VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS) +VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS) +VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) +VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +NULL, // #231 +NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC) +NULL, // #233 +NULL, // #234 +NULL, // #235 +NULL, // #236 +NULL, // #237 +NULL, // #238 +NULL, // #239 +VM_CL_checkpvs, // #240 +NULL, // #241 +NULL, // #242 +NULL, // #243 +NULL, // #244 +NULL, // #245 +NULL, // #246 +NULL, // #247 +NULL, // #248 +NULL, // #249 +NULL, // #250 +NULL, // #251 +NULL, // #252 +NULL, // #253 +NULL, // #254 +NULL, // #255 +NULL, // #256 +NULL, // #257 +NULL, // #258 +NULL, // #259 +NULL, // #260 +NULL, // #261 +NULL, // #262 +VM_CL_skel_create, // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex. +VM_CL_skel_build, // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure +VM_CL_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton +VM_CL_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring) +VM_CL_skel_get_boneparent, // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +VM_CL_skel_find_bone, // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex +VM_CL_skel_get_bonerel, // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) +VM_CL_skel_get_boneabs, // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) +VM_CL_skel_set_bone, // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +VM_CL_skel_mul_bone, // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +VM_CL_skel_mul_bones, // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) +VM_CL_skel_copybones, // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse +VM_CL_skel_delete, // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) +VM_CL_frameforname, // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found +VM_CL_frameduration, // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. +NULL, // #278 +NULL, // #279 +NULL, // #280 +NULL, // #281 +NULL, // #282 +NULL, // #283 +NULL, // #284 +NULL, // #285 +NULL, // #286 +NULL, // #287 +NULL, // #288 +NULL, // #289 +NULL, // #290 +NULL, // #291 +NULL, // #292 +NULL, // #293 +NULL, // #294 +NULL, // #295 +NULL, // #296 +NULL, // #297 +NULL, // #298 +NULL, // #299 +// CSQC range #300-#399 +VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC) +VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC) +VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC) +VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC) +VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC) +VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC) +VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag, float is2d[NYI: , float lines]) R_BeginPolygon +VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex +VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon +VM_CL_R_SetView, // #309 float(float property) getproperty (EXT_CSQC) +VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC) +VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC) +NULL, // #312 +NULL, // #313 +NULL, // #314 +VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC) +VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC) +VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC) +VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC) +VM_freepic, // #319 void(string name) freepic (EXT_CSQC) +VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC) +VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha[, float flag]) drawstring (EXT_CSQC, DP_CSQC) +VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha[, float flag]) drawpic (EXT_CSQC) +VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC) +VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea +VM_drawresetcliparea, // #325 void(void) drawresetcliparea +VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC) +VM_stringwidth, // #327 // FIXME is this okay? +VM_drawsubpic, // #328 // FIXME is this okay? +VM_drawrotpic, // #329 // FIXME is this okay? +VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC) +VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC) +VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC) +VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) +VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC) +VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC) +VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC) +VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC) +VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC) +VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT) +VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC) +VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC) +VM_getkeybind, // #342 string(float keynum[, float bindmap]) getkeybind (EXT_CSQC) +VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (DP_CSQC) +VM_CL_getmousepos, // #344 vector() getmousepos (DP_CSQC) +VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC) +VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC) +VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC) +VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC) +VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC) +VM_isserver, // #350 float() isserver (EXT_CSQC) +VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC) +VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC) +VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too) +VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC) +VM_CL_videoplaying, // #355 +VM_findfont, // #356 float(string fontname) loadfont (DP_GFX_FONTS) +VM_loadfont, // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS) +VM_CL_loadcubemap, // #358 void(string cubemapname) loadcubemap (DP_GFX_) +NULL, // #359 +VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC) +VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC) +VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC) +VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC) +VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC) +VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC) +VM_CL_ReadString, // #366 string() readstring (EXT_CSQC) +VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC) +NULL, // #368 +NULL, // #369 +NULL, // #370 +NULL, // #371 +NULL, // #372 +NULL, // #373 +NULL, // #374 +NULL, // #375 +NULL, // #376 +NULL, // #377 +NULL, // #378 +NULL, // #379 +NULL, // #380 +NULL, // #381 +NULL, // #382 +NULL, // #383 +NULL, // #384 +NULL, // #385 +NULL, // #386 +NULL, // #387 +NULL, // #388 +NULL, // #389 +NULL, // #390 +NULL, // #391 +NULL, // #392 +NULL, // #393 +NULL, // #394 +NULL, // #395 +NULL, // #396 +NULL, // #397 +NULL, // #398 +NULL, // #399 +// LordHavoc's range #400-#499 +VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) +NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR) +VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN) +VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT) +VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT) +VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD) +VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER) +VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB) +VM_CL_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE) +VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN) +VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW) +VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK) +VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1) +VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1) +VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1) +VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1) +VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH) +VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH) +VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS) +VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) +VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS) +VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) +VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) +VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) +VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) +VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) +VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) +VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) +NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) +VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH) +VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH) +VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH) +VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH) +VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING) +VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS) +VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS) +VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO) +VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO) +NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT) +NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT) +NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT) +NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING) +VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET) +NULL, // #458 +VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM) +VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS) +VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS) +VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS) +VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS) +VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS) +VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS) +VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS) +VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS) +VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS) +VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS) +NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC) +VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN) +VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN) +VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN) +VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN) +VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN) +VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS) +VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS) +VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME) +VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR) +VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS) +VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS) +VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING) +VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND) +VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE) +VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE) +VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute +VM_gecko_create, // #487 float gecko_create( string name ) +VM_gecko_destroy, // #488 void gecko_destroy( string name ) +VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI ) +VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype ) +VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y ) +VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h ) +VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name ) +VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16) +VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE) +VM_numentityfields, // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA) +VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA) +VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA) +VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA) +VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA) +VM_CL_ReadPicture, // #501 string() ReadPicture = #501; +VM_CL_boxparticles, // #502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count) boxparticles (DP_CSQC_BOXPARTICLES) +VM_whichpack, // #503 string(string) whichpack = #503; +VM_CL_GetEntity, // #504 float(float entitynum, float fldnum) getentity = #504; vector(float entitynum, float fldnum) getentityvec = #504; +NULL, // #505 +NULL, // #506 +NULL, // #507 +NULL, // #508 +NULL, // #509 +VM_uri_escape, // #510 string(string in) uri_escape = #510; +VM_uri_unescape, // #511 string(string in) uri_unescape = #511; +VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT) +VM_uri_get, // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST) +VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE) +VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST) +VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION) +VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME) +VM_keynumtostring, // #520 string keynumtostring(float keynum) +VM_findkeysforcommand, // #521 string findkeysforcommand(string command[, float bindmap]) +VM_CL_InitParticleSpawner, // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE) +VM_CL_ResetParticle, // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleTheme, // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleThemeSave, // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE) +VM_CL_ParticleThemeFree, // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE) +VM_CL_SpawnParticle, // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE) +VM_CL_SpawnParticleDelayed, // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE) +VM_loadfromdata, // #529 +VM_loadfromfile, // #530 +VM_CL_setpause, // #531 float(float ispaused) setpause = #531 (DP_CSQC_SETPAUSE) +VM_log, // #532 +VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME) +VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME) +VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP) +NULL, // #539 +VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE) +VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE) +VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE) +NULL, // #543 +NULL, // #544 +NULL, // #545 +NULL, // #546 +NULL, // #547 +NULL, // #548 +NULL, // #549 +NULL, // #550 +NULL, // #551 +NULL, // #552 +NULL, // #553 +NULL, // #554 +NULL, // #555 +NULL, // #556 +NULL, // #557 +NULL, // #558 +NULL, // #559 +NULL, // #560 +NULL, // #561 +NULL, // #562 +NULL, // #563 +NULL, // #564 +NULL, // #565 +NULL, // #566 +NULL, // #567 +NULL, // #568 +NULL, // #569 +NULL, // #570 +NULL, // #571 +NULL, // #572 +NULL, // #573 +NULL, // #574 +NULL, // #575 +NULL, // #576 +NULL, // #577 +NULL, // #578 +NULL, // #579 +NULL, // #580 +NULL, // #581 +NULL, // #582 +NULL, // #583 +NULL, // #584 +NULL, // #585 +NULL, // #586 +NULL, // #587 +NULL, // #588 +NULL, // #589 +NULL, // #590 +NULL, // #591 +NULL, // #592 +NULL, // #593 +NULL, // #594 +NULL, // #595 +NULL, // #596 +NULL, // #597 +NULL, // #598 +NULL, // #599 +NULL, // #600 +NULL, // #601 +NULL, // #602 +NULL, // #603 +NULL, // #604 +VM_callfunction, // #605 +VM_writetofile, // #606 +VM_isfunction, // #607 +NULL, // #608 +NULL, // #609 +VM_findkeysforcommand, // #610 string findkeysforcommand(string command[, float bindmap]) +NULL, // #611 +NULL, // #612 +VM_parseentitydata, // #613 +NULL, // #614 +NULL, // #615 +NULL, // #616 +NULL, // #617 +NULL, // #618 +NULL, // #619 +NULL, // #620 +NULL, // #621 +NULL, // #622 +NULL, // #623 +VM_CL_getextresponse, // #624 string getextresponse(void) +NULL, // #625 +NULL, // #626 +VM_sprintf, // #627 string sprintf(string format, ...) +VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE) +VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE) +VM_setkeybind, // #630 float(float key, string bind[, float bindmap]) setkeybind +VM_getbindmaps, // #631 vector(void) getbindmap +VM_setbindmaps, // #632 float(vector bm) setbindmap +NULL, // #633 +NULL, // #634 +NULL, // #635 +NULL, // #636 +NULL, // #637 +VM_CL_RotateMoves, // #638 +VM_digest_hex, // #639 +VM_CL_V_CalcRefdef, // #640 void(entity e) V_CalcRefdef (DP_CSQC_V_CALCREFDEF) +NULL, // #641 +}; + +const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); + +void VM_Polygons_Reset(prvm_prog_t *prog) +{ + vmpolygons_t *polys = &prog->vmpolygons; + + // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system + if(polys->initialized) + { + Mem_FreePool(&polys->pool); + polys->initialized = false; + } +} + +void CLVM_init_cmd(prvm_prog_t *prog) +{ + VM_Cmd_Init(prog); + VM_Polygons_Reset(prog); +} + +void CLVM_reset_cmd(prvm_prog_t *prog) +{ + World_End(&cl.world); + VM_Cmd_Reset(prog); + VM_Polygons_Reset(prog); +} diff --git a/app/jni/clvm_cmds.h b/app/jni/clvm_cmds.h new file mode 100644 index 0000000..259991f --- /dev/null +++ b/app/jni/clvm_cmds.h @@ -0,0 +1,27 @@ +#ifndef __CLVM_CMDS_H__ +#define __CLVM_CMDS_H__ + +/* These are VM built-ins that originate in the client-side programs support + but are reused by the other programs (usually the menu). */ + +void VM_CL_setmodel (void); +void VM_CL_precache_model (void); +void VM_CL_setorigin (void); + +void VM_CL_R_AddDynamicLight (void); +void VM_CL_R_ClearScene (void); +void VM_CL_R_AddEntities (void); +void VM_CL_R_AddEntity (void); +void VM_CL_R_SetView (void); +void VM_CL_R_RenderScene (void); +void VM_CL_R_LoadWorldModel (void); + +void VM_CL_R_PolygonBegin (void); +void VM_CL_R_PolygonVertex (void); +void VM_CL_R_PolygonEnd (void); + +void VM_CL_setattachment(void); +void VM_CL_gettagindex(void); +void VM_CL_gettaginfo(void); + +#endif /* __CLVM_CMDS_H__ */ diff --git a/app/jni/cmd.c b/app/jni/cmd.c new file mode 100644 index 0000000..ea48614 --- /dev/null +++ b/app/jni/cmd.c @@ -0,0 +1,2233 @@ +/* +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" +#include "thread.h" + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; + qboolean initstate; // indicates this command existed at init + char *initialvalue; // backup copy of value at init +} cmdalias_t; + +static cmdalias_t *cmd_alias; + +static qboolean cmd_wait; + +static mempool_t *cmd_mempool; + +static char cmd_tokenizebuffer[CMD_TOKENIZELENGTH]; +static int cmd_tokenizebufferpos = 0; + +//============================================================================= + +/* +============ +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" +============ +*/ +static void Cmd_Wait_f (void) +{ + cmd_wait = true; +} + +typedef struct cmddeferred_s +{ + struct cmddeferred_s *next; + char *value; + double delay; +} cmddeferred_t; + +static cmddeferred_t *cmd_deferred_list = NULL; + +/* +============ +Cmd_Defer_f + +Cause a command to be executed after a delay. +============ +*/ +static void Cmd_Defer_f (void) +{ + if(Cmd_Argc() == 1) + { + cmddeferred_t *next = cmd_deferred_list; + if(!next) + Con_Printf("No commands are pending.\n"); + while(next) + { + Con_Printf("-> In %9.2f: %s\n", next->delay, next->value); + next = next->next; + } + } else if(Cmd_Argc() == 2 && !strcasecmp("clear", Cmd_Argv(1))) + { + while(cmd_deferred_list) + { + cmddeferred_t *cmd = cmd_deferred_list; + cmd_deferred_list = cmd->next; + Mem_Free(cmd->value); + Mem_Free(cmd); + } + } else if(Cmd_Argc() == 3) + { + const char *value = Cmd_Argv(2); + cmddeferred_t *defcmd = (cmddeferred_t*)Mem_Alloc(tempmempool, sizeof(*defcmd)); + size_t len = strlen(value); + + defcmd->delay = atof(Cmd_Argv(1)); + defcmd->value = (char*)Mem_Alloc(tempmempool, len+1); + memcpy(defcmd->value, value, len+1); + defcmd->next = NULL; + + if(cmd_deferred_list) + { + cmddeferred_t *next = cmd_deferred_list; + while(next->next) + next = next->next; + next->next = defcmd; + } else + cmd_deferred_list = defcmd; + /* Stupid me... this changes the order... so commands with the same delay go blub :S + defcmd->next = cmd_deferred_list; + cmd_deferred_list = defcmd;*/ + } else { + Con_Printf("usage: defer \n" + " defer clear\n"); + return; + } +} + +/* +============ +Cmd_Centerprint_f + +Print something to the center of the screen using SCR_Centerprint +============ +*/ +static void Cmd_Centerprint_f (void) +{ + char msg[MAX_INPUTLINE]; + unsigned int i, c, p; + c = Cmd_Argc(); + if(c >= 2) + { + strlcpy(msg, Cmd_Argv(1), sizeof(msg)); + for(i = 2; i < c; ++i) + { + strlcat(msg, " ", sizeof(msg)); + strlcat(msg, Cmd_Argv(i), sizeof(msg)); + } + c = strlen(msg); + for(p = 0, i = 0; i < c; ++i) + { + if(msg[i] == '\\') + { + if(msg[i+1] == 'n') + msg[p++] = '\n'; + else if(msg[i+1] == '\\') + msg[p++] = '\\'; + else { + msg[p++] = '\\'; + msg[p++] = msg[i+1]; + } + ++i; + } else { + msg[p++] = msg[i]; + } + } + msg[p] = '\0'; + SCR_CenterPrint(msg); + } +} + +/* +============================================================================= + + COMMAND BUFFER + +============================================================================= +*/ + +static sizebuf_t cmd_text; +static unsigned char cmd_text_buf[CMDBUFSIZE]; +void *cmd_text_mutex = NULL; + +#define Cbuf_LockThreadMutex() (void)(cmd_text_mutex ? Thread_LockMutex(cmd_text_mutex) : 0) +#define Cbuf_UnlockThreadMutex() (void)(cmd_text_mutex ? Thread_UnlockMutex(cmd_text_mutex) : 0) + +/* +============ +Cbuf_AddText + +Adds command text at the end of the buffer +============ +*/ +void Cbuf_AddText (const char *text) +{ + int l; + + l = (int)strlen(text); + + Cbuf_LockThreadMutex(); + if (cmd_text.cursize + l >= cmd_text.maxsize) + Con_Print("Cbuf_AddText: overflow\n"); + else + SZ_Write(&cmd_text, (const unsigned char *)text, l); + Cbuf_UnlockThreadMutex(); +} + + +/* +============ +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 (const char *text) +{ + size_t l = strlen(text); + Cbuf_LockThreadMutex(); + // we need to memmove the existing text and stuff this in before it... + if (cmd_text.cursize + l >= (size_t)cmd_text.maxsize) + Con_Print("Cbuf_InsertText: overflow\n"); + else + { + // we don't have a SZ_Prepend, so... + memmove(cmd_text.data + l, cmd_text.data, cmd_text.cursize); + cmd_text.cursize += l; + memcpy(cmd_text.data, text, l); + } + Cbuf_UnlockThreadMutex(); +} + +/* +============ +Cbuf_Execute_Deferred --blub +============ +*/ +static void Cbuf_Execute_Deferred (void) +{ + static double oldrealtime = 0; + cmddeferred_t *cmd, *prev; + double eat; + if (realtime - oldrealtime < 0 || realtime - oldrealtime > 1800) oldrealtime = realtime; + eat = realtime - oldrealtime; + if (eat < (1.0 / 120.0)) + return; + oldrealtime = realtime; + prev = NULL; + cmd = cmd_deferred_list; + while(cmd) + { + cmd->delay -= eat; + if(cmd->delay <= 0) + { + Cbuf_AddText(cmd->value); + Cbuf_AddText(";\n"); + Mem_Free(cmd->value); + + if(prev) { + prev->next = cmd->next; + Mem_Free(cmd); + cmd = prev->next; + } else { + cmd_deferred_list = cmd->next; + Mem_Free(cmd); + cmd = cmd_deferred_list; + } + continue; + } + prev = cmd; + cmd = cmd->next; + } +} + +/* +============ +Cbuf_Execute +============ +*/ +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ); +void Cbuf_Execute (void) +{ + int i; + char *text; + char line[MAX_INPUTLINE]; + char preprocessed[MAX_INPUTLINE]; + char *firstchar; + qboolean quotes; + char *comment; + + // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes + cmd_tokenizebufferpos = 0; + + while (cmd_text.cursize) + { +// find a \n or ; line break + text = (char *)cmd_text.data; + + quotes = false; + comment = NULL; + for (i=0 ; i < cmd_text.cursize ; i++) + { + if(!comment) + { + if (text[i] == '"') + quotes = !quotes; + + if(quotes) + { + // make sure i doesn't get > cursize which causes a negative + // size in memmove, which is fatal --blub + if (i < (cmd_text.cursize-1) && (text[i] == '\\' && (text[i+1] == '"' || text[i+1] == '\\'))) + i++; + } + else + { + if(text[i] == '/' && text[i + 1] == '/' && (i == 0 || ISWHITESPACE(text[i-1]))) + comment = &text[i]; + if(text[i] == ';') + break; // don't break if inside a quoted string or comment + } + } + + if (text[i] == '\r' || text[i] == '\n') + break; + } + + // better than CRASHING on overlong input lines that may SOMEHOW enter the buffer + if(i >= MAX_INPUTLINE) + { + Con_Printf("Warning: console input buffer had an overlong line. Ignored.\n"); + line[0] = 0; + } + else + { + memcpy (line, text, comment ? (comment - text) : i); + line[comment ? (comment - text) : 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; + memmove (cmd_text.data, text+i, cmd_text.cursize); + } + +// execute the command line + firstchar = line; + while(*firstchar && ISWHITESPACE(*firstchar)) + ++firstchar; + if( + (strncmp(firstchar, "alias", 5) || !ISWHITESPACE(firstchar[5])) + && + (strncmp(firstchar, "bind", 4) || !ISWHITESPACE(firstchar[4])) + && + (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])) + ) + { + if(Cmd_PreprocessString( line, preprocessed, sizeof(preprocessed), NULL )) + Cmd_ExecuteString (preprocessed, src_command, false); + } + else + { + Cmd_ExecuteString (line, src_command, false); + } + + if (cmd_wait) + { // skip out while text still remains in buffer, leaving it + // for next frame + cmd_wait = false; + break; + } + } +} + +void Cbuf_Frame(void) +{ + Cbuf_Execute_Deferred(); + if (cmd_text.cursize) + { + SV_LockThreadMutex(); + Cbuf_Execute(); + SV_UnlockThreadMutex(); + } +} + +/* +============================================================================== + + 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 +=============== +*/ +qboolean host_stuffcmdsrun = false; +static void Cmd_StuffCmds_f (void) +{ + int i, j, l; + // this is for all commandline options combined (and is bounds checked) + char build[MAX_INPUTLINE]; + + if (Cmd_Argc () != 1) + { + Con_Print("stuffcmds : execute command line parameters\n"); + return; + } + + // no reason to run the commandline arguments twice + if (host_stuffcmdsrun) + return; + + host_stuffcmdsrun = true; + build[0] = 0; + l = 0; + for (i = 0;i < com_argc;i++) + { + if (com_argv[i] && com_argv[i][0] == '+' && (com_argv[i][1] < '0' || com_argv[i][1] > '9') && l + strlen(com_argv[i]) - 1 <= sizeof(build) - 1) + { + j = 1; + while (com_argv[i][j]) + build[l++] = com_argv[i][j++]; + i++; + for (;i < com_argc;i++) + { + if (!com_argv[i]) + continue; + if ((com_argv[i][0] == '+' || com_argv[i][0] == '-') && (com_argv[i][1] < '0' || com_argv[i][1] > '9')) + break; + if (l + strlen(com_argv[i]) + 4 > sizeof(build) - 1) + break; + build[l++] = ' '; + if (strchr(com_argv[i], ' ')) + build[l++] = '\"'; + for (j = 0;com_argv[i][j];j++) + build[l++] = com_argv[i][j]; + if (strchr(com_argv[i], ' ')) + build[l++] = '\"'; + } + build[l++] = '\n'; + i--; + } + } + // now terminate the combined string and prepend it to the command buffer + // we already reserved space for the terminator + build[l++] = 0; + Cbuf_InsertText (build); +} + +static void Cmd_Exec(const char *filename) +{ + char *f; + size_t filenameLen = strlen(filename); + qboolean isdefaultcfg = filenameLen >= 11 && !strcmp(filename + filenameLen - 11, "default.cfg"); + + if (!strcmp(filename, "config.cfg")) + { + filename = CONFIGFILENAME; + if (COM_CheckParm("-noconfig")) + return; // don't execute config.cfg + } + + f = (char *)FS_LoadFile (filename, tempmempool, false, NULL); + if (!f) + { + Con_Printf("couldn't exec %s\n",filename); + return; + } + Con_Printf("execing %s\n",filename); + + // if executing default.cfg for the first time, lock the cvar defaults + // it may seem backwards to insert this text BEFORE the default.cfg + // but Cbuf_InsertText inserts before, so this actually ends up after it. + if (isdefaultcfg) + Cbuf_InsertText("\ncvar_lockdefaults\n"); + + // insert newline after the text to make sure the last line is terminated (some text editors omit the trailing newline) + // (note: insertion order here is backwards from execution order, so this adds it after the text, by calling it before...) + Cbuf_InsertText ("\n"); + Cbuf_InsertText (f); + Mem_Free(f); + + if (isdefaultcfg) + { + // special defaults for specific games go here, these execute before default.cfg + // Nehahra pushable crates malfunction in some levels if this is on + // Nehahra NPC AI is confused by blowupfallenzombies + switch(gamemode) + { + case GAME_NORMAL: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + case GAME_NEHAHRA: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + // hipnotic mission pack has issues in their 'friendly monster' ai, which seem to attempt to attack themselves for some reason when findradius() returns non-solid entities. + // hipnotic mission pack has issues with bobbing water entities 'jittering' between different heights on alternate frames at the default 0.0138889 ticrate, 0.02 avoids this issue + // hipnotic mission pack has issues in their proximity mine sticking code, which causes them to bounce off. + case GAME_HIPNOTIC: + case GAME_QUOTH: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.02\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area + case GAME_ROGUE: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 1\n" +"r_shadow_bumpscale_basetexture 0\n" + ); + break; + case GAME_TENEBRAE: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 0\n" +"sv_gameplayfix_findradiusdistancetobox 0\n" +"sv_gameplayfix_grenadebouncedownslopes 0\n" +"sv_gameplayfix_slidemoveprojectiles 0\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 0\n" +"sv_gameplayfix_setmodelrealbox 0\n" +"sv_gameplayfix_droptofloorstartsolid 0\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 0\n" +"sv_gameplayfix_noairborncorpse 0\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 0\n" +"sv_gameplayfix_easierwaterjump 0\n" +"sv_gameplayfix_delayprojectiles 0\n" +"sv_gameplayfix_multiplethinksperframe 0\n" +"sv_gameplayfix_fixedcheckwatertransition 0\n" +"sv_gameplayfix_q1bsptracelinereportstexture 0\n" +"sv_gameplayfix_swiminbmodels 0\n" +"sv_gameplayfix_downtracesupportsongroundflag 0\n" +"sys_ticrate 0.01388889\n" +"r_shadow_gloss 2\n" +"r_shadow_bumpscale_basetexture 4\n" + ); + break; + case GAME_NEXUIZ: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" +"sv_gameplayfix_q2airaccelerate 1\n" +"sv_gameplayfix_stepmultipletimes 1\n" + ); + break; + // Steel Storm: Burning Retribution csqc misinterprets CSQC_InputEvent if type is a value other than 0 or 1 + case GAME_STEELSTORM: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" +"cl_csqc_generatemousemoveevents 0\n" + ); + break; + default: + Cbuf_InsertText("\n" +"sv_gameplayfix_blowupfallenzombies 1\n" +"sv_gameplayfix_findradiusdistancetobox 1\n" +"sv_gameplayfix_grenadebouncedownslopes 1\n" +"sv_gameplayfix_slidemoveprojectiles 1\n" +"sv_gameplayfix_upwardvelocityclearsongroundflag 1\n" +"sv_gameplayfix_setmodelrealbox 1\n" +"sv_gameplayfix_droptofloorstartsolid 1\n" +"sv_gameplayfix_droptofloorstartsolid_nudgetocorrect 1\n" +"sv_gameplayfix_noairborncorpse 1\n" +"sv_gameplayfix_noairborncorpse_allowsuspendeditems 1\n" +"sv_gameplayfix_easierwaterjump 1\n" +"sv_gameplayfix_delayprojectiles 1\n" +"sv_gameplayfix_multiplethinksperframe 1\n" +"sv_gameplayfix_fixedcheckwatertransition 1\n" +"sv_gameplayfix_q1bsptracelinereportstexture 1\n" +"sv_gameplayfix_swiminbmodels 1\n" +"sv_gameplayfix_downtracesupportsongroundflag 1\n" +"sys_ticrate 0.01388889\n" + ); + break; + } + } +} + +/* +=============== +Cmd_Exec_f +=============== +*/ +static void Cmd_Exec_f (void) +{ + fssearch_t *s; + int i; + + if (Cmd_Argc () != 2) + { + Con_Print("exec : execute a script file\n"); + return; + } + + s = FS_Search(Cmd_Argv(1), true, true); + if(!s || !s->numfilenames) + { + Con_Printf("couldn't exec %s\n",Cmd_Argv(1)); + return; + } + + for(i = 0; i < s->numfilenames; ++i) + Cmd_Exec(s->filenames[i]); + + FS_FreeSearch(s); +} + + +/* +=============== +Cmd_Echo_f + +Just prints the rest of the line to the console +=============== +*/ +static void Cmd_Echo_f (void) +{ + int i; + + for (i=1 ; i - toggles between 0 and 1\n toggle - toggles between 0 and \n toggle [string 1] [string 2]...[string n] - cycles through all strings\n"); + else + { // Correct Arguments Specified + // Acquire Potential CVar + cvar_t* cvCVar = Cvar_FindVar( Cmd_Argv(1) ); + + if(cvCVar != NULL) + { // Valid CVar + if(nNumArgs == 2) + { // Default Usage + if(cvCVar->integer) + Cvar_SetValueQuick(cvCVar, 0); + else + Cvar_SetValueQuick(cvCVar, 1); + } + else + if(nNumArgs == 3) + { // 0 and Specified Usage + if(cvCVar->integer == atoi(Cmd_Argv(2) ) ) + // CVar is Specified Value; // Reset to 0 + Cvar_SetValueQuick(cvCVar, 0); + else + if(cvCVar->integer == 0) + // CVar is 0; Specify Value + Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + else + // CVar does not match; Reset to 0 + Cvar_SetValueQuick(cvCVar, 0); + } + else + { // Variable Values Specified + int nCnt; + int bFound = 0; + + for(nCnt = 2; nCnt < nNumArgs; nCnt++) + { // Cycle through Values + if( strcmp(cvCVar->string, Cmd_Argv(nCnt) ) == 0) + { // Current Value Located; Increment to Next + if( (nCnt + 1) == nNumArgs) + // Max Value Reached; Reset + Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + else + // Next Value + Cvar_SetQuick(cvCVar, Cmd_Argv(nCnt + 1) ); + + // End Loop + nCnt = nNumArgs; + // Assign Found + bFound = 1; + } + } + if(!bFound) + // Value not Found; Reset to Original + Cvar_SetQuick(cvCVar, Cmd_Argv(2) ); + } + + } + else + { // Invalid CVar + Con_Printf("ERROR : CVar '%s' not found\n", Cmd_Argv(1) ); + } + } +} + +/* +=============== +Cmd_Alias_f + +Creates a new command that executes a command string (possibly ; seperated) +=============== +*/ +static void Cmd_Alias_f (void) +{ + cmdalias_t *a; + char cmd[MAX_INPUTLINE]; + int i, c; + const char *s; + size_t alloclen; + + if (Cmd_Argc() == 1) + { + Con_Print("Current alias commands:\n"); + for (a = cmd_alias ; a ; a=a->next) + Con_Printf("%s : %s", a->name, a->value); + return; + } + + s = Cmd_Argv(1); + if (strlen(s) >= MAX_ALIAS_NAME) + { + Con_Print("Alias name is too long\n"); + return; + } + + // if the alias already exists, reuse it + for (a = cmd_alias ; a ; a=a->next) + { + if (!strcmp(s, a->name)) + { + Z_Free (a->value); + break; + } + } + + if (!a) + { + cmdalias_t *prev, *current; + + a = (cmdalias_t *)Z_Malloc (sizeof(cmdalias_t)); + strlcpy (a->name, s, sizeof (a->name)); + // insert it at the right alphanumeric position + for( prev = NULL, current = cmd_alias ; current && strcmp( current->name, a->name ) < 0 ; prev = current, current = current->next ) + ; + if( prev ) { + prev->next = a; + } else { + cmd_alias = a; + } + a->next = current; + } + + +// 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++) + { + if (i != 2) + strlcat (cmd, " ", sizeof (cmd)); + strlcat (cmd, Cmd_Argv(i), sizeof (cmd)); + } + strlcat (cmd, "\n", sizeof (cmd)); + + alloclen = strlen (cmd) + 1; + if(alloclen >= 2) + cmd[alloclen - 2] = '\n'; // to make sure a newline is appended even if too long + a->value = (char *)Z_Malloc (alloclen); + memcpy (a->value, cmd, alloclen); +} + +/* +=============== +Cmd_UnAlias_f + +Remove existing aliases. +=============== +*/ +static void Cmd_UnAlias_f (void) +{ + cmdalias_t *a, *p; + int i; + const char *s; + + if(Cmd_Argc() == 1) + { + Con_Print("unalias: Usage: unalias alias1 [alias2 ...]\n"); + return; + } + + for(i = 1; i < Cmd_Argc(); ++i) + { + s = Cmd_Argv(i); + p = NULL; + for(a = cmd_alias; a; p = a, a = a->next) + { + if(!strcmp(s, a->name)) + { + if (a->initstate) // we can not remove init aliases + continue; + if(a == cmd_alias) + cmd_alias = a->next; + if(p) + p->next = a->next; + Z_Free(a->value); + Z_Free(a); + break; + } + } + if(!a) + Con_Printf("unalias: %s alias not found\n", s); + } +} + +/* +============================================================================= + + COMMAND EXECUTION + +============================================================================= +*/ + +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + const char *name; + const char *description; + xcommand_t consolefunction; + xcommand_t clientfunction; + qboolean csqcfunc; + qboolean initstate; // indicates this command existed at init +} cmd_function_t; + +static int cmd_argc; +static const char *cmd_argv[MAX_ARGS]; +static const char *cmd_null_string = ""; +static const char *cmd_args; +cmd_source_t cmd_source; + + +static cmd_function_t *cmd_functions; // possible commands to execute + +static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias, qboolean *is_multiple) +{ + cvar_t *cvar; + long argno; + char *endptr; + char vabuf[1024]; + + if(is_multiple) + *is_multiple = false; + + if(!varname || !*varname) + return NULL; + + if(alias) + { + if(!strcmp(varname, "*")) + { + if(is_multiple) + *is_multiple = true; + return Cmd_Args(); + } + else if(!strcmp(varname, "#")) + { + return va(vabuf, sizeof(vabuf), "%d", Cmd_Argc()); + } + else if(varname[strlen(varname) - 1] == '-') + { + argno = strtol(varname, &endptr, 10); + if(endptr == varname + strlen(varname) - 1) + { + // whole string is a number, apart from the - + const char *p = Cmd_Args(); + for(; argno > 1; --argno) + if(!COM_ParseToken_Console(&p)) + break; + if(p) + { + if(is_multiple) + *is_multiple = true; + + // kill pre-argument whitespace + for (;*p && ISWHITESPACE(*p);p++) + ; + + return p; + } + } + } + else + { + argno = strtol(varname, &endptr, 10); + if(*endptr == 0) + { + // whole string is a number + // NOTE: we already made sure we don't have an empty cvar name! + if(argno >= 0 && argno < Cmd_Argc()) + return Cmd_Argv(argno); + } + } + } + + if((cvar = Cvar_FindVar(varname)) && !(cvar->flags & CVAR_PRIVATE)) + return cvar->string; + + return NULL; +} + +qboolean Cmd_QuoteString(char *out, size_t outlen, const char *in, const char *quoteset, qboolean putquotes) +{ + qboolean quote_quot = !!strchr(quoteset, '"'); + qboolean quote_backslash = !!strchr(quoteset, '\\'); + qboolean quote_dollar = !!strchr(quoteset, '$'); + + if(putquotes) + { + if(outlen <= 2) + { + *out++ = 0; + return false; + } + *out++ = '"'; --outlen; + --outlen; + } + + while(*in) + { + if(*in == '"' && quote_quot) + { + if(outlen <= 2) + goto fail; + *out++ = '\\'; --outlen; + *out++ = '"'; --outlen; + } + else if(*in == '\\' && quote_backslash) + { + if(outlen <= 2) + goto fail; + *out++ = '\\'; --outlen; + *out++ = '\\'; --outlen; + } + else if(*in == '$' && quote_dollar) + { + if(outlen <= 2) + goto fail; + *out++ = '$'; --outlen; + *out++ = '$'; --outlen; + } + else + { + if(outlen <= 1) + goto fail; + *out++ = *in; --outlen; + } + ++in; + } + if(putquotes) + *out++ = '"'; + *out++ = 0; + return true; +fail: + if(putquotes) + *out++ = '"'; + *out++ = 0; + return false; +} + +static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t *alias) +{ + static char varname[MAX_INPUTLINE]; // cmd_mutex + static char varval[MAX_INPUTLINE]; // cmd_mutex + const char *varstr = NULL; + char *varfunc; + qboolean required = false; + qboolean optional = false; + static char asis[] = "asis"; // just to suppress const char warnings + + if(varlen >= MAX_INPUTLINE) + varlen = MAX_INPUTLINE - 1; + memcpy(varname, var, varlen); + varname[varlen] = 0; + varfunc = strchr(varname, ' '); + + if(varfunc) + { + *varfunc = 0; + ++varfunc; + } + + if(*var == 0) + { + // empty cvar name? + if(alias) + Con_Printf("Warning: Could not expand $ in alias %s\n", alias->name); + else + Con_Printf("Warning: Could not expand $\n"); + return "$"; + } + + if(varfunc) + { + char *p; + // ? means optional + while((p = strchr(varfunc, '?'))) + { + optional = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // ! means required + while((p = strchr(varfunc, '!'))) + { + required = true; + memmove(p, p+1, strlen(p)); // with final NUL + } + // kill spaces + while((p = strchr(varfunc, ' '))) + { + memmove(p, p+1, strlen(p)); // with final NUL + } + // if no function is left, NULL it + if(!*varfunc) + varfunc = NULL; + } + + if(varname[0] == '$') + varstr = Cmd_GetDirectCvarValue(Cmd_GetDirectCvarValue(varname + 1, alias, NULL), alias, NULL); + else + { + qboolean is_multiple = false; + // Exception: $* and $n- don't use the quoted form by default + varstr = Cmd_GetDirectCvarValue(varname, alias, &is_multiple); + if(is_multiple) + if(!varfunc) + varfunc = asis; + } + + if(!varstr) + { + if(required) + { + if(alias) + Con_Printf("Error: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Error: Could not expand $%s\n", varname); + return NULL; + } + else if(optional) + { + return ""; + } + else + { + if(alias) + Con_Printf("Warning: Could not expand $%s in alias %s\n", varname, alias->name); + else + Con_Printf("Warning: Could not expand $%s\n", varname); + dpsnprintf(varval, sizeof(varval), "$%s", varname); + return varval; + } + } + + if(!varfunc || !strcmp(varfunc, "q")) // note: quoted form is default, use "asis" to override! + { + // quote it so it can be used inside double quotes + // we just need to replace " by \", and of course, double backslashes + Cmd_QuoteString(varval, sizeof(varval), varstr, "\"\\", false); + return varval; + } + else if(!strcmp(varfunc, "asis")) + { + return varstr; + } + else + Con_Printf("Unknown variable function %s\n", varfunc); + + return varstr; +} + +/* +Cmd_PreprocessString + +Preprocesses strings and replaces $*, $param#, $cvar accordingly. Also strips comments. +*/ +static qboolean Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) { + const char *in; + size_t eat, varlen; + unsigned outlen; + const char *val; + + // don't crash if there's no room in the outtext buffer + if( maxoutlen == 0 ) { + return false; + } + maxoutlen--; // because of \0 + + in = intext; + outlen = 0; + + while( *in && outlen < maxoutlen ) { + if( *in == '$' ) { + // this is some kind of expansion, see what comes after the $ + in++; + + // The console does the following preprocessing: + // + // - $$ is transformed to a single dollar sign. + // - $var or ${var} are expanded to the contents of the named cvar, + // with quotation marks and backslashes quoted so it can safely + // be used inside quotation marks (and it should always be used + // that way) + // - ${var asis} inserts the cvar value as is, without doing this + // quoting + // - ${var ?} silently expands to the empty string if + // $var does not exist + // - ${var !} fails expansion and executes nothing if + // $var does not exist + // - prefix the cvar name with a dollar sign to do indirection; + // for example, if $x has the value timelimit, ${$x} will return + // the value of $timelimit + // - when expanding an alias, the special variable name $* refers + // to all alias parameters, and a number refers to that numbered + // alias parameter, where the name of the alias is $0, the first + // parameter is $1 and so on; as a special case, $* inserts all + // parameters, without extra quoting, so one can use $* to just + // pass all parameters around. All parameters starting from $n + // can be referred to as $n- (so $* is equivalent to $1-). + // - ${* q} and ${n- q} force quoting anyway + // + // Note: when expanding an alias, cvar expansion is done in the SAME step + // as alias expansion so that alias parameters or cvar values containing + // dollar signs have no unwanted bad side effects. However, this needs to + // be accounted for when writing complex aliases. For example, + // alias foo "set x NEW; echo $x" + // actually expands to + // "set x NEW; echo OLD" + // and will print OLD! To work around this, use a second alias: + // alias foo "set x NEW; foo2" + // alias foo2 "echo $x" + // + // Also note: lines starting with alias are exempt from cvar expansion. + // If you want cvar expansion, write "alias" instead: + // + // set x 1 + // alias foo "echo $x" + // "alias" bar "echo $x" + // set x 2 + // + // foo will print 2, because the variable $x will be expanded when the alias + // gets expanded. bar will print 1, because the variable $x was expanded + // at definition time. foo can be equivalently defined as + // + // "alias" foo "echo $$x" + // + // because at definition time, $$ will get replaced to a single $. + + if( *in == '$' ) { + val = "$"; + eat = 1; + } else if(*in == '{') { + varlen = strcspn(in + 1, "}"); + if(in[varlen + 1] == '}') + { + val = Cmd_GetCvarValue(in + 1, varlen, alias); + if(!val) + return false; + eat = varlen + 2; + } + else + { + // ran out of data? + val = NULL; + eat = varlen + 1; + } + } else { + varlen = strspn(in, "#*0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); + val = Cmd_GetCvarValue(in, varlen, alias); + if(!val) + return false; + eat = varlen; + } + if(val) + { + // insert the cvar value + while(*val && outlen < maxoutlen) + outtext[outlen++] = *val++; + in += eat; + } + else + { + // copy the unexpanded text + outtext[outlen++] = '$'; + while(eat && outlen < maxoutlen) + { + outtext[outlen++] = *in++; + --eat; + } + } + } + else + outtext[outlen++] = *in++; + } + outtext[outlen] = 0; + return true; +} + +/* +============ +Cmd_ExecuteAlias + +Called for aliases and fills in the alias into the cbuffer +============ +*/ +static void Cmd_ExecuteAlias (cmdalias_t *alias) +{ + static char buffer[ MAX_INPUTLINE ]; // cmd_mutex + static char buffer2[ MAX_INPUTLINE ]; // cmd_mutex + qboolean ret = Cmd_PreprocessString( alias->value, buffer, sizeof(buffer) - 2, alias ); + if(!ret) + return; + // insert at start of command buffer, so that aliases execute in order + // (fixes bug introduced by Black on 20050705) + + // Note: Cbuf_PreprocessString will be called on this string AGAIN! So we + // have to make sure that no second variable expansion takes place, otherwise + // alias parameters containing dollar signs can have bad effects. + Cmd_QuoteString(buffer2, sizeof(buffer2), buffer, "$", false); + Cbuf_InsertText( buffer2 ); +} + +/* +======== +Cmd_List + + CmdList Added by EvilTypeGuy eviltypeguy@qeradiant.com + Thanks to Matthias "Maddes" Buecher, http://www.inside3d.com/qip/ + +======== +*/ +static void Cmd_List_f (void) +{ + cmd_function_t *cmd; + const char *partial; + size_t len; + int count; + qboolean ispattern; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = strlen(partial); + ispattern = (strchr(partial, '*') || strchr(partial, '?')); + } + else + { + partial = NULL; + len = 0; + ispattern = false; + } + + count = 0; + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (partial && (ispattern ? !matchpattern_with_separator(cmd->name, partial, false, "", false) : strncmp(partial, cmd->name, len))) + continue; + Con_Printf("%s : %s\n", cmd->name, cmd->description); + count++; + } + + if (len) + { + if(ispattern) + Con_Printf("%i Command%s matching \"%s\"\n\n", count, (count > 1) ? "s" : "", partial); + else + Con_Printf("%i Command%s beginning with \"%s\"\n\n", count, (count > 1) ? "s" : "", partial); + } + else + Con_Printf("%i Command%s\n\n", count, (count > 1) ? "s" : ""); +} + +static void Cmd_Apropos_f(void) +{ + cmd_function_t *cmd; + cvar_t *cvar; + cmdalias_t *alias; + const char *partial; + int count; + qboolean ispattern; + char vabuf[1024]; + + if (Cmd_Argc() > 1) + partial = Cmd_Args(); + else + { + Con_Printf("usage: apropos \n"); + return; + } + + ispattern = partial && (strchr(partial, '*') || strchr(partial, '?')); + if(!ispattern) + partial = va(vabuf, sizeof(vabuf), "*%s*", partial); + + count = 0; + for (cvar = cvar_vars; cvar; cvar = cvar->next) + { + if (!matchpattern_with_separator(cvar->name, partial, true, "", false)) + if (!matchpattern_with_separator(cvar->description, partial, true, "", false)) + continue; + Con_Printf ("cvar ^3%s^7 is \"%s\" [\"%s\"] %s\n", cvar->name, cvar->string, cvar->defstring, cvar->description); + count++; + } + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (!matchpattern_with_separator(cmd->name, partial, true, "", false)) + if (!matchpattern_with_separator(cmd->description, partial, true, "", false)) + continue; + Con_Printf("command ^2%s^7: %s\n", cmd->name, cmd->description); + count++; + } + for (alias = cmd_alias; alias; alias = alias->next) + { + // procede here a bit differently as an alias value always got a final \n + if (!matchpattern_with_separator(alias->name, partial, true, "", false)) + if (!matchpattern_with_separator(alias->value, partial, true, "\n", false)) // when \n is as separator wildcards don't match it + continue; + Con_Printf("alias ^5%s^7: %s", alias->name, alias->value); // do not print an extra \n + count++; + } + Con_Printf("%i result%s\n\n", count, (count > 1) ? "s" : ""); +} + +/* +============ +Cmd_Init +============ +*/ +void Cmd_Init (void) +{ + cmd_mempool = Mem_AllocPool("commands", 0, NULL); + // space for commands and script files + cmd_text.data = cmd_text_buf; + cmd_text.maxsize = sizeof(cmd_text_buf); + cmd_text.cursize = 0; + + if (Thread_HasThreads()) + cmd_text_mutex = Thread_CreateMutex(); +} + +void Cmd_Init_Commands (void) +{ +// +// register our commands +// + Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f, "execute commandline parameters (must be present in quake.rc script)"); + Cmd_AddCommand ("exec",Cmd_Exec_f, "execute a script file"); + Cmd_AddCommand ("echo",Cmd_Echo_f, "print a message to the console (useful in scripts)"); + Cmd_AddCommand ("alias",Cmd_Alias_f, "create a script function (parameters are passed in as $X (being X a number), $* for all parameters, $X- for all parameters starting from $X). Without arguments show the list of all alias"); + Cmd_AddCommand ("unalias",Cmd_UnAlias_f, "remove an alias"); + Cmd_AddCommand ("cmd", Cmd_ForwardToServer, "send a console commandline to the server (used by some mods)"); + Cmd_AddCommand ("wait", Cmd_Wait_f, "make script execution wait for next rendered frame"); + Cmd_AddCommand ("set", Cvar_Set_f, "create or change the value of a console variable"); + Cmd_AddCommand ("seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg"); + Cmd_AddCommand ("unset", Cvar_Del_f, "delete a cvar (does not work for static ones like _cl_name, or read-only ones)"); +#ifdef FILLALLCVARSWITHRUBBISH + Cmd_AddCommand ("fillallcvarswithrubbish", Cvar_FillAll_f, "fill all cvars with a specified number of characters to provoke buffer overruns"); +#endif /* FILLALLCVARSWITHRUBBISH */ + + // 2000-01-09 CmdList, CvarList commands By Matthias "Maddes" Buecher + // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com + Cmd_AddCommand ("cmdlist", Cmd_List_f, "lists all console commands beginning with the specified prefix or matching the specified wildcard pattern"); + Cmd_AddCommand ("cvarlist", Cvar_List_f, "lists all console variables beginning with the specified prefix or matching the specified wildcard pattern"); + Cmd_AddCommand ("apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description"); + + Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f, "stores the current values of all cvars into their default values, only used once during startup after parsing default.cfg"); + Cmd_AddCommand ("cvar_resettodefaults_all", Cvar_ResetToDefaults_All_f, "sets all cvars to their locked default values"); + Cmd_AddCommand ("cvar_resettodefaults_nosaveonly", Cvar_ResetToDefaults_NoSaveOnly_f, "sets all non-saved cvars to their locked default values (variables that will not be saved to config.cfg)"); + Cmd_AddCommand ("cvar_resettodefaults_saveonly", Cvar_ResetToDefaults_SaveOnly_f, "sets all saved cvars to their locked default values (variables that will be saved to config.cfg)"); + + Cmd_AddCommand ("cprint", Cmd_Centerprint_f, "print something at the screen center"); + Cmd_AddCommand ("defer", Cmd_Defer_f, "execute a command in the future"); + + // DRESK - 5/14/06 + // Support Doom3-style Toggle Command + Cmd_AddCommand( "toggle", Cmd_Toggle_f, "toggles a console variable's values (use for more info)"); +} + +/* +============ +Cmd_Shutdown +============ +*/ +void Cmd_Shutdown(void) +{ + if (cmd_text_mutex) + { + // we usually have this locked when we get here from Host_Quit_f + Cbuf_UnlockThreadMutex(); + Thread_DestroyMutex(cmd_text_mutex); + } + cmd_text_mutex = NULL; + + Mem_FreePool(&cmd_mempool); +} + +/* +============ +Cmd_Argc +============ +*/ +int Cmd_Argc (void) +{ + return cmd_argc; +} + +/* +============ +Cmd_Argv +============ +*/ +const char *Cmd_Argv (int arg) +{ + if (arg >= cmd_argc ) + return cmd_null_string; + return cmd_argv[arg]; +} + +/* +============ +Cmd_Args +============ +*/ +const char *Cmd_Args (void) +{ + return cmd_args; +} + + +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +============ +*/ +// AK: This function should only be called from ExcuteString because the current design is a bit of an hack +static void Cmd_TokenizeString (const char *text) +{ + int l; + + cmd_argc = 0; + cmd_args = NULL; + + while (1) + { + // skip whitespace up to a /n + while (*text && ISWHITESPACE(*text) && *text != '\r' && *text != '\n') + text++; + + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + if (*text == '\n' || *text == '\r') + { + // a newline separates commands in the buffer + if (*text == '\r' && text[1] == '\n') + text++; + text++; + break; + } + + if (!*text) + return; + + if (cmd_argc == 1) + cmd_args = text; + + if (!COM_ParseToken_Console(&text)) + return; + + if (cmd_argc < MAX_ARGS) + { + l = (int)strlen(com_token) + 1; + if (cmd_tokenizebufferpos + l > CMD_TOKENIZELENGTH) + { + Con_Printf("Cmd_TokenizeString: ran out of %i character buffer space for command arguements\n", CMD_TOKENIZELENGTH); + break; + } + memcpy (cmd_tokenizebuffer + cmd_tokenizebufferpos, com_token, l); + cmd_argv[cmd_argc] = cmd_tokenizebuffer + cmd_tokenizebufferpos; + cmd_tokenizebufferpos += l; + cmd_argc++; + } + } +} + + +/* +============ +Cmd_AddCommand +============ +*/ +void Cmd_AddCommand_WithClientCommand (const char *cmd_name, xcommand_t consolefunction, xcommand_t clientfunction, const char *description) +{ + cmd_function_t *cmd; + cmd_function_t *prev, *current; + +// fail if the command is a variable name + if (Cvar_FindVar( cmd_name )) + { + Con_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); + return; + } + +// fail if the command already exists + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!strcmp (cmd_name, cmd->name)) + { + if (consolefunction || clientfunction) + { + Con_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); + return; + } + else //[515]: csqc + { + cmd->csqcfunc = true; + return; + } + } + } + + cmd = (cmd_function_t *)Mem_Alloc(cmd_mempool, sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->consolefunction = consolefunction; + cmd->clientfunction = clientfunction; + cmd->description = description; + if(!consolefunction && !clientfunction) //[515]: csqc + cmd->csqcfunc = true; + cmd->next = cmd_functions; + +// insert it at the right alphanumeric position + for( prev = NULL, current = cmd_functions ; current && strcmp( current->name, cmd->name ) < 0 ; prev = current, current = current->next ) + ; + if( prev ) { + prev->next = cmd; + } else { + cmd_functions = cmd; + } + cmd->next = current; +} + +void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description) +{ + Cmd_AddCommand_WithClientCommand (cmd_name, function, NULL, description); +} + +/* +============ +Cmd_Exists +============ +*/ +qboolean Cmd_Exists (const char *cmd_name) +{ + cmd_function_t *cmd; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!strcmp (cmd_name,cmd->name)) + return true; + + return false; +} + + +/* +============ +Cmd_CompleteCommand +============ +*/ +const char *Cmd_CompleteCommand (const char *partial) +{ + cmd_function_t *cmd; + size_t len; + + len = strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cmd = cmd_functions; cmd; cmd = cmd->next) + if (!strncasecmp(partial, cmd->name, len)) + return cmd->name; + + return NULL; +} + +/* + Cmd_CompleteCountPossible + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +int Cmd_CompleteCountPossible (const char *partial) +{ + cmd_function_t *cmd; + size_t len; + int h; + + h = 0; + len = strlen(partial); + + if (!len) + return 0; + + // Loop through the command list and count all partial matches + for (cmd = cmd_functions; cmd; cmd = cmd->next) + if (!strncasecmp(partial, cmd->name, len)) + h++; + + return h; +} + +/* + Cmd_CompleteBuildList + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +const char **Cmd_CompleteBuildList (const char *partial) +{ + cmd_function_t *cmd; + size_t len = 0; + size_t bpos = 0; + size_t sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (const char *); + const char **buf; + + len = strlen(partial); + buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *)); + // Loop through the alias list and print all matches + for (cmd = cmd_functions; cmd; cmd = cmd->next) + if (!strncasecmp(partial, cmd->name, len)) + buf[bpos++] = cmd->name; + + buf[bpos] = NULL; + return buf; +} + +// written by LordHavoc +void Cmd_CompleteCommandPrint (const char *partial) +{ + cmd_function_t *cmd; + size_t len = strlen(partial); + // Loop through the command list and print all matches + for (cmd = cmd_functions; cmd; cmd = cmd->next) + if (!strncasecmp(partial, cmd->name, len)) + Con_Printf("^2%s^7: %s\n", cmd->name, cmd->description); +} + +/* + Cmd_CompleteAlias + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +const char *Cmd_CompleteAlias (const char *partial) +{ + cmdalias_t *alias; + size_t len; + + len = strlen(partial); + + if (!len) + return NULL; + + // Check functions + for (alias = cmd_alias; alias; alias = alias->next) + if (!strncasecmp(partial, alias->name, len)) + return alias->name; + + return NULL; +} + +// written by LordHavoc +void Cmd_CompleteAliasPrint (const char *partial) +{ + cmdalias_t *alias; + size_t len = strlen(partial); + // Loop through the alias list and print all matches + for (alias = cmd_alias; alias; alias = alias->next) + if (!strncasecmp(partial, alias->name, len)) + Con_Printf("^5%s^7: %s", alias->name, alias->value); +} + + +/* + Cmd_CompleteAliasCountPossible + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +int Cmd_CompleteAliasCountPossible (const char *partial) +{ + cmdalias_t *alias; + size_t len; + int h; + + h = 0; + + len = strlen(partial); + + if (!len) + return 0; + + // Loop through the command list and count all partial matches + for (alias = cmd_alias; alias; alias = alias->next) + if (!strncasecmp(partial, alias->name, len)) + h++; + + return h; +} + +/* + Cmd_CompleteAliasBuildList + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +const char **Cmd_CompleteAliasBuildList (const char *partial) +{ + cmdalias_t *alias; + size_t len = 0; + size_t bpos = 0; + size_t sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (const char *); + const char **buf; + + len = strlen(partial); + buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *)); + // Loop through the alias list and print all matches + for (alias = cmd_alias; alias; alias = alias->next) + if (!strncasecmp(partial, alias->name, len)) + buf[bpos++] = alias->name; + + buf[bpos] = NULL; + return buf; +} + +void Cmd_ClearCsqcFuncs (void) +{ + cmd_function_t *cmd; + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + cmd->csqcfunc = false; +} + +/* +============ +Cmd_ExecuteString + +A complete command line has been parsed, so try to execute it +FIXME: lookupnoadd the token to speed search? +============ +*/ +void Cmd_ExecuteString (const char *text, cmd_source_t src, qboolean lockmutex) +{ + int oldpos; + int found; + cmd_function_t *cmd; + cmdalias_t *a; + + oldpos = cmd_tokenizebufferpos; + cmd_source = src; + found = false; + + Cmd_TokenizeString (text); + +// execute the command line + if (!Cmd_Argc()) + goto done; // no tokens + +// check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!strcasecmp (cmd_argv[0],cmd->name)) + { + if (cmd->csqcfunc && CL_VM_ConsoleCommand (text)) //[515]: csqc + goto done; + switch (src) + { + case src_command: + if (cmd->consolefunction) + cmd->consolefunction (); + else if (cmd->clientfunction) + { + if (cls.state == ca_connected) + { + // forward remote commands to the server for execution + Cmd_ForwardToServer(); + } + else + Con_Printf("Can not send command \"%s\", not connected.\n", Cmd_Argv(0)); + } + else + Con_Printf("Command \"%s\" can not be executed\n", Cmd_Argv(0)); + found = true; + goto command_found; + case src_client: + if (cmd->clientfunction) + { + cmd->clientfunction (); + goto done; + } + break; + } + break; + } + } +command_found: + + // if it's a client command and no command was found, say so. + if (cmd_source == src_client) + { + Con_Printf("player \"%s\" tried to %s\n", host_client->name, text); + goto done; + } + +// check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!strcasecmp (cmd_argv[0], a->name)) + { + Cmd_ExecuteAlias(a); + goto done; + } + } + + if(found) // if the command was hooked and found, all is good + goto done; + +// check cvars + if (!Cvar_Command () && host_framecount > 0) + Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0)); + +done: + cmd_tokenizebufferpos = oldpos; +} + + +/* +=================== +Cmd_ForwardStringToServer + +Sends an entire command string over to the server, unprocessed +=================== +*/ +void Cmd_ForwardStringToServer (const char *s) +{ + char temp[128]; + if (cls.state != ca_connected) + { + Con_Printf("Can't \"%s\", not connected\n", s); + return; + } + + if (!cls.netcon) + return; + + // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my + // attention, it has been eradicated from here, its only (former) use in + // all of darkplaces. + if (cls.protocol == PROTOCOL_QUAKEWORLD) + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + else + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + if ((!strncmp(s, "say ", 4) || !strncmp(s, "say_team ", 9)) && cl_locs_enable.integer) + { + // say/say_team commands can replace % character codes with status info + while (*s) + { + if (*s == '%' && s[1]) + { + // handle proquake message macros + temp[0] = 0; + switch (s[1]) + { + case 'l': // current location + CL_Locs_FindLocationName(temp, sizeof(temp), cl.movement_origin); + break; + case 'h': // current health + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_HEALTH]); + break; + case 'a': // current armor + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_ARMOR]); + break; + case 'x': // current rockets + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_ROCKETS]); + break; + case 'c': // current cells + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_CELLS]); + break; + // silly proquake macros + case 'd': // loc at last death + CL_Locs_FindLocationName(temp, sizeof(temp), cl.lastdeathorigin); + break; + case 't': // current time + dpsnprintf(temp, sizeof(temp), "%.0f:%.0f", floor(cl.time / 60), cl.time - floor(cl.time / 60) * 60); + break; + case 'r': // rocket launcher status ("I have RL", "I need rockets", "I need RL") + if (!(cl.stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)) + dpsnprintf(temp, sizeof(temp), "I need RL"); + else if (!cl.stats[STAT_ROCKETS]) + dpsnprintf(temp, sizeof(temp), "I need rockets"); + else + dpsnprintf(temp, sizeof(temp), "I have RL"); + break; + case 'p': // powerup status (outputs "quad" "pent" and "eyes" according to status) + if (cl.stats[STAT_ITEMS] & IT_QUAD) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "quad", sizeof(temp)); + } + if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "pent", sizeof(temp)); + } + if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "eyes", sizeof(temp)); + } + break; + case 'w': // weapon status (outputs "SSG:NG:SNG:GL:RL:LG" with the text between : characters omitted if you lack the weapon) + if (cl.stats[STAT_ITEMS] & IT_SUPER_SHOTGUN) + strlcat(temp, "SSG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_NAILGUN) + strlcat(temp, "NG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_SUPER_NAILGUN) + strlcat(temp, "SNG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_GRENADE_LAUNCHER) + strlcat(temp, "GL", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER) + strlcat(temp, "RL", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_LIGHTNING) + strlcat(temp, "LG", sizeof(temp)); + break; + default: + // not a recognized macro, print it as-is... + temp[0] = s[0]; + temp[1] = s[1]; + temp[2] = 0; + break; + } + // write the resulting text + SZ_Write(&cls.netcon->message, (unsigned char *)temp, strlen(temp)); + s += 2; + continue; + } + MSG_WriteByte(&cls.netcon->message, *s); + s++; + } + MSG_WriteByte(&cls.netcon->message, 0); + } + else // any other command is passed on as-is + SZ_Write(&cls.netcon->message, (const unsigned char *)s, (int)strlen(s) + 1); +} + +/* +=================== +Cmd_ForwardToServer + +Sends the entire command line over to the server +=================== +*/ +void Cmd_ForwardToServer (void) +{ + const char *s; + char vabuf[1024]; + if (!strcasecmp(Cmd_Argv(0), "cmd")) + { + // we want to strip off "cmd", so just send the args + s = Cmd_Argc() > 1 ? Cmd_Args() : ""; + } + else + { + // we need to keep the command name, so send Cmd_Argv(0), a space and then Cmd_Args() + s = va(vabuf, sizeof(vabuf), "%s %s", Cmd_Argv(0), Cmd_Argc() > 1 ? Cmd_Args() : ""); + } + // don't send an empty forward message if the user tries "cmd" by itself + if (!s || !*s) + return; + Cmd_ForwardStringToServer(s); +} + + +/* +================ +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 (const char *parm) +{ + int i; + + if (!parm) + { + Con_Printf ("Cmd_CheckParm: NULL"); + return 0; + } + + for (i = 1; i < Cmd_Argc (); i++) + if (!strcasecmp (parm, Cmd_Argv (i))) + return i; + + return 0; +} + + + +void Cmd_SaveInitState(void) +{ + cmd_function_t *f; + cmdalias_t *a; + for (f = cmd_functions;f;f = f->next) + f->initstate = true; + for (a = cmd_alias;a;a = a->next) + { + a->initstate = true; + a->initialvalue = Mem_strdup(zonemempool, a->value); + } + Cvar_SaveInitState(); +} + +void Cmd_RestoreInitState(void) +{ + cmd_function_t *f, **fp; + cmdalias_t *a, **ap; + for (fp = &cmd_functions;(f = *fp);) + { + if (f->initstate) + fp = &f->next; + else + { + // destroy this command, it didn't exist at init + Con_DPrintf("Cmd_RestoreInitState: Destroying command %s\n", f->name); + *fp = f->next; + Z_Free(f); + } + } + for (ap = &cmd_alias;(a = *ap);) + { + if (a->initstate) + { + // restore this alias, it existed at init + if (strcmp(a->value ? a->value : "", a->initialvalue ? a->initialvalue : "")) + { + Con_DPrintf("Cmd_RestoreInitState: Restoring alias %s\n", a->name); + if (a->value) + Z_Free(a->value); + a->value = Mem_strdup(zonemempool, a->initialvalue); + } + ap = &a->next; + } + else + { + // free this alias, it didn't exist at init... + Con_DPrintf("Cmd_RestoreInitState: Destroying alias %s\n", a->name); + *ap = a->next; + if (a->value) + Z_Free(a->value); + Z_Free(a); + } + } + Cvar_RestoreInitState(); +} diff --git a/app/jni/cmd.h b/app/jni/cmd.h new file mode 100644 index 0000000..c8bf80c --- /dev/null +++ b/app/jni/cmd.h @@ -0,0 +1,173 @@ +/* +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 (); + +*/ + +#ifndef CMD_H +#define CMD_H + +/// allocates an initial text buffer that will grow as needed +void Cbuf_Init (void); + +void Cmd_Init_Commands (void); + +void Cbuf_Shutdown (void); + +/*! as new commands are generated from the console or keybindings, + * the text is added to the end of the command buffer. + */ +void Cbuf_AddText (const 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_InsertText (const char *text); + +/*! Pulls off 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. + * \note Do not call inside a command function! + */ +void Cbuf_Execute (void); +/*! Performs deferred commands and runs Cbuf_Execute, called by Host_Main */ +void Cbuf_Frame (void); + +//=========================================================================== + +/* + +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_Shutdown (void); + +// called by Host_Init, this marks cvars, commands and aliases with their init values +void Cmd_SaveInitState (void); +// called by FS_GameDir_f, this restores cvars, commands and aliases to init values +void Cmd_RestoreInitState (void); + +void Cmd_AddCommand_WithClientCommand (const char *cmd_name, xcommand_t consolefunction, xcommand_t clientfunction, const char *description); +void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description); +// 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 + +/// used by the cvar code to check for cvar / command name overlap +qboolean Cmd_Exists (const char *cmd_name); + +/// attempts to match a partial command for automatic command line completion +/// returns NULL if nothing fits +const char *Cmd_CompleteCommand (const char *partial); + +int Cmd_CompleteAliasCountPossible (const char *partial); + +const char **Cmd_CompleteAliasBuildList (const char *partial); + +int Cmd_CompleteCountPossible (const char *partial); + +const char **Cmd_CompleteBuildList (const char *partial); + +void Cmd_CompleteCommandPrint (const char *partial); + +const char *Cmd_CompleteAlias (const char *partial); + +void Cmd_CompleteAliasPrint (const char *partial); + +// Enhanced console completion by Fett erich@heintz.com + +// Added by EvilTypeGuy eviltypeguy@qeradiant.com + +int Cmd_Argc (void); +const char *Cmd_Argv (int arg); +const 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 always safe. + +/// 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 (const char *parm); + +//void Cmd_TokenizeString (char *text); +// Takes a null terminated string. Does not need to be /n terminated. +// breaks the string up into arg tokens. + +/// 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_ExecuteString (const char *text, cmd_source_t src, qboolean lockmutex); + +/// adds the string as a clc_stringcmd to the client message. +/// (used when there is no reason to generate a local command to do it) +void Cmd_ForwardStringToServer (const char *s); + +/// 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_ForwardToServer (void); + +/// used by command functions to send output to either the graphics console or +/// passed as a print message to the client +void Cmd_Print(const char *text); + +/// quotes a string so that it can be used as a command argument again; +/// quoteset is a string that contains one or more of ", \, $ and specifies +/// the characters to be quoted (you usually want to either pass "\"\\" or +/// "\"\\$"). Returns true on success, and false on overrun (in which case out +/// will contain a part of the quoted string). If putquotes is set, the +/// enclosing quote marks are also put. +qboolean Cmd_QuoteString(char *out, size_t outlen, const char *in, const char *quoteset, qboolean putquotes); + +void Cmd_ClearCsqcFuncs (void); + +#endif + diff --git a/app/jni/collision.c b/app/jni/collision.c new file mode 100644 index 0000000..ef237e9 --- /dev/null +++ b/app/jni/collision.c @@ -0,0 +1,1988 @@ + +#include "quakedef.h" +#include "polygon.h" + +#define COLLISION_EDGEDIR_DOT_EPSILON (0.999f) +#define COLLISION_EDGECROSS_MINLENGTH2 (1.0f / 4194304.0f) +#define COLLISION_SNAPSCALE (32.0f) +#define COLLISION_SNAP (1.0f / COLLISION_SNAPSCALE) +#define COLLISION_SNAP2 (2.0f / COLLISION_SNAPSCALE) +#define COLLISION_PLANE_DIST_EPSILON (2.0f / COLLISION_SNAPSCALE) + +cvar_t collision_impactnudge = {0, "collision_impactnudge", "0.03125", "how much to back off from the impact"}; +cvar_t collision_startnudge = {0, "collision_startnudge", "0", "how much to bias collision trace start"}; +cvar_t collision_endnudge = {0, "collision_endnudge", "0", "how much to bias collision trace end"}; +cvar_t collision_enternudge = {0, "collision_enternudge", "0", "how much to bias collision entry fraction"}; +cvar_t collision_leavenudge = {0, "collision_leavenudge", "0", "how much to bias collision exit fraction"}; +cvar_t collision_prefernudgedfraction = {0, "collision_prefernudgedfraction", "1", "whether to sort collision events by nudged fraction (1) or real fraction (0)"}; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +cvar_t collision_endposnudge = {0, "collision_endposnudge", "0", "workaround to fix trace_endpos sometimes being returned where it would be inside solid by making that collision hit (recommended: values like 1)"}; +#endif +cvar_t collision_debug_tracelineasbox = {0, "collision_debug_tracelineasbox", "0", "workaround for any bugs in Collision_TraceLineBrushFloat by using Collision_TraceBrushBrushFloat"}; +cvar_t collision_cache = {0, "collision_cache", "1", "store results of collision traces for next frame to reuse if possible (optimization)"}; +//cvar_t collision_triangle_neighborsides = {0, "collision_triangle_neighborsides", "1", "override automatic side generation if triangle has neighbors with face planes that form a convex edge (perfect solution, but can not work for all edges)"}; +cvar_t collision_triangle_bevelsides = {0, "collision_triangle_bevelsides", "1", "generate sloped edge planes on triangles - if 0, see axialedgeplanes"}; +cvar_t collision_triangle_axialsides = {0, "collision_triangle_axialsides", "1", "generate axially-aligned edge planes on triangles - otherwise use perpendicular edge planes"}; + +mempool_t *collision_mempool; + +void Collision_Init (void) +{ + Cvar_RegisterVariable(&collision_impactnudge); + Cvar_RegisterVariable(&collision_startnudge); + Cvar_RegisterVariable(&collision_endnudge); + Cvar_RegisterVariable(&collision_enternudge); + Cvar_RegisterVariable(&collision_leavenudge); + Cvar_RegisterVariable(&collision_prefernudgedfraction); +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + Cvar_RegisterVariable(&collision_endposnudge); +#endif + Cvar_RegisterVariable(&collision_debug_tracelineasbox); + Cvar_RegisterVariable(&collision_cache); +// Cvar_RegisterVariable(&collision_triangle_neighborsides); + Cvar_RegisterVariable(&collision_triangle_bevelsides); + Cvar_RegisterVariable(&collision_triangle_axialsides); + collision_mempool = Mem_AllocPool("collision cache", 0, NULL); + Collision_Cache_Init(collision_mempool); +} + + + + + + + + + + + + + + +static void Collision_PrintBrushAsQHull(colbrushf_t *brush, const char *name) +{ + int i; + Con_Printf("3 %s\n%i\n", name, brush->numpoints); + for (i = 0;i < brush->numpoints;i++) + Con_Printf("%f %f %f\n", brush->points[i].v[0], brush->points[i].v[1], brush->points[i].v[2]); + // FIXME: optimize! + Con_Printf("4\n%i\n", brush->numplanes); + for (i = 0;i < brush->numplanes;i++) + Con_Printf("%f %f %f %f\n", brush->planes[i].normal[0], brush->planes[i].normal[1], brush->planes[i].normal[2], brush->planes[i].dist); +} + +static void Collision_ValidateBrush(colbrushf_t *brush) +{ + int j, k, pointsoffplanes, pointonplanes, pointswithinsufficientplanes, printbrush; + float d; + printbrush = false; + if (!brush->numpoints) + { + Con_Print("Collision_ValidateBrush: brush with no points!\n"); + printbrush = true; + } +#if 0 + // it's ok for a brush to have one point and no planes... + if (brush->numplanes == 0 && brush->numpoints != 1) + { + Con_Print("Collision_ValidateBrush: brush with no planes and more than one point!\n"); + printbrush = true; + } +#endif + if (brush->numplanes) + { + pointsoffplanes = 0; + pointswithinsufficientplanes = 0; + for (k = 0;k < brush->numplanes;k++) + if (DotProduct(brush->planes[k].normal, brush->planes[k].normal) < 0.0001f) + Con_Printf("Collision_ValidateBrush: plane #%i (%f %f %f %f) is degenerate\n", k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist); + for (j = 0;j < brush->numpoints;j++) + { + pointonplanes = 0; + for (k = 0;k < brush->numplanes;k++) + { + d = DotProduct(brush->points[j].v, brush->planes[k].normal) - brush->planes[k].dist; + if (d > COLLISION_PLANE_DIST_EPSILON) + { + Con_Printf("Collision_ValidateBrush: point #%i (%f %f %f) infront of plane #%i (%f %f %f %f)\n", j, brush->points[j].v[0], brush->points[j].v[1], brush->points[j].v[2], k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist); + printbrush = true; + } + if (fabs(d) > COLLISION_PLANE_DIST_EPSILON) + pointsoffplanes++; + else + pointonplanes++; + } + if (pointonplanes < 3) + pointswithinsufficientplanes++; + } + if (pointswithinsufficientplanes) + { + Con_Print("Collision_ValidateBrush: some points have insufficient planes, every point must be on at least 3 planes to form a corner.\n"); + printbrush = true; + } + if (pointsoffplanes == 0) // all points are on all planes + { + Con_Print("Collision_ValidateBrush: all points lie on all planes (degenerate, no brush volume!)\n"); + printbrush = true; + } + } + if (printbrush) + Collision_PrintBrushAsQHull(brush, "unnamed"); +} + +static float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints) +{ + float dist, bestdist; + if (!numpoints) + return 0; + bestdist = DotProduct(points->v, normal); + points++; + while(--numpoints) + { + dist = DotProduct(points->v, normal); + bestdist = min(bestdist, dist); + points++; + } + return bestdist; +} + +static float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints) +{ + float dist, bestdist; + if (!numpoints) + return 0; + bestdist = DotProduct(points->v, normal); + points++; + while(--numpoints) + { + dist = DotProduct(points->v, normal); + bestdist = max(bestdist, dist); + points++; + } + return bestdist; +} + +static void Collision_CalcEdgeDirsForPolygonBrushFloat(colbrushf_t *brush) +{ + int i, j; + for (i = 0, j = brush->numpoints - 1;i < brush->numpoints;j = i, i++) + VectorSubtract(brush->points[i].v, brush->points[j].v, brush->edgedirs[j].v); +} + +colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const colplanef_t *originalplanes, int supercontents, int q3surfaceflags, const texture_t *texture, int hasaabbplanes) +{ + // TODO: planesbuf could be replaced by a remapping table + int j, k, l, m, w, xyzflags; + int numpointsbuf = 0, maxpointsbuf = 256, numedgedirsbuf = 0, maxedgedirsbuf = 256, numplanesbuf = 0, maxplanesbuf = 256, numelementsbuf = 0, maxelementsbuf = 256; + int isaabb = true; + double maxdist; + colbrushf_t *brush; + colpointf_t pointsbuf[256]; + colpointf_t edgedirsbuf[256]; + colplanef_t planesbuf[256]; + int elementsbuf[1024]; + int polypointbuf[256]; + int pmaxpoints = 64; + int pnumpoints; + double p[2][3*64]; +#if 0 + // enable these if debugging to avoid seeing garbage in unused data- + memset(pointsbuf, 0, sizeof(pointsbuf)); + memset(edgedirsbuf, 0, sizeof(edgedirsbuf)); + memset(planesbuf, 0, sizeof(planesbuf)); + memset(elementsbuf, 0, sizeof(elementsbuf)); + memset(polypointbuf, 0, sizeof(polypointbuf)); + memset(p, 0, sizeof(p)); +#endif + + // check if there are too many planes and skip the brush + if (numoriginalplanes >= maxplanesbuf) + { + Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many planes for buffer\n"); + return NULL; + } + + // figure out how large a bounding box we need to properly compute this brush + maxdist = 0; + for (j = 0;j < numoriginalplanes;j++) + maxdist = max(maxdist, fabs(originalplanes[j].dist)); + // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024 + maxdist = floor(maxdist * (4.0 / 1024.0) + 2) * 1024.0; + // construct a collision brush (points, planes, and renderable mesh) from + // a set of planes, this also optimizes out any unnecessary planes (ones + // whose polygon is clipped away by the other planes) + for (j = 0;j < numoriginalplanes;j++) + { + // add the new plane + VectorCopy(originalplanes[j].normal, planesbuf[numplanesbuf].normal); + planesbuf[numplanesbuf].dist = originalplanes[j].dist; + planesbuf[numplanesbuf].q3surfaceflags = originalplanes[j].q3surfaceflags; + planesbuf[numplanesbuf].texture = originalplanes[j].texture; + numplanesbuf++; + + // create a large polygon from the plane + w = 0; + PolygonD_QuadForPlane(p[w], originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist, maxdist); + pnumpoints = 4; + // clip it by all other planes + for (k = 0;k < numoriginalplanes && pnumpoints >= 3 && pnumpoints <= pmaxpoints;k++) + { + // skip the plane this polygon + // (nothing happens if it is processed, this is just an optimization) + if (k != j) + { + // we want to keep the inside of the brush plane so we flip + // the cutting plane + PolygonD_Divide(pnumpoints, p[w], -originalplanes[k].normal[0], -originalplanes[k].normal[1], -originalplanes[k].normal[2], -originalplanes[k].dist, COLLISION_PLANE_DIST_EPSILON, pmaxpoints, p[!w], &pnumpoints, 0, NULL, NULL, NULL); + w = !w; + } + } + + // if nothing is left, skip it + if (pnumpoints < 3) + { + //Con_DPrintf("Collision_NewBrushFromPlanes: warning: polygon for plane %f %f %f %f clipped away\n", originalplanes[j].normal[0], originalplanes[j].normal[1], originalplanes[j].normal[2], originalplanes[j].dist); + continue; + } + + for (k = 0;k < pnumpoints;k++) + { + int l, m; + m = 0; + for (l = 0;l < numoriginalplanes;l++) + if (fabs(DotProduct(&p[w][k*3], originalplanes[l].normal) - originalplanes[l].dist) < COLLISION_PLANE_DIST_EPSILON) + m++; + if (m < 3) + break; + } + if (k < pnumpoints) + { + Con_DPrintf("Collision_NewBrushFromPlanes: warning: polygon point does not lie on at least 3 planes\n"); + //return NULL; + } + + // check if there are too many polygon vertices for buffer + if (pnumpoints > pmaxpoints) + { + Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n"); + return NULL; + } + + // check if there are too many triangle elements for buffer + if (numelementsbuf + (pnumpoints - 2) * 3 > maxelementsbuf) + { + Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many triangle elements for buffer\n"); + return NULL; + } + + // add the unique points for this polygon + for (k = 0;k < pnumpoints;k++) + { + float v[3]; + // downgrade to float precision before comparing + VectorCopy(&p[w][k*3], v); + + // check if there is already a matching point (no duplicates) + for (m = 0;m < numpointsbuf;m++) + if (VectorDistance2(v, pointsbuf[m].v) < COLLISION_SNAP2) + break; + + // if there is no match, add a new one + if (m == numpointsbuf) + { + // check if there are too many and skip the brush + if (numpointsbuf >= maxpointsbuf) + { + Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many points for buffer\n"); + return NULL; + } + // add the new one + VectorCopy(&p[w][k*3], pointsbuf[numpointsbuf].v); + numpointsbuf++; + } + + // store the index into a buffer + polypointbuf[k] = m; + } + + // add the triangles for the polygon + // (this particular code makes a triangle fan) + for (k = 0;k < pnumpoints - 2;k++) + { + elementsbuf[numelementsbuf++] = polypointbuf[0]; + elementsbuf[numelementsbuf++] = polypointbuf[k + 1]; + elementsbuf[numelementsbuf++] = polypointbuf[k + 2]; + } + + // add the unique edgedirs for this polygon + for (k = 0, l = pnumpoints-1;k < pnumpoints;l = k, k++) + { + float dir[3]; + // downgrade to float precision before comparing + VectorSubtract(&p[w][k*3], &p[w][l*3], dir); + VectorNormalize(dir); + + // check if there is already a matching edgedir (no duplicates) + for (m = 0;m < numedgedirsbuf;m++) + if (DotProduct(dir, edgedirsbuf[m].v) >= COLLISION_EDGEDIR_DOT_EPSILON) + break; + // skip this if there is + if (m < numedgedirsbuf) + continue; + + // try again with negated edgedir + VectorNegate(dir, dir); + // check if there is already a matching edgedir (no duplicates) + for (m = 0;m < numedgedirsbuf;m++) + if (DotProduct(dir, edgedirsbuf[m].v) >= COLLISION_EDGEDIR_DOT_EPSILON) + break; + // if there is no match, add a new one + if (m == numedgedirsbuf) + { + // check if there are too many and skip the brush + if (numedgedirsbuf >= maxedgedirsbuf) + { + Con_DPrint("Collision_NewBrushFromPlanes: failed to build collision brush: too many edgedirs for buffer\n"); + return NULL; + } + // add the new one + VectorCopy(dir, edgedirsbuf[numedgedirsbuf].v); + numedgedirsbuf++; + } + } + + // if any normal is not purely axial, it's not an axis-aligned box + if (isaabb && (originalplanes[j].normal[0] == 0) + (originalplanes[j].normal[1] == 0) + (originalplanes[j].normal[2] == 0) < 2) + isaabb = false; + } + + // if nothing is left, there's nothing to allocate + if (numplanesbuf < 4) + { + Con_DPrintf("Collision_NewBrushFromPlanes: failed to build collision brush: %i triangles, %i planes (input was %i planes), %i vertices\n", numelementsbuf / 3, numplanesbuf, numoriginalplanes, numpointsbuf); + return NULL; + } + + // if no triangles or points could be constructed, then this routine failed but the brush is not discarded + if (numelementsbuf < 12 || numpointsbuf < 4) + Con_DPrintf("Collision_NewBrushFromPlanes: unable to rebuild triangles/points for collision brush: %i triangles, %i planes (input was %i planes), %i vertices\n", numelementsbuf / 3, numplanesbuf, numoriginalplanes, numpointsbuf); + + // validate plane distances + for (j = 0;j < numplanesbuf;j++) + { + float d = furthestplanedist_float(planesbuf[j].normal, pointsbuf, numpointsbuf); + if (fabs(planesbuf[j].dist - d) > COLLISION_PLANE_DIST_EPSILON) + Con_DPrintf("plane %f %f %f %f mismatches dist %f\n", planesbuf[j].normal[0], planesbuf[j].normal[1], planesbuf[j].normal[2], planesbuf[j].dist, d); + } + + // allocate the brush and copy to it + brush = (colbrushf_t *)Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colpointf_t) * numpointsbuf + sizeof(colpointf_t) * numedgedirsbuf + sizeof(colplanef_t) * numplanesbuf + sizeof(int) * numelementsbuf); + brush->isaabb = isaabb; + brush->hasaabbplanes = hasaabbplanes; + brush->supercontents = supercontents; + brush->numplanes = numplanesbuf; + brush->numedgedirs = numedgedirsbuf; + brush->numpoints = numpointsbuf; + brush->numtriangles = numelementsbuf / 3; + brush->planes = (colplanef_t *)(brush + 1); + brush->points = (colpointf_t *)(brush->planes + brush->numplanes); + brush->edgedirs = (colpointf_t *)(brush->points + brush->numpoints); + brush->elements = (int *)(brush->points + brush->numpoints); + brush->q3surfaceflags = q3surfaceflags; + brush->texture = texture; + for (j = 0;j < brush->numpoints;j++) + { + brush->points[j].v[0] = pointsbuf[j].v[0]; + brush->points[j].v[1] = pointsbuf[j].v[1]; + brush->points[j].v[2] = pointsbuf[j].v[2]; + } + for (j = 0;j < brush->numedgedirs;j++) + { + brush->edgedirs[j].v[0] = edgedirsbuf[j].v[0]; + brush->edgedirs[j].v[1] = edgedirsbuf[j].v[1]; + brush->edgedirs[j].v[2] = edgedirsbuf[j].v[2]; + } + for (j = 0;j < brush->numplanes;j++) + { + brush->planes[j].normal[0] = planesbuf[j].normal[0]; + brush->planes[j].normal[1] = planesbuf[j].normal[1]; + brush->planes[j].normal[2] = planesbuf[j].normal[2]; + brush->planes[j].dist = planesbuf[j].dist; + brush->planes[j].q3surfaceflags = planesbuf[j].q3surfaceflags; + brush->planes[j].texture = planesbuf[j].texture; + } + for (j = 0;j < brush->numtriangles * 3;j++) + brush->elements[j] = elementsbuf[j]; + + xyzflags = 0; + VectorClear(brush->mins); + VectorClear(brush->maxs); + for (j = 0;j < min(6, numoriginalplanes);j++) + { + if (originalplanes[j].normal[0] == 1) {xyzflags |= 1;brush->maxs[0] = originalplanes[j].dist;} + else if (originalplanes[j].normal[0] == -1) {xyzflags |= 2;brush->mins[0] = -originalplanes[j].dist;} + else if (originalplanes[j].normal[1] == 1) {xyzflags |= 4;brush->maxs[1] = originalplanes[j].dist;} + else if (originalplanes[j].normal[1] == -1) {xyzflags |= 8;brush->mins[1] = -originalplanes[j].dist;} + else if (originalplanes[j].normal[2] == 1) {xyzflags |= 16;brush->maxs[2] = originalplanes[j].dist;} + else if (originalplanes[j].normal[2] == -1) {xyzflags |= 32;brush->mins[2] = -originalplanes[j].dist;} + } + // if not all xyzflags were set, then this is not a brush from q3map/q3map2, and needs reconstruction of the bounding box + // (this case works for any brush with valid points, but sometimes brushes are not reconstructed properly and hence the points are not valid, so this is reserved as a fallback case) + if (xyzflags != 63) + { + VectorCopy(brush->points[0].v, brush->mins); + VectorCopy(brush->points[0].v, brush->maxs); + for (j = 1;j < brush->numpoints;j++) + { + brush->mins[0] = min(brush->mins[0], brush->points[j].v[0]); + brush->mins[1] = min(brush->mins[1], brush->points[j].v[1]); + brush->mins[2] = min(brush->mins[2], brush->points[j].v[2]); + brush->maxs[0] = max(brush->maxs[0], brush->points[j].v[0]); + brush->maxs[1] = max(brush->maxs[1], brush->points[j].v[1]); + brush->maxs[2] = max(brush->maxs[2], brush->points[j].v[2]); + } + } + brush->mins[0] -= 1; + brush->mins[1] -= 1; + brush->mins[2] -= 1; + brush->maxs[0] += 1; + brush->maxs[1] += 1; + brush->maxs[2] += 1; + Collision_ValidateBrush(brush); + return brush; +} + + + +void Collision_CalcPlanesForTriangleBrushFloat(colbrushf_t *brush) +{ + int i; + float edge0[3], edge1[3], edge2[3]; + colpointf_t *p; + + TriangleNormal(brush->points[0].v, brush->points[1].v, brush->points[2].v, brush->planes[0].normal); + if (DotProduct(brush->planes[0].normal, brush->planes[0].normal) < 0.0001f) + { + // there's no point in processing a degenerate triangle (GIGO - Garbage In, Garbage Out) + // note that some of these exist in q3bsp bspline patches + brush->numplanes = 0; + return; + } + + // there are 5 planes (front, back, sides) and 3 edges + brush->numplanes = 5; + brush->numedgedirs = 3; + VectorNormalize(brush->planes[0].normal); + brush->planes[0].dist = DotProduct(brush->points->v, brush->planes[0].normal); + VectorNegate(brush->planes[0].normal, brush->planes[1].normal); + brush->planes[1].dist = -brush->planes[0].dist; + // edge directions are easy to calculate + VectorSubtract(brush->points[2].v, brush->points[0].v, edge0); + VectorSubtract(brush->points[0].v, brush->points[1].v, edge1); + VectorSubtract(brush->points[1].v, brush->points[2].v, edge2); + VectorCopy(edge0, brush->edgedirs[0].v); + VectorCopy(edge1, brush->edgedirs[1].v); + VectorCopy(edge2, brush->edgedirs[2].v); + // now select an algorithm to generate the side planes + if (collision_triangle_bevelsides.integer) + { + // use 45 degree slopes at the edges of the triangle to make a sinking trace error turn into "riding up" the slope rather than getting stuck + CrossProduct(edge0, brush->planes->normal, brush->planes[2].normal); + CrossProduct(edge1, brush->planes->normal, brush->planes[3].normal); + CrossProduct(edge2, brush->planes->normal, brush->planes[4].normal); + VectorNormalize(brush->planes[2].normal); + VectorNormalize(brush->planes[3].normal); + VectorNormalize(brush->planes[4].normal); + VectorAdd(brush->planes[2].normal, brush->planes[0].normal, brush->planes[2].normal); + VectorAdd(brush->planes[3].normal, brush->planes[0].normal, brush->planes[3].normal); + VectorAdd(brush->planes[4].normal, brush->planes[0].normal, brush->planes[4].normal); + VectorNormalize(brush->planes[2].normal); + VectorNormalize(brush->planes[3].normal); + VectorNormalize(brush->planes[4].normal); + } + else if (collision_triangle_axialsides.integer) + { + float projectionnormal[3], projectionedge0[3], projectionedge1[3], projectionedge2[3]; + int i, best; + float dist, bestdist; + bestdist = fabs(brush->planes[0].normal[0]); + best = 0; + for (i = 1;i < 3;i++) + { + dist = fabs(brush->planes[0].normal[i]); + if (bestdist < dist) + { + bestdist = dist; + best = i; + } + } + VectorClear(projectionnormal); + if (brush->planes[0].normal[best] < 0) + projectionnormal[best] = -1; + else + projectionnormal[best] = 1; + VectorCopy(edge0, projectionedge0); + VectorCopy(edge1, projectionedge1); + VectorCopy(edge2, projectionedge2); + projectionedge0[best] = 0; + projectionedge1[best] = 0; + projectionedge2[best] = 0; + CrossProduct(projectionedge0, projectionnormal, brush->planes[2].normal); + CrossProduct(projectionedge1, projectionnormal, brush->planes[3].normal); + CrossProduct(projectionedge2, projectionnormal, brush->planes[4].normal); + VectorNormalize(brush->planes[2].normal); + VectorNormalize(brush->planes[3].normal); + VectorNormalize(brush->planes[4].normal); + } + else + { + CrossProduct(edge0, brush->planes->normal, brush->planes[2].normal); + CrossProduct(edge1, brush->planes->normal, brush->planes[3].normal); + CrossProduct(edge2, brush->planes->normal, brush->planes[4].normal); + VectorNormalize(brush->planes[2].normal); + VectorNormalize(brush->planes[3].normal); + VectorNormalize(brush->planes[4].normal); + } + brush->planes[2].dist = DotProduct(brush->points[2].v, brush->planes[2].normal); + brush->planes[3].dist = DotProduct(brush->points[0].v, brush->planes[3].normal); + brush->planes[4].dist = DotProduct(brush->points[1].v, brush->planes[4].normal); + + if (developer_extra.integer) + { + // validity check - will be disabled later + Collision_ValidateBrush(brush); + for (i = 0;i < brush->numplanes;i++) + { + int j; + for (j = 0, p = brush->points;j < brush->numpoints;j++, p++) + if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + COLLISION_PLANE_DIST_EPSILON) + Con_DPrintf("Error in brush plane generation, plane %i\n", i); + } + } +} + +colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents, int q3surfaceflags, const texture_t *texture) +{ + colbrushf_t *brush; + brush = (colbrushf_t *)Mem_Alloc(mempool, sizeof(colbrushf_t) + sizeof(colplanef_t) * (numpoints + 2) + sizeof(colpointf_t) * numpoints); + brush->isaabb = false; + brush->hasaabbplanes = false; + brush->supercontents = supercontents; + brush->numpoints = numpoints; + brush->numedgedirs = numpoints; + brush->numplanes = numpoints + 2; + brush->planes = (colplanef_t *)(brush + 1); + brush->points = (colpointf_t *)points; + brush->edgedirs = (colpointf_t *)(brush->planes + brush->numplanes); + brush->q3surfaceflags = q3surfaceflags; + brush->texture = texture; + Sys_Error("Collision_AllocBrushFromPermanentPolygonFloat: FIXME: this code needs to be updated to generate a mesh..."); + return brush; +} + +// NOTE: start and end of each brush pair must have same numplanes/numpoints +void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *trace_start, const colbrushf_t *trace_end, const colbrushf_t *other_start, const colbrushf_t *other_end) +{ + int nplane, nplane2, nedge1, nedge2, hitq3surfaceflags = 0; + int tracenumedgedirs = trace_start->numedgedirs; + //int othernumedgedirs = other_start->numedgedirs; + int tracenumpoints = trace_start->numpoints; + int othernumpoints = other_start->numpoints; + int numplanes1 = other_start->numplanes; + int numplanes2 = numplanes1 + trace_start->numplanes; + int numplanes3 = numplanes2 + trace_start->numedgedirs * other_start->numedgedirs * 2; + vec_t enterfrac = -1, leavefrac = 1, startdist, enddist, ie, f, imove, enterfrac2 = -1; + vec4_t startplane; + vec4_t endplane; + vec4_t newimpactplane; + const texture_t *hittexture = NULL; + vec_t startdepth = 1; + vec3_t startdepthnormal; + + VectorClear(startdepthnormal); + Vector4Clear(newimpactplane); + + // fast case for AABB vs compiled brushes (which begin with AABB planes and also have precomputed bevels for AABB collisions) + if (trace_start->isaabb && other_start->hasaabbplanes) + numplanes3 = numplanes2 = numplanes1; + + // Separating Axis Theorem: + // if a supporting vector (plane normal) can be found that separates two + // objects, they are not colliding. + // + // Minkowski Sum: + // reduce the size of one object to a point while enlarging the other to + // represent the space that point can not occupy. + // + // try every plane we can construct between the two brushes and measure + // the distance between them. + for (nplane = 0;nplane < numplanes3;nplane++) + { + if (nplane < numplanes1) + { + nplane2 = nplane; + VectorCopy(other_start->planes[nplane2].normal, startplane); + VectorCopy(other_end->planes[nplane2].normal, endplane); + } + else if (nplane < numplanes2) + { + nplane2 = nplane - numplanes1; + VectorCopy(trace_start->planes[nplane2].normal, startplane); + VectorCopy(trace_end->planes[nplane2].normal, endplane); + } + else + { + // pick an edgedir from each brush and cross them + nplane2 = nplane - numplanes2; + nedge1 = nplane2 >> 1; + nedge2 = nedge1 / tracenumedgedirs; + nedge1 -= nedge2 * tracenumedgedirs; + if (nplane2 & 1) + { + CrossProduct(trace_start->edgedirs[nedge1].v, other_start->edgedirs[nedge2].v, startplane); + if (VectorLength2(startplane) < COLLISION_EDGECROSS_MINLENGTH2) + continue; // degenerate crossproduct + CrossProduct(trace_end->edgedirs[nedge1].v, other_end->edgedirs[nedge2].v, endplane); + if (VectorLength2(endplane) < COLLISION_EDGECROSS_MINLENGTH2) + continue; // degenerate crossproduct + } + else + { + CrossProduct(other_start->edgedirs[nedge2].v, trace_start->edgedirs[nedge1].v, startplane); + if (VectorLength2(startplane) < COLLISION_EDGECROSS_MINLENGTH2) + continue; // degenerate crossproduct + CrossProduct(other_end->edgedirs[nedge2].v, trace_end->edgedirs[nedge1].v, endplane); + if (VectorLength2(endplane) < COLLISION_EDGECROSS_MINLENGTH2) + continue; // degenerate crossproduct + } + VectorNormalize(startplane); + VectorNormalize(endplane); + } + startplane[3] = furthestplanedist_float(startplane, other_start->points, othernumpoints); + endplane[3] = furthestplanedist_float(startplane, other_end->points, othernumpoints); + startdist = nearestplanedist_float(startplane, trace_start->points, tracenumpoints) - startplane[3] - collision_startnudge.value; + enddist = nearestplanedist_float(endplane, trace_end->points, tracenumpoints) - endplane[3] - collision_endnudge.value; + //Con_Printf("%c%i: startdist = %f, enddist = %f, startdist / (startdist - enddist) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, startdist, enddist, startdist / (startdist - enddist)); + + // aside from collisions, this is also used for error correction + if (startdist < collision_impactnudge.value && nplane < numplanes1 && (startdepth < startdist || startdepth == 1)) + { + startdepth = startdist; + VectorCopy(startplane, startdepthnormal); + } + + if (startdist > enddist) + { + // moving into brush + if (enddist >= collision_enternudge.value) + return; + if (startdist > 0) + { + // enter + imove = 1 / (startdist - enddist); + f = (startdist - collision_enternudge.value) * imove; + if (f < 0) + f = 0; + // check if this will reduce the collision time range + if (enterfrac < f) + { + // reduced collision time range + enterfrac = f; + // if the collision time range is now empty, no collision + if (enterfrac > leavefrac) + return; + // if the collision would be further away than the trace's + // existing collision data, we don't care about this + // collision + if (enterfrac > trace->realfraction) + return; + // calculate the nudged fraction and impact normal we'll + // need if we accept this collision later + enterfrac2 = (startdist - collision_impactnudge.value) * imove; + ie = 1.0f - enterfrac; + newimpactplane[0] = startplane[0] * ie + endplane[0] * enterfrac; + newimpactplane[1] = startplane[1] * ie + endplane[1] * enterfrac; + newimpactplane[2] = startplane[2] * ie + endplane[2] * enterfrac; + newimpactplane[3] = startplane[3] * ie + endplane[3] * enterfrac; + if (nplane < numplanes1) + { + // use the plane from other + nplane2 = nplane; + hitq3surfaceflags = other_start->planes[nplane2].q3surfaceflags; + hittexture = other_start->planes[nplane2].texture; + } + else if (nplane < numplanes2) + { + // use the plane from trace + nplane2 = nplane - numplanes1; + hitq3surfaceflags = trace_start->planes[nplane2].q3surfaceflags; + hittexture = trace_start->planes[nplane2].texture; + } + else + { + hitq3surfaceflags = other_start->q3surfaceflags; + hittexture = other_start->texture; + } + } + } + } + else + { + // moving out of brush + if (startdist > 0) + return; + if (enddist > 0) + { + // leave + f = (startdist + collision_leavenudge.value) / (startdist - enddist); + if (f > 1) + f = 1; + // check if this will reduce the collision time range + if (leavefrac > f) + { + // reduced collision time range + leavefrac = f; + // if the collision time range is now empty, no collision + if (enterfrac > leavefrac) + return; + } + } + } + } + + // at this point we know the trace overlaps the brush because it was not + // rejected at any point in the loop above + + // see if the trace started outside the brush or not + if (enterfrac > -1) + { + // started outside, and overlaps, therefore there is a collision here + // store out the impact information + if (trace->hitsupercontentsmask & other_start->supercontents) + { + trace->hitsupercontents = other_start->supercontents; + trace->hitq3surfaceflags = hitq3surfaceflags; + trace->hittexture = hittexture; + trace->realfraction = bound(0, enterfrac, 1); + trace->fraction = bound(0, enterfrac2, 1); + if (collision_prefernudgedfraction.integer) + trace->realfraction = trace->fraction; + VectorCopy(newimpactplane, trace->plane.normal); + trace->plane.dist = newimpactplane[3]; + } + } + else + { + // started inside, update startsolid and friends + trace->startsupercontents |= other_start->supercontents; + if (trace->hitsupercontentsmask & other_start->supercontents) + { + trace->startsolid = true; + if (leavefrac < 1) + trace->allsolid = true; + VectorCopy(newimpactplane, trace->plane.normal); + trace->plane.dist = newimpactplane[3]; + if (trace->startdepth > startdepth) + { + trace->startdepth = startdepth; + VectorCopy(startdepthnormal, trace->startdepthnormal); + } + } + } +} + +// NOTE: start and end of each brush pair must have same numplanes/numpoints +void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *other_start, const colbrushf_t *other_end) +{ + int nplane, hitq3surfaceflags = 0; + int numplanes = other_start->numplanes; + vec_t enterfrac = -1, leavefrac = 1, startdist, enddist, ie, f, imove, enterfrac2 = -1; + vec4_t startplane; + vec4_t endplane; + vec4_t newimpactplane; + const texture_t *hittexture = NULL; + vec_t startdepth = 1; + vec3_t startdepthnormal; + + if (collision_debug_tracelineasbox.integer) + { + colboxbrushf_t thisbrush_start, thisbrush_end; + Collision_BrushForBox(&thisbrush_start, linestart, linestart, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, lineend, lineend, 0, 0, NULL); + Collision_TraceBrushBrushFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, other_start, other_end); + return; + } + + VectorClear(startdepthnormal); + Vector4Clear(newimpactplane); + + // Separating Axis Theorem: + // if a supporting vector (plane normal) can be found that separates two + // objects, they are not colliding. + // + // Minkowski Sum: + // reduce the size of one object to a point while enlarging the other to + // represent the space that point can not occupy. + // + // try every plane we can construct between the two brushes and measure + // the distance between them. + for (nplane = 0;nplane < numplanes;nplane++) + { + VectorCopy(other_start->planes[nplane].normal, startplane); + startplane[3] = other_start->planes[nplane].dist; + VectorCopy(other_end->planes[nplane].normal, endplane); + endplane[3] = other_end->planes[nplane].dist; + startdist = DotProduct(linestart, startplane) - startplane[3] - collision_startnudge.value; + enddist = DotProduct(lineend, endplane) - endplane[3] - collision_endnudge.value; + //Con_Printf("%c%i: startdist = %f, enddist = %f, startdist / (startdist - enddist) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, startdist, enddist, startdist / (startdist - enddist)); + + // aside from collisions, this is also used for error correction + if (startdist < collision_impactnudge.value && (startdepth < startdist || startdepth == 1)) + { + startdepth = startdist; + VectorCopy(startplane, startdepthnormal); + } + + if (startdist > enddist) + { + // moving into brush + if (enddist >= collision_enternudge.value) + return; + if (startdist > 0) + { + // enter + imove = 1 / (startdist - enddist); + f = (startdist - collision_enternudge.value) * imove; + if (f < 0) + f = 0; + // check if this will reduce the collision time range + if (enterfrac < f) + { + // reduced collision time range + enterfrac = f; + // if the collision time range is now empty, no collision + if (enterfrac > leavefrac) + return; + // if the collision would be further away than the trace's + // existing collision data, we don't care about this + // collision + if (enterfrac > trace->realfraction) + return; + // calculate the nudged fraction and impact normal we'll + // need if we accept this collision later + enterfrac2 = (startdist - collision_impactnudge.value) * imove; + ie = 1.0f - enterfrac; + newimpactplane[0] = startplane[0] * ie + endplane[0] * enterfrac; + newimpactplane[1] = startplane[1] * ie + endplane[1] * enterfrac; + newimpactplane[2] = startplane[2] * ie + endplane[2] * enterfrac; + newimpactplane[3] = startplane[3] * ie + endplane[3] * enterfrac; + hitq3surfaceflags = other_start->planes[nplane].q3surfaceflags; + hittexture = other_start->planes[nplane].texture; + } + } + } + else + { + // moving out of brush + if (startdist > 0) + return; + if (enddist > 0) + { + // leave + f = (startdist + collision_leavenudge.value) / (startdist - enddist); + if (f > 1) + f = 1; + // check if this will reduce the collision time range + if (leavefrac > f) + { + // reduced collision time range + leavefrac = f; + // if the collision time range is now empty, no collision + if (enterfrac > leavefrac) + return; + } + } + } + } + + // at this point we know the trace overlaps the brush because it was not + // rejected at any point in the loop above + + // see if the trace started outside the brush or not + if (enterfrac > -1) + { + // started outside, and overlaps, therefore there is a collision here + // store out the impact information + if (trace->hitsupercontentsmask & other_start->supercontents) + { + trace->hitsupercontents = other_start->supercontents; + trace->hitq3surfaceflags = hitq3surfaceflags; + trace->hittexture = hittexture; + trace->realfraction = bound(0, enterfrac, 1); + trace->fraction = bound(0, enterfrac2, 1); + if (collision_prefernudgedfraction.integer) + trace->realfraction = trace->fraction; + VectorCopy(newimpactplane, trace->plane.normal); + trace->plane.dist = newimpactplane[3]; + } + } + else + { + // started inside, update startsolid and friends + trace->startsupercontents |= other_start->supercontents; + if (trace->hitsupercontentsmask & other_start->supercontents) + { + trace->startsolid = true; + if (leavefrac < 1) + trace->allsolid = true; + VectorCopy(newimpactplane, trace->plane.normal); + trace->plane.dist = newimpactplane[3]; + if (trace->startdepth > startdepth) + { + trace->startdepth = startdepth; + VectorCopy(startdepthnormal, trace->startdepthnormal); + } + } + } +} + +qboolean Collision_PointInsideBrushFloat(const vec3_t point, const colbrushf_t *brush) +{ + int nplane; + const colplanef_t *plane; + + if (!BoxesOverlap(point, point, brush->mins, brush->maxs)) + return false; + for (nplane = 0, plane = brush->planes;nplane < brush->numplanes;nplane++, plane++) + if (DotProduct(plane->normal, point) > plane->dist) + return false; + return true; +} + +void Collision_TracePointBrushFloat(trace_t *trace, const vec3_t point, const colbrushf_t *thatbrush) +{ + if (!Collision_PointInsideBrushFloat(point, thatbrush)) + return; + + trace->startsupercontents |= thatbrush->supercontents; + if (trace->hitsupercontentsmask & thatbrush->supercontents) + { + trace->startsolid = true; + trace->allsolid = true; + } +} + +static void Collision_SnapCopyPoints(int numpoints, const colpointf_t *in, colpointf_t *out, float fractionprecision, float invfractionprecision) +{ + int i; + for (i = 0;i < numpoints;i++) + { + out[i].v[0] = floor(in[i].v[0] * fractionprecision + 0.5f) * invfractionprecision; + out[i].v[1] = floor(in[i].v[1] * fractionprecision + 0.5f) * invfractionprecision; + out[i].v[2] = floor(in[i].v[2] * fractionprecision + 0.5f) * invfractionprecision; + } +} + +void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numtriangles, const int *element3i, const float *vertex3f, int stride, float *bbox6f, int supercontents, int q3surfaceflags, const texture_t *texture, const vec3_t segmentmins, const vec3_t segmentmaxs) +{ + int i; + colpointf_t points[3]; + colpointf_t edgedirs[3]; + colplanef_t planes[5]; + colbrushf_t brush; + memset(&brush, 0, sizeof(brush)); + brush.isaabb = false; + brush.hasaabbplanes = false; + brush.numpoints = 3; + brush.numedgedirs = 3; + brush.numplanes = 5; + brush.points = points; + brush.edgedirs = edgedirs; + brush.planes = planes; + brush.supercontents = supercontents; + brush.q3surfaceflags = q3surfaceflags; + brush.texture = texture; + for (i = 0;i < brush.numplanes;i++) + { + brush.planes[i].q3surfaceflags = q3surfaceflags; + brush.planes[i].texture = texture; + } + if(stride > 0) + { + int k, cnt, tri; + cnt = (numtriangles + stride - 1) / stride; + for(i = 0; i < cnt; ++i) + { + if(BoxesOverlap(bbox6f + i * 6, bbox6f + i * 6 + 3, segmentmins, segmentmaxs)) + { + for(k = 0; k < stride; ++k) + { + tri = i * stride + k; + if(tri >= numtriangles) + break; + VectorCopy(vertex3f + element3i[tri * 3 + 0] * 3, points[0].v); + VectorCopy(vertex3f + element3i[tri * 3 + 1] * 3, points[1].v); + VectorCopy(vertex3f + element3i[tri * 3 + 2] * 3, points[2].v); + Collision_SnapCopyPoints(brush.numpoints, points, points, COLLISION_SNAPSCALE, COLLISION_SNAP); + Collision_CalcEdgeDirsForPolygonBrushFloat(&brush); + Collision_CalcPlanesForTriangleBrushFloat(&brush); + //Collision_PrintBrushAsQHull(&brush, "brush"); + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &brush, &brush); + } + } + } + } + else if(stride == 0) + { + for (i = 0;i < numtriangles;i++, element3i += 3) + { + if (TriangleBBoxOverlapsBox(vertex3f + element3i[0]*3, vertex3f + element3i[1]*3, vertex3f + element3i[2]*3, segmentmins, segmentmaxs)) + { + VectorCopy(vertex3f + element3i[0] * 3, points[0].v); + VectorCopy(vertex3f + element3i[1] * 3, points[1].v); + VectorCopy(vertex3f + element3i[2] * 3, points[2].v); + Collision_SnapCopyPoints(brush.numpoints, points, points, COLLISION_SNAPSCALE, COLLISION_SNAP); + Collision_CalcEdgeDirsForPolygonBrushFloat(&brush); + Collision_CalcPlanesForTriangleBrushFloat(&brush); + //Collision_PrintBrushAsQHull(&brush, "brush"); + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &brush, &brush); + } + } + } + else + { + for (i = 0;i < numtriangles;i++, element3i += 3) + { + VectorCopy(vertex3f + element3i[0] * 3, points[0].v); + VectorCopy(vertex3f + element3i[1] * 3, points[1].v); + VectorCopy(vertex3f + element3i[2] * 3, points[2].v); + Collision_SnapCopyPoints(brush.numpoints, points, points, COLLISION_SNAPSCALE, COLLISION_SNAP); + Collision_CalcEdgeDirsForPolygonBrushFloat(&brush); + Collision_CalcPlanesForTriangleBrushFloat(&brush); + //Collision_PrintBrushAsQHull(&brush, "brush"); + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &brush, &brush); + } + } +} + +void Collision_TraceLineTriangleMeshFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numtriangles, const int *element3i, const float *vertex3f, int stride, float *bbox6f, int supercontents, int q3surfaceflags, const texture_t *texture, const vec3_t segmentmins, const vec3_t segmentmaxs) +{ + int i; + // FIXME: snap vertices? + if(stride > 0) + { + int k, cnt, tri; + cnt = (numtriangles + stride - 1) / stride; + for(i = 0; i < cnt; ++i) + { + if(BoxesOverlap(bbox6f + i * 6, bbox6f + i * 6 + 3, segmentmins, segmentmaxs)) + { + for(k = 0; k < stride; ++k) + { + tri = i * stride + k; + if(tri >= numtriangles) + break; + Collision_TraceLineTriangleFloat(trace, linestart, lineend, vertex3f + element3i[tri * 3 + 0] * 3, vertex3f + element3i[tri * 3 + 1] * 3, vertex3f + element3i[tri * 3 + 2] * 3, supercontents, q3surfaceflags, texture); + } + } + } + } + else + { + for (i = 0;i < numtriangles;i++, element3i += 3) + Collision_TraceLineTriangleFloat(trace, linestart, lineend, vertex3f + element3i[0] * 3, vertex3f + element3i[1] * 3, vertex3f + element3i[2] * 3, supercontents, q3surfaceflags, texture); + } +} + +void Collision_TraceBrushTriangleFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const float *v0, const float *v1, const float *v2, int supercontents, int q3surfaceflags, const texture_t *texture) +{ + int i; + colpointf_t points[3]; + colpointf_t edgedirs[3]; + colplanef_t planes[5]; + colbrushf_t brush; + memset(&brush, 0, sizeof(brush)); + brush.isaabb = false; + brush.hasaabbplanes = false; + brush.numpoints = 3; + brush.numedgedirs = 3; + brush.numplanes = 5; + brush.points = points; + brush.edgedirs = edgedirs; + brush.planes = planes; + brush.supercontents = supercontents; + brush.q3surfaceflags = q3surfaceflags; + brush.texture = texture; + for (i = 0;i < brush.numplanes;i++) + { + brush.planes[i].q3surfaceflags = q3surfaceflags; + brush.planes[i].texture = texture; + } + VectorCopy(v0, points[0].v); + VectorCopy(v1, points[1].v); + VectorCopy(v2, points[2].v); + Collision_SnapCopyPoints(brush.numpoints, points, points, COLLISION_SNAPSCALE, COLLISION_SNAP); + Collision_CalcEdgeDirsForPolygonBrushFloat(&brush); + Collision_CalcPlanesForTriangleBrushFloat(&brush); + //Collision_PrintBrushAsQHull(&brush, "brush"); + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &brush, &brush); +} + +void Collision_BrushForBox(colboxbrushf_t *boxbrush, const vec3_t mins, const vec3_t maxs, int supercontents, int q3surfaceflags, const texture_t *texture) +{ + int i; + memset(boxbrush, 0, sizeof(*boxbrush)); + boxbrush->brush.isaabb = true; + boxbrush->brush.hasaabbplanes = true; + boxbrush->brush.points = boxbrush->points; + boxbrush->brush.edgedirs = boxbrush->edgedirs; + boxbrush->brush.planes = boxbrush->planes; + boxbrush->brush.supercontents = supercontents; + boxbrush->brush.q3surfaceflags = q3surfaceflags; + boxbrush->brush.texture = texture; + if (VectorCompare(mins, maxs)) + { + // point brush + boxbrush->brush.numpoints = 1; + boxbrush->brush.numedgedirs = 0; + boxbrush->brush.numplanes = 0; + VectorCopy(mins, boxbrush->brush.points[0].v); + } + else + { + boxbrush->brush.numpoints = 8; + boxbrush->brush.numedgedirs = 3; + boxbrush->brush.numplanes = 6; + // there are 8 points on a box + // there are 3 edgedirs on a box (both signs are tested in collision) + // there are 6 planes on a box + VectorSet(boxbrush->brush.points[0].v, mins[0], mins[1], mins[2]); + VectorSet(boxbrush->brush.points[1].v, maxs[0], mins[1], mins[2]); + VectorSet(boxbrush->brush.points[2].v, mins[0], maxs[1], mins[2]); + VectorSet(boxbrush->brush.points[3].v, maxs[0], maxs[1], mins[2]); + VectorSet(boxbrush->brush.points[4].v, mins[0], mins[1], maxs[2]); + VectorSet(boxbrush->brush.points[5].v, maxs[0], mins[1], maxs[2]); + VectorSet(boxbrush->brush.points[6].v, mins[0], maxs[1], maxs[2]); + VectorSet(boxbrush->brush.points[7].v, maxs[0], maxs[1], maxs[2]); + VectorSet(boxbrush->brush.edgedirs[0].v, 1, 0, 0); + VectorSet(boxbrush->brush.edgedirs[1].v, 0, 1, 0); + VectorSet(boxbrush->brush.edgedirs[2].v, 0, 0, 1); + VectorSet(boxbrush->brush.planes[0].normal, -1, 0, 0);boxbrush->brush.planes[0].dist = -mins[0]; + VectorSet(boxbrush->brush.planes[1].normal, 1, 0, 0);boxbrush->brush.planes[1].dist = maxs[0]; + VectorSet(boxbrush->brush.planes[2].normal, 0, -1, 0);boxbrush->brush.planes[2].dist = -mins[1]; + VectorSet(boxbrush->brush.planes[3].normal, 0, 1, 0);boxbrush->brush.planes[3].dist = maxs[1]; + VectorSet(boxbrush->brush.planes[4].normal, 0, 0, -1);boxbrush->brush.planes[4].dist = -mins[2]; + VectorSet(boxbrush->brush.planes[5].normal, 0, 0, 1);boxbrush->brush.planes[5].dist = maxs[2]; + for (i = 0;i < 6;i++) + { + boxbrush->brush.planes[i].q3surfaceflags = q3surfaceflags; + boxbrush->brush.planes[i].texture = texture; + } + } + boxbrush->brush.supercontents = supercontents; + boxbrush->brush.q3surfaceflags = q3surfaceflags; + boxbrush->brush.texture = texture; + VectorSet(boxbrush->brush.mins, mins[0] - 1, mins[1] - 1, mins[2] - 1); + VectorSet(boxbrush->brush.maxs, maxs[0] + 1, maxs[1] + 1, maxs[2] + 1); + //Collision_ValidateBrush(&boxbrush->brush); +} + +//pseudocode for detecting line/sphere overlap without calculating an impact point +//linesphereorigin = sphereorigin - linestart;linediff = lineend - linestart;linespherefrac = DotProduct(linesphereorigin, linediff) / DotProduct(linediff, linediff);return VectorLength2(linesphereorigin - bound(0, linespherefrac, 1) * linediff) >= sphereradius*sphereradius; + +// LordHavoc: currently unused, but tested +// note: this can be used for tracing a moving sphere vs a stationary sphere, +// by simply adding the moving sphere's radius to the sphereradius parameter, +// all the results are correct (impactpoint, impactnormal, and fraction) +float Collision_ClipTrace_Line_Sphere(double *linestart, double *lineend, double *sphereorigin, double sphereradius, double *impactpoint, double *impactnormal) +{ + double dir[3], scale, v[3], deviationdist2, impactdist, linelength; + // make sure the impactpoint and impactnormal are valid even if there is + // no collision + VectorCopy(lineend, impactpoint); + VectorClear(impactnormal); + // calculate line direction + VectorSubtract(lineend, linestart, dir); + // normalize direction + linelength = VectorLength(dir); + if (linelength) + { + scale = 1.0 / linelength; + VectorScale(dir, scale, dir); + } + // this dotproduct calculates the distance along the line at which the + // sphere origin is (nearest point to the sphere origin on the line) + impactdist = DotProduct(sphereorigin, dir) - DotProduct(linestart, dir); + // calculate point on line at that distance, and subtract the + // sphereorigin from it, so we have a vector to measure for the distance + // of the line from the sphereorigin (deviation, how off-center it is) + VectorMA(linestart, impactdist, dir, v); + VectorSubtract(v, sphereorigin, v); + deviationdist2 = sphereradius * sphereradius - VectorLength2(v); + // if squared offset length is outside the squared sphere radius, miss + if (deviationdist2 < 0) + return 1; // miss (off to the side) + // nudge back to find the correct impact distance + impactdist -= sqrt(deviationdist2); + if (impactdist >= linelength) + return 1; // miss (not close enough) + if (impactdist < 0) + return 1; // miss (linestart is past or inside sphere) + // calculate new impactpoint + VectorMA(linestart, impactdist, dir, impactpoint); + // calculate impactnormal (surface normal at point of impact) + VectorSubtract(impactpoint, sphereorigin, impactnormal); + // normalize impactnormal + VectorNormalize(impactnormal); + // return fraction of movement distance + return impactdist / linelength; +} + +void Collision_TraceLineTriangleFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const float *point0, const float *point1, const float *point2, int supercontents, int q3surfaceflags, const texture_t *texture) +{ +#if 1 + // more optimized + float d1, d2, d, f, impact[3], edgenormal[3], faceplanenormal[3], faceplanedist, faceplanenormallength2, edge01[3], edge21[3], edge02[3]; + + // this function executes: + // 32 ops when line starts behind triangle + // 38 ops when line ends infront of triangle + // 43 ops when line fraction is already closer than this triangle + // 72 ops when line is outside edge 01 + // 92 ops when line is outside edge 21 + // 115 ops when line is outside edge 02 + // 123 ops when line impacts triangle and updates trace results + + // this code is designed for clockwise triangles, conversion to + // counterclockwise would require swapping some things around... + // it is easier to simply swap the point0 and point2 parameters to this + // function when calling it than it is to rewire the internals. + + // calculate the faceplanenormal of the triangle, this represents the front side + // 15 ops + VectorSubtract(point0, point1, edge01); + VectorSubtract(point2, point1, edge21); + CrossProduct(edge01, edge21, faceplanenormal); + // there's no point in processing a degenerate triangle (GIGO - Garbage In, Garbage Out) + // 6 ops + faceplanenormallength2 = DotProduct(faceplanenormal, faceplanenormal); + if (faceplanenormallength2 < 0.0001f) + return; + // calculate the distance + // 5 ops + faceplanedist = DotProduct(point0, faceplanenormal); + + // if start point is on the back side there is no collision + // (we don't care about traces going through the triangle the wrong way) + + // calculate the start distance + // 6 ops + d1 = DotProduct(faceplanenormal, linestart); + if (d1 <= faceplanedist) + return; + + // calculate the end distance + // 6 ops + d2 = DotProduct(faceplanenormal, lineend); + // if both are in front, there is no collision + if (d2 >= faceplanedist) + return; + + // from here on we know d1 is >= 0 and d2 is < 0 + // this means the line starts infront and ends behind, passing through it + + // calculate the recipricol of the distance delta, + // so we can use it multiple times cheaply (instead of division) + // 2 ops + d = 1.0f / (d1 - d2); + // calculate the impact fraction by taking the start distance (> 0) + // and subtracting the face plane distance (this is the distance of the + // triangle along that same normal) + // then multiply by the recipricol distance delta + // 2 ops + f = (d1 - faceplanedist) * d; + // skip out if this impact is further away than previous ones + // 1 ops + if (f > trace->realfraction) + return; + // calculate the perfect impact point for classification of insidedness + // 9 ops + impact[0] = linestart[0] + f * (lineend[0] - linestart[0]); + impact[1] = linestart[1] + f * (lineend[1] - linestart[1]); + impact[2] = linestart[2] + f * (lineend[2] - linestart[2]); + + // calculate the edge normal and reject if impact is outside triangle + // (an edge normal faces away from the triangle, to get the desired normal + // a crossproduct with the faceplanenormal is used, and because of the way + // the insidedness comparison is written it does not need to be normalized) + + // first use the two edges from the triangle plane math + // the other edge only gets calculated if the point survives that long + + // 20 ops + CrossProduct(edge01, faceplanenormal, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point1, edgenormal)) + return; + + // 20 ops + CrossProduct(faceplanenormal, edge21, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point2, edgenormal)) + return; + + // 23 ops + VectorSubtract(point0, point2, edge02); + CrossProduct(faceplanenormal, edge02, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point0, edgenormal)) + return; + + // 8 ops (rare) + + // store the new trace fraction + trace->realfraction = f; + + // calculate a nudged fraction to keep it out of the surface + // (the main fraction remains perfect) + trace->fraction = f - collision_impactnudge.value * d; + + if (collision_prefernudgedfraction.integer) + trace->realfraction = trace->fraction; + + // store the new trace plane (because collisions only happen from + // the front this is always simply the triangle normal, never flipped) + d = 1.0 / sqrt(faceplanenormallength2); + VectorScale(faceplanenormal, d, trace->plane.normal); + trace->plane.dist = faceplanedist * d; + + trace->hitsupercontents = supercontents; + trace->hitq3surfaceflags = q3surfaceflags; + trace->hittexture = texture; +#else + float d1, d2, d, f, fnudged, impact[3], edgenormal[3], faceplanenormal[3], faceplanedist, edge[3]; + + // this code is designed for clockwise triangles, conversion to + // counterclockwise would require swapping some things around... + // it is easier to simply swap the point0 and point2 parameters to this + // function when calling it than it is to rewire the internals. + + // calculate the unnormalized faceplanenormal of the triangle, + // this represents the front side + TriangleNormal(point0, point1, point2, faceplanenormal); + // there's no point in processing a degenerate triangle + // (GIGO - Garbage In, Garbage Out) + if (DotProduct(faceplanenormal, faceplanenormal) < 0.0001f) + return; + // calculate the unnormalized distance + faceplanedist = DotProduct(point0, faceplanenormal); + + // calculate the unnormalized start distance + d1 = DotProduct(faceplanenormal, linestart) - faceplanedist; + // if start point is on the back side there is no collision + // (we don't care about traces going through the triangle the wrong way) + if (d1 <= 0) + return; + + // calculate the unnormalized end distance + d2 = DotProduct(faceplanenormal, lineend) - faceplanedist; + // if both are in front, there is no collision + if (d2 >= 0) + return; + + // from here on we know d1 is >= 0 and d2 is < 0 + // this means the line starts infront and ends behind, passing through it + + // calculate the recipricol of the distance delta, + // so we can use it multiple times cheaply (instead of division) + d = 1.0f / (d1 - d2); + // calculate the impact fraction by taking the start distance (> 0) + // and subtracting the face plane distance (this is the distance of the + // triangle along that same normal) + // then multiply by the recipricol distance delta + f = d1 * d; + // skip out if this impact is further away than previous ones + if (f > trace->realfraction) + return; + // calculate the perfect impact point for classification of insidedness + impact[0] = linestart[0] + f * (lineend[0] - linestart[0]); + impact[1] = linestart[1] + f * (lineend[1] - linestart[1]); + impact[2] = linestart[2] + f * (lineend[2] - linestart[2]); + + // calculate the edge normal and reject if impact is outside triangle + // (an edge normal faces away from the triangle, to get the desired normal + // a crossproduct with the faceplanenormal is used, and because of the way + // the insidedness comparison is written it does not need to be normalized) + + VectorSubtract(point2, point0, edge); + CrossProduct(edge, faceplanenormal, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point0, edgenormal)) + return; + + VectorSubtract(point0, point1, edge); + CrossProduct(edge, faceplanenormal, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point1, edgenormal)) + return; + + VectorSubtract(point1, point2, edge); + CrossProduct(edge, faceplanenormal, edgenormal); + if (DotProduct(impact, edgenormal) > DotProduct(point2, edgenormal)) + return; + + // store the new trace fraction + trace->realfraction = bound(0, f, 1); + + // store the new trace plane (because collisions only happen from + // the front this is always simply the triangle normal, never flipped) + VectorNormalize(faceplanenormal); + VectorCopy(faceplanenormal, trace->plane.normal); + trace->plane.dist = DotProduct(point0, faceplanenormal); + + // calculate the normalized start and end distances + d1 = DotProduct(trace->plane.normal, linestart) - trace->plane.dist; + d2 = DotProduct(trace->plane.normal, lineend) - trace->plane.dist; + + // calculate a nudged fraction to keep it out of the surface + // (the main fraction remains perfect) + fnudged = (d1 - collision_impactnudge.value) / (d1 - d2); + trace->fraction = bound(0, fnudged, 1); + + // store the new trace endpos + // not needed, it's calculated later when the trace is finished + //trace->endpos[0] = linestart[0] + fnudged * (lineend[0] - linestart[0]); + //trace->endpos[1] = linestart[1] + fnudged * (lineend[1] - linestart[1]); + //trace->endpos[2] = linestart[2] + fnudged * (lineend[2] - linestart[2]); + trace->hitsupercontents = supercontents; + trace->hitq3surfaceflags = q3surfaceflags; + trace->hittexture = texture; +#endif +} + +void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const colbrushf_t *end, vec3_t mins, vec3_t maxs, float startfrac, float endfrac) +{ + int i; + colpointf_t *ps, *pe; + float tempstart[3], tempend[3]; + VectorLerp(start->points[0].v, startfrac, end->points[0].v, mins); + VectorCopy(mins, maxs); + for (i = 0, ps = start->points, pe = end->points;i < start->numpoints;i++, ps++, pe++) + { + VectorLerp(ps->v, startfrac, pe->v, tempstart); + VectorLerp(ps->v, endfrac, pe->v, tempend); + mins[0] = min(mins[0], min(tempstart[0], tempend[0])); + mins[1] = min(mins[1], min(tempstart[1], tempend[1])); + mins[2] = min(mins[2], min(tempstart[2], tempend[2])); + maxs[0] = min(maxs[0], min(tempstart[0], tempend[0])); + maxs[1] = min(maxs[1], min(tempstart[1], tempend[1])); + maxs[2] = min(maxs[2], min(tempstart[2], tempend[2])); + } + mins[0] -= 1; + mins[1] -= 1; + mins[2] -= 1; + maxs[0] += 1; + maxs[1] += 1; + maxs[2] += 1; +} + +//=========================================== + +static void Collision_TranslateBrush(const vec3_t shift, colbrushf_t *brush) +{ + int i; + // now we can transform the data + for(i = 0; i < brush->numplanes; ++i) + { + brush->planes[i].dist += DotProduct(shift, brush->planes[i].normal); + } + for(i = 0; i < brush->numpoints; ++i) + { + VectorAdd(brush->points[i].v, shift, brush->points[i].v); + } + VectorAdd(brush->mins, shift, brush->mins); + VectorAdd(brush->maxs, shift, brush->maxs); +} + +static void Collision_TransformBrush(const matrix4x4_t *matrix, colbrushf_t *brush) +{ + int i; + vec3_t v; + // we're breaking any AABB properties here... + brush->isaabb = false; + brush->hasaabbplanes = false; + // now we can transform the data + for(i = 0; i < brush->numplanes; ++i) + { + Matrix4x4_TransformPositivePlane(matrix, brush->planes[i].normal[0], brush->planes[i].normal[1], brush->planes[i].normal[2], brush->planes[i].dist, brush->planes[i].normal); + } + for(i = 0; i < brush->numedgedirs; ++i) + { + Matrix4x4_Transform(matrix, brush->edgedirs[i].v, v); + VectorCopy(v, brush->edgedirs[i].v); + } + for(i = 0; i < brush->numpoints; ++i) + { + Matrix4x4_Transform(matrix, brush->points[i].v, v); + VectorCopy(v, brush->points[i].v); + } + VectorCopy(brush->points[0].v, brush->mins); + VectorCopy(brush->points[0].v, brush->maxs); + for(i = 1; i < brush->numpoints; ++i) + { + if(brush->points[i].v[0] < brush->mins[0]) brush->mins[0] = brush->points[i].v[0]; + if(brush->points[i].v[1] < brush->mins[1]) brush->mins[1] = brush->points[i].v[1]; + if(brush->points[i].v[2] < brush->mins[2]) brush->mins[2] = brush->points[i].v[2]; + if(brush->points[i].v[0] > brush->maxs[0]) brush->maxs[0] = brush->points[i].v[0]; + if(brush->points[i].v[1] > brush->maxs[1]) brush->maxs[1] = brush->points[i].v[1]; + if(brush->points[i].v[2] > brush->maxs[2]) brush->maxs[2] = brush->points[i].v[2]; + } +} + +typedef struct collision_cachedtrace_parameters_s +{ + dp_model_t *model; + vec3_t end; + vec3_t start; + int hitsupercontentsmask; + matrix4x4_t matrix; +} +collision_cachedtrace_parameters_t; + +typedef struct collision_cachedtrace_s +{ + qboolean valid; + collision_cachedtrace_parameters_t p; + trace_t result; +} +collision_cachedtrace_t; + +static mempool_t *collision_cachedtrace_mempool; +static collision_cachedtrace_t *collision_cachedtrace_array; +static int collision_cachedtrace_firstfree; +static int collision_cachedtrace_lastused; +static int collision_cachedtrace_max; +static int collision_cachedtrace_sequence; +static int collision_cachedtrace_hashsize; +static int *collision_cachedtrace_hash; +static unsigned int *collision_cachedtrace_arrayfullhashindex; +static unsigned int *collision_cachedtrace_arrayhashindex; +static unsigned int *collision_cachedtrace_arraynext; +static unsigned char *collision_cachedtrace_arrayused; +static qboolean collision_cachedtrace_rebuildhash; + +void Collision_Cache_Reset(qboolean resetlimits) +{ + if (collision_cachedtrace_hash) + Mem_Free(collision_cachedtrace_hash); + if (collision_cachedtrace_array) + Mem_Free(collision_cachedtrace_array); + if (collision_cachedtrace_arrayfullhashindex) + Mem_Free(collision_cachedtrace_arrayfullhashindex); + if (collision_cachedtrace_arrayhashindex) + Mem_Free(collision_cachedtrace_arrayhashindex); + if (collision_cachedtrace_arraynext) + Mem_Free(collision_cachedtrace_arraynext); + if (collision_cachedtrace_arrayused) + Mem_Free(collision_cachedtrace_arrayused); + if (resetlimits || !collision_cachedtrace_max) + collision_cachedtrace_max = collision_cache.integer ? 128 : 1; + collision_cachedtrace_firstfree = 1; + collision_cachedtrace_lastused = 0; + collision_cachedtrace_hashsize = collision_cachedtrace_max; + collision_cachedtrace_array = (collision_cachedtrace_t *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_max * sizeof(collision_cachedtrace_t)); + collision_cachedtrace_hash = (int *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_hashsize * sizeof(int)); + collision_cachedtrace_arrayfullhashindex = (unsigned int *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_max * sizeof(unsigned int)); + collision_cachedtrace_arrayhashindex = (unsigned int *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_max * sizeof(unsigned int)); + collision_cachedtrace_arraynext = (unsigned int *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_max * sizeof(unsigned int)); + collision_cachedtrace_arrayused = (unsigned char *)Mem_Alloc(collision_cachedtrace_mempool, collision_cachedtrace_max * sizeof(unsigned char)); + collision_cachedtrace_sequence = 1; + collision_cachedtrace_rebuildhash = false; +} + +void Collision_Cache_Init(mempool_t *mempool) +{ + collision_cachedtrace_mempool = mempool; + Collision_Cache_Reset(true); +} + +static void Collision_Cache_RebuildHash(void) +{ + int index; + int range = collision_cachedtrace_lastused + 1; + int sequence = collision_cachedtrace_sequence; + int firstfree = collision_cachedtrace_max; + int lastused = 0; + int *hash = collision_cachedtrace_hash; + unsigned int hashindex; + unsigned int *arrayhashindex = collision_cachedtrace_arrayhashindex; + unsigned int *arraynext = collision_cachedtrace_arraynext; + collision_cachedtrace_rebuildhash = false; + memset(collision_cachedtrace_hash, 0, collision_cachedtrace_hashsize * sizeof(int)); + for (index = 1;index < range;index++) + { + if (collision_cachedtrace_arrayused[index] == sequence) + { + hashindex = arrayhashindex[index]; + arraynext[index] = hash[hashindex]; + hash[hashindex] = index; + lastused = index; + } + else + { + if (firstfree > index) + firstfree = index; + collision_cachedtrace_arrayused[index] = 0; + } + } + collision_cachedtrace_firstfree = firstfree; + collision_cachedtrace_lastused = lastused; +} + +void Collision_Cache_NewFrame(void) +{ + if (collision_cache.integer) + { + if (collision_cachedtrace_max < 128) + Collision_Cache_Reset(true); + } + else + { + if (collision_cachedtrace_max > 1) + Collision_Cache_Reset(true); + } + // rebuild hash if sequence would overflow byte, otherwise increment + if (collision_cachedtrace_sequence == 255) + { + Collision_Cache_RebuildHash(); + collision_cachedtrace_sequence = 1; + } + else + { + collision_cachedtrace_rebuildhash = true; + collision_cachedtrace_sequence++; + } +} + +static unsigned int Collision_Cache_HashIndexForArray(unsigned int *array, unsigned int size) +{ + unsigned int i; + unsigned int hashindex = 0; + // this is a super-cheesy checksum, designed only for speed + for (i = 0;i < size;i++) + hashindex += array[i] * (1 + i); + return hashindex; +} + +static collision_cachedtrace_t *Collision_Cache_Lookup(dp_model_t *model, const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + int hashindex = 0; + unsigned int fullhashindex; + int index = 0; + int range; + int sequence = collision_cachedtrace_sequence; + int *hash = collision_cachedtrace_hash; + unsigned int *arrayfullhashindex = collision_cachedtrace_arrayfullhashindex; + unsigned int *arraynext = collision_cachedtrace_arraynext; + collision_cachedtrace_t *cached = collision_cachedtrace_array + index; + collision_cachedtrace_parameters_t params; + // all non-cached traces use the same index + if (!collision_cache.integer) + r_refdef.stats[r_stat_photoncache_traced]++; + else + { + // cached trace lookup + memset(¶ms, 0, sizeof(params)); + params.model = model; + VectorCopy(start, params.start); + VectorCopy(end, params.end); + params.hitsupercontentsmask = hitsupercontentsmask; + params.matrix = *matrix; + fullhashindex = Collision_Cache_HashIndexForArray((unsigned int *)¶ms, sizeof(params) / sizeof(unsigned int)); + hashindex = (int)(fullhashindex % (unsigned int)collision_cachedtrace_hashsize); + for (index = hash[hashindex];index;index = arraynext[index]) + { + if (arrayfullhashindex[index] != fullhashindex) + continue; + cached = collision_cachedtrace_array + index; + //if (memcmp(&cached->p, ¶ms, sizeof(params))) + if (cached->p.model != params.model + || cached->p.end[0] != params.end[0] + || cached->p.end[1] != params.end[1] + || cached->p.end[2] != params.end[2] + || cached->p.start[0] != params.start[0] + || cached->p.start[1] != params.start[1] + || cached->p.start[2] != params.start[2] + || cached->p.hitsupercontentsmask != params.hitsupercontentsmask + || cached->p.matrix.m[0][0] != params.matrix.m[0][0] + || cached->p.matrix.m[0][1] != params.matrix.m[0][1] + || cached->p.matrix.m[0][2] != params.matrix.m[0][2] + || cached->p.matrix.m[0][3] != params.matrix.m[0][3] + || cached->p.matrix.m[1][0] != params.matrix.m[1][0] + || cached->p.matrix.m[1][1] != params.matrix.m[1][1] + || cached->p.matrix.m[1][2] != params.matrix.m[1][2] + || cached->p.matrix.m[1][3] != params.matrix.m[1][3] + || cached->p.matrix.m[2][0] != params.matrix.m[2][0] + || cached->p.matrix.m[2][1] != params.matrix.m[2][1] + || cached->p.matrix.m[2][2] != params.matrix.m[2][2] + || cached->p.matrix.m[2][3] != params.matrix.m[2][3] + || cached->p.matrix.m[3][0] != params.matrix.m[3][0] + || cached->p.matrix.m[3][1] != params.matrix.m[3][1] + || cached->p.matrix.m[3][2] != params.matrix.m[3][2] + || cached->p.matrix.m[3][3] != params.matrix.m[3][3] + ) + continue; + // found a matching trace in the cache + r_refdef.stats[r_stat_photoncache_cached]++; + cached->valid = true; + collision_cachedtrace_arrayused[index] = collision_cachedtrace_sequence; + return cached; + } + r_refdef.stats[r_stat_photoncache_traced]++; + // find an unused cache entry + for (index = collision_cachedtrace_firstfree, range = collision_cachedtrace_max;index < range;index++) + if (collision_cachedtrace_arrayused[index] == 0) + break; + if (index == range) + { + // all claimed, but probably some are stale... + for (index = 1, range = collision_cachedtrace_max;index < range;index++) + if (collision_cachedtrace_arrayused[index] != sequence) + break; + if (index < range) + { + // found a stale one, rebuild the hash + Collision_Cache_RebuildHash(); + } + else + { + // we need to grow the cache + collision_cachedtrace_max *= 2; + Collision_Cache_Reset(false); + index = 1; + } + } + // link the new cache entry into the hash bucket + collision_cachedtrace_firstfree = index + 1; + if (collision_cachedtrace_lastused < index) + collision_cachedtrace_lastused = index; + cached = collision_cachedtrace_array + index; + collision_cachedtrace_arraynext[index] = collision_cachedtrace_hash[hashindex]; + collision_cachedtrace_hash[hashindex] = index; + collision_cachedtrace_arrayhashindex[index] = hashindex; + cached->valid = false; + cached->p = params; + collision_cachedtrace_arrayfullhashindex[index] = fullhashindex; + collision_cachedtrace_arrayused[index] = collision_cachedtrace_sequence; + } + return cached; +} + +void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, matrix, inversematrix, start, end, hitsupercontentsmask); + if (cached->valid) + { + *trace = cached->result; + return; + } + + Collision_ClipLineToGenericEntity(trace, model, NULL, NULL, vec3_origin, vec3_origin, 0, matrix, inversematrix, start, end, hitsupercontentsmask, true); + + cached->result = *trace; +} + +void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents) +{ + collision_cachedtrace_t *cached = Collision_Cache_Lookup(model, &identitymatrix, &identitymatrix, start, end, hitsupercontents); + if (cached->valid) + { + *trace = cached->result; + return; + } + + Collision_ClipLineToWorld(trace, model, start, end, hitsupercontents, true); + + cached->result = *trace; +} + +void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask) +{ + float starttransformed[3], endtransformed[3]; + + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + + Matrix4x4_Transform(inversematrix, start, starttransformed); + Matrix4x4_Transform(inversematrix, end, endtransformed); +#if COLLISIONPARANOID >= 3 + Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]); +#endif + + if (model && model->TraceBox) + { + if(model->TraceBrush && (inversematrix->m[0][1] || inversematrix->m[0][2] || inversematrix->m[1][0] || inversematrix->m[1][2] || inversematrix->m[2][0] || inversematrix->m[2][1])) + { + // we get here if TraceBrush exists, AND we have a rotation component (SOLID_BSP case) + // using starttransformed, endtransformed is WRONG in this case! + // should rather build a brush and trace using it + colboxbrushf_t thisbrush_start, thisbrush_end; + Collision_BrushForBox(&thisbrush_start, mins, maxs, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, mins, maxs, 0, 0, NULL); + Collision_TranslateBrush(start, &thisbrush_start.brush); + Collision_TranslateBrush(end, &thisbrush_end.brush); + Collision_TransformBrush(inversematrix, &thisbrush_start.brush); + Collision_TransformBrush(inversematrix, &thisbrush_end.brush); + //Collision_TranslateBrush(starttransformed, &thisbrush_start.brush); + //Collision_TranslateBrush(endtransformed, &thisbrush_end.brush); + model->TraceBrush(model, frameblend, skeleton, trace, &thisbrush_start.brush, &thisbrush_end.brush, hitsupercontentsmask); + } + else // this is only approximate if rotated, quite useless + model->TraceBox(model, frameblend, skeleton, trace, starttransformed, mins, maxs, endtransformed, hitsupercontentsmask); + } + else // and this requires that the transformation matrix doesn't have angles components, like SV_TraceBox ensures; FIXME may get called if a model is SOLID_BSP but has no TraceBox function + Collision_ClipTrace_Box(trace, bodymins, bodymaxs, starttransformed, mins, maxs, endtransformed, hitsupercontentsmask, bodysupercontents, 0, NULL); + trace->fraction = bound(0, trace->fraction, 1); + trace->realfraction = bound(0, trace->realfraction, 1); + + VectorLerp(start, trace->fraction, end, trace->endpos); + // transform plane + // NOTE: this relies on plane.dist being directly after plane.normal + Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); +} + +void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents) +{ + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + // ->TraceBox: TraceBrush not needed here, as worldmodel is never rotated + if (model && model->TraceBox) + model->TraceBox(model, NULL, NULL, trace, start, mins, maxs, end, hitsupercontents); + trace->fraction = bound(0, trace->fraction, 1); + trace->realfraction = bound(0, trace->realfraction, 1); + VectorLerp(start, trace->fraction, end, trace->endpos); +} + +void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces) +{ + float starttransformed[3], endtransformed[3]; + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + + Matrix4x4_Transform(inversematrix, start, starttransformed); + Matrix4x4_Transform(inversematrix, end, endtransformed); +#if COLLISIONPARANOID >= 3 + Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]); +#endif + + if (model && model->TraceLineAgainstSurfaces && hitsurfaces) + model->TraceLineAgainstSurfaces(model, frameblend, skeleton, trace, starttransformed, endtransformed, hitsupercontentsmask); + else if (model && model->TraceLine) + model->TraceLine(model, frameblend, skeleton, trace, starttransformed, endtransformed, hitsupercontentsmask); + else + Collision_ClipTrace_Box(trace, bodymins, bodymaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, hitsupercontentsmask, bodysupercontents, 0, NULL); + trace->fraction = bound(0, trace->fraction, 1); + trace->realfraction = bound(0, trace->realfraction, 1); + + VectorLerp(start, trace->fraction, end, trace->endpos); + // transform plane + // NOTE: this relies on plane.dist being directly after plane.normal + Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); +} + +void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces) +{ + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + if (model && model->TraceLineAgainstSurfaces && hitsurfaces) + model->TraceLineAgainstSurfaces(model, NULL, NULL, trace, start, end, hitsupercontents); + else if (model && model->TraceLine) + model->TraceLine(model, NULL, NULL, trace, start, end, hitsupercontents); + trace->fraction = bound(0, trace->fraction, 1); + trace->realfraction = bound(0, trace->realfraction, 1); + VectorLerp(start, trace->fraction, end, trace->endpos); +} + +void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask) +{ + float starttransformed[3]; + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + + Matrix4x4_Transform(inversematrix, start, starttransformed); +#if COLLISIONPARANOID >= 3 + Con_Printf("trans(%f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2]); +#endif + + if (model && model->TracePoint) + model->TracePoint(model, NULL, NULL, trace, starttransformed, hitsupercontentsmask); + else + Collision_ClipTrace_Point(trace, bodymins, bodymaxs, starttransformed, hitsupercontentsmask, bodysupercontents, 0, NULL); + + VectorCopy(start, trace->endpos); + // transform plane + // NOTE: this relies on plane.dist being directly after plane.normal + Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal); +} + +void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents) +{ + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->realfraction = 1; + if (model && model->TracePoint) + model->TracePoint(model, NULL, NULL, trace, start, hitsupercontents); + VectorCopy(start, trace->endpos); +} + +void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel) +{ + // take the 'best' answers from the new trace and combine with existing data + if (trace->allsolid) + cliptrace->allsolid = true; + if (trace->startsolid) + { + if (isbmodel) + cliptrace->bmodelstartsolid = true; + cliptrace->startsolid = true; + if (cliptrace->realfraction == 1) + cliptrace->ent = touch; + if (cliptrace->startdepth > trace->startdepth) + { + cliptrace->startdepth = trace->startdepth; + VectorCopy(trace->startdepthnormal, cliptrace->startdepthnormal); + } + } + // don't set this except on the world, because it can easily confuse + // monsters underwater if there's a bmodel involved in the trace + // (inopen && inwater is how they check water visibility) + //if (trace->inopen) + // cliptrace->inopen = true; + if (trace->inwater) + cliptrace->inwater = true; + if ((trace->realfraction < cliptrace->realfraction) && (VectorLength2(trace->plane.normal) > 0)) + { + cliptrace->fraction = trace->fraction; + cliptrace->realfraction = trace->realfraction; + VectorCopy(trace->endpos, cliptrace->endpos); + cliptrace->plane = trace->plane; + cliptrace->ent = touch; + cliptrace->hitsupercontents = trace->hitsupercontents; + cliptrace->hitq3surfaceflags = trace->hitq3surfaceflags; + cliptrace->hittexture = trace->hittexture; + } + cliptrace->startsupercontents |= trace->startsupercontents; +} + +void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t end) +{ + // now undo our moving end 1 qu farther... + trace->fraction = bound(trace->fraction, trace->fraction / shorten_factor - 1e-6, 1); // we subtract 1e-6 to guard for roundoff errors + trace->realfraction = bound(trace->realfraction, trace->realfraction / shorten_factor - 1e-6, 1); // we subtract 1e-6 to guard for roundoff errors + if(trace->fraction >= 1) // trace would NOT hit if not expanded! + { + trace->fraction = 1; + trace->realfraction = 1; + VectorCopy(end, trace->endpos); + memset(&trace->plane, 0, sizeof(trace->plane)); + trace->ent = NULL; + trace->hitsupercontentsmask = 0; + trace->hitsupercontents = 0; + trace->hitq3surfaceflags = 0; + trace->hittexture = NULL; + } +} diff --git a/app/jni/collision.h b/app/jni/collision.h new file mode 100644 index 0000000..0da1247 --- /dev/null +++ b/app/jni/collision.h @@ -0,0 +1,191 @@ + +#ifndef COLLISION_H +#define COLLISION_H + +typedef struct plane_s +{ + vec3_t normal; + float dist; +} +plane_t; + +struct texture_s; +typedef struct trace_s +{ + // if true, the entire trace was in solid (see hitsupercontentsmask) + int allsolid; + // if true, the initial point was in solid (see hitsupercontentsmask) + int startsolid; + // this is set to true in world.c if startsolid was set in a trace against world + int worldstartsolid; + // this is set to true in world.c if startsolid was set in a trace against a SOLID_BSP entity, in other words this is true if the entity is stuck in a door or wall, but not if stuck in another normal entity + int bmodelstartsolid; + // if true, the trace passed through empty somewhere + // (set only by Q1BSP tracing) + int inopen; + // if true, the trace passed through water/slime/lava somewhere + // (set only by Q1BSP tracing) + int inwater; + // fraction of the total distance that was traveled before impact + // (1.0 = did not hit anything) + double fraction; + // like fraction but is not nudged away from the surface (better for + // comparisons between two trace structs, as only one nudge for the final + // result is ever needed) + double realfraction; + // final position of the trace (simply a point between start and end) + double endpos[3]; + // surface normal at impact (not really correct for edge collisions) + plane_t plane; + // entity the surface is on + // (not set by trace functions, only by physics) + void *ent; + // which SUPERCONTENTS bits to collide with, I.E. to consider solid + // (this also affects startsolid/allsolid) + int hitsupercontentsmask; + // the supercontents mask at the start point + int startsupercontents; + // the supercontents of the impacted surface + int hitsupercontents; + // the q3 surfaceflags of the impacted surface + int hitq3surfaceflags; + // the texture of the impacted surface + const struct texture_s *hittexture; + // initially false, set when the start leaf is found + // (set only by Q1BSP tracing and entity box tracing) + int startfound; + // if startsolid, contains the minimum penetration depth found in the + // trace, and the normal needed to push it out of that solid + double startdepth; + double startdepthnormal[3]; +} +trace_t; + +void Collision_Init(void); +void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture); +void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture); + +void Collision_Cache_Reset(qboolean resetlimits); +void Collision_Cache_Init(mempool_t *mempool); +void Collision_Cache_NewFrame(void); + +typedef struct colpointf_s +{ + vec3_t v; +} +colpointf_t; + +typedef struct colplanef_s +{ + const struct texture_s *texture; + int q3surfaceflags; + vec3_t normal; + vec_t dist; +} +colplanef_t; + +typedef struct colbrushf_s +{ + // culling box + vec3_t mins; + vec3_t maxs; + // used to avoid tracing against the same brush more than once per sweep + int markframe; + // the content flags of this brush + int supercontents; + // bounding planes (face planes) of this brush + int numplanes; + colplanef_t *planes; + // edge directions (normals) of this brush + int numedgedirs; + colpointf_t *edgedirs; + // points (corners) of this brush + int numpoints; + colpointf_t *points; + // renderable triangles representing this brush, using the points + int numtriangles; + int *elements; + // texture data for cases where an edgedir is used + const struct texture_s *texture; + int q3surfaceflags; + // optimized collisions for common cases + int isaabb; // indicates this is an axis aligned box + int hasaabbplanes; // indicates this has precomputed planes for AABB collisions +} +colbrushf_t; + +typedef struct colboxbrushf_s +{ + colpointf_t points[8]; + colpointf_t edgedirs[6]; + colplanef_t planes[6]; + colbrushf_t brush; +} +colboxbrushf_t; + +void Collision_CalcPlanesForTriangleBrushFloat(colbrushf_t *brush); +colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents, int q3surfaceflags, const texture_t *texture); +colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const colplanef_t *originalplanes, int supercontents, int q3surfaceflags, const texture_t *texture, int hasaabbplanes); +void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end); +void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numtriangles, const int *element3i, const float *vertex3f, int stride, float *bbox6f, int supercontents, int q3surfaceflags, const texture_t *texture, const vec3_t segmentmins, const vec3_t segmentmaxs); +void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end); +void Collision_TraceLineTriangleMeshFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numtriangles, const int *element3i, const float *vertex3f, int stride, float *bbox6f, int supercontents, int q3surfaceflags, const texture_t *texture, const vec3_t segmentmins, const vec3_t segmentmaxs); +void Collision_TracePointBrushFloat(trace_t *trace, const vec3_t point, const colbrushf_t *thatbrush); +qboolean Collision_PointInsideBrushFloat(const vec3_t point, const colbrushf_t *brush); + +void Collision_BrushForBox(colboxbrushf_t *boxbrush, const vec3_t mins, const vec3_t maxs, int supercontents, int q3surfaceflags, const texture_t *texture); + +void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const colbrushf_t *end, vec3_t mins, vec3_t maxs, float startfrac, float endfrac); + +float Collision_ClipTrace_Line_Sphere(double *linestart, double *lineend, double *sphereorigin, double sphereradius, double *impactpoint, double *impactnormal); +void Collision_TraceLineTriangleFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const float *point0, const float *point1, const float *point2, int supercontents, int q3surfaceflags, const texture_t *texture); +void Collision_TraceBrushTriangleFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const float *v0, const float *v1, const float *v2, int supercontents, int q3surfaceflags, const texture_t *texture); + +// traces a box move against a single entity +// mins and maxs are relative +// +// if the entire move stays in a single solid brush, trace.allsolid will be set +// +// if the starting point is in a solid, it will be allowed to move out to an +// open area, and trace.startsolid will be set +// +// type is one of the MOVE_ values such as MOVE_NOMONSTERS which skips box +// entities, only colliding with SOLID_BSP entities (doors, lifts) +// +// passedict is excluded from clipping checks +struct frameblend_s; +struct skeleton_s; +void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask); +void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces); +void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask); +// like above but does not do a transform and does nothing if model is NULL +void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents); +void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces); +void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents); +// caching surface trace for renderer (NOT THREAD SAFE) +void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask); +void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents); +// combines data from two traces: +// merges contents flags, startsolid, allsolid, inwater +// updates fraction, endpos, plane and surface info if new fraction is shorter +void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel); + +// shorten a trace by the given factor +void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t end); + +// this enables rather large debugging spew! +// settings: +// 0 = no spew +// 1 = spew trace calls if something odd is happening +// 2 = spew trace calls always +// 3 = spew detailed trace flow (bsp tree recursion info) +#define COLLISIONPARANOID 0 + +// make every trace qu longer, and shorten the result, to work around a stupid bug somewhere +#define COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +extern cvar_t collision_endposnudge; +#endif + + +#endif diff --git a/app/jni/common.c b/app/jni/common.c new file mode 100644 index 0000000..a669680 --- /dev/null +++ b/app/jni/common.c @@ -0,0 +1,2276 @@ +/* +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 +#include +#ifndef WIN32 +#include +#endif + +#include "quakedef.h" +#include "utf8lib.h" + +#include "snprintf.h" + +cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"}; +cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"}; + +char com_token[MAX_INPUTLINE]; +int com_argc; +const char **com_argv; +int com_selffd = -1; + +gamemode_t gamemode; +const char *gamename; +const char *gamedirname1; +const char *gamedirname2; +const char *gamescreenshotname; +const char *gameuserdirname; +char com_modname[MAX_OSPATH] = ""; + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + + +float BuffBigFloat (const unsigned char *buffer) +{ + union + { + float f; + unsigned int i; + } + u; + u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + return u.f; +} + +int BuffBigLong (const unsigned char *buffer) +{ + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; +} + +short BuffBigShort (const unsigned char *buffer) +{ + return (buffer[0] << 8) | buffer[1]; +} + +float BuffLittleFloat (const unsigned char *buffer) +{ + union + { + float f; + unsigned int i; + } + u; + u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; + return u.f; +} + +int BuffLittleLong (const unsigned char *buffer) +{ + return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; +} + +short BuffLittleShort (const unsigned char *buffer) +{ + return (buffer[1] << 8) | buffer[0]; +} + +void StoreBigLong (unsigned char *buffer, unsigned int i) +{ + buffer[0] = (i >> 24) & 0xFF; + buffer[1] = (i >> 16) & 0xFF; + buffer[2] = (i >> 8) & 0xFF; + buffer[3] = i & 0xFF; +} + +void StoreBigShort (unsigned char *buffer, unsigned short i) +{ + buffer[0] = (i >> 8) & 0xFF; + buffer[1] = i & 0xFF; +} + +void StoreLittleLong (unsigned char *buffer, unsigned int i) +{ + buffer[0] = i & 0xFF; + buffer[1] = (i >> 8) & 0xFF; + buffer[2] = (i >> 16) & 0xFF; + buffer[3] = (i >> 24) & 0xFF; +} + +void StoreLittleShort (unsigned char *buffer, unsigned short i) +{ + buffer[0] = i & 0xFF; + buffer[1] = (i >> 8) & 0xFF; +} + +/* +============================================================================ + + CRC FUNCTIONS + +============================================================================ +*/ + +// 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 +}; + +unsigned short CRC_Block(const unsigned char *data, size_t size) +{ + unsigned short crc = CRC_INIT_VALUE; + while (size--) + crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)]; + return crc ^ CRC_XOR_VALUE; +} + +unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size) +{ + unsigned short crc = CRC_INIT_VALUE; + while (size--) + crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))]; + return crc ^ CRC_XOR_VALUE; +} + +// QuakeWorld +static unsigned char chktbl[1024 + 4] = +{ + 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01, + 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a, + 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58, + 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3, + 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b, + 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36, + 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8, + 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27, + 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd, + 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63, + 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2, + 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d, + 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65, + 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f, + 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f, + 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42, + 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59, + 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9, + 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69, + 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba, + 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85, + 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4, + 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8, + 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa, + 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05, + 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7, + 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a, + 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb, + 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b, + 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d, + 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce, + 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3, + + // map checksum goes here + 0x00,0x00,0x00,0x00 +}; + +// QuakeWorld +unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence) +{ + unsigned char *p; + unsigned char chkb[60 + 4]; + + p = chktbl + (sequence % (sizeof(chktbl) - 8)); + + if (length > 60) + length = 60; + memcpy(chkb, base, length); + + chkb[length] = (sequence & 0xff) ^ p[0]; + chkb[length+1] = p[1]; + chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2]; + chkb[length+3] = p[3]; + + return CRC_Block(chkb, length + 4) & 0xff; +} + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +// +// writing functions +// + +void MSG_WriteChar (sizebuf_t *sb, int c) +{ + unsigned char *buf; + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteByte (sizebuf_t *sb, int c) +{ + unsigned char *buf; + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteShort (sizebuf_t *sb, int c) +{ + unsigned char *buf; + + buf = SZ_GetSpace (sb, 2); + buf[0] = c&0xff; + buf[1] = c>>8; +} + +void MSG_WriteLong (sizebuf_t *sb, int c) +{ + unsigned char *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, (unsigned char *)&dat.l, 4); +} + +void MSG_WriteString (sizebuf_t *sb, const char *s) +{ + if (!s || !*s) + MSG_WriteChar (sb, 0); + else + SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1); +} + +void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s) +{ + if (s && *s) + SZ_Write (sb, (unsigned char *)s, (int)strlen(s)); +} + +void MSG_WriteCoord13i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteShort (sb, (int)(f * 8.0 + 0.5)); + else + MSG_WriteShort (sb, (int)(f * 8.0 - 0.5)); +} + +void MSG_WriteCoord16i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteShort (sb, (int)(f + 0.5)); + else + MSG_WriteShort (sb, (int)(f - 0.5)); +} + +void MSG_WriteCoord32f (sizebuf_t *sb, float f) +{ + MSG_WriteFloat (sb, f); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol) +{ + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD) + MSG_WriteCoord13i (sb, f); + else if (protocol == PROTOCOL_DARKPLACES1) + MSG_WriteCoord32f (sb, f); + else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) + MSG_WriteCoord16i (sb, f); + else + MSG_WriteCoord32f (sb, f); +} + +void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol) +{ + MSG_WriteCoord (sb, v[0], protocol); + MSG_WriteCoord (sb, v[1], protocol); + MSG_WriteCoord (sb, v[2], protocol); +} + +// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem +void MSG_WriteAngle8i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255); + else + MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255); +} + +void MSG_WriteAngle16i (sizebuf_t *sb, float f) +{ + if (f >= 0) + MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535); + else + MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535); +} + +void MSG_WriteAngle32f (sizebuf_t *sb, float f) +{ + MSG_WriteFloat (sb, f); +} + +void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol) +{ + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD) + MSG_WriteAngle8i (sb, f); + else + MSG_WriteAngle16i (sb, f); +} + +// +// reading functions +// + +void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size) +{ + memset(buf, 0, sizeof(*buf)); + buf->data = data; + buf->maxsize = buf->cursize = size; + MSG_BeginReading(buf); +} + +void MSG_BeginReading(sizebuf_t *sb) +{ + sb->readcount = 0; + sb->badread = false; +} + +int MSG_ReadLittleShort(sizebuf_t *sb) +{ + if (sb->readcount+2 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 2; + return (short)(sb->data[sb->readcount-2] | (sb->data[sb->readcount-1]<<8)); +} + +int MSG_ReadBigShort (sizebuf_t *sb) +{ + if (sb->readcount+2 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 2; + return (short)((sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]); +} + +int MSG_ReadLittleLong (sizebuf_t *sb) +{ + if (sb->readcount+4 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 4; + return sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24); +} + +int MSG_ReadBigLong (sizebuf_t *sb) +{ + if (sb->readcount+4 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 4; + return (sb->data[sb->readcount-4]<<24) + (sb->data[sb->readcount-3]<<16) + (sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]; +} + +float MSG_ReadLittleFloat (sizebuf_t *sb) +{ + union + { + float f; + int l; + } dat; + if (sb->readcount+4 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 4; + dat.l = sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24); + return dat.f; +} + +float MSG_ReadBigFloat (sizebuf_t *sb) +{ + union + { + float f; + int l; + } dat; + if (sb->readcount+4 > sb->cursize) + { + sb->badread = true; + return -1; + } + sb->readcount += 4; + dat.l = (sb->data[sb->readcount-4]<<24) | (sb->data[sb->readcount-3]<<16) | (sb->data[sb->readcount-2]<<8) | sb->data[sb->readcount-1]; + return dat.f; +} + +char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring) +{ + int c; + size_t l = 0; + // read string into sbfer, but only store as many characters as will fit + while ((c = MSG_ReadByte(sb)) > 0) + if (l < maxstring - 1) + string[l++] = c; + string[l] = 0; + return string; +} + +int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out) +{ + int l, c; + for (l = 0;l < numbytes && (c = MSG_ReadByte(sb)) != -1;l++) + out[l] = c; + return l; +} + +float MSG_ReadCoord13i (sizebuf_t *sb) +{ + return MSG_ReadLittleShort(sb) * (1.0/8.0); +} + +float MSG_ReadCoord16i (sizebuf_t *sb) +{ + return (signed short) MSG_ReadLittleShort(sb); +} + +float MSG_ReadCoord32f (sizebuf_t *sb) +{ + return MSG_ReadLittleFloat(sb); +} + +float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol) +{ + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD) + return MSG_ReadCoord13i(sb); + else if (protocol == PROTOCOL_DARKPLACES1) + return MSG_ReadCoord32f(sb); + else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4) + return MSG_ReadCoord16i(sb); + else + return MSG_ReadCoord32f(sb); +} + +void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol) +{ + v[0] = MSG_ReadCoord(sb, protocol); + v[1] = MSG_ReadCoord(sb, protocol); + v[2] = MSG_ReadCoord(sb, protocol); +} + +// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem +float MSG_ReadAngle8i (sizebuf_t *sb) +{ + return (signed char) MSG_ReadByte (sb) * (360.0/256.0); +} + +float MSG_ReadAngle16i (sizebuf_t *sb) +{ + return (signed short)MSG_ReadShort (sb) * (360.0/65536.0); +} + +float MSG_ReadAngle32f (sizebuf_t *sb) +{ + return MSG_ReadFloat (sb); +} + +float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol) +{ + if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD) + return MSG_ReadAngle8i (sb); + else + return MSG_ReadAngle16i (sb); +} + + +//=========================================================================== + +void SZ_Clear (sizebuf_t *buf) +{ + buf->cursize = 0; +} + +unsigned char *SZ_GetSpace (sizebuf_t *buf, int length) +{ + unsigned char *data; + + if (buf->cursize + length > buf->maxsize) + { + if (!buf->allowoverflow) + Host_Error ("SZ_GetSpace: overflow without allowoverflow set"); + + if (length > buf->maxsize) + Host_Error ("SZ_GetSpace: %i is > full buffer size", length); + + buf->overflowed = true; + Con_Print("SZ_GetSpace: overflow\n"); + SZ_Clear (buf); + } + + data = buf->data + buf->cursize; + buf->cursize += length; + + return data; +} + +void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length) +{ + memcpy (SZ_GetSpace(buf,length),data,length); +} + +// LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my +// attention, it has been eradicated from here, its only (former) use in +// all of darkplaces. + +static const char *hexchar = "0123456789ABCDEF"; +void Com_HexDumpToConsole(const unsigned char *data, int size) +{ + int i, j, n; + char text[1024]; + char *cur, *flushpointer; + const unsigned char *d; + cur = text; + flushpointer = text + 512; + for (i = 0;i < size;) + { + n = 16; + if (n > size - i) + n = size - i; + d = data + i; + // print offset + *cur++ = hexchar[(i >> 12) & 15]; + *cur++ = hexchar[(i >> 8) & 15]; + *cur++ = hexchar[(i >> 4) & 15]; + *cur++ = hexchar[(i >> 0) & 15]; + *cur++ = ':'; + // print hex + for (j = 0;j < 16;j++) + { + if (j < n) + { + *cur++ = hexchar[(d[j] >> 4) & 15]; + *cur++ = hexchar[(d[j] >> 0) & 15]; + } + else + { + *cur++ = ' '; + *cur++ = ' '; + } + if ((j & 3) == 3) + *cur++ = ' '; + } + // print text + for (j = 0;j < 16;j++) + { + if (j < n) + { + // color change prefix character has to be treated specially + if (d[j] == STRING_COLOR_TAG) + { + *cur++ = STRING_COLOR_TAG; + *cur++ = STRING_COLOR_TAG; + } + else if (d[j] >= (unsigned char) ' ') + *cur++ = d[j]; + else + *cur++ = '.'; + } + else + *cur++ = ' '; + } + *cur++ = '\n'; + i += n; + if (cur >= flushpointer || i >= size) + { + *cur++ = 0; + Con_Print(text); + cur = text; + } + } +} + +void SZ_HexDumpToConsole(const sizebuf_t *buf) +{ + Com_HexDumpToConsole(buf->data, buf->cursize); +} + + +//============================================================================ + +/* +============== +COM_Wordwrap + +Word wraps a string. The wordWidth function is guaranteed to be called exactly +once for each word in the string, so it may be stateful, no idea what that +would be good for any more. At the beginning of the string, it will be called +for the char 0 to initialize a clean state, and then once with the string " " +(a space) so the routine knows how long a space is. + +In case no single character fits into the given width, the wordWidth function +must return the width of exactly one character. + +Wrapped lines get the isContinuation flag set and are continuationWidth less wide. + +The sum of the return values of the processLine function will be returned. +============== +*/ +int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL) +{ + // Logic is as follows: + // + // For each word or whitespace: + // Newline found? Output current line, advance to next line. This is not a continuation. Continue. + // Space found? Always add it to the current line, no matter if it fits. + // Word found? Check if current line + current word fits. + // If it fits, append it. Continue. + // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue. + + qboolean isContinuation = false; + float spaceWidth; + const char *startOfLine = string; + const char *cursor = string; + const char *end = string + length; + float spaceUsedInLine = 0; + float spaceUsedForWord; + int result = 0; + size_t wordLen; + size_t dummy; + + dummy = 0; + wordWidth(passthroughCW, NULL, &dummy, -1); + dummy = 1; + spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1); + + for(;;) + { + char ch = (cursor < end) ? *cursor : 0; + switch(ch) + { + case 0: // end of string + result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation); + goto out; + case '\n': // end of line + result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation); + isContinuation = false; + ++cursor; + startOfLine = cursor; + break; + case ' ': // space + ++cursor; + spaceUsedInLine += spaceWidth; + break; + default: // word + wordLen = 1; + while(cursor + wordLen < end) + { + switch(cursor[wordLen]) + { + case 0: + case '\n': + case ' ': + goto out_inner; + default: + ++wordLen; + break; + } + } + out_inner: + spaceUsedForWord = wordWidth(passthroughCW, cursor, &wordLen, maxWidth - continuationWidth); // this may have reduced wordLen when it won't fit - but this is GOOD. TODO fix words that do fit in a non-continuation line + if(wordLen < 1) // cannot happen according to current spec of wordWidth + { + wordLen = 1; + spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself + } + if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine) + { + // we can simply append it + cursor += wordLen; + spaceUsedInLine += spaceUsedForWord; + } + else + { + // output current line + result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation); + isContinuation = true; + startOfLine = cursor; + cursor += wordLen; + spaceUsedInLine = continuationWidth + spaceUsedForWord; + } + } + } + out: + + return result; + +/* + qboolean isContinuation = false; + float currentWordSpace = 0; + const char *currentWord = 0; + float minReserve = 0; + + float spaceUsedInLine = 0; + const char *currentLine = 0; + const char *currentLineEnd = 0; + float currentLineFinalWhitespace = 0; + const char *p; + + int result = 0; + minReserve = charWidth(passthroughCW, 0); + minReserve += charWidth(passthroughCW, ' '); + + if(maxWidth < continuationWidth + minReserve) + maxWidth = continuationWidth + minReserve; + + charWidth(passthroughCW, 0); + + for(p = string; p < string + length; ++p) + { + char c = *p; + float w = charWidth(passthroughCW, c); + + if(!currentWord) + { + currentWord = p; + currentWordSpace = 0; + } + + if(!currentLine) + { + currentLine = p; + spaceUsedInLine = isContinuation ? continuationWidth : 0; + currentLineEnd = 0; + } + + if(c == ' ') + { + // 1. I can add the word AND a space - then just append it. + if(spaceUsedInLine + currentWordSpace + w <= maxWidth) + { + currentLineEnd = p; // note: space not included here + currentLineFinalWhitespace = w; + spaceUsedInLine += currentWordSpace + w; + } + // 2. I can just add the word - then append it, output current line and go to next one. + else if(spaceUsedInLine + currentWordSpace <= maxWidth) + { + result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation); + currentLine = 0; + isContinuation = true; + } + // 3. Otherwise, output current line and go to next one, where I can add the word. + else if(continuationWidth + currentWordSpace + w <= maxWidth) + { + if(currentLineEnd) + result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation); + currentLine = currentWord; + spaceUsedInLine = continuationWidth + currentWordSpace + w; + currentLineEnd = p; + currentLineFinalWhitespace = w; + isContinuation = true; + } + // 4. We can't even do that? Then output both current and next word as new lines. + else + { + if(currentLineEnd) + { + result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation); + isContinuation = true; + } + result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation); + currentLine = 0; + isContinuation = true; + } + currentWord = 0; + } + else if(c == '\n') + { + // 1. I can add the word - then do it. + if(spaceUsedInLine + currentWordSpace <= maxWidth) + { + result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation); + } + // 2. Otherwise, output current line, next one and make tabula rasa. + else + { + if(currentLineEnd) + { + processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation); + isContinuation = true; + } + result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation); + } + currentWord = 0; + currentLine = 0; + isContinuation = false; + } + else + { + currentWordSpace += w; + if( + spaceUsedInLine + currentWordSpace > maxWidth // can't join this line... + && + continuationWidth + currentWordSpace > maxWidth // can't join any other line... + ) + { + // this word cannot join ANY line... + // so output the current line... + if(currentLineEnd) + { + result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation); + isContinuation = true; + } + + // then this word's beginning... + if(isContinuation) + { + // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces + float pieceWidth = maxWidth - continuationWidth; + const char *pos = currentWord; + currentWordSpace = 0; + + // reset the char width function to a state where no kerning occurs (start of word) + charWidth(passthroughCW, ' '); + while(pos <= p) + { + float w = charWidth(passthroughCW, *pos); + if(currentWordSpace + w > pieceWidth) // this piece won't fit any more + { + // print everything until it + result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true); + // go to here + currentWord = pos; + currentWordSpace = 0; + } + currentWordSpace += w; + ++pos; + } + // now we have a currentWord that fits... set up its next line + // currentWordSpace has been set + // currentWord has been set + spaceUsedInLine = continuationWidth; + currentLine = currentWord; + currentLineEnd = 0; + isContinuation = true; + } + else + { + // we have a guarantee that it will fix (see if clause) + result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation); + + // and use the rest of this word as new start of a line + currentWordSpace = w; + currentWord = p; + spaceUsedInLine = continuationWidth; + currentLine = p; + currentLineEnd = 0; + isContinuation = true; + } + } + } + } + + if(!currentWord) + { + currentWord = p; + currentWordSpace = 0; + } + + if(currentLine) // Same procedure as \n + { + // Can I append the current word? + if(spaceUsedInLine + currentWordSpace <= maxWidth) + result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation); + else + { + if(currentLineEnd) + { + result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation); + isContinuation = true; + } + result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation); + } + } + + return result; +*/ +} + +/* +============== +COM_ParseToken_Simple + +Parse a token out of a string +============== +*/ +int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments) +{ + int len; + int c; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + // handle Windows line ending + if (data[0] == '\r' && data[1] == '\n') + data++; + + if (parsecomments && data[0] == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (parsecomments && data[0] == '/' && data[1] == '*') + { + // comment + data++; + while (*data && (data[0] != '*' || data[1] != '/')) + data++; + if (*data) + data++; + if (*data) + data++; + goto skipwhite; + } + else if (*data == '\"') + { + // quoted string + for (data++;*data && *data != '\"';data++) + { + c = *data; + if (*data == '\\' && parsebackslash) + { + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; + } + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; + } + com_token[len] = 0; + if (*data == '\"') + data++; + *datapointer = data; + return true; + } + else if (*data == '\r') + { + // translate Mac line ending to UNIX + com_token[len++] = '\n';data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else if (*data == '\n') + { + // single character + com_token[len++] = *data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else + { + // regular word + for (;!ISWHITESPACE(*data);data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; + return true; + } +} + +/* +============== +COM_ParseToken_QuakeC + +Parse a token out of a string +============== +*/ +int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline) +{ + int len; + int c; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + // handle Windows line ending + if (data[0] == '\r' && data[1] == '\n') + data++; + + if (data[0] == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (data[0] == '/' && data[1] == '*') + { + // comment + data++; + while (*data && (data[0] != '*' || data[1] != '/')) + data++; + if (*data) + data++; + if (*data) + data++; + goto skipwhite; + } + else if (*data == '\"' || *data == '\'') + { + // quoted string + char quote = *data; + for (data++;*data && *data != quote;data++) + { + c = *data; + if (*data == '\\') + { + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; + } + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; + } + com_token[len] = 0; + if (*data == quote) + data++; + *datapointer = data; + return true; + } + else if (*data == '\r') + { + // translate Mac line ending to UNIX + com_token[len++] = '\n';data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';') + { + // single character + com_token[len++] = *data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else + { + // regular word + for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; + return true; + } +} + +/* +============== +COM_ParseToken_VM_Tokenize + +Parse a token out of a string +============== +*/ +int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline) +{ + int len; + int c; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + // handle Windows line ending + if (data[0] == '\r' && data[1] == '\n') + data++; + + if (data[0] == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (data[0] == '/' && data[1] == '*') + { + // comment + data++; + while (*data && (data[0] != '*' || data[1] != '/')) + data++; + if (*data) + data++; + if (*data) + data++; + goto skipwhite; + } + else if (*data == '\"' || *data == '\'') + { + char quote = *data; + // quoted string + for (data++;*data && *data != quote;data++) + { + c = *data; + if (*data == '\\') + { + data++; + c = *data; + if (c == 'n') + c = '\n'; + else if (c == 't') + c = '\t'; + } + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = c; + } + com_token[len] = 0; + if (*data == quote) + data++; + *datapointer = data; + return true; + } + else if (*data == '\r') + { + // translate Mac line ending to UNIX + com_token[len++] = '\n';data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';') + { + // single character + com_token[len++] = *data++; + com_token[len] = 0; + *datapointer = data; + return true; + } + else + { + // regular word + for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; + return true; + } +} + +/* +============== +COM_ParseToken_Console + +Parse a token out of a string, behaving like the qwcl console +============== +*/ +int COM_ParseToken_Console(const char **datapointer) +{ + int len; + const char *data = *datapointer; + + len = 0; + com_token[0] = 0; + + if (!data) + { + *datapointer = NULL; + return false; + } + +// skip whitespace +skipwhite: + for (;ISWHITESPACE(*data);data++) + { + if (*data == 0) + { + // end of file + *datapointer = NULL; + return false; + } + } + + if (*data == '/' && data[1] == '/') + { + // comment + while (*data && *data != '\n' && *data != '\r') + data++; + goto skipwhite; + } + else if (*data == '\"') + { + // quoted string + for (data++;*data && *data != '\"';data++) + { + // allow escaped " and \ case + if (*data == '\\' && (data[1] == '\"' || data[1] == '\\')) + data++; + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + } + com_token[len] = 0; + if (*data == '\"') + data++; + *datapointer = data; + } + else + { + // regular word + for (;!ISWHITESPACE(*data);data++) + if (len < (int)sizeof(com_token) - 1) + com_token[len++] = *data; + com_token[len] = 0; + *datapointer = data; + } + + return true; +} + + +/* +================ +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 (const char *parm) +{ + int i; + + for (i=1 ; i= 0 && gamemode != gamemode_info[index].mode) + COM_SetGameType(index); +} + +static void COM_SetGameType(int index) +{ + int i, t; + if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]))) + index = 0; + gamemode = gamemode_info[index].mode; + gamename = gamemode_info[index].gamename; + gamedirname1 = gamemode_info[index].gamedirname1; + gamedirname2 = gamemode_info[index].gamedirname2; + gamescreenshotname = gamemode_info[index].gamescreenshotname; + gameuserdirname = gamemode_info[index].gameuserdirname; + + if (gamemode == com_startupgamemode) + { + if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc) + gamename = com_argv[t+1]; + if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc) + gamedirname1 = com_argv[t+1]; + if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc) + gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL; + if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc) + gamescreenshotname = com_argv[t+1]; + if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc) + gameuserdirname = com_argv[t+1]; + } + + if (gamedirname2 && gamedirname2[0]) + Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2); + else + Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1); + for (i = 0;i < fs_numgamedirs;i++) + { + if (i == 0) + Con_Printf(", with mod gamedirs"); + Con_Printf(" %s", fs_gamedirs[i]); + } + Con_Printf("\n"); +} + + +/* +================ +COM_Init +================ +*/ +void COM_Init_Commands (void) +{ + int i, j, n; + char com_cmdline[MAX_INPUTLINE]; + + Cvar_RegisterVariable (®istered); + Cvar_RegisterVariable (&cmdline); + + // reconstitute the command line for the cmdline externally visible cvar + n = 0; + for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++) + { + i = 0; + if (strstr(com_argv[j], " ")) + { + // arg contains whitespace, store quotes around it + com_cmdline[n++] = '\"'; + while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) + com_cmdline[n++] = com_argv[j][i++]; + com_cmdline[n++] = '\"'; + } + else + { + while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i]) + com_cmdline[n++] = com_argv[j][i++]; + } + if (n < ((int)sizeof(com_cmdline) - 1)) + com_cmdline[n++] = ' '; + else + break; + } + com_cmdline[n] = 0; + Cvar_Set ("cmdline", com_cmdline); +} + +/* +============ +va + +varargs print into provided buffer, returns buffer (so that it can be called in-line, unlike dpsnprintf) +============ +*/ +char *va(char *buf, size_t buflen, const char *format, ...) +{ + va_list argptr; + + va_start (argptr, format); + dpvsnprintf (buf, buflen, format,argptr); + va_end (argptr); + + return buf; +} + +char *portable_va(char *buf, size_t buflen, const char *format, ...) +{ + va_list argptr; + + va_start (argptr, format); + portable_snprintf (buf, buflen, format,argptr); + va_end (argptr); + + return buf; +} + +//====================================== + +// snprintf and vsnprintf are NOT portable. Use their DP counterparts instead + +#undef snprintf +#undef vsnprintf + +#ifdef WIN32 +# define snprintf _snprintf +# define vsnprintf _vsnprintf +#endif + + +int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...) +{ + va_list args; + int result; + + va_start (args, format); + result = dpvsnprintf (buffer, buffersize, format, args); + va_end (args); + + return result; +} + + +int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args) +{ + int result; + + result = vsnprintf (buffer, buffersize, format, args); + + if (result < 0 || (size_t)result >= buffersize) + { + buffer[buffersize - 1] = '\0'; + return -1; + } + + return result; +} + + +//====================================== + +void COM_ToLowerString (const char *in, char *out, size_t size_out) +{ + if (size_out == 0) + return; + + if(utf8_enable.integer) + { + *out = 0; + while(*in && size_out > 1) + { + int n; + Uchar ch = u8_getchar_utf8_enabled(in, &in); + ch = u8_tolower(ch); + n = u8_fromchar(ch, out, size_out); + if(n <= 0) + break; + out += n; + size_out -= n; + } + return; + } + + while (*in && size_out > 1) + { + if (*in >= 'A' && *in <= 'Z') + *out++ = *in++ + 'a' - 'A'; + else + *out++ = *in++; + size_out--; + } + *out = '\0'; +} + +void COM_ToUpperString (const char *in, char *out, size_t size_out) +{ + if (size_out == 0) + return; + + if(utf8_enable.integer) + { + *out = 0; + while(*in && size_out > 1) + { + int n; + Uchar ch = u8_getchar_utf8_enabled(in, &in); + ch = u8_toupper(ch); + n = u8_fromchar(ch, out, size_out); + if(n <= 0) + break; + out += n; + size_out -= n; + } + return; + } + + while (*in && size_out > 1) + { + if (*in >= 'a' && *in <= 'z') + *out++ = *in++ + 'A' - 'a'; + else + *out++ = *in++; + size_out--; + } + *out = '\0'; +} + +int COM_StringBeginsWith(const char *s, const char *match) +{ + for (;*s && *match;s++, match++) + if (*s != *match) + return false; + return true; +} + +int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix) +{ + int argc, commentprefixlength; + char *tokenbufend; + const char *l; + argc = 0; + tokenbufend = tokenbuf + tokenbufsize; + l = *text; + commentprefixlength = 0; + if (commentprefix) + commentprefixlength = (int)strlen(commentprefix); + while (*l && *l != '\n' && *l != '\r') + { + if (!ISWHITESPACE(*l)) + { + if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength)) + { + while (*l && *l != '\n' && *l != '\r') + l++; + break; + } + if (argc >= maxargc) + return -1; + argv[argc++] = tokenbuf; + if (*l == '"') + { + l++; + while (*l && *l != '"') + { + if (tokenbuf >= tokenbufend) + return -1; + *tokenbuf++ = *l++; + } + if (*l == '"') + l++; + } + else + { + while (!ISWHITESPACE(*l)) + { + if (tokenbuf >= tokenbufend) + return -1; + *tokenbuf++ = *l++; + } + } + if (tokenbuf >= tokenbufend) + return -1; + *tokenbuf++ = 0; + } + else + l++; + } + // line endings: + // UNIX: \n + // Mac: \r + // Windows: \r\n + if (*l == '\r') + l++; + if (*l == '\n') + l++; + *text = l; + return argc; +} + +/* +============ +COM_StringLengthNoColors + +calculates the visible width of a color coded string. + +*valid is filled with TRUE if the string is a valid colored string (that is, if +it does not end with an unfinished color code). If it gets filled with FALSE, a +fix would be adding a STRING_COLOR_TAG at the end of the string. + +valid can be set to NULL if the caller doesn't care. + +For size_s, specify the maximum number of characters from s to use, or 0 to use +all characters until the zero terminator. +============ +*/ +size_t +COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid) +{ + const char *end = size_s ? (s + size_s) : NULL; + size_t len = 0; + for(;;) + { + switch((s == end) ? 0 : *s) + { + case 0: + if(valid) + *valid = TRUE; + return len; + case STRING_COLOR_TAG: + ++s; + switch((s == end) ? 0 : *s) + { + case STRING_COLOR_RGB_TAG_CHAR: + if (s+1 != end && isxdigit(s[1]) && + s+2 != end && isxdigit(s[2]) && + s+3 != end && isxdigit(s[3]) ) + { + s+=3; + break; + } + ++len; // STRING_COLOR_TAG + ++len; // STRING_COLOR_RGB_TAG_CHAR + break; + case 0: // ends with unfinished color code! + ++len; + if(valid) + *valid = FALSE; + return len; + case STRING_COLOR_TAG: // escaped ^ + ++len; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': // color code + break; + default: // not a color code + ++len; // STRING_COLOR_TAG + ++len; // the character + break; + } + break; + default: + ++len; + break; + } + ++s; + } + // never get here +} + +/* +============ +COM_StringDecolorize + +removes color codes from a string. + +If escape_carets is true, the resulting string will be safe for printing. If +escape_carets is false, the function will just strip color codes (for logging +for example). + +If the output buffer size did not suffice for converting, the function returns +FALSE. Generally, if escape_carets is false, the output buffer needs +strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2 +bytes. In any case, the function makes sure that the resulting string is +zero terminated. + +For size_in, specify the maximum number of characters from in to use, or 0 to use +all characters until the zero terminator. +============ +*/ +qboolean +COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets) +{ +#define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0) + const char *end = size_in ? (in + size_in) : NULL; + if(size_out < 1) + return FALSE; + for(;;) + { + switch((in == end) ? 0 : *in) + { + case 0: + *out++ = 0; + return TRUE; + case STRING_COLOR_TAG: + ++in; + switch((in == end) ? 0 : *in) + { + case STRING_COLOR_RGB_TAG_CHAR: + if (in+1 != end && isxdigit(in[1]) && + in+2 != end && isxdigit(in[2]) && + in+3 != end && isxdigit(in[3]) ) + { + in+=3; + break; + } + APPEND(STRING_COLOR_TAG); + if(escape_carets) + APPEND(STRING_COLOR_TAG); + APPEND(STRING_COLOR_RGB_TAG_CHAR); + break; + case 0: // ends with unfinished color code! + APPEND(STRING_COLOR_TAG); + // finish the code by appending another caret when escaping + if(escape_carets) + APPEND(STRING_COLOR_TAG); + *out++ = 0; + return TRUE; + case STRING_COLOR_TAG: // escaped ^ + APPEND(STRING_COLOR_TAG); + // append a ^ twice when escaping + if(escape_carets) + APPEND(STRING_COLOR_TAG); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': // color code + break; + default: // not a color code + APPEND(STRING_COLOR_TAG); + APPEND(*in); + break; + } + break; + default: + APPEND(*in); + break; + } + ++in; + } + // never get here +#undef APPEND +} + +char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength) +{ + int pos = 0, j; + size_t keylength; + if (!key) + key = ""; + keylength = strlen(key); + if (valuelength < 1 || !value) + { + Con_Printf("InfoString_GetValue: no room in value\n"); + return NULL; + } + value[0] = 0; + if (strchr(key, '\\')) + { + Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key); + return NULL; + } + if (strchr(key, '\"')) + { + Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key); + return NULL; + } + if (!key[0]) + { + Con_Printf("InfoString_GetValue: can not look up a key with no name\n"); + return NULL; + } + while (buffer[pos] == '\\') + { + if (!memcmp(buffer + pos+1, key, keylength)) + { + for (pos++;buffer[pos] && buffer[pos] != '\\';pos++); + pos++; + for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++) + value[j] = buffer[pos+j]; + value[j] = 0; + return value; + } + for (pos++;buffer[pos] && buffer[pos] != '\\';pos++); + for (pos++;buffer[pos] && buffer[pos] != '\\';pos++); + } + // if we reach this point the key was not found + return NULL; +} + +void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value) +{ + int pos = 0, pos2; + size_t keylength; + if (!key) + key = ""; + if (!value) + value = ""; + keylength = strlen(key); + if (strchr(key, '\\') || strchr(value, '\\')) + { + Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value); + return; + } + if (strchr(key, '\"') || strchr(value, '\"')) + { + Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value); + return; + } + if (!key[0]) + { + Con_Printf("InfoString_SetValue: can not set a key with no name\n"); + return; + } + while (buffer[pos] == '\\') + { + if (!memcmp(buffer + pos+1, key, keylength)) + break; + for (pos++;buffer[pos] && buffer[pos] != '\\';pos++); + for (pos++;buffer[pos] && buffer[pos] != '\\';pos++); + } + // if we found the key, find the end of it because we will be replacing it + pos2 = pos; + if (buffer[pos] == '\\') + { + for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++); + for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++); + } + if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2)) + { + Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value); + return; + } + if (value && value[0]) + { + // set the key/value and append the remaining text + char tempbuffer[MAX_INPUTLINE]; + strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer)); + dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer); + } + else + { + // just remove the key from the text + strlcpy(buffer + pos, buffer + pos2, bufferlength - pos); + } +} + +void InfoString_Print(char *buffer) +{ + int i; + char key[MAX_INPUTLINE]; + char value[MAX_INPUTLINE]; + while (*buffer) + { + if (*buffer != '\\') + { + Con_Printf("InfoString_Print: corrupt string\n"); + return; + } + for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++) + if (i < (int)sizeof(key)-1) + key[i++] = *buffer; + key[i] = 0; + if (*buffer != '\\') + { + Con_Printf("InfoString_Print: corrupt string\n"); + return; + } + for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++) + if (i < (int)sizeof(value)-1) + value[i++] = *buffer; + value[i] = 0; + // empty value is an error case + Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE"); + } +} + +//======================================================== +// strlcat and strlcpy, from OpenBSD + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ + + +#ifndef HAVE_STRLCAT +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif // #ifndef HAVE_STRLCAT + + +#ifndef HAVE_STRLCPY +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif // #ifndef HAVE_STRLCPY + +void FindFraction(double val, int *num, int *denom, int denomMax) +{ + int i; + double bestdiff; + // initialize + bestdiff = fabs(val); + *num = 0; + *denom = 1; + + for(i = 1; i <= denomMax; ++i) + { + int inum = (int) floor(0.5 + val * i); + double diff = fabs(val - inum / (double)i); + if(diff < bestdiff) + { + bestdiff = diff; + *num = inum; + *denom = i; + } + } +} + +// decodes an XPM from C syntax +char **XPM_DecodeString(const char *in) +{ + static char *tokens[257]; + static char lines[257][512]; + size_t line = 0; + + // skip until "{" token + while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{")); + + // now, read in succession: string, comma-or-} + while(COM_ParseToken_QuakeC(&in, false)) + { + tokens[line] = lines[line]; + strlcpy(lines[line++], com_token, sizeof(lines[0])); + if(!COM_ParseToken_QuakeC(&in, false)) + return NULL; + if(!strcmp(com_token, "}")) + break; + if(strcmp(com_token, ",")) + return NULL; + if(line >= sizeof(tokens) / sizeof(tokens[0])) + return NULL; + } + + return tokens; +} + +static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes) +{ + unsigned char i0 = (bytes > 0) ? in[0] : 0; + unsigned char i1 = (bytes > 1) ? in[1] : 0; + unsigned char i2 = (bytes > 2) ? in[2] : 0; + unsigned char o0 = base64[i0 >> 2]; + unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077]; + unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077]; + unsigned char o3 = base64[i2 & 077]; + out[0] = (bytes > 0) ? o0 : '?'; + out[1] = (bytes > 0) ? o1 : '?'; + out[2] = (bytes > 1) ? o2 : '='; + out[3] = (bytes > 2) ? o3 : '='; +} + +size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen) +{ + size_t blocks, i; + // expand the out-buffer + blocks = (buflen + 2) / 3; + if(blocks*4 > outbuflen) + return 0; + for(i = blocks; i > 0; ) + { + --i; + base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i); + } + return blocks * 4; +} diff --git a/app/jni/common.h b/app/jni/common.h new file mode 100644 index 0000000..a48a425 --- /dev/null +++ b/app/jni/common.h @@ -0,0 +1,380 @@ +/* +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 COMMON_H +#define COMMON_H + + +/// MSVC has a different name for several standard functions +#ifdef WIN32 +# define strcasecmp _stricmp +# define strncasecmp _strnicmp +#endif + +// Create our own define for Mac OS X +#if defined(__APPLE__) && defined(__MACH__) +# define MACOSX +#endif + +#ifdef SUNOS +#include ///< Needed for FNDELAY +#endif + +//============================================================================ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; ///< if false, do a Sys_Error + qboolean overflowed; ///< set to true if the buffer size failed + unsigned char *data; + int maxsize; + int cursize; + int readcount; + qboolean badread; // set if a read goes beyond end of message +} sizebuf_t; + +void SZ_Clear (sizebuf_t *buf); +unsigned char *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length); +void SZ_HexDumpToConsole(const sizebuf_t *buf); + +void Com_HexDumpToConsole(const unsigned char *data, int size); + +unsigned short CRC_Block(const unsigned char *data, size_t size); +unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size); // for hash lookup functions that use strcasecmp for comparison + +unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence); + +// these are actually md4sum (mdfour.c) +unsigned Com_BlockChecksum (void *buffer, int length); +void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf); + +void COM_Init_Commands(void); + + +//============================================================================ +// Endianess handling +//============================================================================ + +// check mem_bigendian if you need to know the system byte order + +/*! \name Byte order functions. + * @{ + */ + +// unaligned memory access crashes on some platform, so always read bytes... +#define BigShort(l) BuffBigShort((unsigned char *)&(l)) +#define LittleShort(l) BuffLittleShort((unsigned char *)&(l)) +#define BigLong(l) BuffBigLong((unsigned char *)&(l)) +#define LittleLong(l) BuffLittleLong((unsigned char *)&(l)) +#define BigFloat(l) BuffBigFloat((unsigned char *)&(l)) +#define LittleFloat(l) BuffLittleFloat((unsigned char *)&(l)) + +/// Extract a big endian 32bit float from the given \p buffer. +float BuffBigFloat (const unsigned char *buffer); + +/// Extract a big endian 32bit int from the given \p buffer. +int BuffBigLong (const unsigned char *buffer); + +/// Extract a big endian 16bit short from the given \p buffer. +short BuffBigShort (const unsigned char *buffer); + +/// Extract a little endian 32bit float from the given \p buffer. +float BuffLittleFloat (const unsigned char *buffer); + +/// Extract a little endian 32bit int from the given \p buffer. +int BuffLittleLong (const unsigned char *buffer); + +/// Extract a little endian 16bit short from the given \p buffer. +short BuffLittleShort (const unsigned char *buffer); + +/// Encode a big endian 32bit int to the given \p buffer +void StoreBigLong (unsigned char *buffer, unsigned int i); + +/// Encode a big endian 16bit int to the given \p buffer +void StoreBigShort (unsigned char *buffer, unsigned short i); + +/// Encode a little endian 32bit int to the given \p buffer +void StoreLittleLong (unsigned char *buffer, unsigned int i); + +/// Encode a little endian 16bit int to the given \p buffer +void StoreLittleShort (unsigned char *buffer, unsigned short i); +//@} + +//============================================================================ + +// these versions are purely for internal use, never sent in network protocol +// (use Protocol_EnumForNumber and Protocol_NumberToEnum to convert) +typedef enum protocolversion_e +{ + PROTOCOL_UNKNOWN, + PROTOCOL_DARKPLACES7, ///< added QuakeWorld-style movement protocol to allow more consistent prediction + PROTOCOL_DARKPLACES6, ///< various changes + PROTOCOL_DARKPLACES5, ///< uses EntityFrame5 entity snapshot encoder/decoder which is based on a Tribes networking article at http://www.garagegames.com/articles/networking1/ + PROTOCOL_DARKPLACES4, ///< various changes + PROTOCOL_DARKPLACES3, ///< uses EntityFrame4 entity snapshot encoder/decoder which is broken, this attempted to do partial snapshot updates on a QuakeWorld-like protocol, but it is broken and impossible to fix + PROTOCOL_DARKPLACES2, ///< various changes + PROTOCOL_DARKPLACES1, ///< uses EntityFrame entity snapshot encoder/decoder which is a QuakeWorld-like entity snapshot delta compression method + PROTOCOL_QUAKEDP, ///< darkplaces extended quake protocol (used by TomazQuake and others), backwards compatible as long as no extended features are used + PROTOCOL_NEHAHRAMOVIE, ///< Nehahra movie protocol, a big nasty hack dating back to early days of the Quake Standards Group (but only ever used by neh_gl.exe), this is potentially backwards compatible with quake protocol as long as no extended features are used (but in actuality the neh_gl.exe which wrote this protocol ALWAYS wrote the extended information) + PROTOCOL_QUAKE, ///< quake (aka netquake/normalquake/nq) protocol + PROTOCOL_QUAKEWORLD, ///< quakeworld protocol + PROTOCOL_NEHAHRABJP, ///< same as QUAKEDP but with 16bit modelindex + PROTOCOL_NEHAHRABJP2, ///< same as NEHAHRABJP but with 16bit soundindex + PROTOCOL_NEHAHRABJP3 ///< same as NEHAHRABJP2 but with some changes +} +protocolversion_t; + +/*! \name Message IO functions. + * Handles byte ordering and avoids alignment errors + * @{ + */ + +void MSG_InitReadBuffer (sizebuf_t *buf, unsigned char *data, int size); +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, vec_t f); +void MSG_WriteString (sizebuf_t *sb, const char *s); +void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s); +void MSG_WriteAngle8i (sizebuf_t *sb, vec_t f); +void MSG_WriteAngle16i (sizebuf_t *sb, vec_t f); +void MSG_WriteAngle32f (sizebuf_t *sb, vec_t f); +void MSG_WriteCoord13i (sizebuf_t *sb, vec_t f); +void MSG_WriteCoord16i (sizebuf_t *sb, vec_t f); +void MSG_WriteCoord32f (sizebuf_t *sb, vec_t f); +void MSG_WriteCoord (sizebuf_t *sb, vec_t f, protocolversion_t protocol); +void MSG_WriteVector (sizebuf_t *sb, const vec3_t v, protocolversion_t protocol); +void MSG_WriteAngle (sizebuf_t *sb, vec_t f, protocolversion_t protocol); + +void MSG_BeginReading (sizebuf_t *sb); +int MSG_ReadLittleShort (sizebuf_t *sb); +int MSG_ReadBigShort (sizebuf_t *sb); +int MSG_ReadLittleLong (sizebuf_t *sb); +int MSG_ReadBigLong (sizebuf_t *sb); +float MSG_ReadLittleFloat (sizebuf_t *sb); +float MSG_ReadBigFloat (sizebuf_t *sb); +char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring); +int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out); + +#define MSG_ReadChar(sb) ((sb)->readcount >= (sb)->cursize ? ((sb)->badread = true, -1) : (signed char)(sb)->data[(sb)->readcount++]) +#define MSG_ReadByte(sb) ((sb)->readcount >= (sb)->cursize ? ((sb)->badread = true, -1) : (unsigned char)(sb)->data[(sb)->readcount++]) +#define MSG_ReadShort MSG_ReadLittleShort +#define MSG_ReadLong MSG_ReadLittleLong +#define MSG_ReadFloat MSG_ReadLittleFloat + +float MSG_ReadAngle8i (sizebuf_t *sb); +float MSG_ReadAngle16i (sizebuf_t *sb); +float MSG_ReadAngle32f (sizebuf_t *sb); +float MSG_ReadCoord13i (sizebuf_t *sb); +float MSG_ReadCoord16i (sizebuf_t *sb); +float MSG_ReadCoord32f (sizebuf_t *sb); +float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol); +void MSG_ReadVector (sizebuf_t *sb, vec3_t v, protocolversion_t protocol); +float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol); +//@} +//============================================================================ + +typedef float (*COM_WordWidthFunc_t) (void *passthrough, const char *w, size_t *length, float maxWidth); // length is updated to the longest fitting string into maxWidth; if maxWidth < 0, all characters are used and length is used as is +typedef int (*COM_LineProcessorFunc) (void *passthrough, const char *line, size_t length, float width, qboolean isContination); +int COM_Wordwrap(const char *string, size_t length, float continuationSize, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL); + +extern char com_token[MAX_INPUTLINE]; + +int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments); +int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline); +int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline); +int COM_ParseToken_Console(const char **datapointer); + +extern int com_argc; +extern const char **com_argv; +extern int com_selffd; + +int COM_CheckParm (const char *parm); +void COM_Init (void); +void COM_Shutdown (void); +void COM_InitGameType (void); + +char *va(char *buf, size_t buflen, const char *format, ...) DP_FUNC_PRINTF(3); +char *portable_va(char *buf, size_t buflen, const char *format, ...) DP_FUNC_PRINTF(3); +// does a varargs printf into provided buffer, returns buffer (so it can be called in-line unlike dpsnprintf) + + +// snprintf and vsnprintf are NOT portable. Use their DP counterparts instead +#ifdef snprintf +# undef snprintf +#endif +#define snprintf DO_NOT_USE_SNPRINTF__USE_DPSNPRINTF +#ifdef vsnprintf +# undef vsnprintf +#endif +//#define vsnprintf DO_NOT_USE_VSNPRINTF__USE_DPVSNPRINTF + +// dpsnprintf and dpvsnprintf +// return the number of printed characters, excluding the final '\0' +// or return -1 if the buffer isn't big enough to contain the entire string. +// buffer is ALWAYS null-terminated +extern int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...) DP_FUNC_PRINTF(3); +extern int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args); + +// A bunch of functions are forbidden for security reasons (and also to please MSVS 2005, for some of them) +// LordHavoc: added #undef lines here to avoid warnings in Linux +#undef strcat +#define strcat DO_NOT_USE_STRCAT__USE_STRLCAT_OR_MEMCPY +#undef strncat +#define strncat DO_NOT_USE_STRNCAT__USE_STRLCAT_OR_MEMCPY +#undef strcpy +#define strcpy DO_NOT_USE_STRCPY__USE_STRLCPY_OR_MEMCPY +#undef strncpy +#define strncpy DO_NOT_USE_STRNCPY__USE_STRLCPY_OR_MEMCPY +//#undef sprintf +//#define sprintf DO_NOT_USE_SPRINTF__USE_DPSNPRINTF + + +//============================================================================ + +extern struct cvar_s registered; +extern struct cvar_s cmdline; + +typedef enum userdirmode_e +{ + USERDIRMODE_NOHOME, // basedir only + USERDIRMODE_HOME, // Windows basedir, general POSIX (~/.) + USERDIRMODE_MYGAMES, // pre-Vista (My Documents/My Games/), general POSIX (~/.) + USERDIRMODE_SAVEDGAMES, // Vista (%USERPROFILE%/Saved Games/), OSX (~/Library/Application Support/), Linux (~/.config) + USERDIRMODE_COUNT +} +userdirmode_t; + +typedef enum gamemode_e +{ + GAME_NORMAL, + GAME_HIPNOTIC, + GAME_ROGUE, + GAME_QUOTH, + GAME_NEHAHRA, + GAME_NEXUIZ, + GAME_XONOTIC, + GAME_TRANSFUSION, + GAME_GOODVSBAD2, + GAME_TEU, + GAME_BATTLEMECH, + GAME_ZYMOTIC, + GAME_SETHERAL, + GAME_TENEBRAE, // full of evil hackery + GAME_NEOTERIC, + GAME_OPENQUARTZ, //this game sucks + GAME_PRYDON, + GAME_DELUXEQUAKE, + GAME_THEHUNTED, + GAME_DEFEATINDETAIL2, + GAME_DARSANA, + GAME_CONTAGIONTHEORY, + GAME_EDU2P, + GAME_PROPHECY, + GAME_BLOODOMNICIDE, + GAME_STEELSTORM, // added by motorsep + GAME_STEELSTORM2, // added by motorsep + GAME_TOMESOFMEPHISTOPHELES, // added by motorsep + GAME_STRAPBOMB, // added by motorsep for Urre + GAME_MOONHELM, + GAME_COUNT +} +gamemode_t; + +extern gamemode_t gamemode; +extern const char *gamename; +extern const char *gamedirname1; +extern const char *gamedirname2; +extern const char *gamescreenshotname; +extern const char *gameuserdirname; +extern char com_modname[MAX_OSPATH]; + +void COM_ChangeGameTypeForGameDirs(void); + +void COM_ToLowerString (const char *in, char *out, size_t size_out); +void COM_ToUpperString (const char *in, char *out, size_t size_out); +int COM_StringBeginsWith(const char *s, const char *match); + +int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix); + +size_t COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid); +qboolean COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets); +void COM_ToLowerString (const char *in, char *out, size_t size_out); +void COM_ToUpperString (const char *in, char *out, size_t size_out); + +typedef struct stringlist_s +{ + /// maxstrings changes as needed, causing reallocation of strings[] array + int maxstrings; + int numstrings; + char **strings; +} stringlist_t; + +int matchpattern(const char *in, const char *pattern, int caseinsensitive); +int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qboolean wildcard_least_one); +void stringlistinit(stringlist_t *list); +void stringlistfreecontents(stringlist_t *list); +void stringlistappend(stringlist_t *list, const char *text); +void stringlistsort(stringlist_t *list, qboolean uniq); +void listdirectory(stringlist_t *list, const char *basepath, const char *path); + +char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength); +void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value); +void InfoString_Print(char *buffer); + +// strlcat and strlcpy, from OpenBSD +// Most (all?) BSDs already have them +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(MACOSX) +# define HAVE_STRLCAT 1 +# define HAVE_STRLCPY 1 +#endif + +#ifndef HAVE_STRLCAT +/*! + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t strlcat(char *dst, const char *src, size_t siz); +#endif // #ifndef HAVE_STRLCAT + +#ifndef HAVE_STRLCPY +/*! + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t siz); + +#endif // #ifndef HAVE_STRLCPY + +void FindFraction(double val, int *num, int *denom, int denomMax); + +// decodes XPM file to XPM array (as if #include'd) +char **XPM_DecodeString(const char *in); + +size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen); + +#endif + diff --git a/app/jni/conproc.c b/app/jni/conproc.c new file mode 100644 index 0000000..ccbb849 --- /dev/null +++ b/app/jni/conproc.c @@ -0,0 +1,365 @@ +/* +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. + +*/ +// conproc.c + +#include "quakedef.h" + +#include +#include +#include "conproc.h" + +HANDLE heventDone; +HANDLE hfileBuffer; +HANDLE heventChildSend; +HANDLE heventParentSend; +HANDLE hStdout; +HANDLE hStdin; + +DWORD RequestProc (DWORD dwNichts); +LPVOID GetMappedBuffer (HANDLE hfileBuffer); +void ReleaseMappedBuffer (LPVOID pBuffer); +BOOL GetScreenBufferLines (int *piLines); +BOOL SetScreenBufferLines (int iLines); +BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine); +BOOL WriteText (LPCTSTR szText); +int CharToCode (int c); +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy); + + +void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild) +{ + DWORD dwID; + +// ignore if we don't have all the events. + if (!hFile || !heventParent || !heventChild) + return; + + hfileBuffer = hFile; + heventParentSend = heventParent; + heventChildSend = heventChild; + +// so we'll know when to go away. + heventDone = CreateEvent (NULL, false, false, NULL); + + if (!heventDone) + { + Con_Print("Couldn't create heventDone\n"); + return; + } + + if (!CreateThread (NULL, + 0, + (LPTHREAD_START_ROUTINE) RequestProc, + 0, + 0, + &dwID)) + { + CloseHandle (heventDone); + Con_Print("Couldn't create QHOST thread\n"); + return; + } + +// save off the input/output handles. + hStdout = GetStdHandle (STD_OUTPUT_HANDLE); + hStdin = GetStdHandle (STD_INPUT_HANDLE); + +// force 80 character width, at least 25 character height + SetConsoleCXCY (hStdout, 80, 25); +} + + +void DeinitConProc (void) +{ + if (heventDone) + SetEvent (heventDone); +} + + +DWORD RequestProc (DWORD dwNichts) +{ + int *pBuffer; + DWORD dwRet; + HANDLE heventWait[2]; + int iBeginLine, iEndLine; + + heventWait[0] = heventParentSend; + heventWait[1] = heventDone; + + while (1) + { + dwRet = WaitForMultipleObjects (2, heventWait, false, INFINITE); + + // heventDone fired, so we're exiting. + if (dwRet == WAIT_OBJECT_0 + 1) + break; + + pBuffer = (int *) GetMappedBuffer (hfileBuffer); + + // hfileBuffer is invalid. Just leave. + if (!pBuffer) + { + Con_Print("Invalid hfileBuffer\n"); + break; + } + + switch (pBuffer[0]) + { + case CCOM_WRITE_TEXT: + // Param1 : Text + pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1)); + break; + + case CCOM_GET_TEXT: + // Param1 : Begin line + // Param2 : End line + iBeginLine = pBuffer[1]; + iEndLine = pBuffer[2]; + pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine, + iEndLine); + break; + + case CCOM_GET_SCR_LINES: + // No params + pBuffer[0] = GetScreenBufferLines (&pBuffer[1]); + break; + + case CCOM_SET_SCR_LINES: + // Param1 : Number of lines + pBuffer[0] = SetScreenBufferLines (pBuffer[1]); + break; + } + + ReleaseMappedBuffer (pBuffer); + SetEvent (heventChildSend); + } + + return 0; +} + + +LPVOID GetMappedBuffer (HANDLE hfileBuffer) +{ + LPVOID pBuffer; + + pBuffer = MapViewOfFile (hfileBuffer, + FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + return pBuffer; +} + + +void ReleaseMappedBuffer (LPVOID pBuffer) +{ + UnmapViewOfFile (pBuffer); +} + + +BOOL GetScreenBufferLines (int *piLines) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + BOOL bRet; + + bRet = GetConsoleScreenBufferInfo (hStdout, &info); + + if (bRet) + *piLines = info.dwSize.Y; + + return bRet; +} + + +BOOL SetScreenBufferLines (int iLines) +{ + + return SetConsoleCXCY (hStdout, 80, iLines); +} + + +BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine) +{ + COORD coord; + DWORD dwRead; + BOOL bRet; + + coord.X = 0; + coord.Y = iBeginLine; + + bRet = ReadConsoleOutputCharacter( + hStdout, + pszText, + 80 * (iEndLine - iBeginLine + 1), + coord, + &dwRead); + + // Make sure it's null terminated. + if (bRet) + pszText[dwRead] = '\0'; + + return bRet; +} + + +BOOL WriteText (LPCTSTR szText) +{ + DWORD dwWritten; + INPUT_RECORD rec; + char upper, *sz; + + sz = (LPTSTR) szText; + + while (*sz) + { + // 13 is the code for a carriage return (\n) instead of 10. + if (*sz == 10) + *sz = 13; + + upper = toupper(*sz); + + rec.EventType = KEY_EVENT; + rec.Event.KeyEvent.bKeyDown = true; + rec.Event.KeyEvent.wRepeatCount = 1; + rec.Event.KeyEvent.wVirtualKeyCode = upper; + rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz); + rec.Event.KeyEvent.uChar.AsciiChar = *sz; + rec.Event.KeyEvent.uChar.UnicodeChar = *sz; + rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + rec.Event.KeyEvent.bKeyDown = false; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + sz++; + } + + return true; +} + + +int CharToCode (int c) +{ + char upper; + + upper = toupper(c); + + switch (c) + { + case 13: + return 28; + + default: + break; + } + + if (isalpha(c)) + return (30 + upper - 65); + + if (isdigit(c)) + return (1 + upper - 47); + + return c; +} + + +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + COORD coordMax; + + coordMax = GetLargestConsoleWindowSize(hStdout); + + if (cy > coordMax.Y) + cy = coordMax.Y; + + if (cx > coordMax.X) + cx = coordMax.X; + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return false; + +// height + info.srWindow.Left = 0; + info.srWindow.Right = info.dwSize.X - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = cy - 1; + + if (cy < info.dwSize.Y) + { + if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow)) + return false; + + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return false; + } + else if (cy > info.dwSize.Y) + { + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return false; + + if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow)) + return false; + } + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return false; + +// width + info.srWindow.Left = 0; + info.srWindow.Right = cx - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = info.dwSize.Y - 1; + + if (cx < info.dwSize.X) + { + if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow)) + return false; + + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return false; + } + else if (cx > info.dwSize.X) + { + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return false; + + if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow)) + return false; + } + + return true; +} + diff --git a/app/jni/conproc.h b/app/jni/conproc.h new file mode 100644 index 0000000..8fe112a --- /dev/null +++ b/app/jni/conproc.h @@ -0,0 +1,42 @@ +/* +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. + +*/ +// conproc.h + +#ifndef CONPROC_H +#define CONPROC_H + +#define CCOM_WRITE_TEXT 0x2 +// Param1 : Text + +#define CCOM_GET_TEXT 0x3 +// Param1 : Begin line +// Param2 : End line + +#define CCOM_GET_SCR_LINES 0x4 +// No params + +#define CCOM_SET_SCR_LINES 0x5 +// Param1 : Number of lines + +void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild); +void DeinitConProc (void); + +#endif + diff --git a/app/jni/console.c b/app/jni/console.c new file mode 100644 index 0000000..c3ddecb --- /dev/null +++ b/app/jni/console.c @@ -0,0 +1,3014 @@ +/* +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 + +#if !defined(WIN32) || defined(__MINGW32__) +# include +#endif +#include + +#include "quakedef.h" +#include "thread.h" + +// for u8_encodech +#include "ft2.h" + +float con_cursorspeed = 4; + +// lines up from bottom to display +int con_backscroll; + +conbuffer_t con; +void *con_mutex = NULL; + +#define CON_LINES(i) CONBUFFER_LINES(&con, i) +#define CON_LINES_LAST CONBUFFER_LINES_LAST(&con) +#define CON_LINES_COUNT CONBUFFER_LINES_COUNT(&con) + +cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3", "how long notify lines last, in seconds"}; +cvar_t con_notify = {CVAR_SAVE, "con_notify","4", "how many notify lines to show"}; +cvar_t con_notifyalign = {CVAR_SAVE, "con_notifyalign", "", "how to align notify lines: 0 = left, 0.5 = center, 1 = right, empty string = game default)"}; + +cvar_t con_chattime = {CVAR_SAVE, "con_chattime","30", "how long chat lines last, in seconds"}; +cvar_t con_chat = {CVAR_SAVE, "con_chat","0", "how many chat lines to show in a dedicated chat area"}; +cvar_t con_chatpos = {CVAR_SAVE, "con_chatpos","0", "where to put chat (negative: lines from bottom of screen, positive: lines below notify, 0: at top)"}; +cvar_t con_chatrect = {CVAR_SAVE, "con_chatrect","0", "use con_chatrect_x and _y to position con_notify and con_chat freely instead of con_chatpos"}; +cvar_t con_chatrect_x = {CVAR_SAVE, "con_chatrect_x","", "where to put chat, relative x coordinate of left edge on screen (use con_chatwidth for width)"}; +cvar_t con_chatrect_y = {CVAR_SAVE, "con_chatrect_y","", "where to put chat, relative y coordinate of top edge on screen (use con_chat for line count)"}; +cvar_t con_chatwidth = {CVAR_SAVE, "con_chatwidth","1.0", "relative chat window width"}; +cvar_t con_textsize = {CVAR_SAVE, "con_textsize","8", "console text size in virtual 2D pixels"}; +cvar_t con_notifysize = {CVAR_SAVE, "con_notifysize","8", "notify text size in virtual 2D pixels"}; +cvar_t con_chatsize = {CVAR_SAVE, "con_chatsize","8", "chat text size in virtual 2D pixels (if con_chat is enabled)"}; +cvar_t con_chatsound = {CVAR_SAVE, "con_chatsound","1", "enables chat sound to play on message"}; + + +cvar_t sys_specialcharactertranslation = {0, "sys_specialcharactertranslation", "1", "terminal console conchars to ASCII translation (set to 0 if your conchars.tga is for an 8bit character set or if you want raw output)"}; +#ifdef WIN32 +cvar_t sys_colortranslation = {0, "sys_colortranslation", "0", "terminal console color translation (supported values: 0 = strip color codes, 1 = translate to ANSI codes, 2 = no translation)"}; +#else +cvar_t sys_colortranslation = {0, "sys_colortranslation", "1", "terminal console color translation (supported values: 0 = strip color codes, 1 = translate to ANSI codes, 2 = no translation)"}; +#endif + + +cvar_t con_nickcompletion = {CVAR_SAVE, "con_nickcompletion", "1", "tab-complete nicks in console and message input"}; +cvar_t con_nickcompletion_flags = {CVAR_SAVE, "con_nickcompletion_flags", "11", "Bitfield: " + "0: add nothing after completion. " + "1: add the last color after completion. " + "2: add a quote when starting a quote instead of the color. " + "4: will replace 1, will force color, even after a quote. " + "8: ignore non-alphanumerics. " + "16: ignore spaces. "}; +#define NICKS_ADD_COLOR 1 +#define NICKS_ADD_QUOTE 2 +#define NICKS_FORCE_COLOR 4 +#define NICKS_ALPHANUMERICS_ONLY 8 +#define NICKS_NO_SPACES 16 + +cvar_t con_completion_playdemo = {CVAR_SAVE, "con_completion_playdemo", "*.dem", "completion pattern for the playdemo command"}; +cvar_t con_completion_timedemo = {CVAR_SAVE, "con_completion_timedemo", "*.dem", "completion pattern for the timedemo command"}; +cvar_t con_completion_exec = {CVAR_SAVE, "con_completion_exec", "*.cfg", "completion pattern for the exec command"}; + +int con_linewidth; +int con_vislines; + +qboolean con_initialized; + +extern void jni_BigScreenMode(int mode); + +// used for server replies to rcon command +lhnetsocket_t *rcon_redirect_sock = NULL; +lhnetaddress_t *rcon_redirect_dest = NULL; +int rcon_redirect_bufferpos = 0; +char rcon_redirect_buffer[1400]; +qboolean rcon_redirect_proquakeprotocol = false; + +// generic functions for console buffers + +void ConBuffer_Init(conbuffer_t *buf, int textsize, int maxlines, mempool_t *mempool) +{ + buf->active = true; + buf->textsize = textsize; + buf->text = (char *) Mem_Alloc(mempool, textsize); + buf->maxlines = maxlines; + buf->lines = (con_lineinfo_t *) Mem_Alloc(mempool, maxlines * sizeof(*buf->lines)); + buf->lines_first = 0; + buf->lines_count = 0; +} + +/* +================ +ConBuffer_Clear +================ +*/ +void ConBuffer_Clear (conbuffer_t *buf) +{ + buf->lines_count = 0; +} + +/* +================ +ConBuffer_Shutdown +================ +*/ +void ConBuffer_Shutdown(conbuffer_t *buf) +{ + buf->active = false; + if (buf->text) + Mem_Free(buf->text); + if (buf->lines) + Mem_Free(buf->lines); + buf->text = NULL; + buf->lines = NULL; +} + +/* +================ +ConBuffer_FixTimes + +Notifies the console code about the current time +(and shifts back times of other entries when the time +went backwards) +================ +*/ +void ConBuffer_FixTimes(conbuffer_t *buf) +{ + int i; + if(buf->lines_count >= 1) + { + double diff = cl.time - CONBUFFER_LINES_LAST(buf).addtime; + if(diff < 0) + { + for(i = 0; i < buf->lines_count; ++i) + CONBUFFER_LINES(buf, i).addtime += diff; + } + } +} + +/* +================ +ConBuffer_DeleteLine + +Deletes the first line from the console history. +================ +*/ +void ConBuffer_DeleteLine(conbuffer_t *buf) +{ + if(buf->lines_count == 0) + return; + --buf->lines_count; + buf->lines_first = (buf->lines_first + 1) % buf->maxlines; +} + +/* +================ +ConBuffer_DeleteLastLine + +Deletes the last line from the console history. +================ +*/ +void ConBuffer_DeleteLastLine(conbuffer_t *buf) +{ + if(buf->lines_count == 0) + return; + --buf->lines_count; +} + +/* +================ +ConBuffer_BytesLeft + +Checks if there is space for a line of the given length, and if yes, returns a +pointer to the start of such a space, and NULL otherwise. +================ +*/ +static char *ConBuffer_BytesLeft(conbuffer_t *buf, int len) +{ + if(len > buf->textsize) + return NULL; + if(buf->lines_count == 0) + return buf->text; + else + { + char *firstline_start = buf->lines[buf->lines_first].start; + char *lastline_onepastend = CONBUFFER_LINES_LAST(buf).start + CONBUFFER_LINES_LAST(buf).len; + // the buffer is cyclic, so we first have two cases... + if(firstline_start < lastline_onepastend) // buffer is contiguous + { + // put at end? + if(len <= buf->text + buf->textsize - lastline_onepastend) + return lastline_onepastend; + // put at beginning? + else if(len <= firstline_start - buf->text) + return buf->text; + else + return NULL; + } + else // buffer has a contiguous hole + { + if(len <= firstline_start - lastline_onepastend) + return lastline_onepastend; + else + return NULL; + } + } +} + +/* +================ +ConBuffer_AddLine + +Appends a given string as a new line to the console. +================ +*/ +void ConBuffer_AddLine(conbuffer_t *buf, const char *line, int len, int mask) +{ + char *putpos; + con_lineinfo_t *p; + + // developer_memory 1 during shutdown prints while conbuffer_t is being freed + if (!buf->active) + return; + + ConBuffer_FixTimes(buf); + + if(len >= buf->textsize) + { + // line too large? + // only display end of line. + line += len - buf->textsize + 1; + len = buf->textsize - 1; + } + while(!(putpos = ConBuffer_BytesLeft(buf, len + 1)) || buf->lines_count >= buf->maxlines) + ConBuffer_DeleteLine(buf); + memcpy(putpos, line, len); + putpos[len] = 0; + ++buf->lines_count; + + //fprintf(stderr, "Now have %d lines (%d -> %d).\n", buf->lines_count, buf->lines_first, CON_LINES_LAST); + + p = &CONBUFFER_LINES_LAST(buf); + p->start = putpos; + p->len = len; + p->addtime = cl.time; + p->mask = mask; + p->height = -1; // calculate when needed +} + +int ConBuffer_FindPrevLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start) +{ + int i; + if(start == -1) + start = buf->lines_count; + for(i = start - 1; i >= 0; --i) + { + con_lineinfo_t *l = &CONBUFFER_LINES(buf, i); + + if((l->mask & mask_must) != mask_must) + continue; + if(l->mask & mask_mustnot) + continue; + + return i; + } + + return -1; +} + +const char *ConBuffer_GetLine(conbuffer_t *buf, int i) +{ + static char copybuf[MAX_INPUTLINE]; // client only + con_lineinfo_t *l = &CONBUFFER_LINES(buf, i); + size_t sz = l->len+1 > sizeof(copybuf) ? sizeof(copybuf) : l->len+1; + strlcpy(copybuf, l->start, sz); + return copybuf; +} + +/* +============================================================================== + +LOGGING + +============================================================================== +*/ + +/// \name Logging +//@{ +cvar_t log_file = {0, "log_file","", "filename to log messages to"}; +cvar_t log_dest_udp = {0, "log_dest_udp","", "UDP address to log messages to (in QW rcon compatible format); multiple destinations can be separated by spaces; DO NOT SPECIFY DNS NAMES HERE"}; +char log_dest_buffer[1400]; // UDP packet +size_t log_dest_buffer_pos; +unsigned int log_dest_buffer_appending; +char crt_log_file [MAX_OSPATH] = ""; +qfile_t* logfile = NULL; + +unsigned char* logqueue = NULL; +size_t logq_ind = 0; +size_t logq_size = 0; + +void Log_ConPrint (const char *msg); +//@} +static void Log_DestBuffer_Init(void) +{ + memcpy(log_dest_buffer, "\377\377\377\377n", 5); // QW rcon print + log_dest_buffer_pos = 5; +} + +static void Log_DestBuffer_Flush_NoLock(void) +{ + lhnetaddress_t log_dest_addr; + lhnetsocket_t *log_dest_socket; + const char *s = log_dest_udp.string; + qboolean have_opened_temp_sockets = false; + if(s) if(log_dest_buffer_pos > 5) + { + ++log_dest_buffer_appending; + log_dest_buffer[log_dest_buffer_pos++] = 0; + + if(!NetConn_HaveServerPorts() && !NetConn_HaveClientPorts()) // then temporarily open one + { + have_opened_temp_sockets = true; + NetConn_OpenServerPorts(true); + } + + while(COM_ParseToken_Console(&s)) + if(LHNETADDRESS_FromString(&log_dest_addr, com_token, 26000)) + { + log_dest_socket = NetConn_ChooseClientSocketForAddress(&log_dest_addr); + if(!log_dest_socket) + log_dest_socket = NetConn_ChooseServerSocketForAddress(&log_dest_addr); + if(log_dest_socket) + NetConn_WriteString(log_dest_socket, log_dest_buffer, &log_dest_addr); + } + + if(have_opened_temp_sockets) + NetConn_CloseServerPorts(); + --log_dest_buffer_appending; + } + log_dest_buffer_pos = 0; +} + +/* +==================== +Log_DestBuffer_Flush +==================== +*/ +void Log_DestBuffer_Flush(void) +{ + if (con_mutex) + Thread_LockMutex(con_mutex); + Log_DestBuffer_Flush_NoLock(); + if (con_mutex) + Thread_UnlockMutex(con_mutex); +} + +static const char* Log_Timestamp (const char *desc) +{ + static char timestamp [128]; // init/shutdown only + time_t crt_time; +#if _MSC_VER >= 1400 + struct tm crt_tm; +#else + struct tm *crt_tm; +#endif + char timestring [64]; + + // Build the time stamp (ex: "Wed Jun 30 21:49:08 1993"); + time (&crt_time); +#if _MSC_VER >= 1400 + localtime_s (&crt_tm, &crt_time); + strftime (timestring, sizeof (timestring), "%a %b %d %H:%M:%S %Y", &crt_tm); +#else + crt_tm = localtime (&crt_time); + strftime (timestring, sizeof (timestring), "%a %b %d %H:%M:%S %Y", crt_tm); +#endif + + if (desc != NULL) + dpsnprintf (timestamp, sizeof (timestamp), "====== %s (%s) ======\n", desc, timestring); + else + dpsnprintf (timestamp, sizeof (timestamp), "====== %s ======\n", timestring); + + return timestamp; +} + +static void Log_Open (void) +{ + if (logfile != NULL || log_file.string[0] == '\0') + return; + + logfile = FS_OpenRealFile(log_file.string, "a", false); + if (logfile != NULL) + { + strlcpy (crt_log_file, log_file.string, sizeof (crt_log_file)); + FS_Print (logfile, Log_Timestamp ("Log started")); + } +} + +/* +==================== +Log_Close +==================== +*/ +void Log_Close (void) +{ + if (logfile == NULL) + return; + + FS_Print (logfile, Log_Timestamp ("Log stopped")); + FS_Print (logfile, "\n"); + FS_Close (logfile); + + logfile = NULL; + crt_log_file[0] = '\0'; +} + + +/* +==================== +Log_Start +==================== +*/ +void Log_Start (void) +{ + size_t pos; + size_t n; + Log_Open (); + + // Dump the contents of the log queue into the log file and free it + if (logqueue != NULL) + { + unsigned char *temp = logqueue; + logqueue = NULL; + if(logq_ind != 0) + { + if (logfile != NULL) + FS_Write (logfile, temp, logq_ind); + if(*log_dest_udp.string) + { + for(pos = 0; pos < logq_ind; ) + { + if(log_dest_buffer_pos == 0) + Log_DestBuffer_Init(); + n = min(sizeof(log_dest_buffer) - log_dest_buffer_pos - 1, logq_ind - pos); + memcpy(log_dest_buffer + log_dest_buffer_pos, temp + pos, n); + log_dest_buffer_pos += n; + Log_DestBuffer_Flush_NoLock(); + pos += n; + } + } + } + Mem_Free (temp); + logq_ind = 0; + logq_size = 0; + } +} + + +/* +================ +Log_ConPrint +================ +*/ +void Log_ConPrint (const char *msg) +{ + static qboolean inprogress = false; + + // don't allow feedback loops with memory error reports + if (inprogress) + return; + inprogress = true; + + // Until the host is completely initialized, we maintain a log queue + // to store the messages, since the log can't be started before + if (logqueue != NULL) + { + size_t remain = logq_size - logq_ind; + size_t len = strlen (msg); + + // If we need to enlarge the log queue + if (len > remain) + { + size_t factor = ((logq_ind + len) / logq_size) + 1; + unsigned char* newqueue; + + logq_size *= factor; + newqueue = (unsigned char *)Mem_Alloc (tempmempool, logq_size); + memcpy (newqueue, logqueue, logq_ind); + Mem_Free (logqueue); + logqueue = newqueue; + remain = logq_size - logq_ind; + } + memcpy (&logqueue[logq_ind], msg, len); + logq_ind += len; + + inprogress = false; + return; + } + + // Check if log_file has changed + if (strcmp (crt_log_file, log_file.string) != 0) + { + Log_Close (); + Log_Open (); + } + + // If a log file is available + if (logfile != NULL) + FS_Print (logfile, msg); + + inprogress = false; +} + + +/* +================ +Log_Printf +================ +*/ +void Log_Printf (const char *logfilename, const char *fmt, ...) +{ + qfile_t *file; + + file = FS_OpenRealFile(logfilename, "a", true); + if (file != NULL) + { + va_list argptr; + + va_start (argptr, fmt); + FS_VPrintf (file, fmt, argptr); + va_end (argptr); + + FS_Close (file); + } +} + + +/* +============================================================================== + +CONSOLE + +============================================================================== +*/ + +/* +================ +Con_ToggleConsole_f +================ +*/ +void Con_ToggleConsole_f (void) +{ + if (COM_CheckParm ("-noconsole")) + if (!(key_consoleactive & KEY_CONSOLEACTIVE_USER)) + return; // only allow the key bind to turn off console + + // toggle the 'user wants console' bit + key_consoleactive ^= KEY_CONSOLEACTIVE_USER; + + jni_BigScreenMode(key_consoleactive > 0 ? 1 : 0); + + Con_ClearNotify(); +} + +/* +================ +Con_ClearNotify +================ +*/ +void Con_ClearNotify (void) +{ + int i; + for(i = 0; i < CON_LINES_COUNT; ++i) + if(!(CON_LINES(i).mask & CON_MASK_CHAT)) + CON_LINES(i).mask |= CON_MASK_HIDENOTIFY; +} + + +/* +================ +Con_MessageMode_f +================ +*/ +static void Con_MessageMode_f (void) +{ + key_dest = key_message; + chat_mode = 0; // "say" + if(Cmd_Argc() > 1) + { + dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args()); + chat_bufferlen = strlen(chat_buffer); + } +} + + +/* +================ +Con_MessageMode2_f +================ +*/ +static void Con_MessageMode2_f (void) +{ + key_dest = key_message; + chat_mode = 1; // "say_team" + if(Cmd_Argc() > 1) + { + dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args()); + chat_bufferlen = strlen(chat_buffer); + } +} + +/* +================ +Con_CommandMode_f +================ +*/ +static void Con_CommandMode_f (void) +{ + key_dest = key_message; + if(Cmd_Argc() > 1) + { + dpsnprintf(chat_buffer, sizeof(chat_buffer), "%s ", Cmd_Args()); + chat_bufferlen = strlen(chat_buffer); + } + chat_mode = -1; // command +} + +/* +================ +Con_CheckResize +================ +*/ +void Con_CheckResize (void) +{ + int i, width; + float f; + + f = bound(1, con_textsize.value, 128); + if(f != con_textsize.value) + Cvar_SetValueQuick(&con_textsize, f); + width = (int)floor(vid_conwidth.value / con_textsize.value); + width = bound(1, width, con.textsize/4); + // FIXME uses con in a non abstracted way + + if (width == con_linewidth) + return; + + con_linewidth = width; + + for(i = 0; i < CON_LINES_COUNT; ++i) + CON_LINES(i).height = -1; // recalculate when next needed + + Con_ClearNotify(); + con_backscroll = 0; +} + +//[515]: the simplest command ever +//LordHavoc: not so simple after I made it print usage... +static void Con_Maps_f (void) +{ + if (Cmd_Argc() > 2) + { + Con_Printf("usage: maps [mapnameprefix]\n"); + return; + } + else if (Cmd_Argc() == 2) + GetMapList(Cmd_Argv(1), NULL, 0); + else + GetMapList("", NULL, 0); +} + +static void Con_ConDump_f (void) +{ + int i; + qfile_t *file; + if (Cmd_Argc() != 2) + { + Con_Printf("usage: condump \n"); + return; + } + file = FS_OpenRealFile(Cmd_Argv(1), "w", false); + if (!file) + { + Con_Printf("condump: unable to write file \"%s\"\n", Cmd_Argv(1)); + return; + } + if (con_mutex) Thread_LockMutex(con_mutex); + for(i = 0; i < CON_LINES_COUNT; ++i) + { + FS_Write(file, CON_LINES(i).start, CON_LINES(i).len); + FS_Write(file, "\n", 1); + } + if (con_mutex) Thread_UnlockMutex(con_mutex); + FS_Close(file); +} + +void Con_Clear_f (void) +{ + if (con_mutex) Thread_LockMutex(con_mutex); + ConBuffer_Clear(&con); + if (con_mutex) Thread_UnlockMutex(con_mutex); +} + +/* +================ +Con_Init +================ +*/ +void Con_Init (void) +{ + con_linewidth = 80; + ConBuffer_Init(&con, CON_TEXTSIZE, CON_MAXLINES, zonemempool); + if (Thread_HasThreads()) + con_mutex = Thread_CreateMutex(); + + // Allocate a log queue, this will be freed after configs are parsed + logq_size = MAX_INPUTLINE; + logqueue = (unsigned char *)Mem_Alloc (tempmempool, logq_size); + logq_ind = 0; + + Cvar_RegisterVariable (&sys_colortranslation); + Cvar_RegisterVariable (&sys_specialcharactertranslation); + + Cvar_RegisterVariable (&log_file); + Cvar_RegisterVariable (&log_dest_udp); + + // support for the classic Quake option +// COMMANDLINEOPTION: Console: -condebug logs console messages to qconsole.log, see also log_file + if (COM_CheckParm ("-condebug") != 0) + Cvar_SetQuick (&log_file, "qconsole.log"); + + // register our cvars + Cvar_RegisterVariable (&con_chat); + Cvar_RegisterVariable (&con_chatpos); + Cvar_RegisterVariable (&con_chatrect_x); + Cvar_RegisterVariable (&con_chatrect_y); + Cvar_RegisterVariable (&con_chatrect); + Cvar_RegisterVariable (&con_chatsize); + Cvar_RegisterVariable (&con_chattime); + Cvar_RegisterVariable (&con_chatwidth); + Cvar_RegisterVariable (&con_notify); + Cvar_RegisterVariable (&con_notifyalign); + Cvar_RegisterVariable (&con_notifysize); + Cvar_RegisterVariable (&con_notifytime); + Cvar_RegisterVariable (&con_textsize); + Cvar_RegisterVariable (&con_chatsound); + + // --blub + Cvar_RegisterVariable (&con_nickcompletion); + Cvar_RegisterVariable (&con_nickcompletion_flags); + + Cvar_RegisterVariable (&con_completion_playdemo); // *.dem + Cvar_RegisterVariable (&con_completion_timedemo); // *.dem + Cvar_RegisterVariable (&con_completion_exec); // *.cfg + + // register our commands + Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f, "opens or closes the console"); + Cmd_AddCommand ("messagemode", Con_MessageMode_f, "input a chat message to say to everyone"); + Cmd_AddCommand ("messagemode2", Con_MessageMode2_f, "input a chat message to say to only your team"); + Cmd_AddCommand ("commandmode", Con_CommandMode_f, "input a console command"); + Cmd_AddCommand ("clear", Con_Clear_f, "clear console history"); + Cmd_AddCommand ("maps", Con_Maps_f, "list information about available maps"); + Cmd_AddCommand ("condump", Con_ConDump_f, "output console history to a file (see also log_file)"); + + con_initialized = true; + Con_DPrint("Console initialized.\n"); +} + +void Con_Shutdown (void) +{ + if (con_mutex) Thread_LockMutex(con_mutex); + ConBuffer_Shutdown(&con); + if (con_mutex) Thread_UnlockMutex(con_mutex); + if (con_mutex) Thread_DestroyMutex(con_mutex);con_mutex = NULL; +} + +/* +================ +Con_PrintToHistory + +Handles cursor positioning, line wrapping, etc +All console printing must go through this in order to be displayed +If no console is visible, the notify window will pop up. +================ +*/ +static void Con_PrintToHistory(const char *txt, int mask) +{ + // process: + // \n goes to next line + // \r deletes current line and makes a new one + + static int cr_pending = 0; + static char buf[CON_TEXTSIZE]; // con_mutex + static int bufpos = 0; + + if(!con.text) // FIXME uses a non-abstracted property of con + return; + + for(; *txt; ++txt) + { + if(cr_pending) + { + ConBuffer_DeleteLastLine(&con); + cr_pending = 0; + } + switch(*txt) + { + case 0: + break; + case '\r': + ConBuffer_AddLine(&con, buf, bufpos, mask); + bufpos = 0; + cr_pending = 1; + break; + case '\n': + ConBuffer_AddLine(&con, buf, bufpos, mask); + bufpos = 0; + break; + default: + buf[bufpos++] = *txt; + if(bufpos >= con.textsize - 1) // FIXME uses a non-abstracted property of con + { + ConBuffer_AddLine(&con, buf, bufpos, mask); + bufpos = 0; + } + break; + } + } +} + +/*! The translation table between the graphical font and plain ASCII --KB */ +static char qfont_table[256] = { + '\0', '#', '#', '#', '#', '.', '#', '#', + '#', 9, 10, '#', ' ', 13, '.', '.', + '[', ']', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '.', '<', '=', '>', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '<', + + '<', '=', '>', '#', '#', '.', '#', '#', + '#', '#', ' ', '#', ' ', '>', '.', '.', + '[', ']', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '.', '<', '=', '>', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '<' +}; + +void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qboolean proquakeprotocol) +{ + rcon_redirect_sock = sock; + rcon_redirect_dest = dest; + rcon_redirect_proquakeprotocol = proquakeprotocol; + if (rcon_redirect_proquakeprotocol) + { + // reserve space for the packet header + rcon_redirect_buffer[0] = 0; + rcon_redirect_buffer[1] = 0; + rcon_redirect_buffer[2] = 0; + rcon_redirect_buffer[3] = 0; + // this is a reply to a CCREQ_RCON + rcon_redirect_buffer[4] = (char)CCREP_RCON; + } + else + memcpy(rcon_redirect_buffer, "\377\377\377\377n", 5); // QW rcon print + rcon_redirect_bufferpos = 5; +} + +static void Con_Rcon_Redirect_Flush(void) +{ + if(rcon_redirect_sock) + { + rcon_redirect_buffer[rcon_redirect_bufferpos] = 0; + if (rcon_redirect_proquakeprotocol) + { + // update the length in the packet header + StoreBigLong((unsigned char *)rcon_redirect_buffer, NETFLAG_CTL | (rcon_redirect_bufferpos & NETFLAG_LENGTH_MASK)); + } + NetConn_Write(rcon_redirect_sock, rcon_redirect_buffer, rcon_redirect_bufferpos, rcon_redirect_dest); + } + memcpy(rcon_redirect_buffer, "\377\377\377\377n", 5); // QW rcon print + rcon_redirect_bufferpos = 5; + rcon_redirect_proquakeprotocol = false; +} + +void Con_Rcon_Redirect_End(void) +{ + Con_Rcon_Redirect_Flush(); + rcon_redirect_dest = NULL; + rcon_redirect_sock = NULL; +} + +void Con_Rcon_Redirect_Abort(void) +{ + rcon_redirect_dest = NULL; + rcon_redirect_sock = NULL; +} + +/* +================ +Con_Rcon_AddChar +================ +*/ +/// Adds a character to the rcon buffer. +static void Con_Rcon_AddChar(int c) +{ + if(log_dest_buffer_appending) + return; + ++log_dest_buffer_appending; + + // if this print is in response to an rcon command, add the character + // to the rcon redirect buffer + + if (rcon_redirect_dest) + { + rcon_redirect_buffer[rcon_redirect_bufferpos++] = c; + if(rcon_redirect_bufferpos >= (int)sizeof(rcon_redirect_buffer) - 1) + Con_Rcon_Redirect_Flush(); + } + else if(*log_dest_udp.string) // don't duplicate rcon command responses here, these are sent another way + { + if(log_dest_buffer_pos == 0) + Log_DestBuffer_Init(); + log_dest_buffer[log_dest_buffer_pos++] = c; + if(log_dest_buffer_pos >= sizeof(log_dest_buffer) - 1) // minus one, to allow for terminating zero + Log_DestBuffer_Flush_NoLock(); + } + else + log_dest_buffer_pos = 0; + + --log_dest_buffer_appending; +} + +/** + * Convert an RGB color to its nearest quake color. + * I'll cheat on this a bit by translating the colors to HSV first, + * S and V decide if it's black or white, otherwise, H will decide the + * actual color. + * @param _r Red (0-255) + * @param _g Green (0-255) + * @param _b Blue (0-255) + * @return A quake color character. + */ +static char Sys_Con_NearestColor(const unsigned char _r, const unsigned char _g, const unsigned char _b) +{ + float r = ((float)_r)/255.0; + float g = ((float)_g)/255.0; + float b = ((float)_b)/255.0; + float min = min(r, min(g, b)); + float max = max(r, max(g, b)); + + int h; ///< Hue angle [0,360] + float s; ///< Saturation [0,1] + float v = max; ///< In HSV v == max [0,1] + + if(max == min) + s = 0; + else + s = 1.0 - (min/max); + + // Saturation threshold. We now say 0.2 is the minimum value for a color! + if(s < 0.2) + { + // If the value is less than half, return a black color code. + // Otherwise return a white one. + if(v < 0.5) + return '0'; + return '7'; + } + + // Let's get the hue angle to define some colors: + if(max == min) + h = 0; + else if(max == r) + h = (int)(60.0 * (g-b)/(max-min))%360; + else if(max == g) + h = (int)(60.0 * (b-r)/(max-min) + 120); + else // if(max == b) redundant check + h = (int)(60.0 * (r-g)/(max-min) + 240); + + if(h < 36) // *red* to orange + return '1'; + else if(h < 80) // orange over *yellow* to evilish-bright-green + return '3'; + else if(h < 150) // evilish-bright-green over *green* to ugly bright blue + return '2'; + else if(h < 200) // ugly bright blue over *bright blue* to darkish blue + return '5'; + else if(h < 270) // darkish blue over *dark blue* to cool purple + return '4'; + else if(h < 330) // cool purple over *purple* to ugly swiny red + return '6'; + else // ugly red to red closes the circly + return '1'; +} + +/* +================ +Con_MaskPrint +================ +*/ +extern cvar_t timestamps; +extern cvar_t timeformat; +extern qboolean sys_nostdout; +void Con_MaskPrint(int additionalmask, const char *msg) +{ + static int mask = 0; + static int index = 0; + static char line[MAX_INPUTLINE]; + + if (con_mutex) + Thread_LockMutex(con_mutex); + + for (;*msg;msg++) + { + Con_Rcon_AddChar(*msg); + // if this is the beginning of a new line, print timestamp + if (index == 0) + { + const char *timestamp = timestamps.integer ? Sys_TimeString(timeformat.string) : ""; + // reset the color + // FIXME: 1. perhaps we should use a terminal system 2. use a constant instead of 7! + line[index++] = STRING_COLOR_TAG; + // assert( STRING_COLOR_DEFAULT < 10 ) + line[index++] = STRING_COLOR_DEFAULT + '0'; + // special color codes for chat messages must always come first + // for Con_PrintToHistory to work properly + if (*msg == 1 || *msg == 2 || *msg == 3) + { + // play talk wav + if (*msg == 1) + { + if (con_chatsound.value) + { + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + { + if(msg[1] == '\r' && cl.foundtalk2wav) + S_LocalSound ("sound/misc/talk2.wav"); + else + S_LocalSound ("sound/misc/talk.wav"); + } + else + { + if (msg[1] == '(' && cl.foundtalk2wav) + S_LocalSound ("sound/misc/talk2.wav"); + else + S_LocalSound ("sound/misc/talk.wav"); + } + } + } + + // Send to chatbox for say/tell (1) and messages (3) + // 3 is just so that a message can be sent to the chatbox without a sound. + if (*msg == 1 || *msg == 3) + mask = CON_MASK_CHAT; + + line[index++] = STRING_COLOR_TAG; + line[index++] = '3'; + msg++; + Con_Rcon_AddChar(*msg); + } + // store timestamp + for (;*timestamp;index++, timestamp++) + if (index < (int)sizeof(line) - 2) + line[index] = *timestamp; + // add the mask + mask |= additionalmask; + } + // append the character + line[index++] = *msg; + // if this is a newline character, we have a complete line to print + if (*msg == '\n' || index >= (int)sizeof(line) / 2) + { + // terminate the line + line[index] = 0; + // send to log file + Log_ConPrint(line); + // send to scrollable buffer + if (con_initialized && cls.state != ca_dedicated) + { + Con_PrintToHistory(line, mask); + } + // send to terminal or dedicated server window + if (!sys_nostdout) + if (developer.integer || !(mask & CON_MASK_DEVELOPER)) + { + if(sys_specialcharactertranslation.integer) + { + char *p; + const char *q; + p = line; + while(*p) + { + int ch = u8_getchar(p, &q); + if(ch >= 0xE000 && ch <= 0xE0FF && ((unsigned char) qfont_table[ch - 0xE000]) >= 0x20) + { + *p = qfont_table[ch - 0xE000]; + if(q > p+1) + memmove(p+1, q, strlen(q)+1); + p = p + 1; + } + else + p = p + (q - p); + } + } + + if(sys_colortranslation.integer == 1) // ANSI + { + static char printline[MAX_INPUTLINE * 4 + 3]; + // 2 can become 7 bytes, rounding that up to 8, and 3 bytes are added at the end + // a newline can transform into four bytes, but then prevents the three extra bytes from appearing + int lastcolor = 0; + const char *in; + char *out; + int color; + for(in = line, out = printline; *in; ++in) + { + switch(*in) + { + case STRING_COLOR_TAG: + if( in[1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) ) + { + char r = tolower(in[2]); + char g = tolower(in[3]); + char b = tolower(in[4]); + // it's a hex digit already, so the else part needs no check --blub + if(isdigit(r)) r -= '0'; + else r -= 87; + if(isdigit(g)) g -= '0'; + else g -= 87; + if(isdigit(b)) b -= '0'; + else b -= 87; + + color = Sys_Con_NearestColor(r * 17, g * 17, b * 17); + in += 3; // 3 only, the switch down there does the fourth + } + else + color = in[1]; + + switch(color) + { + case STRING_COLOR_TAG: + ++in; + *out++ = STRING_COLOR_TAG; + break; + case '0': + case '7': + // normal color + ++in; + if(lastcolor == 0) break; else lastcolor = 0; + *out++ = 0x1B; *out++ = '['; *out++ = 'm'; + break; + case '1': + // light red + ++in; + if(lastcolor == 1) break; else lastcolor = 1; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '1'; *out++ = 'm'; + break; + case '2': + // light green + ++in; + if(lastcolor == 2) break; else lastcolor = 2; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '2'; *out++ = 'm'; + break; + case '3': + // yellow + ++in; + if(lastcolor == 3) break; else lastcolor = 3; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '3'; *out++ = 'm'; + break; + case '4': + // light blue + ++in; + if(lastcolor == 4) break; else lastcolor = 4; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '4'; *out++ = 'm'; + break; + case '5': + // light cyan + ++in; + if(lastcolor == 5) break; else lastcolor = 5; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '6'; *out++ = 'm'; + break; + case '6': + // light magenta + ++in; + if(lastcolor == 6) break; else lastcolor = 6; + *out++ = 0x1B; *out++ = '['; *out++ = '1'; *out++ = ';'; *out++ = '3'; *out++ = '5'; *out++ = 'm'; + break; + // 7 handled above + case '8': + case '9': + // bold normal color + ++in; + if(lastcolor == 8) break; else lastcolor = 8; + *out++ = 0x1B; *out++ = '['; *out++ = '0'; *out++ = ';'; *out++ = '1'; *out++ = 'm'; + break; + default: + *out++ = STRING_COLOR_TAG; + break; + } + break; + case '\n': + if(lastcolor != 0) + { + *out++ = 0x1B; *out++ = '['; *out++ = 'm'; + lastcolor = 0; + } + *out++ = *in; + break; + default: + *out++ = *in; + break; + } + } + if(lastcolor != 0) + { + *out++ = 0x1B; + *out++ = '['; + *out++ = 'm'; + } + *out++ = 0; + Sys_PrintToTerminal(printline); + } + else if(sys_colortranslation.integer == 2) // Quake + { + Sys_PrintToTerminal(line); + } + else // strip + { + static char printline[MAX_INPUTLINE]; // it can only get shorter here + const char *in; + char *out; + for(in = line, out = printline; *in; ++in) + { + switch(*in) + { + case STRING_COLOR_TAG: + switch(in[1]) + { + case STRING_COLOR_RGB_TAG_CHAR: + if ( isxdigit(in[2]) && isxdigit(in[3]) && isxdigit(in[4]) ) + { + in+=4; + break; + } + *out++ = STRING_COLOR_TAG; + *out++ = STRING_COLOR_RGB_TAG_CHAR; + ++in; + break; + case STRING_COLOR_TAG: + ++in; + *out++ = STRING_COLOR_TAG; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ++in; + break; + default: + *out++ = STRING_COLOR_TAG; + break; + } + break; + default: + *out++ = *in; + break; + } + } + *out++ = 0; + Sys_PrintToTerminal(printline); + } + } + // empty the line buffer + index = 0; + mask = 0; + } + } + + if (con_mutex) + Thread_UnlockMutex(con_mutex); +} + +/* +================ +Con_MaskPrintf +================ +*/ +void Con_MaskPrintf(int mask, const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + Con_MaskPrint(mask, msg); +} + +/* +================ +Con_Print +================ +*/ +void Con_Print(const char *msg) +{ + Con_MaskPrint(CON_MASK_PRINT, msg); +} + +/* +================ +Con_Printf +================ +*/ +void Con_Printf(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + Con_MaskPrint(CON_MASK_PRINT, msg); +} + +/* +================ +Con_DPrint +================ +*/ +void Con_DPrint(const char *msg) +{ + if(developer.integer < 0) // at 0, we still add to the buffer but hide + return; + + Con_MaskPrint(CON_MASK_DEVELOPER, msg); +} + +/* +================ +Con_DPrintf +================ +*/ +void Con_DPrintf(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + if(developer.integer < 0) // at 0, we still add to the buffer but hide + return; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + Con_MaskPrint(CON_MASK_DEVELOPER, msg); +} + + +/* +============================================================================== + +DRAWING + +============================================================================== +*/ + +/* +================ +Con_DrawInput + +The input line scrolls horizontally if typing goes beyond the right edge + +Modified by EvilTypeGuy eviltypeguy@qeradiant.com +================ +*/ +extern cvar_t r_font_disable_freetype; +static void Con_DrawInput (void) +{ + int y; + int i; + char editlinecopy[MAX_INPUTLINE+1], *text; + float x, xo; + size_t len_out; + int col_out; + + if (!key_consoleactive) + return; // don't draw anything + + strlcpy(editlinecopy, key_line, sizeof(editlinecopy)); + text = editlinecopy; + + // Advanced Console Editing by Radix radix@planetquake.com + // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com + // use strlen of edit_line instead of key_linepos to allow editing + // of early characters w/o erasing + + y = (int)strlen(text); + + // append enoug nul-bytes to cover the utf8-versions of the cursor too + for (i = y; i < y + 4 && i < (int)sizeof(editlinecopy); ++i) + text[i] = 0; + + // add the cursor frame + if (r_font_disable_freetype.integer) + { + // this code is freetype incompatible! + if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible + { + if (!utf8_enable.integer) + text[key_linepos] = 11 + 130 * key_insert; // either solid or triangle facing right + else if (y + 3 < (int)sizeof(editlinecopy)-1) + { + int ofs = u8_bytelen(text + key_linepos, 1); + size_t len; + const char *curbuf; + char charbuf16[16]; + curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len, charbuf16); + + if (curbuf) + { + memmove(text + key_linepos + len, text + key_linepos + ofs, sizeof(editlinecopy) - key_linepos - len); + memcpy(text + key_linepos, curbuf, len); + } + } else + text[key_linepos] = '-' + ('+' - '-') * key_insert; + } + } + +// text[key_linepos + 1] = 0; + + len_out = key_linepos; + col_out = -1; + xo = DrawQ_TextWidth_UntilWidth_TrackColors(text, &len_out, con_textsize.value, con_textsize.value, &col_out, false, FONT_CONSOLE, 1000000000); + x = vid_conwidth.value * 0.95 - xo; // scroll + if(x >= 0) + x = 0; + + // draw it + DrawQ_String(x, con_vislines - con_textsize.value*2, text, y + 3, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, FONT_CONSOLE ); + + // add a cursor on top of this (when using freetype) + if (!r_font_disable_freetype.integer) + { + if ((int)(realtime*con_cursorspeed) & 1) // cursor is visible + { + if (!utf8_enable.integer) + { + text[0] = 11 + 130 * key_insert; // either solid or triangle facing right + text[1] = 0; + } + else + { + size_t len; + const char *curbuf; + char charbuf16[16]; + curbuf = u8_encodech(0xE000 + 11 + 130 * key_insert, &len, charbuf16); + memcpy(text, curbuf, len); + text[len] = 0; + } + DrawQ_String(x + xo, con_vislines - con_textsize.value*2, text, 0, con_textsize.value, con_textsize.value, 1.0, 1.0, 1.0, 1.0, 0, &col_out, false, FONT_CONSOLE); + } + } + + // remove cursor +// key_line[key_linepos] = 0; +} + +typedef struct +{ + dp_font_t *font; + float alignment; // 0 = left, 0.5 = center, 1 = right + float fontsize; + float x; + float y; + float width; + float ymin, ymax; + const char *continuationString; + + // PRIVATE: + int colorindex; // init to -1 +} +con_text_info_t; + +static float Con_WordWidthFunc(void *passthrough, const char *w, size_t *length, float maxWidth) +{ + con_text_info_t *ti = (con_text_info_t *) passthrough; + if(w == NULL) + { + ti->colorindex = -1; + return ti->fontsize * ti->font->maxwidth; + } + if(maxWidth >= 0) + return DrawQ_TextWidth_UntilWidth(w, length, ti->fontsize, ti->fontsize, false, ti->font, -maxWidth); // -maxWidth: we want at least one char + else if(maxWidth == -1) + return DrawQ_TextWidth(w, *length, ti->fontsize, ti->fontsize, false, ti->font); + else + { + Sys_PrintfToTerminal("Con_WordWidthFunc: can't get here (maxWidth should never be %f)\n", maxWidth); + // Note: this is NOT a Con_Printf, as it could print recursively + return 0; + } +} + +static int Con_CountLineFunc(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation) +{ + (void) passthrough; + (void) line; + (void) length; + (void) width; + (void) isContinuation; + return 1; +} + +static int Con_DisplayLineFunc(void *passthrough, const char *line, size_t length, float width, qboolean isContinuation) +{ + con_text_info_t *ti = (con_text_info_t *) passthrough; + + if(ti->y < ti->ymin - 0.001) + (void) 0; + else if(ti->y > ti->ymax - ti->fontsize + 0.001) + (void) 0; + else + { + int x = (int) (ti->x + (ti->width - width) * ti->alignment); + if(isContinuation && *ti->continuationString) + x = (int) DrawQ_String(x, ti->y, ti->continuationString, strlen(ti->continuationString), ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, NULL, false, ti->font); + if(length > 0) + DrawQ_String(x, ti->y, line, length, ti->fontsize, ti->fontsize, 1.0, 1.0, 1.0, 1.0, 0, &(ti->colorindex), false, ti->font); + } + + ti->y += ti->fontsize; + return 1; +} + +static int Con_DrawNotifyRect(int mask_must, int mask_mustnot, float maxage, float x, float y, float width, float height, float fontsize, float alignment_x, float alignment_y, const char *continuationString) +{ + int i; + int lines = 0; + int maxlines = (int) floor(height / fontsize + 0.01f); + int startidx; + int nskip = 0; + int continuationWidth = 0; + size_t l; + double t = cl.time; // saved so it won't change + con_text_info_t ti; + + ti.font = (mask_must & CON_MASK_CHAT) ? FONT_CHAT : FONT_NOTIFY; + ti.fontsize = fontsize; + ti.alignment = alignment_x; + ti.width = width; + ti.ymin = y; + ti.ymax = y + height; + ti.continuationString = continuationString; + + l = 0; + Con_WordWidthFunc(&ti, NULL, &l, -1); + l = strlen(continuationString); + continuationWidth = (int) Con_WordWidthFunc(&ti, continuationString, &l, -1); + + // first find the first line to draw by backwards iterating and word wrapping to find their length... + startidx = CON_LINES_COUNT; + for(i = CON_LINES_COUNT - 1; i >= 0; --i) + { + con_lineinfo_t *l = &CON_LINES(i); + int mylines; + + if((l->mask & mask_must) != mask_must) + continue; + if(l->mask & mask_mustnot) + continue; + if(maxage && (l->addtime < t - maxage)) + continue; + + // WE FOUND ONE! + // Calculate its actual height... + mylines = COM_Wordwrap(l->start, l->len, continuationWidth, width, Con_WordWidthFunc, &ti, Con_CountLineFunc, &ti); + if(lines + mylines >= maxlines) + { + nskip = lines + mylines - maxlines; + lines = maxlines; + startidx = i; + break; + } + lines += mylines; + startidx = i; + } + + // then center according to the calculated amount of lines... + ti.x = x; + ti.y = y + alignment_y * (height - lines * fontsize) - nskip * fontsize; + + // then actually draw + for(i = startidx; i < CON_LINES_COUNT; ++i) + { + con_lineinfo_t *l = &CON_LINES(i); + + if((l->mask & mask_must) != mask_must) + continue; + if(l->mask & mask_mustnot) + continue; + if(maxage && (l->addtime < t - maxage)) + continue; + + COM_Wordwrap(l->start, l->len, continuationWidth, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti); + } + + return lines; +} + +/* +================ +Con_DrawNotify + +Draws the last few lines of output transparently over the game top +================ +*/ +void Con_DrawNotify (void) +{ + float x, v, xr; + float chatstart, notifystart, inputsize, height; + float align; + char temptext[MAX_INPUTLINE]; + int numChatlines; + int chatpos; + + if (con_mutex) Thread_LockMutex(con_mutex); + ConBuffer_FixTimes(&con); + + numChatlines = con_chat.integer; + + chatpos = con_chatpos.integer; + + if (con_notify.integer < 0) + Cvar_SetValueQuick(&con_notify, 0); + if (gamemode == GAME_TRANSFUSION) + v = 8; // vertical offset + else + v = 0; + + // GAME_NEXUIZ: center, otherwise left justify + align = con_notifyalign.value; + if(!*con_notifyalign.string) // empty string, evaluated to 0 above + { + if(gamemode == GAME_NEXUIZ) + align = 0.5; + } + + if(numChatlines || !con_chatrect.integer) + { + if(chatpos == 0) + { + // first chat, input line, then notify + chatstart = v; + notifystart = v + (numChatlines + 1) * con_chatsize.value; + } + else if(chatpos > 0) + { + // first notify, then (chatpos-1) empty lines, then chat, then input + notifystart = v; + chatstart = v + (con_notify.value + (chatpos - 1)) * con_notifysize.value; + } + else // if(chatpos < 0) + { + // first notify, then much space, then chat, then input, then -chatpos-1 empty lines + notifystart = v; + chatstart = vid_conheight.value - (-chatpos-1 + numChatlines + 1) * con_chatsize.value; + } + } + else + { + // just notify and input + notifystart = v; + chatstart = 0; // shut off gcc warning + } + + v = notifystart + con_notifysize.value * Con_DrawNotifyRect(0, CON_MASK_INPUT | CON_MASK_HIDENOTIFY | (numChatlines ? CON_MASK_CHAT : 0) | CON_MASK_DEVELOPER, con_notifytime.value, 0, notifystart, vid_conwidth.value, con_notify.value * con_notifysize.value, con_notifysize.value, align, 0.0, ""); + + if(con_chatrect.integer) + { + x = con_chatrect_x.value * vid_conwidth.value; + v = con_chatrect_y.value * vid_conheight.value; + } + else + { + x = 0; + if(numChatlines) // only do this if chat area is enabled, or this would move the input line wrong + v = chatstart; + } + height = numChatlines * con_chatsize.value; + + if(numChatlines) + { + Con_DrawNotifyRect(CON_MASK_CHAT, CON_MASK_INPUT, con_chattime.value, x, v, vid_conwidth.value * con_chatwidth.value, height, con_chatsize.value, 0.0, 1.0, (utf8_enable.integer ? "^3\xee\x80\x8c\xee\x80\x8c\xee\x80\x8c " : "^3\014\014\014 ")); // 015 is ·> character in conchars.tga + v += height; + } + if (key_dest == key_message) + { + //static char *cursor[2] = { "\xee\x80\x8a", "\xee\x80\x8b" }; // { off, on } + int colorindex = -1; + const char *cursor; + char charbuf16[16]; + cursor = u8_encodech(0xE00A + ((int)(realtime * con_cursorspeed)&1), NULL, charbuf16); + + // LordHavoc: speedup, and other improvements + if (chat_mode < 0) + dpsnprintf(temptext, sizeof(temptext), "]%s%s", chat_buffer, cursor); + else if(chat_mode) + dpsnprintf(temptext, sizeof(temptext), "say_team:%s%s", chat_buffer, cursor); + else + dpsnprintf(temptext, sizeof(temptext), "say:%s%s", chat_buffer, cursor); + + // FIXME word wrap + inputsize = (numChatlines ? con_chatsize : con_notifysize).value; + xr = vid_conwidth.value - DrawQ_TextWidth(temptext, 0, inputsize, inputsize, false, FONT_CHAT); + x = min(xr, x); + DrawQ_String(x, v, temptext, 0, inputsize, inputsize, 1.0, 1.0, 1.0, 1.0, 0, &colorindex, false, FONT_CHAT); + } + if (con_mutex) Thread_UnlockMutex(con_mutex); +} + +/* +================ +Con_LineHeight + +Returns the height of a given console line; calculates it if necessary. +================ +*/ +static int Con_LineHeight(int lineno) +{ + con_lineinfo_t *li = &CON_LINES(lineno); + if(li->height == -1) + { + float width = vid_conwidth.value; + con_text_info_t ti; + con_lineinfo_t *li = &CON_LINES(lineno); + ti.fontsize = con_textsize.value; + ti.font = FONT_CONSOLE; + li->height = COM_Wordwrap(li->start, li->len, 0, width, Con_WordWidthFunc, &ti, Con_CountLineFunc, NULL); + } + return li->height; +} + +/* +================ +Con_DrawConsoleLine + +Draws a line of the console; returns its height in lines. +If alpha is 0, the line is not drawn, but still wrapped and its height +returned. +================ +*/ +static int Con_DrawConsoleLine(int mask_must, int mask_mustnot, float y, int lineno, float ymin, float ymax) +{ + float width = vid_conwidth.value; + con_text_info_t ti; + con_lineinfo_t *li = &CON_LINES(lineno); + + if((li->mask & mask_must) != mask_must) + return 0; + if((li->mask & mask_mustnot) != 0) + return 0; + + ti.continuationString = ""; + ti.alignment = 0; + ti.fontsize = con_textsize.value; + ti.font = FONT_CONSOLE; + ti.x = 0; + ti.y = y - (Con_LineHeight(lineno) - 1) * ti.fontsize; + ti.ymin = ymin; + ti.ymax = ymax; + ti.width = width; + + return COM_Wordwrap(li->start, li->len, 0, width, Con_WordWidthFunc, &ti, Con_DisplayLineFunc, &ti); +} + +/* +================ +Con_LastVisibleLine + +Calculates the last visible line index and how much to show of it based on +con_backscroll. +================ +*/ +static void Con_LastVisibleLine(int mask_must, int mask_mustnot, int *last, int *limitlast) +{ + int lines_seen = 0; + int i; + + if(con_backscroll < 0) + con_backscroll = 0; + + *last = 0; + + // now count until we saw con_backscroll actual lines + for(i = CON_LINES_COUNT - 1; i >= 0; --i) + if((CON_LINES(i).mask & mask_must) == mask_must) + if((CON_LINES(i).mask & mask_mustnot) == 0) + { + int h = Con_LineHeight(i); + + // line is the last visible line? + *last = i; + if(lines_seen + h > con_backscroll && lines_seen <= con_backscroll) + { + *limitlast = lines_seen + h - con_backscroll; + return; + } + + lines_seen += h; + } + + // if we get here, no line was on screen - scroll so that one line is + // visible then. + con_backscroll = lines_seen - 1; + *limitlast = 1; +} + +/* +================ +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) +{ + float alpha, alpha0; + double sx, sy; + int mask_must = 0; + int mask_mustnot = (developer.integer>0) ? 0 : CON_MASK_DEVELOPER; + cachepic_t *conbackpic; + + if (lines <= 0) + return; + + if (con_mutex) Thread_LockMutex(con_mutex); + + if (con_backscroll < 0) + con_backscroll = 0; + + con_vislines = lines; + + r_draw2d_force = true; + +// draw the background + alpha0 = cls.signon == SIGNONS ? scr_conalpha.value : 1.0f; // always full alpha when not in game + if((alpha = alpha0 * scr_conalphafactor.value) > 0) + { + sx = scr_conscroll_x.value; + sy = scr_conscroll_y.value; + conbackpic = scr_conbrightness.value >= 0.01f ? Draw_CachePic_Flags("gfx/conback", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0) : NULL; + sx *= realtime; sy *= realtime; + sx -= floor(sx); sy -= floor(sy); + if (conbackpic && conbackpic->tex != r_texture_notexture) + DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, + 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0); + else + DrawQ_Fill(0, lines - vid_conheight.integer, vid_conwidth.integer, vid_conheight.integer, 0.0f, 0.0f, 0.0f, alpha, 0); + } + if((alpha = alpha0 * scr_conalpha2factor.value) > 0) + { + sx = scr_conscroll2_x.value; + sy = scr_conscroll2_y.value; + conbackpic = Draw_CachePic_Flags("gfx/conback2", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0); + sx *= realtime; sy *= realtime; + sx -= floor(sx); sy -= floor(sy); + if(conbackpic && conbackpic->tex != r_texture_notexture) + DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, + 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0); + } + if((alpha = alpha0 * scr_conalpha3factor.value) > 0) + { + sx = scr_conscroll3_x.value; + sy = scr_conscroll3_y.value; + conbackpic = Draw_CachePic_Flags("gfx/conback3", (sx != 0 || sy != 0) ? CACHEPICFLAG_NOCLAMP : 0); + sx *= realtime; sy *= realtime; + sx -= floor(sx); sy -= floor(sy); + if(conbackpic && conbackpic->tex != r_texture_notexture) + DrawQ_SuperPic(0, lines - vid_conheight.integer, conbackpic, vid_conwidth.integer, vid_conheight.integer, + 0 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 0 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 1 + sx, 1 + sy, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, alpha, + 0); + } + DrawQ_String(vid_conwidth.integer - DrawQ_TextWidth(engineversion, 0, con_textsize.value, con_textsize.value, false, FONT_CONSOLE), lines - con_textsize.value, engineversion, 0, con_textsize.value, con_textsize.value, 1, 0, 0, 1, 0, NULL, true, FONT_CONSOLE); + +// draw the text +#if 0 + { + int i; + int count = CON_LINES_COUNT; + float ymax = con_vislines - 2 * con_textsize.value; + float y = ymax + con_textsize.value * con_backscroll; + for (i = 0;i < count && y >= 0;i++) + y -= Con_DrawConsoleLine(mask_must, mask_mustnot, y - con_textsize.value, CON_LINES_COUNT - 1 - i, 0, ymax) * con_textsize.value; + // fix any excessive scrollback for the next frame + if (i >= count && y >= 0) + { + con_backscroll -= (int)(y / con_textsize.value); + if (con_backscroll < 0) + con_backscroll = 0; + } + } +#else + if(CON_LINES_COUNT > 0) + { + int i, last, limitlast; + float y; + float ymax = con_vislines - 2 * con_textsize.value; + Con_LastVisibleLine(mask_must, mask_mustnot, &last, &limitlast); + //Con_LastVisibleLine(mask_must, mask_mustnot, &last, &limitlast); + y = ymax - con_textsize.value; + + if(limitlast) + y += (CON_LINES(last).height - limitlast) * con_textsize.value; + i = last; + + for(;;) + { + y -= Con_DrawConsoleLine(mask_must, mask_mustnot, y, i, 0, ymax) * con_textsize.value; + if(i == 0) + break; // top of console buffer + if(y < 0) + break; // top of console window + limitlast = 0; + --i; + } + } +#endif + +// draw the input prompt, user text, and cursor if desired + Con_DrawInput (); + + r_draw2d_force = false; + if (con_mutex) Thread_UnlockMutex(con_mutex); +} + +/* +GetMapList + +Made by [515] +Prints not only map filename, but also +its format (q1/q2/q3/hl) and even its message +*/ +//[515]: here is an ugly hack.. two gotos... oh my... *but it works* +//LordHavoc: rewrote bsp type detection, rewrote message extraction to do proper worldspawn parsing +//LordHavoc: added .ent file loading, and redesigned error handling to still try the .ent file even if the map format is not recognized, this also eliminated one goto +//LordHavoc: FIXME: man this GetMapList is STILL ugly code even after my cleanups... +qboolean GetMapList (const char *s, char *completedname, int completednamebufferlength) +{ + fssearch_t *t; + char message[1024]; + int i, k, max, p, o, min; + unsigned char *len; + qfile_t *f; + unsigned char buf[1024]; + + dpsnprintf(message, sizeof(message), "maps/%s*.bsp", s); + t = FS_Search(message, 1, true); + if(!t) + return false; + if (t->numfilenames > 1) + Con_Printf("^1 %i maps found :\n", t->numfilenames); + len = (unsigned char *)Z_Malloc(t->numfilenames); + min = 666; + for(max=i=0;inumfilenames;i++) + { + k = (int)strlen(t->filenames[i]); + k -= 9; + if(max < k) + max = k; + else + if(min > k) + min = k; + len[i] = k; + } + o = (int)strlen(s); + for(i=0;inumfilenames;i++) + { + int lumpofs = 0, lumplen = 0; + char *entities = NULL; + const char *data = NULL; + char keyname[64]; + char entfilename[MAX_QPATH]; + char desc[64]; + desc[0] = 0; + strlcpy(message, "^1ERROR: open failed^7", sizeof(message)); + p = 0; + f = FS_OpenVirtualFile(t->filenames[i], true); + if(f) + { + strlcpy(message, "^1ERROR: not a known map format^7", sizeof(message)); + memset(buf, 0, 1024); + FS_Read(f, buf, 1024); + if (!memcmp(buf, "IBSP", 4)) + { + p = LittleLong(((int *)buf)[1]); + if (p == Q3BSPVERSION) + { + q3dheader_t *header = (q3dheader_t *)buf; + lumpofs = LittleLong(header->lumps[Q3LUMP_ENTITIES].fileofs); + lumplen = LittleLong(header->lumps[Q3LUMP_ENTITIES].filelen); + dpsnprintf(desc, sizeof(desc), "Q3BSP%i", p); + } + else if (p == Q2BSPVERSION) + { + q2dheader_t *header = (q2dheader_t *)buf; + lumpofs = LittleLong(header->lumps[Q2LUMP_ENTITIES].fileofs); + lumplen = LittleLong(header->lumps[Q2LUMP_ENTITIES].filelen); + dpsnprintf(desc, sizeof(desc), "Q2BSP%i", p); + } + else + dpsnprintf(desc, sizeof(desc), "IBSP%i", p); + } + else if (BuffLittleLong(buf) == BSPVERSION) + { + lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES); + lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4); + dpsnprintf(desc, sizeof(desc), "BSP29"); + } + else if (BuffLittleLong(buf) == 30) + { + lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES); + lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4); + dpsnprintf(desc, sizeof(desc), "BSPHL"); + } + else if (!memcmp(buf, "BSP2", 4)) + { + lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES); + lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4); + dpsnprintf(desc, sizeof(desc), "BSP2"); + } + else if (!memcmp(buf, "2PSB", 4)) + { + lumpofs = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES); + lumplen = BuffLittleLong(buf + 4 + 8 * LUMP_ENTITIES + 4); + dpsnprintf(desc, sizeof(desc), "BSP2RMQe"); + } + else + { + dpsnprintf(desc, sizeof(desc), "unknown%i", BuffLittleLong(buf)); + } + strlcpy(entfilename, t->filenames[i], sizeof(entfilename)); + memcpy(entfilename + strlen(entfilename) - 4, ".ent", 5); + entities = (char *)FS_LoadFile(entfilename, tempmempool, true, NULL); + if (!entities && lumplen >= 10) + { + FS_Seek(f, lumpofs, SEEK_SET); + entities = (char *)Z_Malloc(lumplen + 1); + FS_Read(f, entities, lumplen); + } + if (entities) + { + // if there are entities to parse, a missing message key just + // means there is no title, so clear the message string now + message[0] = 0; + data = entities; + for (;;) + { + int l; + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; + if (com_token[0] == '{') + continue; + if (com_token[0] == '}') + break; + // skip leading whitespace + for (k = 0;com_token[k] && ISWHITESPACE(com_token[k]);k++); + for (l = 0;l < (int)sizeof(keyname) - 1 && com_token[k+l] && !ISWHITESPACE(com_token[k+l]);l++) + keyname[l] = com_token[k+l]; + keyname[l] = 0; + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; + if (developer_extra.integer) + Con_DPrintf("key: %s %s\n", keyname, com_token); + if (!strcmp(keyname, "message")) + { + // get the message contents + strlcpy(message, com_token, sizeof(message)); + break; + } + } + } + } + if (entities) + Z_Free(entities); + if(f) + FS_Close(f); + *(t->filenames[i]+len[i]+5) = 0; + Con_Printf("%16s (%-8s) %s\n", t->filenames[i]+5, desc, message); + } + Con_Print("\n"); + for(p=o;pfilenames[0]+5+p); + if(k == 0) + goto endcomplete; + for(i=1;inumfilenames;i++) + if(*(t->filenames[i]+5+p) != k) + goto endcomplete; + } +endcomplete: + if(p > o && completedname && completednamebufferlength > 0) + { + memset(completedname, 0, completednamebufferlength); + memcpy(completedname, (t->filenames[0]+5), min(p, completednamebufferlength - 1)); + } + Z_Free(len); + FS_FreeSearch(t); + return p > o; +} + +/* + Con_DisplayList + + New function for tab-completion system + Added by EvilTypeGuy + MEGA Thanks to Taniwha + +*/ +void Con_DisplayList(const char **list) +{ + int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4); + const char **walk = list; + + while (*walk) { + len = (int)strlen(*walk); + if (len > maxlen) + maxlen = len; + walk++; + } + maxlen += 1; + + while (*list) { + len = (int)strlen(*list); + if (pos + maxlen >= width) { + Con_Print("\n"); + pos = 0; + } + + Con_Print(*list); + for (i = 0; i < (maxlen - len); i++) + Con_Print(" "); + + pos += maxlen; + list++; + } + + if (pos) + Con_Print("\n\n"); +} + +/* + SanitizeString strips color tags from the string in + and writes the result on string out +*/ +static void SanitizeString(char *in, char *out) +{ + while(*in) + { + if(*in == STRING_COLOR_TAG) + { + ++in; + if(!*in) + { + out[0] = STRING_COLOR_TAG; + out[1] = 0; + return; + } + else if (*in >= '0' && *in <= '9') // ^[0-9] found + { + ++in; + if(!*in) + { + *out = 0; + return; + } else if (*in == STRING_COLOR_TAG) // ^[0-9]^ found, don't print ^[0-9] + continue; + } + else if (*in == STRING_COLOR_RGB_TAG_CHAR) // ^x found + { + if ( isxdigit(in[1]) && isxdigit(in[2]) && isxdigit(in[3]) ) + { + in+=4; + if (!*in) + { + *out = 0; + return; + } else if (*in == STRING_COLOR_TAG) // ^xrgb^ found, don't print ^xrgb + continue; + } + else in--; + } + else if (*in != STRING_COLOR_TAG) + --in; + } + *out = qfont_table[*(unsigned char*)in]; + ++in; + ++out; + } + *out = 0; +} + +// Now it becomes TRICKY :D --blub +static char Nicks_list[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]; // contains the nicks with colors and all that +static char Nicks_sanlist[MAX_SCOREBOARD][MAX_SCOREBOARDNAME]; // sanitized list for completion when there are other possible matches. +// means: when somebody uses a cvar's name as his name, we won't ever get his colors in there... +static int Nicks_offset[MAX_SCOREBOARD]; // when nicks use a space, we need this to move the completion list string starts to avoid invalid memcpys +static int Nicks_matchpos; + +// co against <<:BLASTER:>> is true!? +static int Nicks_strncasecmp_nospaces(char *a, char *b, unsigned int a_len) +{ + while(a_len) + { + if(tolower(*a) == tolower(*b)) + { + if(*a == 0) + return 0; + --a_len; + ++a; + ++b; + continue; + } + if(!*a) + return -1; + if(!*b) + return 1; + if(*a == ' ') + return (*a < *b) ? -1 : 1; + if(*b == ' ') + ++b; + else + return (*a < *b) ? -1 : 1; + } + return 0; +} +static int Nicks_strncasecmp(char *a, char *b, unsigned int a_len) +{ + char space_char; + if(!(con_nickcompletion_flags.integer & NICKS_ALPHANUMERICS_ONLY)) + { + if(con_nickcompletion_flags.integer & NICKS_NO_SPACES) + return Nicks_strncasecmp_nospaces(a, b, a_len); + return strncasecmp(a, b, a_len); + } + + space_char = (con_nickcompletion_flags.integer & NICKS_NO_SPACES) ? 'a' : ' '; + + // ignore non alphanumerics of B + // if A contains a non-alphanumeric, B must contain it as well though! + while(a_len) + { + qboolean alnum_a, alnum_b; + + if(tolower(*a) == tolower(*b)) + { + if(*a == 0) // end of both strings, they're equal + return 0; + --a_len; + ++a; + ++b; + continue; + } + // not equal, end of one string? + if(!*a) + return -1; + if(!*b) + return 1; + // ignore non alphanumerics + alnum_a = ( (*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || (*a >= '0' && *a <= '9') || *a == space_char); + alnum_b = ( (*b >= 'a' && *b <= 'z') || (*b >= 'A' && *b <= 'Z') || (*b >= '0' && *b <= '9') || *b == space_char); + if(!alnum_a) // b must contain this + return (*a < *b) ? -1 : 1; + if(!alnum_b) + ++b; + // otherwise, both are alnum, they're just not equal, return the appropriate number + else + return (*a < *b) ? -1 : 1; + } + return 0; +} + + +/* Nicks_CompleteCountPossible + + Count the number of possible nicks to complete + */ +static int Nicks_CompleteCountPossible(char *line, int pos, char *s, qboolean isCon) +{ + char name[128]; + int i, p; + int match; + int spos; + int count = 0; + + if(!con_nickcompletion.integer) + return 0; + + // changed that to 1 + if(!line[0])// || !line[1]) // we want at least... 2 written characters + return 0; + + for(i = 0; i < cl.maxclients; ++i) + { + p = i; + if(!cl.scores[p].name[0]) + continue; + + SanitizeString(cl.scores[p].name, name); + //Con_Printf(" ^2Sanitized: ^7%s -> %s", cl.scores[p].name, name); + + if(!name[0]) + continue; + + match = -1; + spos = pos - 1; // no need for a minimum of characters :) + + while(spos >= 0) + { + if(spos > 0 && line[spos-1] != ' ' && line[spos-1] != ';' && line[spos-1] != '\"' && line[spos-1] != '\'') + { + if(!(isCon && line[spos-1] == ']' && spos == 1) && // console start + !(spos > 1 && line[spos-1] >= '0' && line[spos-1] <= '9' && line[spos-2] == STRING_COLOR_TAG)) // color start + { + --spos; + continue; + } + } + if(isCon && spos == 0) + break; + if(Nicks_strncasecmp(line+spos, name, pos-spos) == 0) + match = spos; + --spos; + } + if(match < 0) + continue; + //Con_Printf("Possible match: %s|%s\n", cl.scores[p].name, name); + strlcpy(Nicks_list[count], cl.scores[p].name, sizeof(Nicks_list[count])); + + // the sanitized list + strlcpy(Nicks_sanlist[count], name, sizeof(Nicks_sanlist[count])); + if(!count) + { + Nicks_matchpos = match; + } + + Nicks_offset[count] = s - (&line[match]); + //Con_Printf("offset for %s: %i\n", name, Nicks_offset[count]); + + ++count; + } + return count; +} + +static void Cmd_CompleteNicksPrint(int count) +{ + int i; + for(i = 0; i < count; ++i) + Con_Printf("%s\n", Nicks_list[i]); +} + +static void Nicks_CutMatchesNormal(int count) +{ + // cut match 0 down to the longest possible completion + int i; + unsigned int c, l; + c = strlen(Nicks_sanlist[0]) - 1; + for(i = 1; i < count; ++i) + { + l = strlen(Nicks_sanlist[i]) - 1; + if(l < c) + c = l; + + for(l = 0; l <= c; ++l) + if(tolower(Nicks_sanlist[0][l]) != tolower(Nicks_sanlist[i][l])) + { + c = l-1; + break; + } + } + Nicks_sanlist[0][c+1] = 0; + //Con_Printf("List0: %s\n", Nicks_sanlist[0]); +} + +static unsigned int Nicks_strcleanlen(const char *s) +{ + unsigned int l = 0; + while(*s) + { + if( (*s >= 'a' && *s <= 'z') || + (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || + *s == ' ') + ++l; + ++s; + } + return l; +} + +static void Nicks_CutMatchesAlphaNumeric(int count) +{ + // cut match 0 down to the longest possible completion + int i; + unsigned int c, l; + char tempstr[sizeof(Nicks_sanlist[0])]; + char *a, *b; + char space_char = (con_nickcompletion_flags.integer & NICKS_NO_SPACES) ? 'a' : ' '; // yes this is correct, we want NO spaces when no spaces + + c = strlen(Nicks_sanlist[0]); + for(i = 0, l = 0; i < (int)c; ++i) + { + if( (Nicks_sanlist[0][i] >= 'a' && Nicks_sanlist[0][i] <= 'z') || + (Nicks_sanlist[0][i] >= 'A' && Nicks_sanlist[0][i] <= 'Z') || + (Nicks_sanlist[0][i] >= '0' && Nicks_sanlist[0][i] <= '9') || Nicks_sanlist[0][i] == space_char) // this is what's COPIED + { + tempstr[l++] = Nicks_sanlist[0][i]; + } + } + tempstr[l] = 0; + + for(i = 1; i < count; ++i) + { + a = tempstr; + b = Nicks_sanlist[i]; + while(1) + { + if(!*a) + break; + if(!*b) + { + *a = 0; + break; + } + if(tolower(*a) == tolower(*b)) + { + ++a; + ++b; + continue; + } + if( (*b >= 'a' && *b <= 'z') || (*b >= 'A' && *b <= 'Z') || (*b >= '0' && *b <= '9') || *b == space_char) + { + // b is alnum, so cut + *a = 0; + break; + } + ++b; + } + } + // Just so you know, if cutmatchesnormal doesn't kill the first entry, then even the non-alnums fit + Nicks_CutMatchesNormal(count); + //if(!Nicks_sanlist[0][0]) + if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr)) + { + // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there + strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0])); + } +} + +static void Nicks_CutMatchesNoSpaces(int count) +{ + // cut match 0 down to the longest possible completion + int i; + unsigned int c, l; + char tempstr[sizeof(Nicks_sanlist[0])]; + char *a, *b; + + c = strlen(Nicks_sanlist[0]); + for(i = 0, l = 0; i < (int)c; ++i) + { + if(Nicks_sanlist[0][i] != ' ') // here it's what's NOT copied + { + tempstr[l++] = Nicks_sanlist[0][i]; + } + } + tempstr[l] = 0; + + for(i = 1; i < count; ++i) + { + a = tempstr; + b = Nicks_sanlist[i]; + while(1) + { + if(!*a) + break; + if(!*b) + { + *a = 0; + break; + } + if(tolower(*a) == tolower(*b)) + { + ++a; + ++b; + continue; + } + if(*b != ' ') + { + *a = 0; + break; + } + ++b; + } + } + // Just so you know, if cutmatchesnormal doesn't kill the first entry, then even the non-alnums fit + Nicks_CutMatchesNormal(count); + //if(!Nicks_sanlist[0][0]) + //Con_Printf("TS: %s\n", tempstr); + if(Nicks_strcleanlen(Nicks_sanlist[0]) < strlen(tempstr)) + { + // if the clean sanitized one is longer than the current one, use it, it has crap chars which definitely are in there + strlcpy(Nicks_sanlist[0], tempstr, sizeof(Nicks_sanlist[0])); + } +} + +static void Nicks_CutMatches(int count) +{ + if(con_nickcompletion_flags.integer & NICKS_ALPHANUMERICS_ONLY) + Nicks_CutMatchesAlphaNumeric(count); + else if(con_nickcompletion_flags.integer & NICKS_NO_SPACES) + Nicks_CutMatchesNoSpaces(count); + else + Nicks_CutMatchesNormal(count); +} + +static const char **Nicks_CompleteBuildList(int count) +{ + const char **buf; + int bpos = 0; + // the list is freed by Con_CompleteCommandLine, so create a char** + buf = (const char **)Mem_Alloc(tempmempool, count * sizeof(const char *) + sizeof (const char *)); + + for(; bpos < count; ++bpos) + buf[bpos] = Nicks_sanlist[bpos] + Nicks_offset[bpos]; + + Nicks_CutMatches(count); + + buf[bpos] = NULL; + return buf; +} + +/* + Nicks_AddLastColor + Restores the previous used color, after the autocompleted name. +*/ +static int Nicks_AddLastColor(char *buffer, int pos) +{ + qboolean quote_added = false; + int match; + int color = STRING_COLOR_DEFAULT + '0'; + char r = 0, g = 0, b = 0; + + if(con_nickcompletion_flags.integer & NICKS_ADD_QUOTE && buffer[Nicks_matchpos-1] == '\"') + { + // we'll have to add a quote :) + buffer[pos++] = '\"'; + quote_added = true; + } + + if((!quote_added && con_nickcompletion_flags.integer & NICKS_ADD_COLOR) || con_nickcompletion_flags.integer & NICKS_FORCE_COLOR) + { + // add color when no quote was added, or when flags &4? + // find last color + for(match = Nicks_matchpos-1; match >= 0; --match) + { + if(buffer[match] == STRING_COLOR_TAG) + { + if( isdigit(buffer[match+1]) ) + { + color = buffer[match+1]; + break; + } + else if(buffer[match+1] == STRING_COLOR_RGB_TAG_CHAR) + { + if ( isxdigit(buffer[match+2]) && isxdigit(buffer[match+3]) && isxdigit(buffer[match+4]) ) + { + r = buffer[match+2]; + g = buffer[match+3]; + b = buffer[match+4]; + color = -1; + break; + } + } + } + } + if(!quote_added) + { + if( pos >= 2 && buffer[pos-2] == STRING_COLOR_TAG && isdigit(buffer[pos-1]) ) // when thes use &4 + pos -= 2; + else if( pos >= 5 && buffer[pos-5] == STRING_COLOR_TAG && buffer[pos-4] == STRING_COLOR_RGB_TAG_CHAR + && isxdigit(buffer[pos-3]) && isxdigit(buffer[pos-2]) && isxdigit(buffer[pos-1]) ) + pos -= 5; + } + buffer[pos++] = STRING_COLOR_TAG; + if (color == -1) + { + buffer[pos++] = STRING_COLOR_RGB_TAG_CHAR; + buffer[pos++] = r; + buffer[pos++] = g; + buffer[pos++] = b; + } + else + buffer[pos++] = color; + } + return pos; +} + +int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos) +{ + int n; + /*if(!con_nickcompletion.integer) + return; is tested in Nicks_CompletionCountPossible */ + n = Nicks_CompleteCountPossible(buffer, pos, &buffer[pos], false); + if(n == 1) + { + size_t len; + char *msg; + + msg = Nicks_list[0]; + len = min(size - Nicks_matchpos - 3, strlen(msg)); + memcpy(&buffer[Nicks_matchpos], msg, len); + if( len < (size - 7) ) // space for color (^[0-9] or ^xrgb) and space and \0 + len = Nicks_AddLastColor(buffer, Nicks_matchpos+len); + buffer[len++] = ' '; + buffer[len] = 0; + return len; + } else if(n > 1) + { + int len; + char *msg; + Con_Printf("\n%i possible nicks:\n", n); + Cmd_CompleteNicksPrint(n); + + Nicks_CutMatches(n); + + msg = Nicks_sanlist[0]; + len = min(size - Nicks_matchpos, strlen(msg)); + memcpy(&buffer[Nicks_matchpos], msg, len); + buffer[Nicks_matchpos + len] = 0; + //pos += len; + return Nicks_matchpos + len; + } + return pos; +} + + +/* + Con_CompleteCommandLine + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + Enhanced to tab-complete map names by [515] + +*/ +void Con_CompleteCommandLine (void) +{ + const char *cmd = ""; + char *s; + const char **list[4] = {0, 0, 0, 0}; + char s2[512]; + char command[512]; + int c, v, a, i, cmd_len, pos, k; + int n; // nicks --blub + const char *space, *patterns; + char vabuf[1024]; + + //find what we want to complete + pos = key_linepos; + while(--pos) + { + k = key_line[pos]; + if(k == '\"' || k == ';' || k == ' ' || k == '\'') + break; + } + pos++; + + s = key_line + pos; + strlcpy(s2, key_line + key_linepos, sizeof(s2)); //save chars after cursor + key_line[key_linepos] = 0; //hide them + + space = strchr(key_line + 1, ' '); + if(space && pos == (space - key_line) + 1) + { + strlcpy(command, key_line + 1, min(sizeof(command), (unsigned int)(space - key_line))); + + patterns = Cvar_VariableString(va(vabuf, sizeof(vabuf), "con_completion_%s", command)); // TODO maybe use a better place for this? + if(patterns && !*patterns) + patterns = NULL; // get rid of the empty string + + if(!strcmp(command, "map") || !strcmp(command, "changelevel") || (patterns && !strcmp(patterns, "map"))) + { + //maps search + char t[MAX_QPATH]; + if (GetMapList(s, t, sizeof(t))) + { + // first move the cursor + key_linepos += (int)strlen(t) - (int)strlen(s); + + // and now do the actual work + *s = 0; + strlcat(key_line, t, MAX_INPUTLINE); + strlcat(key_line, s2, MAX_INPUTLINE); //add back chars after cursor + + // and fix the cursor + if(key_linepos > (int) strlen(key_line)) + key_linepos = (int) strlen(key_line); + } + return; + } + else + { + if(patterns) + { + char t[MAX_QPATH]; + stringlist_t resultbuf, dirbuf; + + // Usage: + // // store completion patterns (space separated) for command foo in con_completion_foo + // set con_completion_foo "foodata/*.foodefault *.foo" + // foo + // + // Note: patterns with slash are always treated as absolute + // patterns; patterns without slash search in the innermost + // directory the user specified. There is no way to "complete into" + // a directory as of now, as directories seem to be unknown to the + // FS subsystem. + // + // Examples: + // set con_completion_playermodel "models/player/*.zym models/player/*.md3 models/player/*.psk models/player/*.dpm" + // set con_completion_playdemo "*.dem" + // set con_completion_play "*.wav *.ogg" + // + // TODO somehow add support for directories; these shall complete + // to their name + an appended slash. + + stringlistinit(&resultbuf); + stringlistinit(&dirbuf); + while(COM_ParseToken_Simple(&patterns, false, false, true)) + { + fssearch_t *search; + if(strchr(com_token, '/')) + { + search = FS_Search(com_token, true, true); + } + else + { + const char *slash = strrchr(s, '/'); + if(slash) + { + strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash + strlcat(t, com_token, sizeof(t)); + search = FS_Search(t, true, true); + } + else + search = FS_Search(com_token, true, true); + } + if(search) + { + for(i = 0; i < search->numfilenames; ++i) + if(!strncmp(search->filenames[i], s, strlen(s))) + if(FS_FileType(search->filenames[i]) == FS_FILETYPE_FILE) + stringlistappend(&resultbuf, search->filenames[i]); + FS_FreeSearch(search); + } + } + + // In any case, add directory names + { + fssearch_t *search; + const char *slash = strrchr(s, '/'); + if(slash) + { + strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash + strlcat(t, "*", sizeof(t)); + search = FS_Search(t, true, true); + } + else + search = FS_Search("*", true, true); + if(search) + { + for(i = 0; i < search->numfilenames; ++i) + if(!strncmp(search->filenames[i], s, strlen(s))) + if(FS_FileType(search->filenames[i]) == FS_FILETYPE_DIRECTORY) + stringlistappend(&dirbuf, search->filenames[i]); + FS_FreeSearch(search); + } + } + + if(resultbuf.numstrings > 0 || dirbuf.numstrings > 0) + { + const char *p, *q; + unsigned int matchchars; + if(resultbuf.numstrings == 0 && dirbuf.numstrings == 1) + { + dpsnprintf(t, sizeof(t), "%s/", dirbuf.strings[0]); + } + else + if(resultbuf.numstrings == 1 && dirbuf.numstrings == 0) + { + dpsnprintf(t, sizeof(t), "%s ", resultbuf.strings[0]); + } + else + { + stringlistsort(&resultbuf, true); // dirbuf is already sorted + Con_Printf("\n%i possible filenames\n", resultbuf.numstrings + dirbuf.numstrings); + for(i = 0; i < dirbuf.numstrings; ++i) + { + Con_Printf("^4%s^7/\n", dirbuf.strings[i]); + } + for(i = 0; i < resultbuf.numstrings; ++i) + { + Con_Printf("%s\n", resultbuf.strings[i]); + } + matchchars = sizeof(t) - 1; + if(resultbuf.numstrings > 0) + { + p = resultbuf.strings[0]; + q = resultbuf.strings[resultbuf.numstrings - 1]; + for(; *p && *p == *q; ++p, ++q); + matchchars = (unsigned int)(p - resultbuf.strings[0]); + } + if(dirbuf.numstrings > 0) + { + p = dirbuf.strings[0]; + q = dirbuf.strings[dirbuf.numstrings - 1]; + for(; *p && *p == *q; ++p, ++q); + matchchars = min(matchchars, (unsigned int)(p - dirbuf.strings[0])); + } + // now p points to the first non-equal character, or to the end + // of resultbuf.strings[0]. We want to append the characters + // from resultbuf.strings[0] to (not including) p as these are + // the unique prefix + strlcpy(t, (resultbuf.numstrings > 0 ? resultbuf : dirbuf).strings[0], min(matchchars + 1, sizeof(t))); + } + + // first move the cursor + key_linepos += (int)strlen(t) - (int)strlen(s); + + // and now do the actual work + *s = 0; + strlcat(key_line, t, MAX_INPUTLINE); + strlcat(key_line, s2, MAX_INPUTLINE); //add back chars after cursor + + // and fix the cursor + if(key_linepos > (int) strlen(key_line)) + key_linepos = (int) strlen(key_line); + } + stringlistfreecontents(&resultbuf); + stringlistfreecontents(&dirbuf); + + return; // bail out, when we complete for a command that wants a file name + } + } + } + + // Count number of possible matches and print them + c = Cmd_CompleteCountPossible(s); + if (c) + { + Con_Printf("\n%i possible command%s\n", c, (c > 1) ? "s: " : ":"); + Cmd_CompleteCommandPrint(s); + } + v = Cvar_CompleteCountPossible(s); + if (v) + { + Con_Printf("\n%i possible variable%s\n", v, (v > 1) ? "s: " : ":"); + Cvar_CompleteCvarPrint(s); + } + a = Cmd_CompleteAliasCountPossible(s); + if (a) + { + Con_Printf("\n%i possible alias%s\n", a, (a > 1) ? "es: " : ":"); + Cmd_CompleteAliasPrint(s); + } + n = Nicks_CompleteCountPossible(key_line, key_linepos, s, true); + if (n) + { + Con_Printf("\n%i possible nick%s\n", n, (n > 1) ? "s: " : ":"); + Cmd_CompleteNicksPrint(n); + } + + if (!(c + v + a + n)) // No possible matches + { + if(s2[0]) + strlcpy(&key_line[key_linepos], s2, sizeof(key_line) - key_linepos); + return; + } + + if (c) + cmd = *(list[0] = Cmd_CompleteBuildList(s)); + if (v) + cmd = *(list[1] = Cvar_CompleteBuildList(s)); + if (a) + cmd = *(list[2] = Cmd_CompleteAliasBuildList(s)); + if (n) + cmd = *(list[3] = Nicks_CompleteBuildList(n)); + + for (cmd_len = (int)strlen(s);;cmd_len++) + { + const char **l; + for (i = 0; i < 3; i++) + if (list[i]) + for (l = list[i];*l;l++) + if ((*l)[cmd_len] != cmd[cmd_len]) + goto done; + // all possible matches share this character, so we continue... + if (!cmd[cmd_len]) + { + // if all matches ended at the same position, stop + // (this means there is only one match) + break; + } + } +done: + + // prevent a buffer overrun by limiting cmd_len according to remaining space + cmd_len = min(cmd_len, (int)sizeof(key_line) - 1 - pos); + if (cmd) + { + key_linepos = pos; + memcpy(&key_line[key_linepos], cmd, cmd_len); + key_linepos += cmd_len; + // if there is only one match, add a space after it + if (c + v + a + n == 1 && key_linepos < (int)sizeof(key_line) - 1) + { + if(n) + { // was a nick, might have an offset, and needs colors ;) --blub + key_linepos = pos - Nicks_offset[0]; + cmd_len = strlen(Nicks_list[0]); + cmd_len = min(cmd_len, (int)sizeof(key_line) - 3 - pos); + + memcpy(&key_line[key_linepos] , Nicks_list[0], cmd_len); + key_linepos += cmd_len; + if(key_linepos < (int)(sizeof(key_line)-4)) // space for ^, X and space and \0 + key_linepos = Nicks_AddLastColor(key_line, key_linepos); + } + key_line[key_linepos++] = ' '; + } + } + + // use strlcat to avoid a buffer overrun + key_line[key_linepos] = 0; + strlcat(key_line, s2, sizeof(key_line)); + + // free the command, cvar, and alias lists + for (i = 0; i < 4; i++) + if (list[i]) + Mem_Free((void *)list[i]); +} + diff --git a/app/jni/console.h b/app/jni/console.h new file mode 100644 index 0000000..860c501 --- /dev/null +++ b/app/jni/console.h @@ -0,0 +1,151 @@ +/* +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 CONSOLE_H +#define CONSOLE_H + +// +// console +// +extern int con_totallines; +extern int con_backscroll; +extern qboolean con_initialized; + +void Con_Rcon_Redirect_Init(lhnetsocket_t *sock, lhnetaddress_t *dest, qboolean proquakeprotocol); +void Con_Rcon_Redirect_End(void); +void Con_Rcon_Redirect_Abort(void); + +/// If the line width has changed, reformat the buffer. +void Con_CheckResize (void); +void Con_Init (void); +void Con_Init_Commands (void); +void Con_Shutdown (void); +void Con_DrawConsole (int lines); + +/// Prints to a chosen console target +void Con_MaskPrint(int mask, const char *msg); + +// Prints to a chosen console target +void Con_MaskPrintf(int mask, const char *fmt, ...) DP_FUNC_PRINTF(2); + +/// Prints to all appropriate console targets, and adds timestamps +void Con_Print(const char *txt); + +/// Prints to all appropriate console targets. +void Con_Printf(const char *fmt, ...) DP_FUNC_PRINTF(1); + +/// A Con_Print that only shows up if the "developer" cvar is set. +void Con_DPrint(const char *msg); + +/// A Con_Printf that only shows up if the "developer" cvar is set +void Con_DPrintf(const char *fmt, ...) DP_FUNC_PRINTF(1); +void Con_Clear_f (void); +void Con_DrawNotify (void); + +/// Clear all notify lines. +void Con_ClearNotify (void); +void Con_ToggleConsole_f (void); + +int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos); + +qboolean GetMapList (const char *s, char *completedname, int completednamebufferlength); + +/// wrapper function to attempt to either complete the command line +/// or to list possible matches grouped by type +/// (i.e. will display possible variables, aliases, commands +/// that match what they've typed so far) +void Con_CompleteCommandLine(void); + +/// Generic libs/util/console.c function to display a list +/// formatted in columns on the console +void Con_DisplayList(const char **list); + + +/*! \name log + * @{ + */ +void Log_Init (void); +void Log_Close (void); +void Log_Start (void); +void Log_DestBuffer_Flush (void); ///< call this once per frame to send out replies to rcon streaming clients + +void Log_Printf(const char *logfilename, const char *fmt, ...) DP_FUNC_PRINTF(2); +//@} + +// CON_MASK_PRINT is the default (Con_Print/Con_Printf) +// CON_MASK_DEVELOPER is used by Con_DPrint/Con_DPrintf +#define CON_MASK_HIDENOTIFY 128 +#define CON_MASK_CHAT 1 +#define CON_MASK_INPUT 2 +#define CON_MASK_DEVELOPER 4 +#define CON_MASK_PRINT 8 + +typedef struct con_lineinfo_s +{ + char *start; + size_t len; + int mask; + + /// used only by console.c + double addtime; + int height; ///< recalculated line height when needed (-1 to unset) +} +con_lineinfo_t; + +typedef struct conbuffer_s +{ + qboolean active; + int textsize; + char *text; + int maxlines; + con_lineinfo_t *lines; + int lines_first; + int lines_count; ///< cyclic buffer +} +conbuffer_t; + +#define CONBUFFER_LINES(buf, i) (buf)->lines[((buf)->lines_first + (i)) % (buf)->maxlines] +#define CONBUFFER_LINES_COUNT(buf) ((buf)->lines_count) +#define CONBUFFER_LINES_LAST(buf) CONBUFFER_LINES(buf, CONBUFFER_LINES_COUNT(buf) - 1) + +void ConBuffer_Init(conbuffer_t *buf, int textsize, int maxlines, mempool_t *mempool); +void ConBuffer_Clear (conbuffer_t *buf); +void ConBuffer_Shutdown(conbuffer_t *buf); + +/*! Notifies the console code about the current time + * (and shifts back times of other entries when the time + * went backwards) + */ +void ConBuffer_FixTimes(conbuffer_t *buf); + +/// Deletes the first line from the console history. +void ConBuffer_DeleteLine(conbuffer_t *buf); + +/// Deletes the last line from the console history. +void ConBuffer_DeleteLastLine(conbuffer_t *buf); + +/// Appends a given string as a new line to the console. +void ConBuffer_AddLine(conbuffer_t *buf, const char *line, int len, int mask); +int ConBuffer_FindPrevLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start); +int ConBuffer_FindNextLine(conbuffer_t *buf, int mask_must, int mask_mustnot, int start); +const char *ConBuffer_GetLine(conbuffer_t *buf, int i); + +#endif + diff --git a/app/jni/crypto.c b/app/jni/crypto.c new file mode 100644 index 0000000..a681379 --- /dev/null +++ b/app/jni/crypto.c @@ -0,0 +1,2588 @@ +// TODO key loading, generating, saving +#include "quakedef.h" +#include "crypto.h" +#include "common.h" +#include "thread.h" + +#include "hmac.h" +#include "libcurl.h" + +cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"}; +cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"}; +cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"}; +cvar_t crypto_servercpudebug = {CVAR_SAVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"}; +static double crypto_servercpu_accumulator = 0; +static double crypto_servercpu_lastrealtime = 0; +cvar_t crypto_aeslevel = {CVAR_SAVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"}; +int crypto_keyfp_recommended_length; +static const char *crypto_idstring = NULL; +static char crypto_idstring_buf[512]; + +#define PROTOCOL_D0_BLIND_ID FOURCC_D0PK +#define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24)) + +// BEGIN stuff shared with crypto-keygen-standalone +#define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24)) +#define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24)) +#define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24)) +#define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24)) +#define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24)) +#define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24)) +#define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24)) +#define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24)) + +static unsigned long Crypto_LittleLong(const char *data) +{ + return + ((unsigned char) data[0]) | + (((unsigned char) data[1]) << 8) | + (((unsigned char) data[2]) << 16) | + (((unsigned char) data[3]) << 24); +} + +static void Crypto_UnLittleLong(char *data, unsigned long l) +{ + data[0] = l & 0xFF; + data[1] = (l >> 8) & 0xFF; + data[2] = (l >> 16) & 0xFF; + data[3] = (l >> 24) & 0xFF; +} + +static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps) +{ + size_t i; + size_t pos; + pos = 0; + if(header) + { + if(len < 4) + return 0; + if(Crypto_LittleLong(buf) != header) + return 0; + pos += 4; + } + for(i = 0; i < nlumps; ++i) + { + if(pos + 4 > len) + return 0; + lumpsize[i] = Crypto_LittleLong(&buf[pos]); + pos += 4; + if(pos + lumpsize[i] > len) + return 0; + lumps[i] = &buf[pos]; + pos += lumpsize[i]; + } + return pos; +} + +static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps) +{ + size_t i; + size_t pos; + pos = 0; + if(header) + { + if(len < 4) + return 0; + Crypto_UnLittleLong(buf, header); + pos += 4; + } + for(i = 0; i < nlumps; ++i) + { + if(pos + 4 + lumpsize[i] > len) + return 0; + Crypto_UnLittleLong(&buf[pos], lumpsize[i]); + pos += 4; + memcpy(&buf[pos], lumps[i], lumpsize[i]); + pos += lumpsize[i]; + } + return pos; +} +// END stuff shared with xonotic-keygen + +#define USE_AES + +#ifdef CRYPTO_STATIC + +#include + +#define d0_blind_id_dll 1 +#define Crypto_OpenLibrary() true +#define Crypto_CloseLibrary() + +#define qd0_blind_id_new d0_blind_id_new +#define qd0_blind_id_free d0_blind_id_free +//#define qd0_blind_id_clear d0_blind_id_clear +#define qd0_blind_id_copy d0_blind_id_copy +//#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key +//#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject +//#define qd0_blind_id_read_private_key d0_blind_id_read_private_key +#define qd0_blind_id_read_public_key d0_blind_id_read_public_key +//#define qd0_blind_id_write_private_key d0_blind_id_write_private_key +//#define qd0_blind_id_write_public_key d0_blind_id_write_public_key +#define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key +//#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus +#define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus +//#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus +#define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start +#define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request +//#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request +#define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request +//#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage +//#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage +#define qd0_blind_id_read_private_id d0_blind_id_read_private_id +//#define qd0_blind_id_read_public_id d0_blind_id_read_public_id +#define qd0_blind_id_write_private_id d0_blind_id_write_private_id +//#define qd0_blind_id_write_public_id d0_blind_id_write_public_id +#define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start +#define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge +#define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response +#define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify +#define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id +#define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id +#define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE +#define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN +#define qd0_blind_id_util_sha256 d0_blind_id_util_sha256 +#define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign +#define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached +#define qd0_blind_id_setmallocfuncs d0_blind_id_setmallocfuncs +#define qd0_blind_id_setmutexfuncs d0_blind_id_setmutexfuncs +#define qd0_blind_id_verify_public_id d0_blind_id_verify_public_id +#define qd0_blind_id_verify_private_id d0_blind_id_verify_private_id + +#else + +// d0_blind_id interface +#define D0_EXPORT +#ifdef __GNUC__ +#define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define D0_WARN_UNUSED_RESULT +#endif +#define D0_BOOL int + +typedef void *(d0_malloc_t)(size_t len); +typedef void (d0_free_t)(void *p); +typedef void *(d0_createmutex_t)(void); +typedef void (d0_destroymutex_t)(void *); +typedef int (d0_lockmutex_t)(void *); // zero on success +typedef int (d0_unlockmutex_t)(void *); // zero on success + +typedef struct d0_blind_id_s d0_blind_id_t; +typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass); +static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void); +static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a); +//static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key_fastreject) (d0_blind_id_t *ctx, int k, d0_fastreject_function reject, void *pass); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_modulus) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_modulus) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_request) (d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_answer_private_id_request) (const d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_finish_private_id_request) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_request_camouflage) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_request_camouflage) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +//static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_start) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_challenge) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, D0_BOOL *status); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_response) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_verify) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sessionkey_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); // can only be done after successful key exchange, this performs a modpow; key length is limited by SHA_DIGESTSIZE for now; also ONLY valid after successful d0_blind_id_authenticate_with_private_id_verify/d0_blind_id_fingerprint64_public_id +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void); +static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void); +static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign_detached) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen); +static D0_EXPORT void (*qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f); +static D0_EXPORT void (*qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_public_id)(const d0_blind_id_t *ctx, D0_BOOL *status); +static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_private_id)(const d0_blind_id_t *ctx); +static dllfunction_t d0_blind_id_funcs[] = +{ + {"d0_blind_id_new", (void **) &qd0_blind_id_new}, + {"d0_blind_id_free", (void **) &qd0_blind_id_free}, + //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear}, + {"d0_blind_id_copy", (void **) &qd0_blind_id_copy}, + //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key}, + //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject}, + //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key}, + {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key}, + //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key}, + //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key}, + {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key}, + //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus}, + {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus}, + //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus}, + {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start}, + {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request}, + //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request}, + {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request}, + //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage}, + //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage}, + {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id}, + //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id}, + {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id}, + //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id}, + {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start}, + {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge}, + {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response}, + {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify}, + {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id}, + {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id}, + {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE}, + {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN}, + {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256}, + {"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign}, + {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached}, + {"d0_blind_id_setmallocfuncs", (void **) &qd0_blind_id_setmallocfuncs}, + {"d0_blind_id_setmutexfuncs", (void **) &qd0_blind_id_setmutexfuncs}, + {"d0_blind_id_verify_public_id", (void **) &qd0_blind_id_verify_public_id}, + {"d0_blind_id_verify_private_id", (void **) &qd0_blind_id_verify_private_id}, + {NULL, NULL} +}; +// end of d0_blind_id interface + +static dllhandle_t d0_blind_id_dll = NULL; +static qboolean Crypto_OpenLibrary (void) +{ + const char* dllnames [] = + { +#if defined(WIN32) + "libd0_blind_id-0.dll", +#elif defined(MACOSX) + "libd0_blind_id.0.dylib", +#else + "libd0_blind_id.so.0", + "libd0_blind_id.so", // FreeBSD +#endif + NULL + }; + + // Already loaded? + if (d0_blind_id_dll) + return true; + + // Load the DLL + return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs); +} + +static void Crypto_CloseLibrary (void) +{ + Sys_UnloadLibrary (&d0_blind_id_dll); +} + +#endif + +#ifdef CRYPTO_RIJNDAEL_STATIC + +#include + +#define d0_rijndael_dll 1 +#define Crypto_Rijndael_OpenLibrary() true +#define Crypto_Rijndael_CloseLibrary() + +#define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt +#define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt +#define qd0_rijndael_encrypt d0_rijndael_encrypt +#define qd0_rijndael_decrypt d0_rijndael_decrypt + +#else + +// no need to do the #define dance here, as the upper part declares out macros either way + +D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key, + int keybits); +D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key, + int keybits); +D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds, + const unsigned char plaintext[16], unsigned char ciphertext[16]); +D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds, + const unsigned char ciphertext[16], unsigned char plaintext[16]); +#define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8) +#define D0_RIJNDAEL_RKLENGTH(keybits) ((keybits)/8+28) +#define D0_RIJNDAEL_NROUNDS(keybits) ((keybits)/32+6) +static dllfunction_t d0_rijndael_funcs[] = +{ + {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt}, + {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt}, + {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt}, + {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt}, + {NULL, NULL} +}; +// end of d0_blind_id interface + +static dllhandle_t d0_rijndael_dll = NULL; +static qboolean Crypto_Rijndael_OpenLibrary (void) +{ + const char* dllnames [] = + { +#if defined(WIN32) + "libd0_rijndael-0.dll", +#elif defined(MACOSX) + "libd0_rijndael.0.dylib", +#else + "libd0_rijndael.so.0", + "libd0_rijndael.so", // FreeBSD +#endif + NULL + }; + + // Already loaded? + if (d0_rijndael_dll) + return true; + + // Load the DLL + return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs); +} + +static void Crypto_Rijndael_CloseLibrary (void) +{ + Sys_UnloadLibrary (&d0_rijndael_dll); +} + +#endif + +// various helpers +void sha256(unsigned char *out, const unsigned char *in, int n) +{ + qd0_blind_id_util_sha256((char *) out, (const char *) in, n); +} + +static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir) +{ + char vabuf[1024]; + qfile_t *f = NULL; + fs_offset_t n; + if(inuserdir) + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false); + else + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false); + if(!f) + return 0; + n = FS_Read(f, buf, nmax); + if(n < 0) + n = 0; + FS_Close(f); + return (size_t) n; +} + +static qboolean PutWithNul(char **data, size_t *len, const char *str) +{ + // invariant: data points to insertion point + size_t l = strlen(str); + if(l >= *len) + return false; + memcpy(*data, str, l+1); + *data += l+1; + *len -= l+1; + return true; +} + +static const char *GetUntilNul(const char **data, size_t *len) +{ + // invariant: data points to next character to take + const char *data_save = *data; + size_t n; + const char *p; + + if(!*data) + return NULL; + + if(!*len) + { + *data = NULL; + return NULL; + } + + p = (const char *) memchr(*data, 0, *len); + if(!p) // no terminating NUL + { + *data = NULL; + *len = 0; + return NULL; + } + else + { + n = (p - *data) + 1; + *len -= n; + *data += n; + if(*len == 0) + *data = NULL; + return (const char *) data_save; + } + *data = NULL; + return NULL; +} + +// d0pk reading +static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len) +{ + d0_blind_id_t *pk = NULL; + const char *p[2]; + size_t l[2]; + if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2)) + { + pk = qd0_blind_id_new(); + if(pk) + if(qd0_blind_id_read_public_key(pk, p[0], l[0])) + if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1])) + return pk; + } + if(pk) + qd0_blind_id_free(pk); + return NULL; +} + +// d0si reading +static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len) +{ + const char *p[1]; + size_t l[1]; + if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1)) + { + if(qd0_blind_id_read_private_id(pk, p[0], l[0])) + return true; + } + return false; +} + +#define MAX_PUBKEYS 16 +static d0_blind_id_t *pubkeys[MAX_PUBKEYS]; +static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1]; +static qboolean pubkeys_havepriv[MAX_PUBKEYS]; +static qboolean pubkeys_havesig[MAX_PUBKEYS]; +static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1]; +static char challenge_append[1400]; +static size_t challenge_append_length; + +static int keygen_i = -1; +static char keygen_buf[8192]; + +#define MAX_CRYPTOCONNECTS 16 +#define CRYPTOCONNECT_NONE 0 +#define CRYPTOCONNECT_PRECONNECT 1 +#define CRYPTOCONNECT_CONNECT 2 +#define CRYPTOCONNECT_RECONNECT 3 +#define CRYPTOCONNECT_DUPLICATE 4 +typedef struct server_cryptoconnect_s +{ + double lasttime; + lhnetaddress_t address; + crypto_t crypto; + int next_step; +} +server_cryptoconnect_t; +static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS]; + +static int cdata_id = 0; +typedef struct +{ + d0_blind_id_t *id; + int s, c; + int next_step; + char challenge[2048]; + char wantserver_idfp[FP64_SIZE+1]; + qboolean wantserver_aes; + int cdata_id; +} +crypto_data_t; + +// crypto specific helpers +#define CDATA ((crypto_data_t *) crypto->data) +#define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t)) +#define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL + +static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create) +{ + crypto_t *crypto; + int i, best; + + if(!d0_blind_id_dll) + return NULL; // no support + + for(i = 0; i < MAX_CRYPTOCONNECTS; ++i) + if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address)) + break; + if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data)) + { + crypto = &cryptoconnects[i].crypto; + cryptoconnects[i].lasttime = realtime; + return crypto; + } + if(!allow_create) + return NULL; + best = 0; + for(i = 1; i < MAX_CRYPTOCONNECTS; ++i) + if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime) + best = i; + crypto = &cryptoconnects[best].crypto; + cryptoconnects[best].lasttime = realtime; + memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address)); + CLEAR_CDATA; + return crypto; +} + +qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto) +{ + // no check needed here (returned pointers are only used in prefilled fields) + if(!crypto || !crypto->authenticated) + { + Con_Printf("Passed an invalid crypto connect instance\n"); + memset(out, 0, sizeof(*out)); + return false; + } + CLEAR_CDATA; + memcpy(out, crypto, sizeof(*out)); + memset(crypto, 0, sizeof(*crypto)); + return true; +} + +crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress) +{ + // no check needed here (returned pointers are only used in prefilled fields) + return Crypto_ServerFindInstance(peeraddress, false); +} + +typedef struct crypto_storedhostkey_s +{ + struct crypto_storedhostkey_s *next; + lhnetaddress_t addr; + int keyid; + char idfp[FP64_SIZE+1]; + int aeslevel; +} +crypto_storedhostkey_t; +static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE]; + +static void Crypto_InitHostKeys(void) +{ + int i; + for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i) + crypto_storedhostkey_hashtable[i] = NULL; +} + +static void Crypto_ClearHostKeys(void) +{ + int i; + crypto_storedhostkey_t *hk, *hkn; + for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i) + { + for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn) + { + hkn = hk->next; + Z_Free(hk); + } + crypto_storedhostkey_hashtable[i] = NULL; + } +} + +static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress) +{ + char buf[128]; + int hashindex; + crypto_storedhostkey_t **hkp; + qboolean found = false; + + LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1); + hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE; + for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next)); + + if(*hkp) + { + crypto_storedhostkey_t *hk = *hkp; + *hkp = hk->next; + Z_Free(hk); + found = true; + } + + return found; +} + +static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain) +{ + char buf[128]; + int hashindex; + crypto_storedhostkey_t *hk; + int keyid; + char idfp[FP64_SIZE+1]; + int aeslevel; + + if(!d0_blind_id_dll) + return; + + // syntax of keystring: + // aeslevel id@key id@key ... + + if(!*keystring) + return; + aeslevel = bound(0, *keystring - '0', 3); + while(*keystring && *keystring != ' ') + ++keystring; + + keyid = -1; + while(*keystring && keyid < 0) + { + // id@key + const char *idstart, *idend, *keystart, *keyend; + ++keystring; // skip the space + idstart = keystring; + while(*keystring && *keystring != ' ' && *keystring != '@') + ++keystring; + idend = keystring; + if(!*keystring) + break; + ++keystring; + keystart = keystring; + while(*keystring && *keystring != ' ') + ++keystring; + keyend = keystring; + + if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE) + { + for(keyid = 0; keyid < MAX_PUBKEYS; ++keyid) + if(pubkeys[keyid]) + if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE)) + { + memcpy(idfp, idstart, FP64_SIZE); + idfp[FP64_SIZE] = 0; + break; + } + if(keyid >= MAX_PUBKEYS) + keyid = -1; + } + } + + if(keyid < 0) + return; + + LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1); + hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE; + for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next); + + if(hk) + { + if(complain) + { + if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1)) + Con_Printf("Server %s tried to change the host key to a value not in the host cache. Connecting to it will fail. To accept the new host key, do crypto_hostkey_clear %s\n", buf, buf); + if(hk->aeslevel > aeslevel) + Con_Printf("Server %s tried to reduce encryption status, not accepted. Connecting to it will fail. To accept, do crypto_hostkey_clear %s\n", buf, buf); + } + hk->aeslevel = max(aeslevel, hk->aeslevel); + return; + } + + // great, we did NOT have it yet + hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk)); + memcpy(&hk->addr, peeraddress, sizeof(hk->addr)); + hk->keyid = keyid; + memcpy(hk->idfp, idfp, FP64_SIZE+1); + hk->next = crypto_storedhostkey_hashtable[hashindex]; + hk->aeslevel = aeslevel; + crypto_storedhostkey_hashtable[hashindex] = hk; +} + +qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel) +{ + char buf[128]; + int hashindex; + crypto_storedhostkey_t *hk; + + if(!d0_blind_id_dll) + return false; + + LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1); + hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE; + for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next); + + if(!hk) + return false; + + if(keyid) + *keyid = hk->keyid; + if(keyfp) + strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen); + if(idfp) + strlcpy(idfp, hk->idfp, idfplen); + if(aeslevel) + *aeslevel = hk->aeslevel; + + return true; +} +int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qboolean *issigned) // return value: -1 if more to come, +1 if valid, 0 if end of list +{ + if(keyid < 0 || keyid >= MAX_PUBKEYS) + return 0; + if(keyfp) + *keyfp = 0; + if(idfp) + *idfp = 0; + if(!pubkeys[keyid]) + return -1; + if(keyfp) + strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen); + if(idfp) + if(pubkeys_havepriv[keyid]) + strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen); + if(issigned) + *issigned = pubkeys_havesig[keyid]; + return 1; +} +// end + +// init/shutdown code +static void Crypto_BuildChallengeAppend(void) +{ + char *p, *lengthptr, *startptr; + size_t n; + int i; + p = challenge_append; + n = sizeof(challenge_append); + Crypto_UnLittleLong(p, PROTOCOL_VLEN); + p += 4; + n -= 4; + lengthptr = p; + Crypto_UnLittleLong(p, 0); + p += 4; + n -= 4; + Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID); + p += 4; + n -= 4; + startptr = p; + for(i = 0; i < MAX_PUBKEYS; ++i) + if(pubkeys_havepriv[i]) + PutWithNul(&p, &n, pubkeys_fp64[i]); + PutWithNul(&p, &n, ""); + for(i = 0; i < MAX_PUBKEYS; ++i) + if(!pubkeys_havepriv[i] && pubkeys[i]) + PutWithNul(&p, &n, pubkeys_fp64[i]); + Crypto_UnLittleLong(lengthptr, p - startptr); + challenge_append_length = p - challenge_append; +} + +static qboolean Crypto_SavePubKeyTextFile(int i) +{ + qfile_t *f; + char vabuf[1024]; + + if(!pubkeys_havepriv[i]) + return false; + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d-public-fp%s.txt", *fs_userdir ? fs_userdir : fs_basedir, i, sessionid.string), "w", false); + if(!f) + return false; + + // we ignore errors for this file, as it's not necessary to have + FS_Printf(f, "ID-Fingerprint: %s\n", pubkeys_priv_fp64[i]); + FS_Printf(f, "ID-Is-Signed: %s\n", pubkeys_havesig[i] ? "yes" : "no"); + FS_Printf(f, "ID-Is-For-Key: %s\n", pubkeys_fp64[i]); + FS_Printf(f, "\n"); + FS_Printf(f, "This is a PUBLIC ID file for DarkPlaces.\n"); + FS_Printf(f, "You are free to share this file or its contents.\n"); + FS_Printf(f, "\n"); + FS_Printf(f, "This file will be automatically generated again if deleted.\n"); + FS_Printf(f, "\n"); + FS_Printf(f, "However, NEVER share the accompanying SECRET ID file called\n"); + FS_Printf(f, "key_%d.d0si%s, as doing so would compromise security!\n", i, sessionid.string); + FS_Close(f); + + return true; +} + +void Crypto_LoadKeys(void) +{ + char buf[8192]; + size_t len, len2; + int i; + char vabuf[1024]; + + if(!d0_blind_id_dll) // don't if we can't + return; + + if(crypto_idstring) // already loaded? then not + return; + + Host_LockSession(); // we use the session ID here + + // load keys + // note: we are just a CLIENT + // so we load: + // PUBLIC KEYS to accept (including modulus) + // PRIVATE KEY of user + + crypto_idstring = NULL; + dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0); + for(i = 0; i < MAX_PUBKEYS; ++i) + { + memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i])); + memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i])); + pubkeys_havepriv[i] = false; + pubkeys_havesig[i] = false; + len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false); + if((pubkeys[i] = Crypto_ReadPublicKey(buf, len))) + { + len2 = FP64_SIZE; + if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL + { + Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]); + len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true); + if(len) + { + if(Crypto_AddPrivateKey(pubkeys[i], buf, len)) + { + len2 = FP64_SIZE; + if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL + { + D0_BOOL status = 0; + + Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]); + + // verify the key we just loaded (just in case) + if(qd0_blind_id_verify_private_id(pubkeys[i]) && qd0_blind_id_verify_public_id(pubkeys[i], &status)) + { + pubkeys_havepriv[i] = true; + strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf)); + + // verify the key we just got (just in case) + if(status) + pubkeys_havesig[i] = true; + else + Con_Printf("NOTE: this ID has not yet been signed!\n"); + + Crypto_SavePubKeyTextFile(i); + } + else + { + Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n"); + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; + } + } + else + { + Con_Printf("d0_blind_id_fingerprint64_public_id failed\n"); + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; + } + } + } + } + else + { + // can't really happen + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; + } + } + } + crypto_idstring = crypto_idstring_buf; + + keygen_i = -1; + Crypto_BuildChallengeAppend(); + + // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length) + crypto_keyfp_recommended_length = 0; + memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS); + while(crypto_keyfp_recommended_length < FP64_SIZE) + { + memset(buf, 0, 256); + for(i = 0; i < MAX_PUBKEYS; ++i) + if(pubkeys[i]) + { + if(!buf[256 + i]) + ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]]; + if(pubkeys_havepriv[i]) + if(!buf[256 + MAX_PUBKEYS + i]) + ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]]; + } + for(i = 0; i < MAX_PUBKEYS; ++i) + if(pubkeys[i]) + { + if(!buf[256 + i]) + if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2) + buf[256 + i] = 1; + if(pubkeys_havepriv[i]) + if(!buf[256 + MAX_PUBKEYS + i]) + if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2) + buf[256 + MAX_PUBKEYS + i] = 1; + } + ++crypto_keyfp_recommended_length; + for(i = 0; i < MAX_PUBKEYS; ++i) + if(pubkeys[i]) + { + if(!buf[256 + i]) + break; + if(pubkeys_havepriv[i]) + if(!buf[256 + MAX_PUBKEYS + i]) + break; + } + if(i >= MAX_PUBKEYS) + break; + } + if(crypto_keyfp_recommended_length < 7) + crypto_keyfp_recommended_length = 7; +} + +static void Crypto_UnloadKeys(void) +{ + int i; + + keygen_i = -1; + for(i = 0; i < MAX_PUBKEYS; ++i) + { + if(pubkeys[i]) + qd0_blind_id_free(pubkeys[i]); + pubkeys[i] = NULL; + pubkeys_havepriv[i] = false; + pubkeys_havesig[i] = false; + memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i])); + memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i])); + challenge_append_length = 0; + } + crypto_idstring = NULL; +} + +static mempool_t *cryptomempool; + +#ifdef __cplusplus +extern "C" +{ +#endif +static void *Crypto_d0_malloc(size_t len) +{ + return Mem_Alloc(cryptomempool, len); +} + +static void Crypto_d0_free(void *p) +{ + Mem_Free(p); +} + +static void *Crypto_d0_createmutex(void) +{ + return Thread_CreateMutex(); +} + +static void Crypto_d0_destroymutex(void *m) +{ + Thread_DestroyMutex(m); +} + +static int Crypto_d0_lockmutex(void *m) +{ + return Thread_LockMutex(m); +} + +static int Crypto_d0_unlockmutex(void *m) +{ + return Thread_UnlockMutex(m); +} +#ifdef __cplusplus +} +#endif + +void Crypto_Shutdown(void) +{ + crypto_t *crypto; + int i; + + Crypto_Rijndael_CloseLibrary(); + + if(d0_blind_id_dll) + { + // free memory + for(i = 0; i < MAX_CRYPTOCONNECTS; ++i) + { + crypto = &cryptoconnects[i].crypto; + CLEAR_CDATA; + } + memset(cryptoconnects, 0, sizeof(cryptoconnects)); + crypto = &cls.crypto; + CLEAR_CDATA; + + Crypto_UnloadKeys(); + + qd0_blind_id_SHUTDOWN(); + + Crypto_CloseLibrary(); + } + + Mem_FreePool(&cryptomempool); +} + +void Crypto_Init(void) +{ + cryptomempool = Mem_AllocPool("crypto", 0, NULL); + + if(!Crypto_OpenLibrary()) + return; + + qd0_blind_id_setmallocfuncs(Crypto_d0_malloc, Crypto_d0_free); + if (Thread_HasThreads()) + qd0_blind_id_setmutexfuncs(Crypto_d0_createmutex, Crypto_d0_destroymutex, Crypto_d0_lockmutex, Crypto_d0_unlockmutex); + + if(!qd0_blind_id_INITIALIZE()) + { + Crypto_Rijndael_CloseLibrary(); + Crypto_CloseLibrary(); + Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n"); + return; + } + + (void) Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical + + Crypto_InitHostKeys(); +} +// end + +qboolean Crypto_Available(void) +{ + if(!d0_blind_id_dll) + return false; + return true; +} + +// keygen code +static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata) +{ + const char *p[1]; + size_t l[1]; + static char buf[8192]; + static char buf2[8192]; + size_t buf2size; + qfile_t *f = NULL; + D0_BOOL status; + char vabuf[1024]; + + SV_LockThreadMutex(); + + if(!d0_blind_id_dll) + { + Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i]) + { + Con_Printf("overflow of keygen_i\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(keygen_i < 0) + { + Con_Printf("Unexpected response from keygen server:\n"); + Com_HexDumpToConsole(buffer, length_received); + SV_UnlockThreadMutex(); + return; + } + if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1)) + { + if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER) + { + Con_Printf("Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5); + } + else + { + Con_Printf("Invalid response from keygen server:\n"); + Com_HexDumpToConsole(buffer, length_received); + } + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0])) + { + Con_Printf("d0_blind_id_finish_private_id_request failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + // verify the key we just got (just in case) + if(!qd0_blind_id_verify_public_id(pubkeys[keygen_i], &status) || !status) + { + Con_Printf("d0_blind_id_verify_public_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + // we have a valid key now! + // make the rest of crypto.c know that + Con_Printf("Received signature for private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]); + pubkeys_havesig[keygen_i] = true; + + // write the key to disk + p[0] = buf; + l[0] = sizeof(buf); + if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0])) + { + Con_Printf("d0_blind_id_write_private_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1))) + { + Con_Printf("Crypto_UnParsePack failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string)); + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false); + if(!f) + { + Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + FS_Write(f, buf2, buf2size); + FS_Close(f); + + Crypto_SavePubKeyTextFile(keygen_i); + + Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string); + + keygen_i = -1; + SV_UnlockThreadMutex(); +} + +static void Crypto_KeyGen_f(void) +{ + int i; + const char *p[1]; + size_t l[1]; + static char buf[8192]; + static char buf2[8192]; + size_t buf2size; + size_t buf2l, buf2pos; + char vabuf[1024]; + size_t len2; + qfile_t *f = NULL; + + if(!d0_blind_id_dll) + { + Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); + return; + } + if(Cmd_Argc() != 3) + { + Con_Printf("usage:\n%s id url\n", Cmd_Argv(0)); + return; + } + SV_LockThreadMutex(); + Crypto_LoadKeys(); + i = atoi(Cmd_Argv(1)); + if(!pubkeys[i]) + { + Con_Printf("there is no public key %d\n", i); + SV_UnlockThreadMutex(); + return; + } + if(keygen_i >= 0) + { + Con_Printf("there is already a keygen run on the way\n"); + SV_UnlockThreadMutex(); + return; + } + keygen_i = i; + + // how to START the keygenning... + if(pubkeys_havepriv[keygen_i]) + { + if(pubkeys_havesig[keygen_i]) + { + Con_Printf("there is already a signed private key for %d\n", i); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // if we get here, we only need a signature, no new keygen run needed + Con_Printf("Only need a signature for an existing key...\n"); + } + else + { + // we also need a new ID itself + if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i])) + { + Con_Printf("d0_blind_id_start failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // verify the key we just got (just in case) + if(!qd0_blind_id_verify_private_id(pubkeys[keygen_i])) + { + Con_Printf("d0_blind_id_verify_private_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + // we have a valid key now! + // make the rest of crypto.c know that + len2 = FP64_SIZE; + if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL + { + Con_Printf("Generated private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]); + pubkeys_havepriv[keygen_i] = true; + strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf)); + crypto_idstring = crypto_idstring_buf; + Crypto_BuildChallengeAppend(); + } + // write the key to disk + p[0] = buf; + l[0] = sizeof(buf); + if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0])) + { + Con_Printf("d0_blind_id_write_private_id failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1))) + { + Con_Printf("Crypto_UnParsePack failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + + FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string)); + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false); + if(!f) + { + Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + FS_Write(f, buf2, buf2size); + FS_Close(f); + + Crypto_SavePubKeyTextFile(keygen_i); + + Con_Printf("Saved unsigned key to key_%d.d0si%s\n", keygen_i, sessionid.string); + } + p[0] = buf; + l[0] = sizeof(buf); + if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0])) + { + Con_Printf("d0_blind_id_generate_private_id_request failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + buf2pos = strlen(Cmd_Argv(2)); + memcpy(buf2, Cmd_Argv(2), buf2pos); + if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1))) + { + Con_Printf("Crypto_UnParsePack failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1))) + { + Con_Printf("base64_encode failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + buf2l += buf2pos; + buf2[buf2l] = 0; + if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL)) + { + Con_Printf("curl failed\n"); + keygen_i = -1; + SV_UnlockThreadMutex(); + return; + } + Con_Printf("Signature generation in progress...\n"); + SV_UnlockThreadMutex(); +} +// end + +// console commands +static void Crypto_Reload_f(void) +{ + Crypto_ClearHostKeys(); + Crypto_UnloadKeys(); + Crypto_LoadKeys(); +} + +static void Crypto_Keys_f(void) +{ + int i; + if(!d0_blind_id_dll) + { + Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); + return; + } + for(i = 0; i < MAX_PUBKEYS; ++i) + { + if(pubkeys[i]) + { + Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]); + if(pubkeys_havepriv[i]) + { + Con_Printf(" private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]); + if(!pubkeys_havesig[i]) + Con_Printf(" NOTE: this ID has not yet been signed!\n"); + } + } + } +} + +static void Crypto_HostKeys_f(void) +{ + int i; + crypto_storedhostkey_t *hk; + char buf[128]; + + if(!d0_blind_id_dll) + { + Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); + return; + } + for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i) + { + for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next) + { + LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1); + Con_Printf("%d %s@%.*s %s\n", + hk->aeslevel, + hk->idfp, + crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid], + buf); + } + } +} + +static void Crypto_HostKey_Clear_f(void) +{ + lhnetaddress_t addr; + int i; + + if(!d0_blind_id_dll) + { + Con_Print("libd0_blind_id DLL not found, this command is inactive.\n"); + return; + } + + for(i = 1; i < Cmd_Argc(); ++i) + { + LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000); + if(Crypto_ClearHostKey(&addr)) + { + Con_Printf("cleared host key for %s\n", Cmd_Argv(i)); + } + } +} + +void Crypto_Init_Commands(void) +{ + if(d0_blind_id_dll) + { + Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys"); + Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key"); + Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys"); + Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys"); + Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key"); + Cvar_RegisterVariable(&crypto_developer); + if(d0_rijndael_dll) + Cvar_RegisterVariable(&crypto_aeslevel); + else + crypto_aeslevel.integer = 0; // make sure + Cvar_RegisterVariable(&crypto_servercpupercent); + Cvar_RegisterVariable(&crypto_servercpumaxtime); + Cvar_RegisterVariable(&crypto_servercpudebug); + } +} +// end + +// AES encryption +static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len) +{ + const unsigned char *xorpos = iv; + unsigned char xorbuf[16]; + unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)]; + size_t i; + qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8); + while(len > 16) + { + for(i = 0; i < 16; ++i) + xorbuf[i] = src[i] ^ xorpos[i]; + qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst); + xorpos = dst; + len -= 16; + src += 16; + dst += 16; + } + if(len > 0) + { + for(i = 0; i < len; ++i) + xorbuf[i] = src[i] ^ xorpos[i]; + for(; i < 16; ++i) + xorbuf[i] = xorpos[i]; + qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst); + } +} +static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len) +{ + const unsigned char *xorpos = iv; + unsigned char xorbuf[16]; + unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)]; + size_t i; + qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8); + while(len > 16) + { + qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf); + for(i = 0; i < 16; ++i) + dst[i] = xorbuf[i] ^ xorpos[i]; + xorpos = src; + len -= 16; + src += 16; + dst += 16; + } + if(len > 0) + { + qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf); + for(i = 0; i < len; ++i) + dst[i] = xorbuf[i] ^ xorpos[i]; + } +} + +// NOTE: we MUST avoid the following begins of the packet: +// 1. 0xFF, 0xFF, 0xFF, 0xFF +// 2. 0x80, 0x00, length/256, length%256 +// this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F +const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len) +{ + unsigned char h[32]; + int i; + if(crypto->authenticated) + { + if(crypto->use_aes) + { + // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding + // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet + // HMAC is needed to not leak information about packet content + if(developer_networking.integer) + { + Con_Print("To be encrypted:\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + } + if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE)) + { + Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len); + return NULL; + } + *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES + ((unsigned char *) data_dst)[0] = *len_dst - len_src; + memcpy(((unsigned char *) data_dst)+1, h, 15); + aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src); + // IV dst src len + } + else + { + // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data + if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE)) + { + Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len); + return NULL; + } + *len_dst = len_src + 16; + memcpy(data_dst, h, 16); + memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src); + + // handle the "avoid" conditions: + i = BuffBigLong((unsigned char *) data_dst); + if( + (i == (int)0xFFFFFFFF) // avoid QW control packet + || + (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet + ) + *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it + } + return data_dst; + } + else + { + *len_dst = len_src; + return data_src; + } +} + +const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len) +{ + unsigned char h[32]; + int i; + + // silently handle non-crypto packets + i = BuffBigLong((unsigned char *) data_src); + if( + (i == (int)0xFFFFFFFF) // avoid QW control packet + || + (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet + ) + return NULL; + + if(crypto->authenticated) + { + if(crypto->use_aes) + { + if(len_src < 16 || ((len_src - 16) % 16)) + { + Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len); + return NULL; + } + *len_dst = len_src - ((unsigned char *) data_src)[0]; + if(len < *len_dst || *len_dst > len_src - 16) + { + Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len); + return NULL; + } + seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst); + // IV dst src len + if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, *len_dst, crypto->dhkey, DHKEY_SIZE)) + { + Con_Printf("HMAC fail\n"); + return NULL; + } + if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length + { + Con_Printf("HMAC mismatch\n"); + return NULL; + } + if(developer_networking.integer) + { + Con_Print("Decrypted:\n"); + Com_HexDumpToConsole((const unsigned char *) data_dst, *len_dst); + } + return data_dst; // no need to copy + } + else + { + if(len_src < 16) + { + Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len); + return NULL; + } + *len_dst = len_src - 16; + if(len < *len_dst) + { + Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len); + return NULL; + } + //memcpy(data_dst, data_src + 16, *len_dst); + if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, *len_dst, crypto->dhkey, DHKEY_SIZE)) + { + Con_Printf("HMAC fail\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + return NULL; + } + + if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length + { + // undo the "avoid conditions" + if( + (i == (int)0x7FFFFFFF) // avoided QW control packet + || + (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet + ) + { + // do the avoidance on the hash too + h[0] ^= 0x80; + if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length + { + Con_Printf("HMAC mismatch\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + return NULL; + } + } + else + { + Con_Printf("HMAC mismatch\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + return NULL; + } + } + return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used + } + } + else + { + *len_dst = len_src; + return data_src; + } +} +// end + +const char *Crypto_GetInfoResponseDataString(void) +{ + crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer; + return crypto_idstring; +} + +// network protocol +qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out) +{ + // cheap op, all is precomputed + if(!d0_blind_id_dll) + return false; // no support + // append challenge + if(maxlen_out <= *len_out + challenge_append_length) + return false; + memcpy(data_out + *len_out, challenge_append, challenge_append_length); + *len_out += challenge_append_length; + return false; +} + +static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client) +{ + if(!msg_client) + msg_client = msg; + Con_DPrintf("rejecting client: %s\n", msg); + if(*msg_client) + dpsnprintf(data_out, *len_out, "reject %s", msg_client); + *len_out = strlen(data_out); + return CRYPTO_DISCARD; +} + +static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg) +{ + *len_out = 0; + Con_DPrintf("%s\n", msg); + return CRYPTO_DISCARD; +} + +static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress) +{ + // if "connect": reject if in the middle of crypto handshake + crypto_t *crypto = NULL; + char *data_out_p = data_out; + const char *string = data_in; + int aeslevel; + D0_BOOL aes; + D0_BOOL status; + char infostringvalue[MAX_INPUTLINE]; + char vabuf[1024]; + + if(!d0_blind_id_dll) + return CRYPTO_NOMATCH; // no support + + if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3) + { + const char *s; + int i; + // sorry, we have to verify the challenge here to not reflect network spam + + if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue)))) + return CRYPTO_NOMATCH; // will be later accepted if encryption was set up + // validate the challenge + for (i = 0;i < MAX_CHALLENGES;i++) + if(challenge[i].time > 0) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s)) + break; + // if the challenge is not recognized, drop the packet + if (i == MAX_CHALLENGES) // challenge mismatch is silent + return CRYPTO_DISCARD; // pre-challenge: rather be silent + + crypto = Crypto_ServerFindInstance(peeraddress, false); + if(!crypto || !crypto->authenticated) + return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL); + } + else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3)) + { + const char *cnt, *s, *p; + int id; + int clientid = -1, serverid = -1; + cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue)); + id = (cnt ? atoi(cnt) : -1); + cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue)); + if(!cnt) + return CRYPTO_DISCARD; // pre-challenge: rather be silent + GetUntilNul(&data_in, &len_in); + if(!data_in) + return CRYPTO_DISCARD; // pre-challenge: rather be silent + if(!strcmp(cnt, "0")) + { + int i; + if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue)))) + return CRYPTO_DISCARD; // pre-challenge: rather be silent + // validate the challenge + for (i = 0;i < MAX_CHALLENGES;i++) + if(challenge[i].time > 0) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s)) + break; + // if the challenge is not recognized, drop the packet + if (i == MAX_CHALLENGES) // challenge mismatch is silent + return CRYPTO_DISCARD; // pre-challenge: rather be silent + + if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue)))) + aeslevel = 0; // not supported + else + aeslevel = bound(0, atoi(s), 3); + switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3)) + { + default: // dummy, never happens, but to make gcc happy... + case 0: + if(aeslevel >= 3) + return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL); + aes = false; + break; + case 1: + aes = (aeslevel >= 2); + break; + case 2: + aes = (aeslevel >= 1); + break; + case 3: + if(aeslevel <= 0) + return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL); + aes = true; + break; + } + + p = GetUntilNul(&data_in, &len_in); + if(p && *p) + { + for(i = 0; i < MAX_PUBKEYS; ++i) + { + if(pubkeys[i]) + if(!strcmp(p, pubkeys_fp64[i])) + if(pubkeys_havepriv[i]) + if(serverid < 0) + serverid = i; + } + if(serverid < 0) + return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL); + } + p = GetUntilNul(&data_in, &len_in); + if(p && *p) + { + for(i = 0; i < MAX_PUBKEYS; ++i) + { + if(pubkeys[i]) + if(!strcmp(p, pubkeys_fp64[i])) + if(clientid < 0) + clientid = i; + } + if(clientid < 0) + return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL); + } + + crypto = Crypto_ServerFindInstance(peeraddress, true); + if(!crypto) + return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL); + MAKE_CDATA; + CDATA->cdata_id = id; + CDATA->s = serverid; + CDATA->c = clientid; + memset(crypto->dhkey, 0, sizeof(crypto->dhkey)); + CDATA->challenge[0] = 0; + crypto->client_keyfp[0] = 0; + crypto->client_idfp[0] = 0; + crypto->server_keyfp[0] = 0; + crypto->server_idfp[0] = 0; + crypto->use_aes = aes != 0; + + if(CDATA->s >= 0) + { + // I am the server, and my key is ok... so let's set server_keyfp and server_idfp + strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp)); + strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp)); + + if(!CDATA->id) + CDATA->id = qd0_blind_id_new(); + if(!CDATA->id) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error"); + } + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s])) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error"); + } + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes)); + if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error"); + } + CDATA->next_step = 2; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else if(CDATA->c >= 0) + { + if(!CDATA->id) + CDATA->id = qd0_blind_id_new(); + if(!CDATA->id) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error"); + } + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c])) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error"); + } + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes)); + if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error"); + } + CDATA->next_step = 6; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL); + } + } + else if(!strcmp(cnt, "2")) + { + size_t fpbuflen; + crypto = Crypto_ServerFindInstance(peeraddress, false); + if(!crypto) + return CRYPTO_NOMATCH; // pre-challenge, rather be silent + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 2) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id)); + if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error"); + } + fpbuflen = DHKEY_SIZE; + if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error"); + } + if(CDATA->c >= 0) + { + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c])) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error"); + } + CDATA->next_step = 4; + } + else + { + // session key is FINISHED (no server part is to be expected)! By this, all keys are set up + crypto->authenticated = true; + CDATA->next_step = 0; + } + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else if(!strcmp(cnt, "4")) + { + crypto = Crypto_ServerFindInstance(peeraddress, false); + if(!crypto) + return CRYPTO_NOMATCH; // pre-challenge, rather be silent + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 4) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id)); + if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error"); + } + CDATA->next_step = 6; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else if(!strcmp(cnt, "6")) + { + static char msgbuf[32]; + size_t msgbuflen = sizeof(msgbuf); + size_t fpbuflen; + int i; + unsigned char dhkey[DHKEY_SIZE]; + crypto = Crypto_ServerFindInstance(peeraddress, false); + if(!crypto) + return CRYPTO_NOMATCH; // pre-challenge, rather be silent + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 6) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + + if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error"); + } + if(status) + strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp)); + else + crypto->client_keyfp[0] = 0; + memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp)); + fpbuflen = FP64_SIZE; + if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error"); + } + fpbuflen = DHKEY_SIZE; + if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error"); + } + // XOR the two DH keys together to make one + for(i = 0; i < DHKEY_SIZE; ++i) + crypto->dhkey[i] ^= dhkey[i]; + + // session key is FINISHED (no server part is to be expected)! By this, all keys are set up + crypto->authenticated = true; + CDATA->next_step = 0; + // send a challenge-less challenge + PutWithNul(&data_out_p, len_out, "challenge "); + *len_out = data_out_p - data_out; + --*len_out; // remove NUL terminator + return CRYPTO_MATCH; + } + return CRYPTO_NOMATCH; // pre-challenge, rather be silent + } + return CRYPTO_NOMATCH; +} + +int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress) +{ + int ret; + double t = 0; + static double complain_time = 0; + const char *cnt; + qboolean do_time = false; + qboolean do_reject = false; + char infostringvalue[MAX_INPUTLINE]; + if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0) + if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5)) + { + do_time = true; + cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue)); + if(cnt) + if(!strcmp(cnt, "0")) + do_reject = true; + } + if(do_time) + { + // check if we may perform crypto... + if(crypto_servercpupercent.value > 0) + { + crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01; + if(crypto_servercpumaxtime.value) + if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value) + crypto_servercpu_accumulator = crypto_servercpumaxtime.value; + } + else + { + if(crypto_servercpumaxtime.value > 0) + if(realtime != crypto_servercpu_lastrealtime) + crypto_servercpu_accumulator = crypto_servercpumaxtime.value; + } + crypto_servercpu_lastrealtime = realtime; + if(do_reject && crypto_servercpu_accumulator < 0) + { + if(realtime > complain_time + 5) + Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n"); + *len_out = 0; + return CRYPTO_DISCARD; + } + t = Sys_DirtyTime(); + } + ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress); + if(do_time) + { + t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards + if(crypto_servercpudebug.integer) + Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000); + crypto_servercpu_accumulator -= t; + if(crypto_servercpudebug.integer) + Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000); + } + return ret; +} + +static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg) +{ + dpsnprintf(data_out, *len_out, "reject %s", msg); + *len_out = strlen(data_out); + return CRYPTO_REPLACE; +} + +static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg) +{ + *len_out = 0; + Con_Printf("%s\n", msg); + return CRYPTO_DISCARD; +} + +int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress) +{ + crypto_t *crypto = &cls.crypto; + const char *string = data_in; + const char *s; + D0_BOOL aes; + char *data_out_p = data_out; + D0_BOOL status; + char infostringvalue[MAX_INPUTLINE]; + char vabuf[1024]; + + if(!d0_blind_id_dll) + return CRYPTO_NOMATCH; // no support + + // if "challenge": verify challenge, and discard message, send next crypto protocol message instead + // otherwise, just handle actual protocol messages + + if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll) + { + int wantserverid = -1; + Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); + if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out + { + if(wantserverid >= 0) + return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); + if(crypto_aeslevel.integer >= 3) + return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)"); + } + return CRYPTO_NOMATCH; + } + else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll) + { + int wantserverid = -1; + Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); + //if(!crypto || !crypto->authenticated) + { + if(wantserverid >= 0) + return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); + if(crypto_aeslevel.integer >= 3) + return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)"); + } + return CRYPTO_NOMATCH; + } + else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in)) + { + int wantserverid = -1; + + // these three are harmless + if(string[4] == CCREP_SERVER_INFO) + return CRYPTO_NOMATCH; + if(string[4] == CCREP_PLAYER_INFO) + return CRYPTO_NOMATCH; + if(string[4] == CCREP_RULE_INFO) + return CRYPTO_NOMATCH; + + Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL); + //if(!crypto || !crypto->authenticated) + { + if(wantserverid >= 0) + return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present"); + if(crypto_aeslevel.integer >= 3) + return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)"); + } + return CRYPTO_NOMATCH; + } + else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13)) + { + s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue)); + if(s) + Crypto_StoreHostKey(peeraddress, s, true); + return CRYPTO_NOMATCH; + } + else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15)) + { + char save = 0; + const char *p; + p = strchr(string + 15, '\n'); + if(p) + { + save = *p; + * (char *) p = 0; // cut off the string there + } + s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue)); + if(s) + Crypto_StoreHostKey(peeraddress, s, true); + if(p) + { + * (char *) p = save; + // invoking those nasal demons again (do not run this on the DS9k) + } + return CRYPTO_NOMATCH; + } + else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying) + { + const char *vlen_blind_id_ptr = NULL; + size_t len_blind_id_ptr = 0; + unsigned long k, v; + const char *challenge = data_in + 10; + const char *p; + int i; + int clientid = -1, serverid = -1, wantserverid = -1; + qboolean server_can_auth = true; + char wantserver_idfp[FP64_SIZE+1]; + int wantserver_aeslevel = 0; + + // if we have a stored host key for the server, assume serverid to already be selected! + // (the loop will refuse to overwrite this one then) + wantserver_idfp[0] = 0; + Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel); + // requirement: wantserver_idfp is a full ID if wantserverid set + + // if we leave, we have to consider the connection + // unauthenticated; NOTE: this may be faked by a clever + // attacker to force an unauthenticated connection; so we have + // a safeguard check in place when encryption is required too + // in place, or when authentication is required by the server + crypto->authenticated = false; + + GetUntilNul(&data_in, &len_in); + if(!data_in) + return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") : + (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) : + CRYPTO_NOMATCH; + + // FTEQW extension protocol + while(len_in >= 8) + { + k = Crypto_LittleLong(data_in); + v = Crypto_LittleLong(data_in + 4); + data_in += 8; + len_in -= 8; + switch(k) + { + case PROTOCOL_VLEN: + if(len_in >= 4 + v) + { + k = Crypto_LittleLong(data_in); + data_in += 4; + len_in -= 4; + switch(k) + { + case PROTOCOL_D0_BLIND_ID: + vlen_blind_id_ptr = data_in; + len_blind_id_ptr = v; + break; + } + data_in += v; + len_in -= v; + } + break; + default: + break; + } + } + + if(!vlen_blind_id_ptr) + return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") : + (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) : + CRYPTO_NOMATCH; + + data_in = vlen_blind_id_ptr; + len_in = len_blind_id_ptr; + + // parse fingerprints + // once we found a fingerprint we can auth to (ANY), select it as clientfp + // once we found a fingerprint in the first list that we know, select it as serverfp + + for(;;) + { + p = GetUntilNul(&data_in, &len_in); + if(!p) + break; + if(!*p) + { + if(!server_can_auth) + break; // other protocol message may follow + server_can_auth = false; + if(clientid >= 0) + break; + continue; + } + for(i = 0; i < MAX_PUBKEYS; ++i) + { + if(pubkeys[i]) + if(!strcmp(p, pubkeys_fp64[i])) + { + if(pubkeys_havepriv[i]) + if(clientid < 0) + clientid = i; + if(server_can_auth) + if(serverid < 0) + if(wantserverid < 0 || i == wantserverid) + serverid = i; + } + } + if(clientid >= 0 && serverid >= 0) + break; + } + + // if stored host key is not found: + if(wantserverid >= 0 && serverid < 0) + return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect"); + + if(serverid >= 0 || clientid >= 0) + { + // TODO at this point, fill clientside crypto struct! + MAKE_CDATA; + CDATA->cdata_id = ++cdata_id; + CDATA->s = serverid; + CDATA->c = clientid; + memset(crypto->dhkey, 0, sizeof(crypto->dhkey)); + strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge)); + crypto->client_keyfp[0] = 0; + crypto->client_idfp[0] = 0; + crypto->server_keyfp[0] = 0; + crypto->server_idfp[0] = 0; + memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp)); + + if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting + switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3)) + { + default: // dummy, never happens, but to make gcc happy... + case 0: + if(wantserver_aeslevel >= 3) + return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL); + CDATA->wantserver_aes = false; + break; + case 1: + CDATA->wantserver_aes = (wantserver_aeslevel >= 2); + break; + case 2: + CDATA->wantserver_aes = (wantserver_aeslevel >= 1); + break; + case 3: + if(wantserver_aeslevel <= 0) + return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL); + CDATA->wantserver_aes = true; + break; + } + + // build outgoing message + // append regular stuff + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge)); + PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : ""); + PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : ""); + + if(clientid >= 0) + { + // I am the client, and my key is ok... so let's set client_keyfp and client_idfp + strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp)); + strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp)); + } + + if(serverid >= 0) + { + if(!CDATA->id) + CDATA->id = qd0_blind_id_new(); + if(!CDATA->id) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed"); + } + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s])) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed"); + } + CDATA->next_step = 1; + *len_out = data_out_p - data_out; + } + else if(clientid >= 0) + { + // skip over server auth, perform client auth only + if(!CDATA->id) + CDATA->id = qd0_blind_id_new(); + if(!CDATA->id) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed"); + } + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c])) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed"); + } + if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed"); + } + CDATA->next_step = 5; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + } + else + *len_out = data_out_p - data_out; + + return CRYPTO_DISCARD; + } + else + { + if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting + if(wantserver_aeslevel >= 3) + return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other"); + return (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) : + CRYPTO_NOMATCH; + } + } + else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying) + { + const char *cnt; + int id; + cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue)); + id = (cnt ? atoi(cnt) : -1); + cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue)); + if(!cnt) + return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt"); + GetUntilNul(&data_in, &len_in); + if(!data_in) + return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment"); + + if(!strcmp(cnt, "1")) + { + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 1) + return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + + cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering" + + if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))) + aes = atoi(s); + else + aes = false; + // we CANNOT toggle the AES status any more! + // as the server already decided + if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting + if(!aes && CDATA->wantserver_aes) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption"); + } + if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard"); + } + if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard"); + } + crypto->use_aes = aes != 0; + + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id)); + if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed"); + } + CDATA->next_step = 3; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else if(!strcmp(cnt, "3")) + { + static char msgbuf[32]; + size_t msgbuflen = sizeof(msgbuf); + size_t fpbuflen; + + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 3) + return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + + cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering" + + if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)"); + } + if(status) + strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp)); + else + crypto->server_keyfp[0] = 0; + memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp)); + fpbuflen = FP64_SIZE; + if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed"); + } + if(CDATA->wantserver_idfp[0]) + if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp))) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect"); + } + fpbuflen = DHKEY_SIZE; + if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed"); + } + + // cache the server key + Crypto_StoreHostKey(&cls.connect_address, va(vabuf, sizeof(vabuf), "%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false); + + if(CDATA->c >= 0) + { + // client will auth next + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id)); + if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c])) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed"); + } + if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed"); + } + CDATA->next_step = 5; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + else + { + // session key is FINISHED (no server part is to be expected)! By this, all keys are set up + crypto->authenticated = true; + CDATA->next_step = 0; + // assume we got the empty challenge to finish the protocol + PutWithNul(&data_out_p, len_out, "challenge "); + *len_out = data_out_p - data_out; + --*len_out; // remove NUL terminator + return CRYPTO_REPLACE; + } + } + else if(!strcmp(cnt, "5")) + { + size_t fpbuflen; + unsigned char dhkey[DHKEY_SIZE]; + int i; + + if(id >= 0) + if(CDATA->cdata_id != id) + return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id)); + if(CDATA->next_step != 5) + return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step)); + + cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering" + + if(CDATA->s < 0) // only if server didn't auth + { + if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))) + aes = atoi(s); + else + aes = false; + if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting + if(!aes && CDATA->wantserver_aes) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption"); + } + if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard"); + } + if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard"); + } + crypto->use_aes = aes != 0; + } + + PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id)); + if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed"); + } + fpbuflen = DHKEY_SIZE; + if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen)) + { + CLEAR_CDATA; + return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed"); + } + // XOR the two DH keys together to make one + for(i = 0; i < DHKEY_SIZE; ++i) + crypto->dhkey[i] ^= dhkey[i]; + // session key is FINISHED! By this, all keys are set up + crypto->authenticated = true; + CDATA->next_step = 0; + data_out_p += *len_out; + *len_out = data_out_p - data_out; + return CRYPTO_DISCARD; + } + return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server"); + } + + return CRYPTO_NOMATCH; +} + +size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size) +{ + if(keyid < 0 || keyid >= MAX_PUBKEYS) + return 0; + if(!pubkeys_havepriv[keyid]) + return 0; + if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size)) + return signed_size; + return 0; +} + +size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size) +{ + if(keyid < 0 || keyid >= MAX_PUBKEYS) + return 0; + if(!pubkeys_havepriv[keyid]) + return 0; + if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size)) + return signed_size; + return 0; +} diff --git a/app/jni/crypto.h b/app/jni/crypto.h new file mode 100644 index 0000000..ddc00a9 --- /dev/null +++ b/app/jni/crypto.h @@ -0,0 +1,158 @@ +#ifndef CRYPTO_H +#define CRYPTO_H + +extern cvar_t crypto_developer; +extern cvar_t crypto_aeslevel; +#define ENCRYPTION_REQUIRED (crypto_aeslevel.integer >= 3) + +extern int crypto_keyfp_recommended_length; // applies to LOCAL IDs, and to ALL keys + +#define CRYPTO_HEADERSIZE 31 +// AES case causes 16 to 31 bytes overhead +// SHA256 case causes 16 bytes overhead as we truncate to 128bit + +#include "lhnet.h" + +#define FP64_SIZE 44 +#define DHKEY_SIZE 16 + +typedef struct +{ + unsigned char dhkey[DHKEY_SIZE]; // shared key, not NUL terminated + char client_idfp[FP64_SIZE+1]; + char client_keyfp[FP64_SIZE+1]; // NULL if signature fail + char server_idfp[FP64_SIZE+1]; + char server_keyfp[FP64_SIZE+1]; // NULL if signature fail + qboolean authenticated; + qboolean use_aes; + void *data; +} +crypto_t; + +void Crypto_Init(void); +void Crypto_Init_Commands(void); +void Crypto_LoadKeys(void); // NOTE: when this is called, the SV_LockThreadMutex MUST be active +void Crypto_Shutdown(void); +qboolean Crypto_Available(void); +void sha256(unsigned char *out, const unsigned char *in, int n); // may ONLY be called if Crypto_Available() +const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len); +const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len); +#define CRYPTO_NOMATCH 0 // process as usual (packet was not used) +#define CRYPTO_MATCH 1 // process as usual (packet was used) +#define CRYPTO_DISCARD 2 // discard this packet +#define CRYPTO_REPLACE 3 // make the buffer the current packet +int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress); +int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress); + +// if len_out is nonzero, the packet is to be sent to the client + +qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen); +crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress); +qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *in); // also clears allocated memory +const char *Crypto_GetInfoResponseDataString(void); + +// retrieves a host key for an address (can be exposed to menuqc, or used by the engine to look up stored keys e.g. for server bookmarking) +// pointers may be NULL +qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel); +int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qboolean *issigned); // return value: -1 if more to come, +1 if valid, 0 if end of list + +size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size); +size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size); + +// netconn protocol: +// non-crypto: +// getchallenge > +// < challenge +// connect > +// < accept (or: reject) +// crypto: +// getchallenge > +// < challenge SP NUL vlen d0pk NUL NUL +// +// IF serverfp: +// d0pk\cnt\0\challenge\\aeslevel\ NUL NUL +// > +// check if client would get accepted; if not, do "reject" now +// require non-control packets to be encrypted require non-control packets to be encrypted +// do not send anything yet do not send anything yet +// RESET to serverfp RESET to serverfp +// d0_blind_id_authenticate_with_private_id_start() = 1 +// < d0pk\cnt\1\aes\ NUL *startdata* +// d0_blind_id_authenticate_with_private_id_challenge() = 1 +// d0pk\cnt\2 NUL *challengedata* > +// d0_blind_id_authenticate_with_private_id_response() = 0 +// < d0pk\cnt\3 NUL *responsedata* +// d0_blind_id_authenticate_with_private_id_verify() = 1 +// store server's fingerprint NOW +// d0_blind_id_sessionkey_public_id() = 1 d0_blind_id_sessionkey_public_id() = 1 +// +// IF clientfp AND NOT serverfp: +// RESET to clientfp RESET to clientfp +// d0_blind_id_authenticate_with_private_id_start() = 1 +// d0pk\cnt\0\challenge\\aeslevel\ NUL NUL NUL *startdata* +// > +// check if client would get accepted; if not, do "reject" now +// require non-control packets to be encrypted require non-control packets to be encrypted +// d0_blind_id_authenticate_with_private_id_challenge() = 1 +// < d0pk\cnt\5\aes\ NUL *challengedata* +// +// IF clientfp AND serverfp: +// RESET to clientfp RESET to clientfp +// d0_blind_id_authenticate_with_private_id_start() = 1 +// d0pk\cnt\4 NUL *startdata* > +// d0_blind_id_authenticate_with_private_id_challenge() = 1 +// < d0pk\cnt\5 NUL *challengedata* +// +// IF clientfp: +// d0_blind_id_authenticate_with_private_id_response() = 0 +// d0pk\cnt\6 NUL *responsedata* > +// d0_blind_id_authenticate_with_private_id_verify() = 1 +// store client's fingerprint NOW +// d0_blind_id_sessionkey_public_id() = 1 d0_blind_id_sessionkey_public_id() = 1 +// note: the ... is the "connect" message, except without the challenge. Reinterpret as regular connect message on server side +// +// enforce encrypted transmission (key is XOR of the two DH keys) +// +// IF clientfp: +// < challenge (mere sync message) +// +// connect\... > +// < accept (ALWAYS accept if connection is encrypted, ignore challenge as it had been checked before) +// +// commence with ingame protocol + +// in short: +// server: +// getchallenge NUL d0_blind_id: reply with challenge with added fingerprints +// cnt=0: IF server will auth, cnt=1, ELSE cnt=5 +// cnt=2: cnt=3 +// cnt=4: cnt=5 +// cnt=6: send "challenge" +// client: +// challenge with added fingerprints: cnt=0; if client will auth but not server, append client auth start +// cnt=1: cnt=2 +// cnt=3: IF client will auth, cnt=4, ELSE rewrite as "challenge" +// cnt=5: cnt=6, server will continue by sending "challenge" (let's avoid sending two packets as response to one) +// other change: +// accept empty "challenge", and challenge-less connect in case crypto protocol has executed and finished +// statusResponse and infoResponse get an added d0_blind_id key that lists +// the keys the server can auth with and to in key@ca SPACE key@ca notation +// any d0pk\ message has an appended "id" parameter; messages with an unexpected "id" are ignored to prevent errors from multiple concurrent auth runs + + +// comparison to OTR: +// - encryption: yes +// - authentication: yes +// - deniability: no (attacker requires the temporary session key to prove you +// have sent a specific message, the private key itself does not suffice), no +// measures are taken to provide forgeability to even provide deniability +// against an attacker who knows the temporary session key, as using CTR mode +// for the encryption - which, together with deriving the MAC key from the +// encryption key, and MACing the ciphertexts instead of the plaintexts, +// would provide forgeability and thus deniability - requires longer +// encrypted packets and deniability was not a goal of this, as we may e.g. +// reserve the right to capture packet dumps + extra state info to prove a +// client/server has sent specific packets to prove cheating) +// - perfect forward secrecy: yes (session key is derived via DH key exchange) + +#endif diff --git a/app/jni/csprogs.c b/app/jni/csprogs.c new file mode 100644 index 0000000..36cecf8 --- /dev/null +++ b/app/jni/csprogs.c @@ -0,0 +1,1252 @@ +#include "quakedef.h" +#include "progsvm.h" +#include "clprogdefs.h" +#include "csprogs.h" +#include "cl_collision.h" +#include "snd_main.h" +#include "clvm_cmds.h" +#include "prvm_cmds.h" + +//============================================================================ +// Client prog handling +//[515]: omg !!! optimize it ! a lot of hacks here and there also :P + +#define CSQC_RETURNVAL prog->globals.fp[OFS_RETURN] +#define CSQC_BEGIN +#define CSQC_END + +void CL_VM_PreventInformationLeaks(void) +{ + prvm_prog_t *prog = CLVM_prog; + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + VM_ClearTraceGlobals(prog); + PRVM_clientglobalfloat(trace_networkentity) = 0; + CSQC_END +} + +//[515]: these are required funcs +static const char *cl_required_func[] = +{ + "CSQC_Init", + "CSQC_InputEvent", + "CSQC_UpdateView", + "CSQC_ConsoleCommand", +}; + +static int cl_numrequiredfunc = sizeof(cl_required_func) / sizeof(char*); + +#define CL_REQFIELDS (sizeof(cl_reqfields) / sizeof(prvm_required_field_t)) + +prvm_required_field_t cl_reqfields[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) {ev_float, #x }, +#define PRVM_DECLARE_clientfieldvector(x) {ev_vector, #x }, +#define PRVM_DECLARE_clientfieldstring(x) {ev_string, #x }, +#define PRVM_DECLARE_clientfieldedict(x) {ev_entity, #x }, +#define PRVM_DECLARE_clientfieldfunction(x) {ev_function, #x }, +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + +#define CL_REQGLOBALS (sizeof(cl_reqglobals) / sizeof(prvm_required_field_t)) + +prvm_required_field_t cl_reqglobals[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) {ev_float, #x}, +#define PRVM_DECLARE_clientglobalvector(x) {ev_vector, #x}, +#define PRVM_DECLARE_clientglobalstring(x) {ev_string, #x}, +#define PRVM_DECLARE_clientglobaledict(x) {ev_entity, #x}, +#define PRVM_DECLARE_clientglobalfunction(x) {ev_function, #x}, +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + +void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin) +{ + prvm_prog_t *prog = CLVM_prog; + if(cl.csqc_loaded) + { + CSQC_BEGIN + PRVM_clientglobalfloat(dmg_take) = dmg_take; + PRVM_clientglobalfloat(dmg_save) = dmg_save; + VectorCopy(dmg_origin, PRVM_clientglobalvector(dmg_origin)); + CSQC_END + } +} + +void CSQC_UpdateNetworkTimes(double newtime, double oldtime) +{ + prvm_prog_t *prog = CLVM_prog; + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + PRVM_clientglobalfloat(servertime) = newtime; + PRVM_clientglobalfloat(serverprevtime) = oldtime; + PRVM_clientglobalfloat(serverdeltatime) = newtime - oldtime; + CSQC_END +} + +//[515]: set globals before calling R_UpdateView, WEIRD CRAP +static void CSQC_SetGlobals (double frametime) +{ + vec3_t pmove_org; + prvm_prog_t *prog = CLVM_prog; + CSQC_BEGIN + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobalfloat(frametime) = frametime; + PRVM_clientglobalfloat(servercommandframe) = cls.servermovesequence; + PRVM_clientglobalfloat(clientcommandframe) = cl.movecmd[0].sequence; + VectorCopy(cl.viewangles, PRVM_clientglobalvector(input_angles)); + // // FIXME: this actually belongs into getinputstate().. [12/17/2007 Black] + PRVM_clientglobalfloat(input_buttons) = cl.movecmd[0].buttons; + VectorSet(PRVM_clientglobalvector(input_movevalues), cl.movecmd[0].forwardmove, cl.movecmd[0].sidemove, cl.movecmd[0].upmove); + VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin); + VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles); + + // LordHavoc: Spike says not to do this, but without pmove_org the + // CSQC is useless as it can't alter the view origin without + // completely replacing it + Matrix4x4_OriginFromMatrix(&cl.entities[cl.viewentity].render.matrix, pmove_org); + VectorCopy(pmove_org, PRVM_clientglobalvector(pmove_org)); + VectorCopy(cl.movement_velocity, PRVM_clientglobalvector(pmove_vel)); + PRVM_clientglobalfloat(pmove_onground) = cl.onground; + PRVM_clientglobalfloat(pmove_inwater) = cl.inwater; + + VectorCopy(cl.viewangles, PRVM_clientglobalvector(view_angles)); + VectorCopy(cl.punchangle, PRVM_clientglobalvector(view_punchangle)); + VectorCopy(cl.punchvector, PRVM_clientglobalvector(view_punchvector)); + PRVM_clientglobalfloat(maxclients) = cl.maxclients; + + PRVM_clientglobalfloat(player_localentnum) = cl.viewentity; + + CSQC_R_RecalcView(); + CSQC_END +} + +void CSQC_Predraw (prvm_edict_t *ed) +{ + prvm_prog_t *prog = CLVM_prog; + int b; + if(!PRVM_clientedictfunction(ed, predraw)) + return; + b = PRVM_clientglobaledict(self); + PRVM_clientglobaledict(self) = PRVM_EDICT_TO_PROG(ed); + prog->ExecuteProgram(prog, PRVM_clientedictfunction(ed, predraw), "CSQC_Predraw: NULL function\n"); + PRVM_clientglobaledict(self) = b; +} + +void CSQC_Think (prvm_edict_t *ed) +{ + prvm_prog_t *prog = CLVM_prog; + int b; + if(PRVM_clientedictfunction(ed, think)) + if(PRVM_clientedictfloat(ed, nextthink) && PRVM_clientedictfloat(ed, nextthink) <= PRVM_clientglobalfloat(time)) + { + PRVM_clientedictfloat(ed, nextthink) = 0; + b = PRVM_clientglobaledict(self); + PRVM_clientglobaledict(self) = PRVM_EDICT_TO_PROG(ed); + prog->ExecuteProgram(prog, PRVM_clientedictfunction(ed, think), "CSQC_Think: NULL function\n"); + PRVM_clientglobaledict(self) = b; + } +} + +extern cvar_t cl_noplayershadow; +extern cvar_t r_equalize_entities_fullbright; +qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum) +{ + prvm_prog_t *prog = CLVM_prog; + int renderflags; + int c; + float scale; + entity_render_t *entrender; + dp_model_t *model; + + model = CL_GetModelFromEdict(ed); + if (!model) + return false; + + if (edictnum) + { + if (r_refdef.scene.numentities >= r_refdef.scene.maxentities) + return false; + entrender = cl.csqcrenderentities + edictnum; + r_refdef.scene.entities[r_refdef.scene.numentities++] = entrender; + entrender->entitynumber = edictnum + MAX_EDICTS; + //entrender->shadertime = 0; // shadertime was set by spawn() + entrender->flags = 0; + entrender->effects = 0; + entrender->alpha = 1; + entrender->scale = 1; + VectorSet(entrender->colormod, 1, 1, 1); + VectorSet(entrender->glowmod, 1, 1, 1); + entrender->allowdecals = true; + } + else + { + entrender = CL_NewTempEntity(0); + if (!entrender) + return false; + } + + entrender->userwavefunc_param[0] = PRVM_clientedictfloat(ed, userwavefunc_param0); + entrender->userwavefunc_param[1] = PRVM_clientedictfloat(ed, userwavefunc_param1); + entrender->userwavefunc_param[2] = PRVM_clientedictfloat(ed, userwavefunc_param2); + entrender->userwavefunc_param[3] = PRVM_clientedictfloat(ed, userwavefunc_param3); + + entrender->model = model; + entrender->skinnum = (int)PRVM_clientedictfloat(ed, skin); + entrender->effects |= entrender->model->effects; + renderflags = (int)PRVM_clientedictfloat(ed, renderflags); + entrender->alpha = PRVM_clientedictfloat(ed, alpha); + entrender->scale = scale = PRVM_clientedictfloat(ed, scale); + VectorCopy(PRVM_clientedictvector(ed, colormod), entrender->colormod); + VectorCopy(PRVM_clientedictvector(ed, glowmod), entrender->glowmod); + if(PRVM_clientedictfloat(ed, effects)) entrender->effects |= (int)PRVM_clientedictfloat(ed, effects); + if (!entrender->alpha) + entrender->alpha = 1.0f; + if (!entrender->scale) + entrender->scale = scale = 1.0f; + if (!VectorLength2(entrender->colormod)) + VectorSet(entrender->colormod, 1, 1, 1); + if (!VectorLength2(entrender->glowmod)) + VectorSet(entrender->glowmod, 1, 1, 1); + + // LordHavoc: use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad) + CL_GetTagMatrix(prog, &entrender->matrix, ed, 0); + + // set up the animation data + VM_GenerateFrameGroupBlend(prog, ed->priv.server->framegroupblend, ed); + VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model, cl.time); + VM_UpdateEdictSkeleton(prog, ed, model, ed->priv.server->frameblend); + if (PRVM_clientedictfloat(ed, shadertime)) // hack for csprogs.dat files that do not set shadertime, leaves the value at entity spawn time + entrender->shadertime = PRVM_clientedictfloat(ed, shadertime); + + // transparent offset + if (renderflags & RF_USETRANSPARENTOFFSET) + entrender->transparent_offset = PRVM_clientglobalfloat(transparent_offset); + + // model light + if (renderflags & RF_MODELLIGHT) + { + if (PRVM_clientedictvector(ed, modellight_ambient)) VectorCopy(PRVM_clientedictvector(ed, modellight_ambient), entrender->modellight_ambient); else VectorClear(entrender->modellight_ambient); + if (PRVM_clientedictvector(ed, modellight_diffuse)) VectorCopy(PRVM_clientedictvector(ed, modellight_diffuse), entrender->modellight_diffuse); else VectorClear(entrender->modellight_diffuse); + if (PRVM_clientedictvector(ed, modellight_dir)) VectorCopy(PRVM_clientedictvector(ed, modellight_dir), entrender->modellight_lightdir); else VectorClear(entrender->modellight_lightdir); + entrender->flags |= RENDER_CUSTOMIZEDMODELLIGHT; + } + + if(renderflags) + { + if(renderflags & RF_VIEWMODEL) entrender->flags |= RENDER_VIEWMODEL | RENDER_NODEPTHTEST; + if(renderflags & RF_EXTERNALMODEL) entrender->flags |= RENDER_EXTERIORMODEL; + if(renderflags & RF_WORLDOBJECT) entrender->flags |= RENDER_WORLDOBJECT; + if(renderflags & RF_DEPTHHACK) entrender->flags |= RENDER_NODEPTHTEST; + if(renderflags & RF_ADDITIVE) entrender->flags |= RENDER_ADDITIVE; + if(renderflags & RF_DYNAMICMODELLIGHT) entrender->flags |= RENDER_DYNAMICMODELLIGHT; + } + + c = (int)PRVM_clientedictfloat(ed, colormap); + if (c <= 0) + CL_SetEntityColormapColors(entrender, -1); + else if (c <= cl.maxclients && cl.scores != NULL) + CL_SetEntityColormapColors(entrender, cl.scores[c-1].colors); + else + CL_SetEntityColormapColors(entrender, c); + + entrender->flags &= ~(RENDER_SHADOW | RENDER_LIGHT | RENDER_NOSELFSHADOW); + // either fullbright or lit + if(!r_fullbright.integer) + { + if (!(entrender->effects & EF_FULLBRIGHT) && !(renderflags & RF_FULLBRIGHT)) + entrender->flags |= RENDER_LIGHT; + else if(r_equalize_entities_fullbright.integer) + entrender->flags |= RENDER_LIGHT | RENDER_EQUALIZE; + } + // hide player shadow during intermission or nehahra movie + if (!(entrender->effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) + && (entrender->alpha >= 1) + && !(renderflags & RF_NOSHADOW) + && !(entrender->flags & RENDER_VIEWMODEL) + && (!(entrender->flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) + entrender->flags |= RENDER_SHADOW; + if (entrender->flags & RENDER_VIEWMODEL) + entrender->flags |= RENDER_NOSELFSHADOW; + if (entrender->effects & EF_NOSELFSHADOW) + entrender->flags |= RENDER_NOSELFSHADOW; + if (entrender->effects & EF_NODEPTHTEST) + entrender->flags |= RENDER_NODEPTHTEST; + if (entrender->effects & EF_ADDITIVE) + entrender->flags |= RENDER_ADDITIVE; + if (entrender->effects & EF_DOUBLESIDED) + entrender->flags |= RENDER_DOUBLESIDED; + if (entrender->effects & EF_DYNAMICMODELLIGHT) + entrender->flags |= RENDER_DYNAMICMODELLIGHT; + + // make the other useful stuff + memcpy(entrender->framegroupblend, ed->priv.server->framegroupblend, sizeof(ed->priv.server->framegroupblend)); + CL_UpdateRenderEntity(entrender); + + // override animation data with full control + memcpy(entrender->frameblend, ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend)); + if (ed->priv.server->skeleton.relativetransforms) + entrender->skeleton = &ed->priv.server->skeleton; + else + entrender->skeleton = NULL; + + return true; +} + +// 0 = keydown, key, character (EXT_CSQC) +// 1 = keyup, key, character (EXT_CSQC) +// 2 = mousemove relative, x, y (EXT_CSQC) +// 3 = mousemove absolute, x, y (DP_CSQC) +qboolean CL_VM_InputEvent (int eventtype, int x, int y) +{ + prvm_prog_t *prog = CLVM_prog; + qboolean r; + + if(!cl.csqc_loaded) + return false; + + CSQC_BEGIN + if (!PRVM_clientfunction(CSQC_InputEvent)) + r = false; + else + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + PRVM_G_FLOAT(OFS_PARM0) = eventtype; + PRVM_G_FLOAT(OFS_PARM1) = x; // key or x + PRVM_G_FLOAT(OFS_PARM2) = y; // ascii or y + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_InputEvent), "QC function CSQC_InputEvent is missing"); + r = CSQC_RETURNVAL != 0; + } + CSQC_END + return r; +} + +extern r_refdef_view_t csqc_original_r_refdef_view; +extern r_refdef_view_t csqc_main_r_refdef_view; +qboolean CL_VM_UpdateView (double frametime) +{ + prvm_prog_t *prog = CLVM_prog; + vec3_t emptyvector; + emptyvector[0] = 0; + emptyvector[1] = 0; + emptyvector[2] = 0; +// vec3_t oldangles; + if(!cl.csqc_loaded) + return false; + R_TimeReport("pre-UpdateView"); + CSQC_BEGIN + r_refdef.view.ismain = true; + csqc_original_r_refdef_view = r_refdef.view; + csqc_main_r_refdef_view = r_refdef.view; + //VectorCopy(cl.viewangles, oldangles); + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + CSQC_SetGlobals(frametime); + // clear renderable entity and light lists to prevent crashes if the + // CSQC_UpdateView function does not call R_ClearScene as it should + r_refdef.scene.numentities = 0; + r_refdef.scene.numlights = 0; + // pass in width and height as parameters (EXT_CSQC_1) + PRVM_G_FLOAT(OFS_PARM0) = vid.width; + PRVM_G_FLOAT(OFS_PARM1) = vid.height; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_UpdateView), "QC function CSQC_UpdateView is missing"); + //VectorCopy(oldangles, cl.viewangles); + // Dresk : Reset Dmg Globals Here + CL_VM_UpdateDmgGlobals(0, 0, emptyvector); + r_refdef.view = csqc_main_r_refdef_view; + R_RenderView_UpdateViewVectors(); // we have to do this, as we undid the scene render doing this for us + CSQC_END + + R_TimeReport("UpdateView"); + return true; +} + +qboolean CL_VM_ConsoleCommand (const char *cmd) +{ + prvm_prog_t *prog = CLVM_prog; + int restorevm_tempstringsbuf_cursize; + qboolean r = false; + if(!cl.csqc_loaded) + return false; + CSQC_BEGIN + if (PRVM_clientfunction(CSQC_ConsoleCommand)) + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, cmd); + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_ConsoleCommand), "QC function CSQC_ConsoleCommand is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + r = CSQC_RETURNVAL != 0; + } + CSQC_END + return r; +} + +qboolean CL_VM_Parse_TempEntity (void) +{ + prvm_prog_t *prog = CLVM_prog; + int t; + qboolean r = false; + if(!cl.csqc_loaded) + return false; + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Parse_TempEntity)) + { + t = cl_message.readcount; + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Parse_TempEntity), "QC function CSQC_Parse_TempEntity is missing"); + r = CSQC_RETURNVAL != 0; + if(!r) + { + cl_message.readcount = t; + cl_message.badread = false; + } + } + CSQC_END + return r; +} + +void CL_VM_Parse_StuffCmd (const char *msg) +{ + prvm_prog_t *prog = CLVM_prog; + int restorevm_tempstringsbuf_cursize; + if(msg[0] == 'c') + if(msg[1] == 's') + if(msg[2] == 'q') + if(msg[3] == 'c') + { + // if this is setting a csqc variable, deprotect csqc_progcrc + // temporarily so that it can be set by the cvar command, + // and then reprotect it afterwards + int crcflags = csqc_progcrc.flags; + int sizeflags = csqc_progcrc.flags; + csqc_progcrc.flags &= ~CVAR_READONLY; + csqc_progsize.flags &= ~CVAR_READONLY; + Cmd_ExecuteString (msg, src_command, true); + csqc_progcrc.flags = crcflags; + csqc_progsize.flags = sizeflags; + return; + } + + if(cls.demoplayback) + if(!strncmp(msg, "curl --clear_autodownload\ncurl --pak --forthismap --as ", 55)) + { + // special handling for map download commands + // run these commands IMMEDIATELY, instead of waiting for a client frame + // that way, there is no black screen when playing back demos + // I know this is a really ugly hack, but I can't think of any better way + // FIXME find the actual CAUSE of this, and make demo playback WAIT + // until all maps are loaded, then remove this hack + + char buf[MAX_INPUTLINE]; + const char *p, *q; + size_t l; + + p = msg; + + for(;;) + { + q = strchr(p, '\n'); + if(q) + l = q - p; + else + l = strlen(p); + if(l > sizeof(buf) - 1) + l = sizeof(buf) - 1; + strlcpy(buf, p, l + 1); // strlcpy needs a + 1 as it includes the newline! + + Cmd_ExecuteString(buf, src_command, true); + + p += l; + if(*p == '\n') + ++p; // skip the newline and continue + else + break; // end of string or overflow + } + Cmd_ExecuteString("curl --clear_autodownload", src_command, true); // don't inhibit CSQC loading + return; + } + + if(!cl.csqc_loaded) + { + Cbuf_AddText(msg); + return; + } + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Parse_StuffCmd)) + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, msg); + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Parse_StuffCmd), "QC function CSQC_Parse_StuffCmd is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } + else + Cbuf_AddText(msg); + CSQC_END +} + +static void CL_VM_Parse_Print (const char *msg) +{ + prvm_prog_t *prog = CLVM_prog; + int restorevm_tempstringsbuf_cursize; + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, msg); + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Parse_Print), "QC function CSQC_Parse_Print is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; +} + +void CSQC_AddPrintText (const char *msg) +{ + prvm_prog_t *prog = CLVM_prog; + size_t i; + if(!cl.csqc_loaded) + { + Con_Print(msg); + return; + } + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Parse_Print)) + { + // FIXME: is this bugged? + i = strlen(msg)-1; + if(msg[i] != '\n' && msg[i] != '\r') + { + if(strlen(cl.csqc_printtextbuf)+i >= MAX_INPUTLINE) + { + CL_VM_Parse_Print(cl.csqc_printtextbuf); + cl.csqc_printtextbuf[0] = 0; + } + else + strlcat(cl.csqc_printtextbuf, msg, MAX_INPUTLINE); + return; + } + strlcat(cl.csqc_printtextbuf, msg, MAX_INPUTLINE); + CL_VM_Parse_Print(cl.csqc_printtextbuf); + cl.csqc_printtextbuf[0] = 0; + } + else + Con_Print(msg); + CSQC_END +} + +void CL_VM_Parse_CenterPrint (const char *msg) +{ + prvm_prog_t *prog = CLVM_prog; + int restorevm_tempstringsbuf_cursize; + if(!cl.csqc_loaded) + { + SCR_CenterPrint(msg); + return; + } + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Parse_CenterPrint)) + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, msg); + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Parse_CenterPrint), "QC function CSQC_Parse_CenterPrint is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } + else + SCR_CenterPrint(msg); + CSQC_END +} + +void CL_VM_UpdateIntermissionState (int intermission) +{ + prvm_prog_t *prog = CLVM_prog; + if(cl.csqc_loaded) + { + CSQC_BEGIN + PRVM_clientglobalfloat(intermission) = intermission; + CSQC_END + } +} +void CL_VM_UpdateShowingScoresState (int showingscores) +{ + prvm_prog_t *prog = CLVM_prog; + if(cl.csqc_loaded) + { + CSQC_BEGIN + PRVM_clientglobalfloat(sb_showscores) = showingscores; + CSQC_END + } +} +qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos, int flags, float speed) +{ + prvm_prog_t *prog = CLVM_prog; + qboolean r = false; + if(cl.csqc_loaded) + { + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Event_Sound)) + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + PRVM_G_FLOAT(OFS_PARM0) = ent; + PRVM_G_FLOAT(OFS_PARM1) = CHAN_ENGINE2USER(channel); + PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(prog, cl.sound_name[sound_num] ); + PRVM_G_FLOAT(OFS_PARM3) = volume; + PRVM_G_FLOAT(OFS_PARM4) = attenuation; + VectorCopy(pos, PRVM_G_VECTOR(OFS_PARM5) ); + PRVM_G_FLOAT(OFS_PARM6) = speed * 100.0f; + PRVM_G_FLOAT(OFS_PARM7) = flags; // flags + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Event_Sound), "QC function CSQC_Event_Sound is missing"); + r = CSQC_RETURNVAL != 0; + } + CSQC_END + } + + return r; +} +static void CL_VM_UpdateCoopDeathmatchGlobals (int gametype) +{ + prvm_prog_t *prog = CLVM_prog; + // Avoid global names for clean(er) coding + int localcoop; + int localdeathmatch; + + if(cl.csqc_loaded) + { + if(gametype == GAME_COOP) + { + localcoop = 1; + localdeathmatch = 0; + } + else + if(gametype == GAME_DEATHMATCH) + { + localcoop = 0; + localdeathmatch = 1; + } + else + { + // How did the ServerInfo send an unknown gametype? + // Better just assign the globals as 0... + localcoop = 0; + localdeathmatch = 0; + } + CSQC_BEGIN + PRVM_clientglobalfloat(coop) = localcoop; + PRVM_clientglobalfloat(deathmatch) = localdeathmatch; + CSQC_END + } +} +#if 0 +static float CL_VM_Event (float event) //[515]: needed ? I'd say "YES", but don't know for what :D +{ + prvm_prog_t *prog = CLVM_prog; + float r = 0; + if(!cl.csqc_loaded) + return 0; + CSQC_BEGIN + if(PRVM_clientfunction(CSQC_Event)) + { + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; + PRVM_G_FLOAT(OFS_PARM0) = event; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Event), "QC function CSQC_Event is missing"); + r = CSQC_RETURNVAL; + } + CSQC_END + return r; +} +#endif + +void CSQC_ReadEntities (void) +{ + prvm_prog_t *prog = CLVM_prog; + unsigned short entnum, oldself, realentnum; + if(!cl.csqc_loaded) + { + Host_Error ("CSQC_ReadEntities: CSQC is not loaded"); + return; + } + + CSQC_BEGIN + PRVM_clientglobalfloat(time) = cl.time; + oldself = PRVM_clientglobaledict(self); + while(1) + { + entnum = MSG_ReadShort(&cl_message); + if(!entnum || cl_message.badread) + break; + realentnum = entnum & 0x7FFF; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum]; + if(entnum & 0x8000) + { + if(PRVM_clientglobaledict(self)) + { + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Remove), "QC function CSQC_Ent_Remove is missing"); + cl.csqc_server2csqcentitynumber[realentnum] = 0; + } + else + { + // LordHavoc: removing an entity that is already gone on + // the csqc side is possible for legitimate reasons (such + // as a repeat of the remove message), so no warning is + // needed + //Con_Printf("Bad csqc_server2csqcentitynumber map\n"); //[515]: never happens ? + } + } + else + { + if(!PRVM_clientglobaledict(self)) + { + if(!PRVM_clientfunction(CSQC_Ent_Spawn)) + { + prvm_edict_t *ed; + ed = PRVM_ED_Alloc(prog); + PRVM_clientedictfloat(ed, entnum) = realentnum; + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed); + } + else + { + // entity( float entnum ) CSQC_Ent_Spawn; + // the qc function should set entnum, too (this way it also can return world [2/1/2008 Andreas] + PRVM_G_FLOAT(OFS_PARM0) = (float) realentnum; + // make sure no one gets wrong ideas + PRVM_clientglobaledict(self) = 0; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Spawn), "QC function CSQC_Ent_Spawn is missing"); + PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT( PRVM_G_INT( OFS_RETURN ) ); + } + PRVM_G_FLOAT(OFS_PARM0) = 1; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing"); + } + else { + PRVM_G_FLOAT(OFS_PARM0) = 0; + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Ent_Update), "QC function CSQC_Ent_Update is missing"); + } + } + } + PRVM_clientglobaledict(self) = oldself; + CSQC_END +} + +static void CLVM_begin_increase_edicts(prvm_prog_t *prog) +{ + // links don't survive the transition, so unlink everything + World_UnlinkAll(&cl.world); +} + +static void CLVM_end_increase_edicts(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + + // link every entity except world + for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++) + if (!ent->priv.server->free) + CL_LinkEdict(ent); +} + +static void CLVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e) +{ + int edictnum = PRVM_NUM_FOR_EDICT(e); + entity_render_t *entrender; + CL_ExpandCSQCRenderEntities(edictnum); + entrender = cl.csqcrenderentities + edictnum; + e->priv.server->move = false; // don't move on first frame + memset(entrender, 0, sizeof(*entrender)); + entrender->shadertime = cl.time; +} + +static void CLVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed) +{ + entity_render_t *entrender = cl.csqcrenderentities + PRVM_NUM_FOR_EDICT(ed); + R_DecalSystem_Reset(&entrender->decalsystem); + memset(entrender, 0, sizeof(*entrender)); + World_UnlinkEdict(ed); + memset(ed->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); + VM_RemoveEdictSkeleton(prog, ed); + World_Physics_RemoveFromEntity(&cl.world, ed); + World_Physics_RemoveJointFromEntity(&cl.world, ed); +} + +static void CLVM_count_edicts(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + int active = 0, models = 0, solid = 0; + + for (i=0 ; inum_edicts ; i++) + { + ent = PRVM_EDICT_NUM(i); + if (ent->priv.server->free) + continue; + active++; + if (PRVM_clientedictfloat(ent, solid)) + solid++; + if (PRVM_clientedictstring(ent, model)) + models++; + } + + Con_Printf("num_edicts:%3i\n", prog->num_edicts); + Con_Printf("active :%3i\n", active); + Con_Printf("view :%3i\n", models); + Con_Printf("touch :%3i\n", solid); +} + +static qboolean CLVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent) +{ + return true; +} + +// returns true if the packet is valid, false if end of file is reached +// used for dumping the CSQC download into demo files +qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t len, int crc, int cnt, sizebuf_t *buf, int protocol) +{ + int packetsize = buf->maxsize - 7; // byte short long + int npackets = (len + packetsize - 1) / (packetsize); + char vabuf[1024]; + + if(protocol == PROTOCOL_QUAKEWORLD) + return false; // CSQC can't run in QW anyway + + SZ_Clear(buf); + if(cnt == 0) + { + MSG_WriteByte(buf, svc_stufftext); + MSG_WriteString(buf, va(vabuf, sizeof(vabuf), "\ncl_downloadbegin %lu %s\n", (unsigned long)len, filename)); + return true; + } + else if(cnt >= 1 && cnt <= npackets) + { + unsigned long thispacketoffset = (cnt - 1) * packetsize; + int thispacketsize = len - thispacketoffset; + if(thispacketsize > packetsize) + thispacketsize = packetsize; + + MSG_WriteByte(buf, svc_downloaddata); + MSG_WriteLong(buf, thispacketoffset); + MSG_WriteShort(buf, thispacketsize); + SZ_Write(buf, data + thispacketoffset, thispacketsize); + + return true; + } + else if(cnt == npackets + 1) + { + MSG_WriteByte(buf, svc_stufftext); + MSG_WriteString(buf, va(vabuf, sizeof(vabuf), "\ncl_downloadfinished %lu %d\n", (unsigned long)len, crc)); + return true; + } + return false; +} + +extern cvar_t csqc_usedemoprogs; +void CL_VM_Init (void) +{ + prvm_prog_t *prog = CLVM_prog; + const char* csprogsfn = NULL; + unsigned char *csprogsdata = NULL; + fs_offset_t csprogsdatasize = 0; + int csprogsdatacrc, requiredcrc; + int requiredsize; + char vabuf[1024]; + + // reset csqc_progcrc after reading it, so that changing servers doesn't + // expect csqc on the next server + requiredcrc = csqc_progcrc.integer; + requiredsize = csqc_progsize.integer; + Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); + + // if the server is not requesting a csprogs, then we're done here + if (requiredcrc < 0) + return; + + // see if the requested csprogs.dat file matches the requested crc + if (!cls.demoplayback || csqc_usedemoprogs.integer) + { + csprogsfn = va(vabuf, sizeof(vabuf), "dlcache/%s.%i.%i", csqc_progname.string, requiredsize, requiredcrc); + if(cls.caughtcsprogsdata && cls.caughtcsprogsdatasize == requiredsize && CRC_Block(cls.caughtcsprogsdata, (size_t)cls.caughtcsprogsdatasize) == requiredcrc) + { + Con_DPrintf("Using buffered \"%s\"\n", csprogsfn); + csprogsdata = cls.caughtcsprogsdata; + csprogsdatasize = cls.caughtcsprogsdatasize; + cls.caughtcsprogsdata = NULL; + cls.caughtcsprogsdatasize = 0; + } + else + { + Con_DPrintf("Not using buffered \"%s\" (buffered: %p, %d)\n", csprogsfn, cls.caughtcsprogsdata, (int) cls.caughtcsprogsdatasize); + csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize); + } + } + if (!csprogsdata) + { + csprogsfn = csqc_progname.string; + csprogsdata = FS_LoadFile(csprogsfn, tempmempool, true, &csprogsdatasize); + } + if (csprogsdata) + { + csprogsdatacrc = CRC_Block(csprogsdata, (size_t)csprogsdatasize); + if (csprogsdatacrc != requiredcrc || csprogsdatasize != requiredsize) + { + if (cls.demoplayback) + { + Con_Printf("^1Warning: Your %s is not the same version as the demo was recorded with (CRC/size are %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); + // Mem_Free(csprogsdata); + // return; + // We WANT to continue here, and play the demo with different csprogs! + // After all, this is just a warning. Sure things may go wrong from here. + } + else + { + Mem_Free(csprogsdata); + Con_Printf("^1Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); + CL_Disconnect(); + return; + } + } + } + else + { + if (requiredcrc >= 0) + { + if (cls.demoplayback) + Con_Printf("CL_VM_Init: demo requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string); + else + Con_Printf("CL_VM_Init: server requires CSQC, but \"%s\" wasn't found\n", csqc_progname.string); + CL_Disconnect(); + } + return; + } + + PRVM_Prog_Init(prog); + + // allocate the mempools + prog->progs_mempool = Mem_AllocPool(csqc_progname.string, 0, NULL); + prog->edictprivate_size = 0; // no private struct used + prog->name = "client"; + prog->num_edicts = 1; + prog->max_edicts = 512; + prog->limit_edicts = CL_MAX_EDICTS; + prog->reserved_edicts = 0; + prog->edictprivate_size = sizeof(edict_engineprivate_t); + // TODO: add a shared extension string #define and add real support for csqc extension strings [12/5/2007 Black] + prog->extensionstring = vm_sv_extensions; + prog->builtins = vm_cl_builtins; + prog->numbuiltins = vm_cl_numbuiltins; + + // all callbacks must be defined (pointers are not checked before calling) + prog->begin_increase_edicts = CLVM_begin_increase_edicts; + prog->end_increase_edicts = CLVM_end_increase_edicts; + prog->init_edict = CLVM_init_edict; + prog->free_edict = CLVM_free_edict; + prog->count_edicts = CLVM_count_edicts; + prog->load_edict = CLVM_load_edict; + prog->init_cmd = CLVM_init_cmd; + prog->reset_cmd = CLVM_reset_cmd; + prog->error_cmd = Host_Error; + prog->ExecuteProgram = CLVM_ExecuteProgram; + + PRVM_Prog_Load(prog, csprogsfn, csprogsdata, csprogsdatasize, cl_numrequiredfunc, cl_required_func, CL_REQFIELDS, cl_reqfields, CL_REQGLOBALS, cl_reqglobals); + + if (!prog->loaded) + { + Host_Error("CSQC %s ^2failed to load\n", csprogsfn); + if(!sv.active) + CL_Disconnect(); + Mem_Free(csprogsdata); + return; + } + + Con_DPrintf("CSQC %s ^5loaded (crc=%i, size=%i)\n", csprogsfn, csprogsdatacrc, (int)csprogsdatasize); + + if(cls.demorecording) + { + if(cls.demo_lastcsprogssize != csprogsdatasize || cls.demo_lastcsprogscrc != csprogsdatacrc) + { + int i; + static char buf[NET_MAXMESSAGE]; + sizebuf_t sb; + unsigned char *demobuf; fs_offset_t demofilesize; + + sb.data = (unsigned char *) buf; + sb.maxsize = sizeof(buf); + i = 0; + + CL_CutDemo(&demobuf, &demofilesize); + while(MakeDownloadPacket(csqc_progname.string, csprogsdata, (size_t)csprogsdatasize, csprogsdatacrc, i++, &sb, cls.protocol)) + CL_WriteDemoMessage(&sb); + CL_PasteDemo(&demobuf, &demofilesize); + + cls.demo_lastcsprogssize = csprogsdatasize; + cls.demo_lastcsprogscrc = csprogsdatacrc; + } + } + Mem_Free(csprogsdata); + + // check if OP_STATE animation is possible in this dat file + if (prog->fieldoffsets.nextthink >= 0 && prog->fieldoffsets.frame >= 0 && prog->fieldoffsets.think >= 0 && prog->globaloffsets.self >= 0) + prog->flag |= PRVM_OP_STATE; + + // set time + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = 0; + + PRVM_clientglobalstring(mapname) = PRVM_SetEngineString(prog, cl.worldname); + PRVM_clientglobalfloat(player_localnum) = cl.realplayerentity - 1; + PRVM_clientglobalfloat(player_localentnum) = cl.viewentity; + + // set map description (use world entity 0) + PRVM_clientedictstring(prog->edicts, message) = PRVM_SetEngineString(prog, cl.worldmessage); + VectorCopy(cl.world.mins, PRVM_clientedictvector(prog->edicts, mins)); + VectorCopy(cl.world.maxs, PRVM_clientedictvector(prog->edicts, maxs)); + + // call the prog init + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Init), "QC function CSQC_Init is missing"); + + cl.csqc_loaded = true; + + cl.csqc_vidvars.drawcrosshair = false; + cl.csqc_vidvars.drawenginesbar = false; + + // Update Coop and Deathmatch Globals (at this point the client knows them from ServerInfo) + CL_VM_UpdateCoopDeathmatchGlobals(cl.gametype); +} + +void CL_VM_ShutDown (void) +{ + prvm_prog_t *prog = CLVM_prog; + Cmd_ClearCsqcFuncs(); + //Cvar_SetValueQuick(&csqc_progcrc, -1); + //Cvar_SetValueQuick(&csqc_progsize, -1); + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = 0; + if (PRVM_clientfunction(CSQC_Shutdown)) + prog->ExecuteProgram(prog, PRVM_clientfunction(CSQC_Shutdown), "QC function CSQC_Shutdown is missing"); + PRVM_Prog_Reset(prog); + CSQC_END + Con_DPrint("CSQC ^1unloaded\n"); + cl.csqc_loaded = false; +} + +qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out) +{ + prvm_prog_t *prog = CLVM_prog; + prvm_edict_t *ed; + dp_model_t *mod; + matrix4x4_t matrix; + qboolean r = 0; + + CSQC_BEGIN; + + // FIXME consider attachments here! + + ed = PRVM_EDICT_NUM(entnum - MAX_EDICTS); + + if(!ed->priv.required->free) + { + mod = CL_GetModelFromEdict(ed); + VectorCopy(PRVM_clientedictvector(ed, origin), out); + if(CL_GetTagMatrix(prog, &matrix, ed, 0) == 0) + Matrix4x4_OriginFromMatrix(&matrix, out); + if (mod && mod->soundfromcenter) + VectorMAMAM(1.0f, out, 0.5f, mod->normalmins, 0.5f, mod->normalmaxs, out); + r = 1; + } + + CSQC_END; + + return r; +} + +qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clipplane, vec3_t visorigin) +{ + prvm_prog_t *prog = CLVM_prog; + qboolean ret = false; + prvm_edict_t *ed; + vec3_t forward, left, up, origin, ang; + matrix4x4_t mat, matq; + + CSQC_BEGIN + ed = PRVM_EDICT_NUM(entnum); + // camera: + // camera_transform + if(PRVM_clientedictfunction(ed, camera_transform)) + { + ret = true; + if(viewmatrix || clipplane || visorigin) + { + Matrix4x4_ToVectors(viewmatrix, forward, left, up, origin); + AnglesFromVectors(ang, forward, up, false); + PRVM_clientglobalfloat(time) = cl.time; + PRVM_clientglobaledict(self) = entnum; + VectorCopy(origin, PRVM_G_VECTOR(OFS_PARM0)); + VectorCopy(ang, PRVM_G_VECTOR(OFS_PARM1)); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorScale(left, -1, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_clientglobalvector(trace_endpos)); + prog->ExecuteProgram(prog, PRVM_clientedictfunction(ed, camera_transform), "QC function e.camera_transform is missing"); + VectorCopy(PRVM_G_VECTOR(OFS_RETURN), origin); + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorScale(PRVM_clientglobalvector(v_right), -1, left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + VectorCopy(PRVM_clientglobalvector(trace_endpos), visorigin); + Matrix4x4_Invert_Full(&mat, viewmatrix); + Matrix4x4_FromVectors(viewmatrix, forward, left, up, origin); + Matrix4x4_Concat(&matq, viewmatrix, &mat); + Matrix4x4_TransformPositivePlane(&matq, clipplane->normal[0], clipplane->normal[1], clipplane->normal[2], clipplane->dist, &clipplane->normal[0]); + } + } + CSQC_END + + return ret; +} + +int CL_VM_GetViewEntity(void) +{ + if(cl.csqc_server2csqcentitynumber[cl.viewentity]) + return cl.csqc_server2csqcentitynumber[cl.viewentity] + MAX_EDICTS; + return cl.viewentity; +} diff --git a/app/jni/csprogs.h b/app/jni/csprogs.h new file mode 100644 index 0000000..02fa972 --- /dev/null +++ b/app/jni/csprogs.h @@ -0,0 +1,121 @@ +#ifndef CSPROGS_H +#define CSPROGS_H + +// LordHavoc: changed to match MAX_EDICTS +#define CL_MAX_EDICTS MAX_EDICTS + +#define ENTMASK_ENGINE 1 +#define ENTMASK_ENGINEVIEWMODELS 2 +#define ENTMASK_NORMAL 4 + +#define VF_MIN 1 //(vector) +#define VF_MIN_X 2 //(float) +#define VF_MIN_Y 3 //(float) +#define VF_SIZE 4 //(vector) (viewport size) +#define VF_SIZE_X 5 //(float) +#define VF_SIZE_Y 6 //(float) +#define VF_VIEWPORT 7 //(vector, vector) +#define VF_FOV 8 //(vector) +#define VF_FOVX 9 //(float) +#define VF_FOVY 10 //(float) +#define VF_ORIGIN 11 //(vector) +#define VF_ORIGIN_X 12 //(float) +#define VF_ORIGIN_Y 13 //(float) +#define VF_ORIGIN_Z 14 //(float) +#define VF_ANGLES 15 //(vector) +#define VF_ANGLES_X 16 //(float) +#define VF_ANGLES_Y 17 //(float) +#define VF_ANGLES_Z 18 //(float) + +#define VF_DRAWWORLD 19 //(float) //actually world model and sky +#define VF_DRAWENGINESBAR 20 //(float) +#define VF_DRAWCROSSHAIR 21 //(float) + +#define VF_CL_VIEWANGLES 33 //(vector) //sweet thing for RPGs/... +#define VF_CL_VIEWANGLES_X 34 //(float) +#define VF_CL_VIEWANGLES_Y 35 //(float) +#define VF_CL_VIEWANGLES_Z 36 //(float) + +// FTEQW's extension range +#define VF_PERSPECTIVE 200 //(float) + +// what is this doing here? This is a DP extension introduced by Black, should be in 4xx range +#define VF_CLEARSCREEN 201 //(float) + +// what is this doing here? This is a DP extension introduced by VorteX, should be in 4xx range +#define VF_FOG_DENSITY 202 //(float) +#define VF_FOG_COLOR 203 //(vector) +#define VF_FOG_COLOR_R 204 //(float) +#define VF_FOG_COLOR_G 205 //(float) +#define VF_FOG_COLOR_B 206 //(float) +#define VF_FOG_ALPHA 207 //(float) +#define VF_FOG_START 208 //(float) +#define VF_FOG_END 209 //(float) +#define VF_FOG_HEIGHT 210 //(float) +#define VF_FOG_FADEDEPTH 211 //(float) + +// DP's extension range +#define VF_MAINVIEW 400 //(float) +#define VF_MINFPS_QUALITY 401 //(float) + +#define RF_VIEWMODEL 1 // The entity is never drawn in mirrors. In engines with realtime lighting, it casts no shadows. +#define RF_EXTERNALMODEL 2 // The entity is appears in mirrors but not in the normal view. It does still cast shadows in engines with realtime lighting. +#define RF_DEPTHHACK 4 // The entity appears closer to the view than normal, either by scaling it wierdly or by just using a depthrange. This will usually be found in conjunction with RF_VIEWMODEL +#define RF_ADDITIVE 8 // Add the entity acording to it's alpha values instead of the normal blend +#define RF_USEAXIS 16 // When set, the entity will use the v_forward, v_right and v_up globals instead of it's angles field for orientation. Angles will be ignored compleatly. + // Note that to use this properly, you'll NEED to use the predraw function to set the globals. +//#define RF_DOUBLESIDED 32 +#define RF_USETRANSPARENTOFFSET 64 // Allows QC to customize origin used for transparent sorting via transparent_origin global, helps to fix transparent sorting bugs on a very large entities +#define RF_WORLDOBJECT 128 // for large outdoor entities that should not be culled +#define RF_MODELLIGHT 4096 // CSQC-set model light +#define RF_DYNAMICMODELLIGHT 8192 // origin-dependent model light + +#define RF_FULLBRIGHT 256 +#define RF_NOSHADOW 512 + +extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat +extern cvar_t csqc_progcrc; +extern cvar_t csqc_progsize; + +void CL_VM_PreventInformationLeaks(void); + +qboolean MakeDownloadPacket(const char *filename, unsigned char *data, size_t len, int crc, int cnt, sizebuf_t *buf, int protocol); + +qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out); + +qboolean CL_VM_TransformView(int entnum, matrix4x4_t *viewmatrix, mplane_t *clipplane, vec3_t visorigin); + +void CL_VM_Init(void); +void CL_VM_ShutDown(void); +void CL_VM_UpdateIntermissionState(int intermission); +void CL_VM_UpdateShowingScoresState(int showingscores); +qboolean CL_VM_InputEvent(int eventtype, int x, int y); +qboolean CL_VM_ConsoleCommand(const char *cmd); +void CL_VM_UpdateDmgGlobals(int dmg_take, int dmg_save, vec3_t dmg_origin); +void CL_VM_UpdateIntermissionState(int intermission); +qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos, int flags, float speed); +qboolean CL_VM_Parse_TempEntity(void); +void CL_VM_Parse_StuffCmd(const char *msg); +void CL_VM_Parse_CenterPrint(const char *msg); +int CL_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent); +int CL_GetTagMatrix(prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex); +void CL_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix); +/* VMs exposing the polygon calls must call this on Init/Reset */ +void VM_Polygons_Reset(prvm_prog_t *prog); +void QW_CL_StartUpload(unsigned char *data, int size); + +void CSQC_UpdateNetworkTimes(double newtime, double oldtime); +void CSQC_AddPrintText(const char *msg); +void CSQC_ReadEntities(void); +void CSQC_RelinkAllEntities(int drawmask); +void CSQC_RelinkCSQCEntities(void); +void CSQC_Predraw(prvm_edict_t *ed); +void CSQC_Think(prvm_edict_t *ed); +qboolean CSQC_AddRenderEdict(prvm_edict_t *ed, int edictnum);//csprogs.c +void CSQC_R_RecalcView(void); + +dp_model_t *CL_GetModelByIndex(int modelindex); + +int CL_VM_GetViewEntity(void); + +#endif diff --git a/app/jni/curves.c b/app/jni/curves.c new file mode 100644 index 0000000..cf7569d --- /dev/null +++ b/app/jni/curves.c @@ -0,0 +1,440 @@ + +/* +this code written by Forest Hale, on 2004-10-17, and placed into public domain +this implements Quadratic BSpline surfaces as seen in Quake3 by id Software + +a small rant on misuse of the name 'bezier': many people seem to think that +bezier is a generic term for splines, but it is not, it is a term for a +specific type of bspline (4 control points, cubic bspline), bsplines are the +generalization of the bezier spline to support dimensions other than cubic. + +example equations for 1-5 control point bsplines being sampled as t=0...1 +1: flat (0th dimension) +o = a +2: linear (1st dimension) +o = a * (1 - t) + b * t +3: quadratic bspline (2nd dimension) +o = a * (1 - t) * (1 - t) + 2 * b * (1 - t) * t + c * t * t +4: cubic (bezier) bspline (3rd dimension) +o = a * (1 - t) * (1 - t) * (1 - t) + 3 * b * (1 - t) * (1 - t) * t + 3 * c * (1 - t) * t * t + d * t * t * t +5: quartic bspline (4th dimension) +o = a * (1 - t) * (1 - t) * (1 - t) * (1 - t) + 4 * b * (1 - t) * (1 - t) * (1 - t) * t + 6 * c * (1 - t) * (1 - t) * t * t + 4 * d * (1 - t) * t * t * t + e * t * t * t * t + +arbitrary dimension bspline +double factorial(int n) +{ + int i; + double f; + f = 1; + for (i = 1;i < n;i++) + f = f * i; + return f; +} +double bsplinesample(int dimensions, double t, double *param) +{ + double o = 0; + for (i = 0;i < dimensions + 1;i++) + o += param[i] * factorial(dimensions)/(factorial(i)*factorial(dimensions-i)) * pow(t, i) * pow(1 - t, dimensions - i); + return o; +} +*/ + +#include "quakedef.h" +#include "mathlib.h" + +#include +#include "curves.h" + +// Calculate number of resulting vertex rows/columns by given patch size and tesselation factor +// tess=0 means that we reduce detalization of base 3x3 patches by removing middle row and column of vertices +// "DimForTess" is "DIMension FOR TESSelation factor" +// NB: tess=0 actually means that tess must be 0.5, but obviously it can't because it is of int type. (so "a*tess"-like code is replaced by "a/2" if tess=0) +int Q3PatchDimForTess(int size, int tess) +{ + if (tess > 0) + return (size - 1) * tess + 1; + else if (tess == 0) + return (size - 1) / 2 + 1; + else + return 0; // Maybe warn about wrong tess here? +} + +// usage: +// to expand a 5x5 patch to 21x21 vertices (4x4 tesselation), one might use this call: +// Q3PatchSubdivideFloat(3, sizeof(float[3]), outvertices, 5, 5, sizeof(float[3]), patchvertices, 4, 4); +void Q3PatchTesselateFloat(int numcomponents, int outputstride, float *outputvertices, int patchwidth, int patchheight, int inputstride, float *patchvertices, int tesselationwidth, int tesselationheight) +{ + int k, l, x, y, component, outputwidth = Q3PatchDimForTess(patchwidth, tesselationwidth); + float px, py, *v, a, b, c, *cp[3][3], temp[3][64]; + int xmax = max(1, 2*tesselationwidth); + int ymax = max(1, 2*tesselationheight); + + // iterate over the individual 3x3 quadratic spline surfaces one at a time + // expanding them to fill the output array (with some overlap to ensure + // the edges are filled) + for (k = 0;k < patchheight-1;k += 2) + { + for (l = 0;l < patchwidth-1;l += 2) + { + // set up control point pointers for quicker lookup later + for (y = 0;y < 3;y++) + for (x = 0;x < 3;x++) + cp[y][x] = (float *)((unsigned char *)patchvertices + ((k+y)*patchwidth+(l+x)) * inputstride); + // for each row... + for (y = 0;y <= ymax;y++) + { + // calculate control points for this row by collapsing the 3 + // rows of control points to one row using py + py = (float)y / (float)ymax; + // calculate quadratic spline weights for py + a = ((1.0f - py) * (1.0f - py)); + b = ((1.0f - py) * (2.0f * py)); + c = (( py) * ( py)); + for (component = 0;component < numcomponents;component++) + { + temp[0][component] = cp[0][0][component] * a + cp[1][0][component] * b + cp[2][0][component] * c; + temp[1][component] = cp[0][1][component] * a + cp[1][1][component] * b + cp[2][1][component] * c; + temp[2][component] = cp[0][2][component] * a + cp[1][2][component] * b + cp[2][2][component] * c; + } + // fetch a pointer to the beginning of the output vertex row + v = (float *)((unsigned char *)outputvertices + ((k * ymax / 2 + y) * outputwidth + l * xmax / 2) * outputstride); + // for each column of the row... + for (x = 0;x <= xmax;x++) + { + // calculate point based on the row control points + px = (float)x / (float)xmax; + // calculate quadratic spline weights for px + // (could be precalculated) + a = ((1.0f - px) * (1.0f - px)); + b = ((1.0f - px) * (2.0f * px)); + c = (( px) * ( px)); + for (component = 0;component < numcomponents;component++) + v[component] = temp[0][component] * a + temp[1][component] * b + temp[2][component] * c; + // advance to next output vertex using outputstride + // (the next vertex may not be directly following this + // one, as this may be part of a larger structure) + v = (float *)((unsigned char *)v + outputstride); + } + } + } + } +#if 0 + // enable this if you want results printed out + printf("vertices[%i][%i] =\n{\n", (patchheight-1)*tesselationheight+1, (patchwidth-1)*tesselationwidth+1); + for (y = 0;y < (patchheight-1)*tesselationheight+1;y++) + { + for (x = 0;x < (patchwidth-1)*tesselationwidth+1;x++) + { + printf("("); + for (component = 0;component < numcomponents;component++) + printf("%f ", outputvertices[(y*((patchwidth-1)*tesselationwidth+1)+x)*numcomponents+component]); + printf(") "); + } + printf("\n"); + } + printf("}\n"); +#endif +} + +static int Q3PatchTesselation(float largestsquared3xcurvearea, float tolerance) +{ + float f; + // f is actually a squared 2x curve area... so the formula had to be adjusted to give roughly the same subdivisions + f = pow(largestsquared3xcurvearea / 64.0f, 0.25f) / tolerance; + //if(f < 0.25) // VERY flat patches + if(f < 0.0001) // TOTALLY flat patches + return 0; + else if(f < 2) + return 1; + else + return (int) floor(log(f) / log(2.0f)) + 1; + // this is always at least 2 + // maps [0.25..0.5[ to -1 (actually, 1 is returned) + // maps [0.5..1[ to 0 (actually, 1 is returned) + // maps [1..2[ to 1 + // maps [2..4[ to 2 + // maps [4..8[ to 4 +} + +static float Squared3xCurveArea(const float *a, const float *control, const float *b, int components) +{ +#if 0 + // mimicing the old behaviour with the new code... + + float deviation; + float quartercurvearea = 0; + int c; + for (c = 0;c < components;c++) + { + deviation = control[c] * 0.5f - a[c] * 0.25f - b[c] * 0.25f; + quartercurvearea += deviation*deviation; + } + + // But as the new code now works on the squared 2x curve area, let's scale the value + return quartercurvearea * quartercurvearea * 64.0; + +#else + // ideally, we'd like the area between the spline a->control->b and the line a->b. + // but as this is hard to calculate, let's calculate an upper bound of it: + // the area of the triangle a->control->b->a. + // + // one can prove that the area of a quadratic spline = 2/3 * the area of + // the triangle of its control points! + // to do it, first prove it for the spline through (0,0), (1,1), (2,0) + // (which is a parabola) and then note that moving the control point + // left/right is just shearing and keeps the area of both the spline and + // the triangle invariant. + // + // why are we going for the spline area anyway? + // we know that: + // + // the area between the spline and the line a->b is a measure of the + // error of approximation of the spline by the line. + // + // also, on circle-like or parabola-like curves, you easily get that the + // double amount of line approximation segments reduces the error to its quarter + // (also, easy to prove for splines by doing it for one specific one, and using + // affine transforms to get all other splines) + // + // so... + // + // let's calculate the area! but we have to avoid the cross product, as + // components is not necessarily 3 + // + // the area of a triangle spanned by vectors a and b is + // + // 0.5 * |a| |b| sin gamma + // + // now, cos gamma is + // + // a.b / (|a| |b|) + // + // so the area is + // + // 0.5 * sqrt(|a|^2 |b|^2 - (a.b)^2) + int c; + float aa = 0, bb = 0, ab = 0; + for (c = 0;c < components;c++) + { + float xa = a[c] - control[c]; + float xb = b[c] - control[c]; + aa += xa * xa; + ab += xa * xb; + bb += xb * xb; + } + // area is 0.5 * sqrt(aa*bb - ab*ab) + // 2x TRIANGLE area is sqrt(aa*bb - ab*ab) + // 3x CURVE area is sqrt(aa*bb - ab*ab) + return aa * bb - ab * ab; +#endif +} + +// returns how much tesselation of each segment is needed to remain under tolerance +int Q3PatchTesselationOnX(int patchwidth, int patchheight, int components, const float *in, float tolerance) +{ + int x, y; + const float *patch; + float squared3xcurvearea, largestsquared3xcurvearea; + largestsquared3xcurvearea = 0; + for (y = 0;y < patchheight;y++) + { + for (x = 0;x < patchwidth-1;x += 2) + { + patch = in + ((y * patchwidth) + x) * components; + squared3xcurvearea = Squared3xCurveArea(&patch[0], &patch[components], &patch[2*components], components); + if (largestsquared3xcurvearea < squared3xcurvearea) + largestsquared3xcurvearea = squared3xcurvearea; + } + } + return Q3PatchTesselation(largestsquared3xcurvearea, tolerance); +} + +// returns how much tesselation of each segment is needed to remain under tolerance +int Q3PatchTesselationOnY(int patchwidth, int patchheight, int components, const float *in, float tolerance) +{ + int x, y; + const float *patch; + float squared3xcurvearea, largestsquared3xcurvearea; + largestsquared3xcurvearea = 0; + for (y = 0;y < patchheight-1;y += 2) + { + for (x = 0;x < patchwidth;x++) + { + patch = in + ((y * patchwidth) + x) * components; + squared3xcurvearea = Squared3xCurveArea(&patch[0], &patch[patchwidth*components], &patch[2*patchwidth*components], components); + if (largestsquared3xcurvearea < squared3xcurvearea) + largestsquared3xcurvearea = squared3xcurvearea; + } + } + return Q3PatchTesselation(largestsquared3xcurvearea, tolerance); +} + +// Find an equal vertex in array. Check only vertices with odd X and Y +static int FindEqualOddVertexInArray(int numcomponents, float *vertex, float *vertices, int width, int height) +{ + int x, y, j; + for (y=0; y 0.05) + // div0: this is notably smaller than the smallest radiant grid + // but large enough so we don't need to get scared of roundoff + // errors + { + found = false; + break; + } + if(found) + return y*width+x; + vertices += numcomponents*2; + } + vertices += numcomponents*(width-1); + } + return -1; +} + +#define SIDE_INVALID -1 +#define SIDE_X 0 +#define SIDE_Y 1 + +static int GetSide(int p1, int p2, int width, int height, int *pointdist) +{ + int x1 = p1 % width, y1 = p1 / width; + int x2 = p2 % width, y2 = p2 / width; + if (p1 < 0 || p2 < 0) + return SIDE_INVALID; + if (x1 == x2) + { + if (y1 != y2) + { + *pointdist = abs(y2 - y1); + return SIDE_Y; + } + else + return SIDE_INVALID; + } + else if (y1 == y2) + { + *pointdist = abs(x2 - x1); + return SIDE_X; + } + else + return SIDE_INVALID; +} + +// Increase tesselation of one of two touching patches to make a seamless connection between them +// Returns 0 in case if patches were not modified, otherwise 1 +int Q3PatchAdjustTesselation(int numcomponents, patchinfo_t *patch1, float *patchvertices1, patchinfo_t *patch2, float *patchvertices2) +{ + // what we are doing here is: + // we take for each corner of one patch + // and check if the other patch contains that corner + // once we have a pair of such matches + + struct {int id1,id2;} commonverts[8]; + int i, j, k, side1, side2, *tess1, *tess2; + int dist1 = 0, dist2 = 0; + qboolean modified = false; + + // Potential paired vertices (corners of the first patch) + commonverts[0].id1 = 0; + commonverts[1].id1 = patch1->xsize-1; + commonverts[2].id1 = patch1->xsize*(patch1->ysize-1); + commonverts[3].id1 = patch1->xsize*patch1->ysize-1; + for (i=0;i<4;++i) + commonverts[i].id2 = FindEqualOddVertexInArray(numcomponents, patchvertices1+numcomponents*commonverts[i].id1, patchvertices2, patch2->xsize, patch2->ysize); + + // Corners of the second patch + commonverts[4].id2 = 0; + commonverts[5].id2 = patch2->xsize-1; + commonverts[6].id2 = patch2->xsize*(patch2->ysize-1); + commonverts[7].id2 = patch2->xsize*patch2->ysize-1; + for (i=4;i<8;++i) + commonverts[i].id1 = FindEqualOddVertexInArray(numcomponents, patchvertices2+numcomponents*commonverts[i].id2, patchvertices1, patch1->xsize, patch1->ysize); + + for (i=0;i<8;++i) + for (j=i+1;j<8;++j) + { + side1 = GetSide(commonverts[i].id1,commonverts[j].id1,patch1->xsize,patch1->ysize,&dist1); + side2 = GetSide(commonverts[i].id2,commonverts[j].id2,patch2->xsize,patch2->ysize,&dist2); + + if (side1 == SIDE_INVALID || side2 == SIDE_INVALID) + continue; + + if(dist1 != dist2) + { + // no patch welding if the resolutions mismatch + continue; + } + + // Update every lod level + for (k=0;klods[k].xtess : &patch1->lods[k].ytess; + tess2 = side2 == SIDE_X ? &patch2->lods[k].xtess : &patch2->lods[k].ytess; + if (*tess1 != *tess2) + { + if (*tess1 < *tess2) + *tess1 = *tess2; + else + *tess2 = *tess1; + modified = true; + } + } + } + + return modified; +} + +#undef SIDE_INVALID +#undef SIDE_X +#undef SIDE_Y + +// calculates elements for a grid of vertices +// (such as those produced by Q3PatchTesselate) +// (note: width and height are the actual vertex size, this produces +// (width-1)*(height-1)*2 triangles, 3 elements each) +void Q3PatchTriangleElements(int *elements, int width, int height, int firstvertex) +{ + int x, y, row0, row1; + for (y = 0;y < height - 1;y++) + { + if(y % 2) + { + // swap the triangle order in odd rows as optimization for collision stride + row0 = firstvertex + (y + 0) * width + width - 2; + row1 = firstvertex + (y + 1) * width + width - 2; + for (x = 0;x < width - 1;x++) + { + *elements++ = row1; + *elements++ = row1 + 1; + *elements++ = row0 + 1; + *elements++ = row0; + *elements++ = row1; + *elements++ = row0 + 1; + row0--; + row1--; + } + } + else + { + row0 = firstvertex + (y + 0) * width; + row1 = firstvertex + (y + 1) * width; + for (x = 0;x < width - 1;x++) + { + *elements++ = row0; + *elements++ = row1; + *elements++ = row0 + 1; + *elements++ = row1; + *elements++ = row1 + 1; + *elements++ = row0 + 1; + row0++; + row1++; + } + } + } +} + diff --git a/app/jni/curves.h b/app/jni/curves.h new file mode 100644 index 0000000..6555a5a --- /dev/null +++ b/app/jni/curves.h @@ -0,0 +1,39 @@ + +#ifndef CURVES_H +#define CURVES_H + +#define PATCH_LODS_NUM 2 +#define PATCH_LOD_COLLISION 0 +#define PATCH_LOD_VISUAL 1 + +typedef struct patchinfo_s +{ + int xsize, ysize; + struct { + int xtess, ytess; + } lods[PATCH_LODS_NUM]; +} patchinfo_t; + +// Calculate number of resulting vertex rows/columns by given patch size and tesselation factor +// When tess=0 it means that we reduce detalization of base 3x3 patches by removing middle row and column +// "DimForTess" is "DIMension FOR TESSelation factor" +int Q3PatchDimForTess(int size, int tess); + +// usage: +// to expand a 5x5 patch to 21x21 vertices (4x4 tesselation), one might use this call: +// Q3PatchSubdivideFloat(3, sizeof(float[3]), outvertices, 5, 5, sizeof(float[3]), patchvertices, 4, 4); +void Q3PatchTesselateFloat(int numcomponents, int outputstride, float *outputvertices, int patchwidth, int patchheight, int inputstride, float *patchvertices, int tesselationwidth, int tesselationheight); +// returns how much tesselation of each segment is needed to remain under tolerance +int Q3PatchTesselationOnX(int patchwidth, int patchheight, int components, const float *in, float tolerance); +// returns how much tesselation of each segment is needed to remain under tolerance +int Q3PatchTesselationOnY(int patchwidth, int patchheight, int components, const float *in, float tolerance); +// calculates elements for a grid of vertices +// (such as those produced by Q3PatchTesselate) +// (note: width and height are the actual vertex size, this produces +// (width-1)*(height-1)*2 triangles, 3 elements each) +void Q3PatchTriangleElements(int *elements, int width, int height, int firstvertex); + +int Q3PatchAdjustTesselation(int numcomponents, patchinfo_t *patch1, float *patchvertices1, patchinfo_t *patch2, float *patchvertices2); + +#endif + diff --git a/app/jni/cvar.c b/app/jni/cvar.c new file mode 100644 index 0000000..b88aafd --- /dev/null +++ b/app/jni/cvar.c @@ -0,0 +1,1027 @@ +/* +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" + +const char *cvar_dummy_description = "custom cvar"; + +cvar_t *cvar_vars = NULL; +cvar_t *cvar_hashtable[CVAR_HASHSIZE]; +const char *cvar_null_string = ""; + +/* +============ +Cvar_FindVar +============ +*/ +cvar_t *Cvar_FindVar (const char *var_name) +{ + int hashindex; + cvar_t *var; + + // use hash lookup to minimize search time + hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name)) % CVAR_HASHSIZE; + for (var = cvar_hashtable[hashindex];var;var = var->nextonhashchain) + if (!strcmp (var_name, var->name)) + return var; + + return NULL; +} + +cvar_t *Cvar_FindVarAfter (const char *prev_var_name, int neededflags) +{ + cvar_t *var; + + if (*prev_var_name) + { + var = Cvar_FindVar (prev_var_name); + if (!var) + return NULL; + var = var->next; + } + else + var = cvar_vars; + + // search for the next cvar matching the needed flags + while (var) + { + if ((var->flags & neededflags) || !neededflags) + break; + var = var->next; + } + return var; +} + +static cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link, cvar_t **prev_alpha) +{ + int hashindex; + cvar_t *var; + + // use hash lookup to minimize search time + hashindex = CRC_Block((const unsigned char *)var_name, strlen(var_name)); + if(parent) *parent = NULL; + if(prev_alpha) *prev_alpha = NULL; + if(link) *link = &cvar_hashtable[hashindex]; + for (var = cvar_hashtable[hashindex];var;var = var->nextonhashchain) + { + if (!strcmp (var_name, var->name)) + { + if(!prev_alpha || var == cvar_vars) + return var; + + *prev_alpha = cvar_vars; + // if prev_alpha happens to become NULL then there has been some inconsistency elsewhere + // already - should I still insert '*prev_alpha &&' in the loop? + while((*prev_alpha)->next != var) + *prev_alpha = (*prev_alpha)->next; + return var; + } + if(parent) *parent = var; + } + + return NULL; +} + +/* +============ +Cvar_VariableValue +============ +*/ +float Cvar_VariableValueOr (const char *var_name, float def) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return def; + return atof (var->string); +} + +float Cvar_VariableValue (const char *var_name) +{ + return Cvar_VariableValueOr(var_name, 0); +} + +/* +============ +Cvar_VariableString +============ +*/ +const char *Cvar_VariableStringOr (const char *var_name, const char *def) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return def; + return var->string; +} + +const char *Cvar_VariableString (const char *var_name) +{ + return Cvar_VariableStringOr(var_name, cvar_null_string); +} + +/* +============ +Cvar_VariableDefString +============ +*/ +const char *Cvar_VariableDefString (const char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return cvar_null_string; + return var->defstring; +} + +/* +============ +Cvar_VariableDescription +============ +*/ +const char *Cvar_VariableDescription (const char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return cvar_null_string; + return var->description; +} + + +/* +============ +Cvar_CompleteVariable +============ +*/ +const char *Cvar_CompleteVariable (const char *partial) +{ + cvar_t *cvar; + size_t len; + + len = strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!strncasecmp (partial,cvar->name, len)) + return cvar->name; + + return NULL; +} + + +/* + CVar_CompleteCountPossible + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + +*/ +int Cvar_CompleteCountPossible (const char *partial) +{ + cvar_t *cvar; + size_t len; + int h; + + h = 0; + len = strlen(partial); + + if (!len) + return 0; + + // Loop through the cvars and count all possible matches + for (cvar = cvar_vars; cvar; cvar = cvar->next) + if (!strncasecmp(partial, cvar->name, len)) + h++; + + return h; +} + +/* + CVar_CompleteBuildList + + New function for tab-completion system + Added by EvilTypeGuy + Thanks to Fett erich@heintz.com + Thanks to taniwha + +*/ +const char **Cvar_CompleteBuildList (const char *partial) +{ + const cvar_t *cvar; + size_t len = 0; + size_t bpos = 0; + size_t sizeofbuf = (Cvar_CompleteCountPossible (partial) + 1) * sizeof (const char *); + const char **buf; + + len = strlen(partial); + buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *)); + // Loop through the alias list and print all matches + for (cvar = cvar_vars; cvar; cvar = cvar->next) + if (!strncasecmp(partial, cvar->name, len)) + buf[bpos++] = cvar->name; + + buf[bpos] = NULL; + return buf; +} + +// written by LordHavoc +void Cvar_CompleteCvarPrint (const char *partial) +{ + cvar_t *cvar; + size_t len = strlen(partial); + // Loop through the command list and print all matches + for (cvar = cvar_vars; cvar; cvar = cvar->next) + if (!strncasecmp(partial, cvar->name, len)) + Con_Printf ("^3%s^7 is \"%s\" [\"%s\"] %s\n", cvar->name, cvar->string, cvar->defstring, cvar->description); +} + +// we assume that prog is already set to the target progs +static void Cvar_UpdateAutoCvar(cvar_t *var) +{ + int i; + int j; + const char *s; + vec3_t v; + prvm_prog_t *prog; + for (i = 0;i < PRVM_PROG_MAX;i++) + { + prog = &prvm_prog_list[i]; + if (prog->loaded && var->globaldefindex_progid[i] == prog->id) + { + // MUST BE SYNCED WITH prvm_edict.c PRVM_LoadProgs + switch(prog->globaldefs[var->globaldefindex[i]].type & ~DEF_SAVEGLOBAL) + { + case ev_float: + PRVM_GLOBALFIELDFLOAT(prog->globaldefs[var->globaldefindex[i]].ofs) = var->value; + break; + case ev_vector: + s = var->string; + VectorClear(v); + for (j = 0;j < 3;j++) + { + while (*s && ISWHITESPACE(*s)) + s++; + if (!*s) + break; + v[j] = atof(s); + while (!ISWHITESPACE(*s)) + s++; + if (!*s) + break; + } + VectorCopy(v, PRVM_GLOBALFIELDVECTOR(prog->globaldefs[var->globaldefindex[i]].ofs)); + break; + case ev_string: + PRVM_ChangeEngineString(prog, var->globaldefindex_stringno[i], var->string); + PRVM_GLOBALFIELDSTRING(prog->globaldefs[var->globaldefindex[i]].ofs) = var->globaldefindex_stringno[i]; + break; + } + } + } +} + +// called after loading a savegame +void Cvar_UpdateAllAutoCvars(void) +{ + cvar_t *var; + for (var = cvar_vars ; var ; var = var->next) + Cvar_UpdateAutoCvar(var); +} + +/* +============ +Cvar_Set +============ +*/ +extern cvar_t sv_disablenotify; +static void Cvar_SetQuick_Internal (cvar_t *var, const char *value) +{ + qboolean changed; + size_t valuelen; + char vabuf[1024]; + + changed = strcmp(var->string, value) != 0; + // LordHavoc: don't reallocate when there is no change + if (!changed) + return; + + // LordHavoc: don't reallocate when the buffer is the same size + valuelen = strlen(value); + if (!var->string || strlen(var->string) != valuelen) + { + Z_Free ((char *)var->string); // free the old value string + + var->string = (char *)Z_Malloc (valuelen + 1); + } + memcpy ((char *)var->string, value, valuelen + 1); + var->value = atof (var->string); + var->integer = (int) var->value; + if ((var->flags & CVAR_NOTIFY) && changed && sv.active && !sv_disablenotify.integer) + SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, var->string); +#if 0 + // TODO: add infostring support to the server? + if ((var->flags & CVAR_SERVERINFO) && changed && sv.active) + { + InfoString_SetValue(svs.serverinfo, sizeof(svs.serverinfo), var->name, var->string); + if (sv.active) + { + MSG_WriteByte (&sv.reliable_datagram, svc_serverinfostring); + MSG_WriteString (&sv.reliable_datagram, var->name); + MSG_WriteString (&sv.reliable_datagram, var->string); + } + } +#endif + if ((var->flags & CVAR_USERINFO) && cls.state != ca_dedicated) + CL_SetInfo(var->name, var->string, true, false, false, false); + else if ((var->flags & CVAR_NQUSERINFOHACK) && cls.state != ca_dedicated) + { + // update the cls.userinfo to have proper values for the + // silly nq config variables. + // + // this is done when these variables are changed rather than at + // connect time because if the user or code checks the userinfo and it + // holds weird values it may cause confusion... + if (!strcmp(var->name, "_cl_color")) + { + int top = (var->integer >> 4) & 15, bottom = var->integer & 15; + CL_SetInfo("topcolor", va(vabuf, sizeof(vabuf), "%i", top), true, false, false, false); + CL_SetInfo("bottomcolor", va(vabuf, sizeof(vabuf), "%i", bottom), true, false, false, false); + if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon) + { + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, va(vabuf, sizeof(vabuf), "color %i %i", top, bottom)); + } + } + else if (!strcmp(var->name, "_cl_rate")) + CL_SetInfo("rate", va(vabuf, sizeof(vabuf), "%i", var->integer), true, false, false, false); + else if (!strcmp(var->name, "_cl_playerskin")) + CL_SetInfo("playerskin", var->string, true, false, false, false); + else if (!strcmp(var->name, "_cl_playermodel")) + CL_SetInfo("playermodel", var->string, true, false, false, false); + else if (!strcmp(var->name, "_cl_name")) + CL_SetInfo("name", var->string, true, false, false, false); + else if (!strcmp(var->name, "rcon_secure")) + { + // whenever rcon_secure is changed to 0, clear rcon_password for + // security reasons (prevents a send-rcon-password-as-plaintext + // attack based on NQ protocol session takeover and svc_stufftext) + if(var->integer <= 0) + Cvar_Set("rcon_password", ""); + } + else if (!strcmp(var->name, "net_slist_favorites")) + NetConn_UpdateFavorites(); + } + + Cvar_UpdateAutoCvar(var); +} + +void Cvar_SetQuick (cvar_t *var, const char *value) +{ + if (var == NULL) + { + Con_Print("Cvar_SetQuick: var == NULL\n"); + return; + } + + if (developer_extra.integer) + Con_DPrintf("Cvar_SetQuick({\"%s\", \"%s\", %i, \"%s\"}, \"%s\");\n", var->name, var->string, var->flags, var->defstring, value); + + Cvar_SetQuick_Internal(var, value); +} + +void Cvar_Set (const char *var_name, const char *value) +{ + cvar_t *var; + var = Cvar_FindVar (var_name); + if (var == NULL) + { + Con_Printf("Cvar_Set: variable %s not found\n", var_name); + return; + } + Cvar_SetQuick(var, value); +} + +/* +============ +Cvar_SetValue +============ +*/ +void Cvar_SetValueQuick(cvar_t *var, float value) +{ + char val[MAX_INPUTLINE]; + + if ((float)((int)value) == value) + dpsnprintf(val, sizeof(val), "%i", (int)value); + else + dpsnprintf(val, sizeof(val), "%f", value); + Cvar_SetQuick(var, val); +} + +void Cvar_SetValue(const char *var_name, float value) +{ + char val[MAX_INPUTLINE]; + + if ((float)((int)value) == value) + dpsnprintf(val, sizeof(val), "%i", (int)value); + else + dpsnprintf(val, sizeof(val), "%f", value); + Cvar_Set(var_name, val); +} + +/* +============ +Cvar_RegisterVariable + +Adds a freestanding variable to the variable list. +============ +*/ +void Cvar_RegisterVariable (cvar_t *variable) +{ + int hashindex; + cvar_t *current, *next, *cvar; + char *oldstr; + size_t alloclen; + + if (developer_extra.integer) + Con_DPrintf("Cvar_RegisterVariable({\"%s\", \"%s\", %i});\n", variable->name, variable->string, variable->flags); + +// first check to see if it has already been defined + cvar = Cvar_FindVar (variable->name); + if (cvar) + { + if (cvar->flags & CVAR_ALLOCATED) + { + if (developer_extra.integer) + Con_DPrintf("... replacing existing allocated cvar {\"%s\", \"%s\", %i}\n", cvar->name, cvar->string, cvar->flags); + // fixed variables replace allocated ones + // (because the engine directly accesses fixed variables) + // NOTE: this isn't actually used currently + // (all cvars are registered before config parsing) + variable->flags |= (cvar->flags & ~CVAR_ALLOCATED); + // cvar->string is now owned by variable instead + variable->string = cvar->string; + variable->defstring = cvar->defstring; + variable->value = atof (variable->string); + variable->integer = (int) variable->value; + // replace cvar with this one... + variable->next = cvar->next; + if (cvar_vars == cvar) + { + // head of the list is easy to change + cvar_vars = variable; + } + else + { + // otherwise find it somewhere in the list + for (current = cvar_vars;current->next != cvar;current = current->next) + ; + current->next = variable; + } + + // get rid of old allocated cvar + // (but not cvar->string and cvar->defstring, because we kept those) + Z_Free((char *)cvar->name); + Z_Free(cvar); + } + else + Con_DPrintf("Can't register variable %s, already 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 = (char *)variable->string; + alloclen = strlen(variable->string) + 1; + variable->string = (char *)Z_Malloc (alloclen); + memcpy ((char *)variable->string, oldstr, alloclen); + variable->defstring = (char *)Z_Malloc (alloclen); + memcpy ((char *)variable->defstring, oldstr, alloclen); + variable->value = atof (variable->string); + variable->integer = (int) variable->value; + +// link the variable in +// alphanumerical order + for( current = NULL, next = cvar_vars ; next && strcmp( next->name, variable->name ) < 0 ; current = next, next = next->next ) + ; + if( current ) { + current->next = variable; + } else { + cvar_vars = variable; + } + variable->next = next; + + // link to head of list in this hash table index + hashindex = CRC_Block((const unsigned char *)variable->name, strlen(variable->name)) % CVAR_HASHSIZE; + variable->nextonhashchain = cvar_hashtable[hashindex]; + cvar_hashtable[hashindex] = variable; +} + +/* +============ +Cvar_Get + +Adds a newly allocated variable to the variable list or sets its value. +============ +*/ +cvar_t *Cvar_Get (const char *name, const char *value, int flags, const char *newdescription) +{ + int hashindex; + cvar_t *current, *next, *cvar; + + if (developer_extra.integer) + Con_DPrintf("Cvar_Get(\"%s\", \"%s\", %i);\n", name, value, flags); + +// first check to see if it has already been defined + cvar = Cvar_FindVar (name); + if (cvar) + { + cvar->flags |= flags; + Cvar_SetQuick_Internal (cvar, value); + if(newdescription && (cvar->flags & CVAR_ALLOCATED)) + { + if(cvar->description != cvar_dummy_description) + Z_Free((char *)cvar->description); + + if(*newdescription) + cvar->description = (char *)Mem_strdup(zonemempool, newdescription); + else + cvar->description = cvar_dummy_description; + } + return cvar; + } + +// check for pure evil + if (!*name) + { + Con_Printf("Cvar_Get: invalid variable name\n"); + return NULL; + } + +// check for overlap with a command + if (Cmd_Exists (name)) + { + Con_Printf("Cvar_Get: %s is a command\n", name); + return NULL; + } + +// allocate a new cvar, cvar name, and cvar string +// TODO: factorize the following code with the one at the end of Cvar_RegisterVariable() +// FIXME: these never get Z_Free'd + cvar = (cvar_t *)Z_Malloc(sizeof(cvar_t)); + cvar->flags = flags | CVAR_ALLOCATED; + cvar->name = (char *)Mem_strdup(zonemempool, name); + cvar->string = (char *)Mem_strdup(zonemempool, value); + cvar->defstring = (char *)Mem_strdup(zonemempool, value); + cvar->value = atof (cvar->string); + cvar->integer = (int) cvar->value; + + if(newdescription && *newdescription) + cvar->description = (char *)Mem_strdup(zonemempool, newdescription); + else + cvar->description = cvar_dummy_description; // actually checked by VM_cvar_type + +// link the variable in +// alphanumerical order + for( current = NULL, next = cvar_vars ; next && strcmp( next->name, cvar->name ) < 0 ; current = next, next = next->next ) + ; + if( current ) + current->next = cvar; + else + cvar_vars = cvar; + cvar->next = next; + + // link to head of list in this hash table index + hashindex = CRC_Block((const unsigned char *)cvar->name, strlen(cvar->name)) % CVAR_HASHSIZE; + cvar->nextonhashchain = cvar_hashtable[hashindex]; + cvar_hashtable[hashindex] = cvar; + + return cvar; +} + + +/* +============ +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\" [\"%s\"]\n", v->name, ((v->flags & CVAR_PRIVATE) ? "********"/*hunter2*/ : v->string), v->defstring); + return true; + } + + if (developer_extra.integer) + Con_DPrint("Cvar_Command: "); + + if (v->flags & CVAR_READONLY) + { + Con_Printf("%s is read-only\n", v->name); + return true; + } + Cvar_Set (v->name, Cmd_Argv(1)); + if (developer_extra.integer) + Con_DPrint("\n"); + return true; +} + + +void Cvar_UnlockDefaults (void) +{ + cvar_t *var; + // unlock the default values of all cvars + for (var = cvar_vars ; var ; var = var->next) + var->flags &= ~CVAR_DEFAULTSET; +} + + +void Cvar_LockDefaults_f (void) +{ + cvar_t *var; + // lock in the default values of all cvars + for (var = cvar_vars ; var ; var = var->next) + { + if (!(var->flags & CVAR_DEFAULTSET)) + { + size_t alloclen; + + //Con_Printf("locking cvar %s (%s -> %s)\n", var->name, var->string, var->defstring); + var->flags |= CVAR_DEFAULTSET; + Z_Free((char *)var->defstring); + alloclen = strlen(var->string) + 1; + var->defstring = (char *)Z_Malloc(alloclen); + memcpy((char *)var->defstring, var->string, alloclen); + } + } +} + +void Cvar_SaveInitState(void) +{ + cvar_t *c; + for (c = cvar_vars;c;c = c->next) + { + c->initstate = true; + c->initflags = c->flags; + c->initdefstring = Mem_strdup(zonemempool, c->defstring); + c->initstring = Mem_strdup(zonemempool, c->string); + c->initvalue = c->value; + c->initinteger = c->integer; + VectorCopy(c->vector, c->initvector); + } +} + +void Cvar_RestoreInitState(void) +{ + int hashindex; + cvar_t *c, **cp; + cvar_t *c2, **cp2; + for (cp = &cvar_vars;(c = *cp);) + { + if (c->initstate) + { + // restore this cvar, it existed at init + if (((c->flags ^ c->initflags) & CVAR_MAXFLAGSVAL) + || strcmp(c->defstring ? c->defstring : "", c->initdefstring ? c->initdefstring : "") + || strcmp(c->string ? c->string : "", c->initstring ? c->initstring : "")) + { + Con_DPrintf("Cvar_RestoreInitState: Restoring cvar \"%s\"\n", c->name); + if (c->defstring) + Z_Free((char *)c->defstring); + c->defstring = Mem_strdup(zonemempool, c->initdefstring); + if (c->string) + Z_Free((char *)c->string); + c->string = Mem_strdup(zonemempool, c->initstring); + } + c->flags = c->initflags; + c->value = c->initvalue; + c->integer = c->initinteger; + VectorCopy(c->initvector, c->vector); + cp = &c->next; + } + else + { + if (!(c->flags & CVAR_ALLOCATED)) + { + Con_DPrintf("Cvar_RestoreInitState: Unable to destroy cvar \"%s\", it was registered after init!\n", c->name); + cp = &c->next; + continue; + } + // remove this cvar, it did not exist at init + Con_DPrintf("Cvar_RestoreInitState: Destroying cvar \"%s\"\n", c->name); + // unlink struct from hash + hashindex = CRC_Block((const unsigned char *)c->name, strlen(c->name)) % CVAR_HASHSIZE; + for (cp2 = &cvar_hashtable[hashindex];(c2 = *cp2);) + { + if (c2 == c) + { + *cp2 = c2->nextonhashchain; + break; + } + else + cp2 = &c2->nextonhashchain; + } + // unlink struct from main list + *cp = c->next; + // free strings + if (c->defstring) + Z_Free((char *)c->defstring); + if (c->string) + Z_Free((char *)c->string); + if (c->description && c->description != cvar_dummy_description) + Z_Free((char *)c->description); + // free struct + Z_Free(c); + } + } +} + +void Cvar_ResetToDefaults_All_f (void) +{ + cvar_t *var; + // restore the default values of all cvars + for (var = cvar_vars ; var ; var = var->next) + if((var->flags & CVAR_NORESETTODEFAULTS) == 0) + Cvar_SetQuick(var, var->defstring); +} + + +void Cvar_ResetToDefaults_NoSaveOnly_f (void) +{ + cvar_t *var; + // restore the default values of all cvars + for (var = cvar_vars ; var ; var = var->next) + if ((var->flags & (CVAR_NORESETTODEFAULTS | CVAR_SAVE)) == 0) + Cvar_SetQuick(var, var->defstring); +} + + +void Cvar_ResetToDefaults_SaveOnly_f (void) +{ + cvar_t *var; + // restore the default values of all cvars + for (var = cvar_vars ; var ; var = var->next) + if ((var->flags & (CVAR_NORESETTODEFAULTS | CVAR_SAVE)) == CVAR_SAVE) + Cvar_SetQuick(var, var->defstring); +} + + +/* +============ +Cvar_WriteVariables + +Writes lines containing "set variable value" for all variables +with the archive flag set to true. +============ +*/ +void Cvar_WriteVariables (qfile_t *f) +{ + cvar_t *var; + char buf1[MAX_INPUTLINE], buf2[MAX_INPUTLINE]; + + // don't save cvars that match their default value + for (var = cvar_vars ; var ; var = var->next) + if ((var->flags & CVAR_SAVE) && (strcmp(var->string, var->defstring) || ((var->flags & CVAR_ALLOCATED) && !(var->flags & CVAR_DEFAULTSET)))) + { + Cmd_QuoteString(buf1, sizeof(buf1), var->name, "\"\\$", false); + Cmd_QuoteString(buf2, sizeof(buf2), var->string, "\"\\$", false); + FS_Printf(f, "%s\"%s\" \"%s\"\n", var->flags & CVAR_ALLOCATED ? "seta " : "", buf1, buf2); + } +} + + +// Added by EvilTypeGuy eviltypeguy@qeradiant.com +// 2000-01-09 CvarList command By Matthias "Maddes" Buecher, http://www.inside3d.com/qip/ +/* +========= +Cvar_List +========= +*/ +void Cvar_List_f (void) +{ + cvar_t *cvar; + const char *partial; + size_t len; + int count; + qboolean ispattern; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = strlen(partial); + ispattern = (strchr(partial, '*') || strchr(partial, '?')); + } + else + { + partial = NULL; + len = 0; + ispattern = false; + } + + count = 0; + for (cvar = cvar_vars; cvar; cvar = cvar->next) + { + if (len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp (partial,cvar->name,len))) + continue; + + Con_Printf("%s is \"%s\" [\"%s\"] %s\n", cvar->name, ((cvar->flags & CVAR_PRIVATE) ? "********"/*hunter2*/ : cvar->string), cvar->defstring, cvar->description); + count++; + } + + if (len) + { + if(ispattern) + Con_Printf("%i cvar%s matching \"%s\"\n", count, (count > 1) ? "s" : "", partial); + else + Con_Printf("%i cvar%s beginning with \"%s\"\n", count, (count > 1) ? "s" : "", partial); + } + else + Con_Printf("%i cvar(s)\n", count); +} +// 2000-01-09 CvarList command by Maddes + +void Cvar_Set_f (void) +{ + cvar_t *cvar; + + // make sure it's the right number of parameters + if (Cmd_Argc() < 3) + { + Con_Printf("Set: wrong number of parameters, usage: set []\n"); + return; + } + + // check if it's read-only + cvar = Cvar_FindVar(Cmd_Argv(1)); + if (cvar && cvar->flags & CVAR_READONLY) + { + Con_Printf("Set: %s is read-only\n", cvar->name); + return; + } + + if (developer_extra.integer) + Con_DPrint("Set: "); + + // all looks ok, create/modify the cvar + Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), 0, Cmd_Argc() > 3 ? Cmd_Argv(3) : NULL); +} + +void Cvar_SetA_f (void) +{ + cvar_t *cvar; + + // make sure it's the right number of parameters + if (Cmd_Argc() < 3) + { + Con_Printf("SetA: wrong number of parameters, usage: seta []\n"); + return; + } + + // check if it's read-only + cvar = Cvar_FindVar(Cmd_Argv(1)); + if (cvar && cvar->flags & CVAR_READONLY) + { + Con_Printf("SetA: %s is read-only\n", cvar->name); + return; + } + + if (developer_extra.integer) + Con_DPrint("SetA: "); + + // all looks ok, create/modify the cvar + Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), CVAR_SAVE, Cmd_Argc() > 3 ? Cmd_Argv(3) : NULL); +} + +void Cvar_Del_f (void) +{ + int i; + cvar_t *cvar, *parent, **link, *prev; + + if(Cmd_Argc() < 2) + { + Con_Printf("Del: wrong number of parameters, useage: unset [ ...]\n"); + return; + } + for(i = 1; i < Cmd_Argc(); ++i) + { + cvar = Cvar_FindVarLink(Cmd_Argv(i), &parent, &link, &prev); + if(!cvar) + { + Con_Printf("Del: %s is not defined\n", Cmd_Argv(i)); + continue; + } + if(cvar->flags & CVAR_READONLY) + { + Con_Printf("Del: %s is read-only\n", cvar->name); + continue; + } + if(!(cvar->flags & CVAR_ALLOCATED)) + { + Con_Printf("Del: %s is static and cannot be deleted\n", cvar->name); + continue; + } + if(cvar == cvar_vars) + { + cvar_vars = cvar->next; + } + else + { + // in this case, prev must be set, otherwise there has been some inconsistensy + // elsewhere already... should I still check for prev != NULL? + prev->next = cvar->next; + } + + if(parent) + parent->nextonhashchain = cvar->nextonhashchain; + else if(link) + *link = cvar->nextonhashchain; + + if(cvar->description != cvar_dummy_description) + Z_Free((char *)cvar->description); + + Z_Free((char *)cvar->name); + Z_Free((char *)cvar->string); + Z_Free((char *)cvar->defstring); + Z_Free(cvar); + } +} + +#ifdef FILLALLCVARSWITHRUBBISH +void Cvar_FillAll_f() +{ + char *buf, *p, *q; + int n, i; + cvar_t *var; + qboolean verify; + if(Cmd_Argc() != 2) + { + Con_Printf("Usage: %s length to plant rubbish\n", Cmd_Argv(0)); + Con_Printf("Usage: %s -length to verify that the rubbish is still there\n", Cmd_Argv(0)); + return; + } + n = atoi(Cmd_Argv(1)); + verify = (n < 0); + if(verify) + n = -n; + buf = Z_Malloc(n + 1); + buf[n] = 0; + for(var = cvar_vars; var; var = var->next) + { + for(i = 0, p = buf, q = var->name; i < n; ++i) + { + *p++ = *q++; + if(!*q) + q = var->name; + } + if(verify && strcmp(var->string, buf)) + { + Con_Printf("\n%s does not contain the right rubbish, either this is the first run or a possible overrun was detected, or something changed it intentionally; it DOES contain: %s\n", var->name, var->string); + } + Cvar_SetQuick(var, buf); + } + Z_Free(buf); +} +#endif /* FILLALLCVARSWITHRUBBISH */ diff --git a/app/jni/cvar.h b/app/jni/cvar.h new file mode 100644 index 0000000..4fd177d --- /dev/null +++ b/app/jni/cvar.h @@ -0,0 +1,245 @@ +/* +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. +*/ + +#ifndef CVAR_H +#define CVAR_H + +// cvar flags + +#define CVAR_SAVE 1 +#define CVAR_NOTIFY 2 +#define CVAR_READONLY 4 +#define CVAR_SERVERINFO 8 +#define CVAR_USERINFO 16 +// CVAR_PRIVATE means do not $ expand or sendcvar this cvar under any circumstances (rcon_password uses this) +#define CVAR_PRIVATE 32 +// this means that this cvar should update a userinfo key but the name does not correspond directly to the userinfo key to update, and may require additional conversion ("_cl_color" for example should update "topcolor" and "bottomcolor") +#define CVAR_NQUSERINFOHACK 64 +// used to determine if flags is valid +#define CVAR_NORESETTODEFAULTS 128 +// for engine-owned cvars that must not be reset on gametype switch (e.g. scr_screenshot_name, which otherwise isn't set to the mod name properly) +#define CVAR_MAXFLAGSVAL 255 +// for internal use only! +#define CVAR_DEFAULTSET (1<<30) +#define CVAR_ALLOCATED (1<<31) + +/* +// type of a cvar for menu purposes +#define CVARMENUTYPE_FLOAT 1 +#define CVARMENUTYPE_INTEGER 2 +#define CVARMENUTYPE_SLIDER 3 +#define CVARMENUTYPE_BOOL 4 +#define CVARMENUTYPE_STRING 5 +#define CVARMENUTYPE_OPTION 6 + +// which menu to put a cvar in +#define CVARMENU_GRAPHICS 1 +#define CVARMENU_SOUND 2 +#define CVARMENU_INPUT 3 +#define CVARMENU_NETWORK 4 +#define CVARMENU_SERVER 5 + +#define MAX_CVAROPTIONS 16 + +typedef struct cvaroption_s +{ + int value; + const char *name; +} +cvaroption_t; + +typedef struct menucvar_s +{ + int type; + float valuemin, valuemax, valuestep; + int numoptions; + cvaroption_t optionlist[MAX_CVAROPTIONS]; +} +menucvar_t; +*/ + +typedef struct cvar_s +{ + int flags; + + const char *name; + + const char *string; + const char *description; + int integer; + float value; + float vector[3]; + + const char *defstring; + + // values at init (for Cvar_RestoreInitState) + qboolean initstate; // indicates this existed at init + int initflags; + const char *initstring; + const char *initdescription; + int initinteger; + float initvalue; + float initvector[3]; + const char *initdefstring; + + unsigned int globaldefindex_progid[3]; + int globaldefindex[3]; + int globaldefindex_stringno[3]; + + //menucvar_t menuinfo; + struct cvar_s *next; + struct cvar_s *nextonhashchain; +} cvar_t; + +/* +void Cvar_MenuSlider(cvar_t *variable, int menu, float slider_min, float slider_max, float slider_step); +void Cvar_MenuBool(cvar_t *variable, int menu, const char *name_false, const char *name_true); +void Cvar_MenuFloat(cvar_t *variable, int menu, float range_min, float range_max); +void Cvar_MenuInteger(cvar_t *variable, int menu, int range_min, int range_max); +void Cvar_MenuString(cvar_t *variable, int menu); +void Cvar_MenuOption(cvar_t *variable, int menu, int value[16], const char *name[16]); +*/ + +/// registers a cvar that already has the name, string, and optionally the +/// archive elements set. +void Cvar_RegisterVariable (cvar_t *variable); + +/// equivelant to " " typed at the console +void Cvar_Set (const char *var_name, const char *value); + +/// expands value to a string and calls Cvar_Set +void Cvar_SetValue (const char *var_name, float value); + +void Cvar_SetQuick (cvar_t *var, const char *value); +void Cvar_SetValueQuick (cvar_t *var, float value); + +float Cvar_VariableValueOr (const char *var_name, float def); +// returns def if not defined + +float Cvar_VariableValue (const char *var_name); +// returns 0 if not defined or non numeric + +const char *Cvar_VariableStringOr (const char *var_name, const char *def); +// returns def if not defined + +const char *Cvar_VariableString (const char *var_name); +// returns an empty string if not defined + +const char *Cvar_VariableDefString (const char *var_name); +// returns an empty string if not defined + +const char *Cvar_VariableDescription (const char *var_name); +// returns an empty string if not defined + +const char *Cvar_CompleteVariable (const char *partial); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +void Cvar_CompleteCvarPrint (const char *partial); + +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_SaveInitState(void); +void Cvar_RestoreInitState(void); + +void Cvar_UnlockDefaults (void); +void Cvar_LockDefaults_f (void); +void Cvar_ResetToDefaults_All_f (void); +void Cvar_ResetToDefaults_NoSaveOnly_f (void); +void Cvar_ResetToDefaults_SaveOnly_f (void); + +void Cvar_WriteVariables (qfile_t *f); +// Writes lines containing "set variable value" for all variables +// with the archive flag set to true. + +cvar_t *Cvar_FindVar (const char *var_name); +cvar_t *Cvar_FindVarAfter (const char *prev_var_name, int neededflags); + +int Cvar_CompleteCountPossible (const char *partial); +const char **Cvar_CompleteBuildList (const char *partial); +// Added by EvilTypeGuy - functions for tab completion system +// Thanks to Fett erich@heintz.com +// Thanks to taniwha + +/// Prints a list of Cvars including a count of them to the user console +/// Referenced in cmd.c in Cmd_Init hence it's inclusion here. +/// Added by EvilTypeGuy eviltypeguy@qeradiant.com +/// Thanks to Matthias "Maddes" Buecher, http://www.inside3d.com/qip/ +void Cvar_List_f (void); + +void Cvar_Set_f (void); +void Cvar_SetA_f (void); +void Cvar_Del_f (void); +// commands to create new cvars (or set existing ones) +// seta creates an archived cvar (saved to config) + +/// allocates a cvar by name and returns its address, +/// or merely sets its value if it already exists. +cvar_t *Cvar_Get (const char *name, const char *value, int flags, const char *newdescription); + +extern const char *cvar_dummy_description; // ALWAYS the same pointer +extern cvar_t *cvar_vars; // used to list all cvars + +void Cvar_UpdateAllAutoCvars(void); // updates ALL autocvars of the active prog to the cvar values (savegame loading) + +#ifdef FILLALLCVARSWITHRUBBISH +void Cvar_FillAll_f(); +#endif /* FILLALLCVARSWITHRUBBISH */ + +#endif + diff --git a/app/jni/dpsoftrast.c b/app/jni/dpsoftrast.c new file mode 100644 index 0000000..039e7fc --- /dev/null +++ b/app/jni/dpsoftrast.c @@ -0,0 +1,5690 @@ +#include +#include +#define _USE_MATH_DEFINES +#include +#include "quakedef.h" +#include "thread.h" +#include "dpsoftrast.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4324) +#endif + +#ifndef __cplusplus +typedef qboolean bool; +#endif + +#define ALIGN_SIZE 16 +#define ATOMIC_SIZE 4 + +#ifdef SSE_POSSIBLE + #if defined(__APPLE__) + #include + #define ALIGN(var) var __attribute__((__aligned__(16))) + #define ATOMIC(var) var __attribute__((__aligned__(4))) + #define MEMORY_BARRIER (_mm_sfence()) + #define ATOMIC_COUNTER volatile int32_t + #define ATOMIC_INCREMENT(counter) (OSAtomicIncrement32Barrier(&(counter))) + #define ATOMIC_DECREMENT(counter) (OSAtomicDecrement32Barrier(&(counter))) + #define ATOMIC_ADD(counter, val) ((void)OSAtomicAdd32Barrier((val), &(counter))) + #elif defined(__GNUC__) && defined(WIN32) + #define ALIGN(var) var __attribute__((__aligned__(16))) + #define ATOMIC(var) var __attribute__((__aligned__(4))) + #define MEMORY_BARRIER (_mm_sfence()) + //(__sync_synchronize()) + #define ATOMIC_COUNTER volatile LONG + // this LONG * cast serves to fix an issue with broken mingw + // packages on Ubuntu; these only declare the function to take + // a LONG *, causing a compile error here. This seems to be + // error- and warn-free on platforms that DO declare + // InterlockedIncrement correctly, like mingw on Windows. + #define ATOMIC_INCREMENT(counter) (InterlockedIncrement((LONG *) &(counter))) + #define ATOMIC_DECREMENT(counter) (InterlockedDecrement((LONG *) &(counter))) + #define ATOMIC_ADD(counter, val) ((void)InterlockedExchangeAdd((LONG *) &(counter), (val))) + #elif defined(__GNUC__) + #define ALIGN(var) var __attribute__((__aligned__(16))) + #define ATOMIC(var) var __attribute__((__aligned__(4))) + #define MEMORY_BARRIER (_mm_sfence()) + //(__sync_synchronize()) + #define ATOMIC_COUNTER volatile int + #define ATOMIC_INCREMENT(counter) (__sync_add_and_fetch(&(counter), 1)) + #define ATOMIC_DECREMENT(counter) (__sync_add_and_fetch(&(counter), -1)) + #define ATOMIC_ADD(counter, val) ((void)__sync_fetch_and_add(&(counter), (val))) + #elif defined(_MSC_VER) + #define ALIGN(var) __declspec(align(16)) var + #define ATOMIC(var) __declspec(align(4)) var + #define MEMORY_BARRIER (_mm_sfence()) + //(MemoryBarrier()) + #define ATOMIC_COUNTER volatile LONG + #define ATOMIC_INCREMENT(counter) (InterlockedIncrement(&(counter))) + #define ATOMIC_DECREMENT(counter) (InterlockedDecrement(&(counter))) + #define ATOMIC_ADD(counter, val) ((void)InterlockedExchangeAdd(&(counter), (val))) + #endif +#endif + +#ifndef ALIGN +#define ALIGN(var) var +#endif +#ifndef ATOMIC +#define ATOMIC(var) var +#endif +#ifndef MEMORY_BARRIER +#define MEMORY_BARRIER ((void)0) +#endif +#ifndef ATOMIC_COUNTER +#define ATOMIC_COUNTER int +#endif +#ifndef ATOMIC_INCREMENT +#define ATOMIC_INCREMENT(counter) (++(counter)) +#endif +#ifndef ATOMIC_DECREMENT +#define ATOMIC_DECREMENT(counter) (--(counter)) +#endif +#ifndef ATOMIC_ADD +#define ATOMIC_ADD(counter, val) ((void)((counter) += (val))) +#endif + +#ifdef SSE_POSSIBLE +#include + +#if defined(__GNUC__) && (__GNUC < 4 || __GNUC_MINOR__ < 6) && !defined(__clang__) + #define _mm_cvtss_f32(val) (__builtin_ia32_vec_ext_v4sf ((__v4sf)(val), 0)) +#endif + +#define MM_MALLOC(size) _mm_malloc(size, ALIGN_SIZE) + +static void *MM_CALLOC(size_t nmemb, size_t size) +{ + void *ptr = _mm_malloc(nmemb*size, ALIGN_SIZE); + if (ptr != NULL) memset(ptr, 0, nmemb*size); + return ptr; +} + +#define MM_FREE _mm_free +#else +#define MM_MALLOC(size) malloc(size) +#define MM_CALLOC(nmemb, size) calloc(nmemb, size) +#define MM_FREE free +#endif + +typedef enum DPSOFTRAST_ARRAY_e +{ + DPSOFTRAST_ARRAY_POSITION, + DPSOFTRAST_ARRAY_COLOR, + DPSOFTRAST_ARRAY_TEXCOORD0, + DPSOFTRAST_ARRAY_TEXCOORD1, + DPSOFTRAST_ARRAY_TEXCOORD2, + DPSOFTRAST_ARRAY_TEXCOORD3, + DPSOFTRAST_ARRAY_TEXCOORD4, + DPSOFTRAST_ARRAY_TEXCOORD5, + DPSOFTRAST_ARRAY_TEXCOORD6, + DPSOFTRAST_ARRAY_TEXCOORD7, + DPSOFTRAST_ARRAY_TOTAL +} +DPSOFTRAST_ARRAY; + +typedef struct DPSOFTRAST_Texture_s +{ + int flags; + int width; + int height; + int depth; + int sides; + DPSOFTRAST_TEXTURE_FILTER filter; + int mipmaps; + int size; + ATOMIC_COUNTER binds; + unsigned char *bytes; + int mipmap[DPSOFTRAST_MAXMIPMAPS][5]; +} +DPSOFTRAST_Texture; + +#define COMMAND_SIZE ALIGN_SIZE +#define COMMAND_ALIGN(var) ALIGN(var) + +typedef COMMAND_ALIGN(struct DPSOFTRAST_Command_s +{ + unsigned char opcode; + unsigned short commandsize; +} +DPSOFTRAST_Command); + +enum { DPSOFTRAST_OPCODE_Reset = 0 }; + +#define DEFCOMMAND(opcodeval, name, fields) \ + enum { DPSOFTRAST_OPCODE_##name = opcodeval }; \ + typedef COMMAND_ALIGN(struct DPSOFTRAST_Command_##name##_s \ + { \ + unsigned char opcode; \ + unsigned short commandsize; \ + fields \ + } DPSOFTRAST_Command_##name ); + +#define DPSOFTRAST_DRAW_MAXCOMMANDPOOL 2097152 +#define DPSOFTRAST_DRAW_MAXCOMMANDSIZE 16384 + +typedef ALIGN(struct DPSOFTRAST_State_Command_Pool_s +{ + int freecommand; + int usedcommands; + ALIGN(unsigned char commands[DPSOFTRAST_DRAW_MAXCOMMANDPOOL]); +} +DPSOFTRAST_State_Command_Pool); + +typedef ALIGN(struct DPSOFTRAST_State_Triangle_s +{ + unsigned char mip[DPSOFTRAST_MAXTEXTUREUNITS]; // texcoord to screen space density values (for picking mipmap of textures) + float w[3]; + ALIGN(float attribs[DPSOFTRAST_ARRAY_TOTAL][3][4]); +} +DPSOFTRAST_State_Triangle); + +#define DPSOFTRAST_CALCATTRIB(triangle, span, data, slope, arrayindex) { \ + slope = _mm_load_ps((triangle)->attribs[arrayindex][0]); \ + data = _mm_add_ps(_mm_load_ps((triangle)->attribs[arrayindex][2]), \ + _mm_add_ps(_mm_mul_ps(_mm_set1_ps((span)->x), slope), \ + _mm_mul_ps(_mm_set1_ps((span)->y), _mm_load_ps((triangle)->attribs[arrayindex][1])))); \ +} +#define DPSOFTRAST_CALCATTRIB4F(triangle, span, data, slope, arrayindex) { \ + slope[0] = (triangle)->attribs[arrayindex][0][0]; \ + slope[1] = (triangle)->attribs[arrayindex][0][1]; \ + slope[2] = (triangle)->attribs[arrayindex][0][2]; \ + slope[3] = (triangle)->attribs[arrayindex][0][3]; \ + data[0] = (triangle)->attribs[arrayindex][2][0] + (span->x)*slope[0] + (span->y)*(triangle)->attribs[arrayindex][1][0]; \ + data[1] = (triangle)->attribs[arrayindex][2][1] + (span->x)*slope[1] + (span->y)*(triangle)->attribs[arrayindex][1][1]; \ + data[2] = (triangle)->attribs[arrayindex][2][2] + (span->x)*slope[2] + (span->y)*(triangle)->attribs[arrayindex][1][2]; \ + data[3] = (triangle)->attribs[arrayindex][2][3] + (span->x)*slope[3] + (span->y)*(triangle)->attribs[arrayindex][1][3]; \ +} + +#define DPSOFTRAST_DRAW_MAXSUBSPAN 16 + +typedef ALIGN(struct DPSOFTRAST_State_Span_s +{ + int triangle; // triangle this span was generated by + int x; // framebuffer x coord + int y; // framebuffer y coord + int startx; // usable range (according to pixelmask) + int endx; // usable range (according to pixelmask) + unsigned char *pixelmask; // true for pixels that passed depth test, false for others + int depthbase; // depthbuffer value at x (add depthslope*startx to get first pixel's depthbuffer value) + int depthslope; // depthbuffer value pixel delta +} +DPSOFTRAST_State_Span); + +#define DPSOFTRAST_DRAW_MAXSPANS 1024 +#define DPSOFTRAST_DRAW_MAXTRIANGLES 128 +#define DPSOFTRAST_DRAW_MAXSPANLENGTH 256 + +#define DPSOFTRAST_VALIDATE_FB 1 +#define DPSOFTRAST_VALIDATE_DEPTHFUNC 2 +#define DPSOFTRAST_VALIDATE_BLENDFUNC 4 +#define DPSOFTRAST_VALIDATE_DRAW (DPSOFTRAST_VALIDATE_FB | DPSOFTRAST_VALIDATE_DEPTHFUNC | DPSOFTRAST_VALIDATE_BLENDFUNC) + +typedef enum DPSOFTRAST_BLENDMODE_e +{ + DPSOFTRAST_BLENDMODE_OPAQUE, + DPSOFTRAST_BLENDMODE_ALPHA, + DPSOFTRAST_BLENDMODE_ADDALPHA, + DPSOFTRAST_BLENDMODE_ADD, + DPSOFTRAST_BLENDMODE_INVMOD, + DPSOFTRAST_BLENDMODE_MUL, + DPSOFTRAST_BLENDMODE_MUL2, + DPSOFTRAST_BLENDMODE_SUBALPHA, + DPSOFTRAST_BLENDMODE_PSEUDOALPHA, + DPSOFTRAST_BLENDMODE_INVADD, + DPSOFTRAST_BLENDMODE_TOTAL +} +DPSOFTRAST_BLENDMODE; + +typedef ALIGN(struct DPSOFTRAST_State_Thread_s +{ + void *thread; + int index; + + int cullface; + int colormask[4]; + int blendfunc[2]; + int blendsubtract; + int depthmask; + int depthtest; + int depthfunc; + int scissortest; + int viewport[4]; + int scissor[4]; + float depthrange[2]; + float polygonoffset[2]; + float clipplane[4]; + ALIGN(float fb_clipplane[4]); + + int shader_mode; + int shader_permutation; + int shader_exactspecularmath; + + DPSOFTRAST_Texture *texbound[DPSOFTRAST_MAXTEXTUREUNITS]; + + ALIGN(float uniform4f[DPSOFTRAST_UNIFORM_TOTAL*4]); + int uniform1i[DPSOFTRAST_UNIFORM_TOTAL]; + + // DPSOFTRAST_VALIDATE_ flags + int validate; + + // derived values (DPSOFTRAST_VALIDATE_FB) + int fb_colormask; + int fb_scissor[4]; + ALIGN(float fb_viewportcenter[4]); + ALIGN(float fb_viewportscale[4]); + + // derived values (DPSOFTRAST_VALIDATE_DEPTHFUNC) + int fb_depthfunc; + + // derived values (DPSOFTRAST_VALIDATE_BLENDFUNC) + int fb_blendmode; + + // band boundaries + int miny1; + int maxy1; + int miny2; + int maxy2; + + ATOMIC(volatile int commandoffset); + + volatile bool waiting; + volatile bool starving; + void *waitcond; + void *drawcond; + void *drawmutex; + + int numspans; + int numtriangles; + DPSOFTRAST_State_Span spans[DPSOFTRAST_DRAW_MAXSPANS]; + DPSOFTRAST_State_Triangle triangles[DPSOFTRAST_DRAW_MAXTRIANGLES]; + unsigned char pixelmaskarray[DPSOFTRAST_DRAW_MAXSPANLENGTH+4]; // LordHavoc: padded to allow some termination bytes +} +DPSOFTRAST_State_Thread); + +typedef ALIGN(struct DPSOFTRAST_State_s +{ + int fb_width; + int fb_height; + unsigned int *fb_depthpixels; + unsigned int *fb_colorpixels[4]; + + int viewport[4]; + ALIGN(float fb_viewportcenter[4]); + ALIGN(float fb_viewportscale[4]); + + float color[4]; + ALIGN(float uniform4f[DPSOFTRAST_UNIFORM_TOTAL*4]); + int uniform1i[DPSOFTRAST_UNIFORM_TOTAL]; + + const float *pointer_vertex3f; + const float *pointer_color4f; + const unsigned char *pointer_color4ub; + const float *pointer_texcoordf[DPSOFTRAST_MAXTEXCOORDARRAYS]; + int stride_vertex; + int stride_color; + int stride_texcoord[DPSOFTRAST_MAXTEXCOORDARRAYS]; + int components_texcoord[DPSOFTRAST_MAXTEXCOORDARRAYS]; + DPSOFTRAST_Texture *texbound[DPSOFTRAST_MAXTEXTUREUNITS]; + + int firstvertex; + int numvertices; + float *post_array4f[DPSOFTRAST_ARRAY_TOTAL]; + float *screencoord4f; + int drawstarty; + int drawendy; + int drawclipped; + + int shader_mode; + int shader_permutation; + int shader_exactspecularmath; + + int texture_max; + int texture_end; + int texture_firstfree; + DPSOFTRAST_Texture *texture; + + int bigendian; + + // error reporting + const char *errorstring; + + bool usethreads; + int interlace; + int numthreads; + DPSOFTRAST_State_Thread *threads; + + ATOMIC(volatile int drawcommand); + + DPSOFTRAST_State_Command_Pool commandpool; +} +DPSOFTRAST_State); + +DPSOFTRAST_State dpsoftrast; + +#define DPSOFTRAST_DEPTHSCALE (1024.0f*1048576.0f) +#define DPSOFTRAST_DEPTHOFFSET (128.0f) +#define DPSOFTRAST_BGRA8_FROM_RGBA32F(r,g,b,a) (((int)(r * 255.0f + 0.5f) << 16) | ((int)(g * 255.0f + 0.5f) << 8) | (int)(b * 255.0f + 0.5f) | ((int)(a * 255.0f + 0.5f) << 24)) +#define DPSOFTRAST_DEPTH32_FROM_DEPTH32F(d) ((int)(DPSOFTRAST_DEPTHSCALE * (1-d))) + +static void DPSOFTRAST_Draw_DepthTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_State_Span *span); +static void DPSOFTRAST_Draw_DepthWrite(const DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Span *span); + +static void DPSOFTRAST_RecalcViewport(const int *viewport, float *fb_viewportcenter, float *fb_viewportscale) +{ + fb_viewportcenter[1] = viewport[0] + 0.5f * viewport[2] - 0.5f; + fb_viewportcenter[2] = dpsoftrast.fb_height - viewport[1] - 0.5f * viewport[3] - 0.5f; + fb_viewportcenter[3] = 0.5f; + fb_viewportcenter[0] = 0.0f; + fb_viewportscale[1] = 0.5f * viewport[2]; + fb_viewportscale[2] = -0.5f * viewport[3]; + fb_viewportscale[3] = 0.5f; + fb_viewportscale[0] = 1.0f; +} + +static void DPSOFTRAST_RecalcThread(DPSOFTRAST_State_Thread *thread) +{ + if (dpsoftrast.interlace) + { + thread->miny1 = (thread->index*dpsoftrast.fb_height)/(2*dpsoftrast.numthreads); + thread->maxy1 = ((thread->index+1)*dpsoftrast.fb_height)/(2*dpsoftrast.numthreads); + thread->miny2 = ((dpsoftrast.numthreads+thread->index)*dpsoftrast.fb_height)/(2*dpsoftrast.numthreads); + thread->maxy2 = ((dpsoftrast.numthreads+thread->index+1)*dpsoftrast.fb_height)/(2*dpsoftrast.numthreads); + } + else + { + thread->miny1 = thread->miny2 = (thread->index*dpsoftrast.fb_height)/dpsoftrast.numthreads; + thread->maxy1 = thread->maxy2 = ((thread->index+1)*dpsoftrast.fb_height)/dpsoftrast.numthreads; + } +} + +static void DPSOFTRAST_RecalcClipPlane(DPSOFTRAST_State_Thread *thread) +{ + thread->fb_clipplane[0] = thread->clipplane[0] / thread->fb_viewportscale[1]; + thread->fb_clipplane[1] = thread->clipplane[1] / thread->fb_viewportscale[2]; + thread->fb_clipplane[2] = thread->clipplane[2] / thread->fb_viewportscale[3]; + thread->fb_clipplane[3] = thread->clipplane[3] / thread->fb_viewportscale[0]; + thread->fb_clipplane[3] -= thread->fb_viewportcenter[1]*thread->fb_clipplane[0] + thread->fb_viewportcenter[2]*thread->fb_clipplane[1] + thread->fb_viewportcenter[3]*thread->fb_clipplane[2] + thread->fb_viewportcenter[0]*thread->fb_clipplane[3]; +} + +static void DPSOFTRAST_RecalcFB(DPSOFTRAST_State_Thread *thread) +{ + // calculate framebuffer scissor, viewport, viewport clipped by scissor, + // and viewport projection values + int x1, x2; + int y1, y2; + x1 = thread->scissor[0]; + x2 = thread->scissor[0] + thread->scissor[2]; + y1 = dpsoftrast.fb_height - thread->scissor[1] - thread->scissor[3]; + y2 = dpsoftrast.fb_height - thread->scissor[1]; + if (!thread->scissortest) {x1 = 0;y1 = 0;x2 = dpsoftrast.fb_width;y2 = dpsoftrast.fb_height;} + if (x1 < 0) x1 = 0; + if (x2 > dpsoftrast.fb_width) x2 = dpsoftrast.fb_width; + if (y1 < 0) y1 = 0; + if (y2 > dpsoftrast.fb_height) y2 = dpsoftrast.fb_height; + thread->fb_scissor[0] = x1; + thread->fb_scissor[1] = y1; + thread->fb_scissor[2] = x2 - x1; + thread->fb_scissor[3] = y2 - y1; + + DPSOFTRAST_RecalcViewport(thread->viewport, thread->fb_viewportcenter, thread->fb_viewportscale); + DPSOFTRAST_RecalcClipPlane(thread); + DPSOFTRAST_RecalcThread(thread); +} + +static void DPSOFTRAST_RecalcDepthFunc(DPSOFTRAST_State_Thread *thread) +{ + thread->fb_depthfunc = thread->depthtest ? thread->depthfunc : GL_ALWAYS; +} + +static void DPSOFTRAST_RecalcBlendFunc(DPSOFTRAST_State_Thread *thread) +{ + if (thread->blendsubtract) + { + switch ((thread->blendfunc[0]<<16)|thread->blendfunc[1]) + { + #define BLENDFUNC(sfactor, dfactor, blendmode) \ + case (sfactor<<16)|dfactor: thread->fb_blendmode = blendmode; break; + BLENDFUNC(GL_SRC_ALPHA, GL_ONE, DPSOFTRAST_BLENDMODE_SUBALPHA) + default: thread->fb_blendmode = DPSOFTRAST_BLENDMODE_OPAQUE; break; + } + } + else + { + switch ((thread->blendfunc[0]<<16)|thread->blendfunc[1]) + { + BLENDFUNC(GL_ONE, GL_ZERO, DPSOFTRAST_BLENDMODE_OPAQUE) + BLENDFUNC(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, DPSOFTRAST_BLENDMODE_ALPHA) + BLENDFUNC(GL_SRC_ALPHA, GL_ONE, DPSOFTRAST_BLENDMODE_ADDALPHA) + BLENDFUNC(GL_ONE, GL_ONE, DPSOFTRAST_BLENDMODE_ADD) + BLENDFUNC(GL_ZERO, GL_ONE_MINUS_SRC_COLOR, DPSOFTRAST_BLENDMODE_INVMOD) + BLENDFUNC(GL_ZERO, GL_SRC_COLOR, DPSOFTRAST_BLENDMODE_MUL) + BLENDFUNC(GL_DST_COLOR, GL_ZERO, DPSOFTRAST_BLENDMODE_MUL) + BLENDFUNC(GL_DST_COLOR, GL_SRC_COLOR, DPSOFTRAST_BLENDMODE_MUL2) + BLENDFUNC(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, DPSOFTRAST_BLENDMODE_PSEUDOALPHA) + BLENDFUNC(GL_ONE_MINUS_DST_COLOR, GL_ONE, DPSOFTRAST_BLENDMODE_INVADD) + default: thread->fb_blendmode = DPSOFTRAST_BLENDMODE_OPAQUE; break; + } + } +} + +#define DPSOFTRAST_ValidateQuick(thread, f) ((thread->validate & (f)) ? (DPSOFTRAST_Validate(thread, f), 0) : 0) + +static void DPSOFTRAST_Validate(DPSOFTRAST_State_Thread *thread, int mask) +{ + mask &= thread->validate; + if (!mask) + return; + if (mask & DPSOFTRAST_VALIDATE_FB) + { + thread->validate &= ~DPSOFTRAST_VALIDATE_FB; + DPSOFTRAST_RecalcFB(thread); + } + if (mask & DPSOFTRAST_VALIDATE_DEPTHFUNC) + { + thread->validate &= ~DPSOFTRAST_VALIDATE_DEPTHFUNC; + DPSOFTRAST_RecalcDepthFunc(thread); + } + if (mask & DPSOFTRAST_VALIDATE_BLENDFUNC) + { + thread->validate &= ~DPSOFTRAST_VALIDATE_BLENDFUNC; + DPSOFTRAST_RecalcBlendFunc(thread); + } +} + +static DPSOFTRAST_Texture *DPSOFTRAST_Texture_GetByIndex(int index) +{ + if (index >= 1 && index < dpsoftrast.texture_end && dpsoftrast.texture[index].bytes) + return &dpsoftrast.texture[index]; + return NULL; +} + +static void DPSOFTRAST_Texture_Grow(void) +{ + DPSOFTRAST_Texture *oldtexture = dpsoftrast.texture; + DPSOFTRAST_State_Thread *thread; + int i; + int j; + DPSOFTRAST_Flush(); + // expand texture array as needed + if (dpsoftrast.texture_max < 1024) + dpsoftrast.texture_max = 1024; + else + dpsoftrast.texture_max *= 2; + dpsoftrast.texture = (DPSOFTRAST_Texture *)realloc(dpsoftrast.texture, dpsoftrast.texture_max * sizeof(DPSOFTRAST_Texture)); + for (i = 0; i < DPSOFTRAST_MAXTEXTUREUNITS; i++) + if (dpsoftrast.texbound[i]) + dpsoftrast.texbound[i] = dpsoftrast.texture + (dpsoftrast.texbound[i] - oldtexture); + for (j = 0; j < dpsoftrast.numthreads; j++) + { + thread = &dpsoftrast.threads[j]; + for (i = 0; i < DPSOFTRAST_MAXTEXTUREUNITS; i++) + if (thread->texbound[i]) + thread->texbound[i] = dpsoftrast.texture + (thread->texbound[i] - oldtexture); + } +} + +int DPSOFTRAST_Texture_New(int flags, int width, int height, int depth) +{ + int w; + int h; + int d; + int size; + int s; + int texnum; + int mipmaps; + int sides = (flags & DPSOFTRAST_TEXTURE_FLAG_CUBEMAP) ? 6 : 1; + int texformat = flags & DPSOFTRAST_TEXTURE_FORMAT_COMPAREMASK; + DPSOFTRAST_Texture *texture; + if (width*height*depth < 1) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: width, height or depth is less than 1"; + return 0; + } + if (width > DPSOFTRAST_TEXTURE_MAXSIZE || height > DPSOFTRAST_TEXTURE_MAXSIZE || depth > DPSOFTRAST_TEXTURE_MAXSIZE) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: texture size is too large"; + return 0; + } + switch(texformat) + { + case DPSOFTRAST_TEXTURE_FORMAT_BGRA8: + case DPSOFTRAST_TEXTURE_FORMAT_RGBA8: + case DPSOFTRAST_TEXTURE_FORMAT_ALPHA8: + break; + case DPSOFTRAST_TEXTURE_FORMAT_DEPTH: + if (flags & DPSOFTRAST_TEXTURE_FLAG_CUBEMAP) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FORMAT_DEPTH only permitted on 2D textures"; + return 0; + } + if (depth != 1) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FORMAT_DEPTH only permitted on 2D textures"; + return 0; + } + if ((flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP) && (texformat == DPSOFTRAST_TEXTURE_FORMAT_DEPTH)) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FORMAT_DEPTH does not permit mipmaps"; + return 0; + } + break; + } + if (depth != 1 && (flags & DPSOFTRAST_TEXTURE_FLAG_CUBEMAP)) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FLAG_CUBEMAP can not be used on 3D textures"; + return 0; + } + if (depth != 1 && (flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP)) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FLAG_MIPMAP can not be used on 3D textures"; + return 0; + } + if (depth != 1 && (flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP)) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FLAG_MIPMAP can not be used on 3D textures"; + return 0; + } + if ((flags & DPSOFTRAST_TEXTURE_FLAG_CUBEMAP) && (flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP)) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: DPSOFTRAST_TEXTURE_FLAG_MIPMAP can not be used on cubemap textures"; + return 0; + } + if ((width & (width-1)) || (height & (height-1)) || (depth & (depth-1))) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_New: dimensions are not power of two"; + return 0; + } + // find first empty slot in texture array + for (texnum = dpsoftrast.texture_firstfree;texnum < dpsoftrast.texture_end;texnum++) + if (!dpsoftrast.texture[texnum].bytes) + break; + dpsoftrast.texture_firstfree = texnum + 1; + if (dpsoftrast.texture_max <= texnum) + DPSOFTRAST_Texture_Grow(); + if (dpsoftrast.texture_end <= texnum) + dpsoftrast.texture_end = texnum + 1; + texture = &dpsoftrast.texture[texnum]; + memset(texture, 0, sizeof(*texture)); + texture->flags = flags; + texture->width = width; + texture->height = height; + texture->depth = depth; + texture->sides = sides; + texture->binds = 0; + w = width; + h = height; + d = depth; + size = 0; + mipmaps = 0; + for (;;) + { + s = w * h * d * sides * 4; + texture->mipmap[mipmaps][0] = size; + texture->mipmap[mipmaps][1] = s; + texture->mipmap[mipmaps][2] = w; + texture->mipmap[mipmaps][3] = h; + texture->mipmap[mipmaps][4] = d; + size += s; + mipmaps++; + if (w * h * d == 1 || !(flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP)) + break; + if (w > 1) w >>= 1; + if (h > 1) h >>= 1; + if (d > 1) d >>= 1; + } + texture->mipmaps = mipmaps; + texture->size = size; + + // allocate the pixels now + texture->bytes = (unsigned char *)MM_CALLOC(1, size); + + return texnum; +} +void DPSOFTRAST_Texture_Free(int index) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (texture->binds) + DPSOFTRAST_Flush(); + if (texture->bytes) + MM_FREE(texture->bytes); + texture->bytes = NULL; + memset(texture, 0, sizeof(*texture)); + // adjust the free range and used range + if (dpsoftrast.texture_firstfree > index) + dpsoftrast.texture_firstfree = index; + while (dpsoftrast.texture_end > 0 && dpsoftrast.texture[dpsoftrast.texture_end-1].bytes == NULL) + dpsoftrast.texture_end--; +} +static void DPSOFTRAST_Texture_CalculateMipmaps(int index) +{ + int i, x, y, z, w, layer0, layer1, row0, row1; + unsigned char *o, *i0, *i1, *i2, *i3; + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (texture->mipmaps <= 1) + return; + for (i = 1;i < texture->mipmaps;i++) + { + for (z = 0;z < texture->mipmap[i][4];z++) + { + layer0 = z*2; + layer1 = z*2+1; + if (layer1 >= texture->mipmap[i-1][4]) + layer1 = texture->mipmap[i-1][4]-1; + for (y = 0;y < texture->mipmap[i][3];y++) + { + row0 = y*2; + row1 = y*2+1; + if (row1 >= texture->mipmap[i-1][3]) + row1 = texture->mipmap[i-1][3]-1; + o = texture->bytes + texture->mipmap[i ][0] + 4*((texture->mipmap[i ][3] * z + y ) * texture->mipmap[i ][2]); + i0 = texture->bytes + texture->mipmap[i-1][0] + 4*((texture->mipmap[i-1][3] * layer0 + row0) * texture->mipmap[i-1][2]); + i1 = texture->bytes + texture->mipmap[i-1][0] + 4*((texture->mipmap[i-1][3] * layer0 + row1) * texture->mipmap[i-1][2]); + i2 = texture->bytes + texture->mipmap[i-1][0] + 4*((texture->mipmap[i-1][3] * layer1 + row0) * texture->mipmap[i-1][2]); + i3 = texture->bytes + texture->mipmap[i-1][0] + 4*((texture->mipmap[i-1][3] * layer1 + row1) * texture->mipmap[i-1][2]); + w = texture->mipmap[i][2]; + if (layer1 > layer0) + { + if (texture->mipmap[i-1][2] > 1) + { + // average 3D texture + for (x = 0;x < w;x++, o += 4, i0 += 8, i1 += 8, i2 += 8, i3 += 8) + { + o[0] = (i0[0] + i0[4] + i1[0] + i1[4] + i2[0] + i2[4] + i3[0] + i3[4] + 4) >> 3; + o[1] = (i0[1] + i0[5] + i1[1] + i1[5] + i2[1] + i2[5] + i3[1] + i3[5] + 4) >> 3; + o[2] = (i0[2] + i0[6] + i1[2] + i1[6] + i2[2] + i2[6] + i3[2] + i3[6] + 4) >> 3; + o[3] = (i0[3] + i0[7] + i1[3] + i1[7] + i2[3] + i2[7] + i3[3] + i3[7] + 4) >> 3; + } + } + else + { + // average 3D mipmap with parent width == 1 + for (x = 0;x < w;x++, o += 4, i0 += 8, i1 += 8) + { + o[0] = (i0[0] + i1[0] + i2[0] + i3[0] + 2) >> 2; + o[1] = (i0[1] + i1[1] + i2[1] + i3[1] + 2) >> 2; + o[2] = (i0[2] + i1[2] + i2[2] + i3[2] + 2) >> 2; + o[3] = (i0[3] + i1[3] + i2[3] + i3[3] + 2) >> 2; + } + } + } + else + { + if (texture->mipmap[i-1][2] > 1) + { + // average 2D texture (common case) + for (x = 0;x < w;x++, o += 4, i0 += 8, i1 += 8) + { + o[0] = (i0[0] + i0[4] + i1[0] + i1[4] + 2) >> 2; + o[1] = (i0[1] + i0[5] + i1[1] + i1[5] + 2) >> 2; + o[2] = (i0[2] + i0[6] + i1[2] + i1[6] + 2) >> 2; + o[3] = (i0[3] + i0[7] + i1[3] + i1[7] + 2) >> 2; + } + } + else + { + // 2D texture with parent width == 1 + o[0] = (i0[0] + i1[0] + 1) >> 1; + o[1] = (i0[1] + i1[1] + 1) >> 1; + o[2] = (i0[2] + i1[2] + 1) >> 1; + o[3] = (i0[3] + i1[3] + 1) >> 1; + } + } + } + } + } +} +void DPSOFTRAST_Texture_UpdatePartial(int index, int mip, const unsigned char *pixels, int blockx, int blocky, int blockwidth, int blockheight) +{ + DPSOFTRAST_Texture *texture; + unsigned char *dst; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (texture->binds) + DPSOFTRAST_Flush(); + if (pixels) + { + dst = texture->bytes + texture->mipmap[0][1] +(-blocky * texture->mipmap[0][2] + blockx) * 4; + while (blockheight > 0) + { + dst -= texture->mipmap[0][2] * 4; + memcpy(dst, pixels, blockwidth * 4); + pixels += blockwidth * 4; + blockheight--; + } + } + DPSOFTRAST_Texture_CalculateMipmaps(index); +} +void DPSOFTRAST_Texture_UpdateFull(int index, const unsigned char *pixels) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (texture->binds) + DPSOFTRAST_Flush(); + if (pixels) + { + int i, stride = texture->mipmap[0][2]*4; + unsigned char *dst = texture->bytes + texture->mipmap[0][1]; + for (i = texture->mipmap[0][3];i > 0;i--) + { + dst -= stride; + memcpy(dst, pixels, stride); + pixels += stride; + } + } + DPSOFTRAST_Texture_CalculateMipmaps(index); +} +int DPSOFTRAST_Texture_GetWidth(int index, int mip) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return 0; + return texture->mipmap[mip][2]; +} +int DPSOFTRAST_Texture_GetHeight(int index, int mip) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return 0; + return texture->mipmap[mip][3]; +} +int DPSOFTRAST_Texture_GetDepth(int index, int mip) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return 0; + return texture->mipmap[mip][4]; +} +unsigned char *DPSOFTRAST_Texture_GetPixelPointer(int index, int mip) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return 0; + if (texture->binds) + DPSOFTRAST_Flush(); + return texture->bytes + texture->mipmap[mip][0]; +} +void DPSOFTRAST_Texture_Filter(int index, DPSOFTRAST_TEXTURE_FILTER filter) +{ + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (!(texture->flags & DPSOFTRAST_TEXTURE_FLAG_MIPMAP) && filter > DPSOFTRAST_TEXTURE_FILTER_LINEAR) + { + dpsoftrast.errorstring = "DPSOFTRAST_Texture_Filter: requested filter mode requires mipmaps"; + return; + } + if (texture->binds) + DPSOFTRAST_Flush(); + texture->filter = filter; +} + +static void DPSOFTRAST_Draw_FlushThreads(void); + +static void DPSOFTRAST_Draw_SyncCommands(void) +{ + if(dpsoftrast.usethreads) MEMORY_BARRIER; + dpsoftrast.drawcommand = dpsoftrast.commandpool.freecommand; +} + +static void DPSOFTRAST_Draw_FreeCommandPool(int space) +{ + DPSOFTRAST_State_Thread *thread; + int i; + int freecommand = dpsoftrast.commandpool.freecommand; + int usedcommands = dpsoftrast.commandpool.usedcommands; + if (usedcommands <= DPSOFTRAST_DRAW_MAXCOMMANDPOOL-space) + return; + DPSOFTRAST_Draw_SyncCommands(); + for(;;) + { + int waitindex = -1; + int commandoffset; + usedcommands = 0; + for (i = 0; i < dpsoftrast.numthreads; i++) + { + thread = &dpsoftrast.threads[i]; + commandoffset = freecommand - thread->commandoffset; + if (commandoffset < 0) + commandoffset += DPSOFTRAST_DRAW_MAXCOMMANDPOOL; + if (commandoffset > usedcommands) + { + waitindex = i; + usedcommands = commandoffset; + } + } + if (usedcommands <= DPSOFTRAST_DRAW_MAXCOMMANDPOOL-space || waitindex < 0) + break; + thread = &dpsoftrast.threads[waitindex]; + Thread_LockMutex(thread->drawmutex); + if (thread->commandoffset != dpsoftrast.drawcommand) + { + thread->waiting = true; + if (thread->starving) Thread_CondSignal(thread->drawcond); + Thread_CondWait(thread->waitcond, thread->drawmutex); + thread->waiting = false; + } + Thread_UnlockMutex(thread->drawmutex); + } + dpsoftrast.commandpool.usedcommands = usedcommands; +} + +#define DPSOFTRAST_ALIGNCOMMAND(size) \ + ((size) + ((COMMAND_SIZE - ((size)&(COMMAND_SIZE-1))) & (COMMAND_SIZE-1))) +#define DPSOFTRAST_ALLOCATECOMMAND(name) \ + ((DPSOFTRAST_Command_##name *) DPSOFTRAST_AllocateCommand( DPSOFTRAST_OPCODE_##name , DPSOFTRAST_ALIGNCOMMAND(sizeof( DPSOFTRAST_Command_##name )))) + +static void *DPSOFTRAST_AllocateCommand(int opcode, int size) +{ + DPSOFTRAST_Command *command; + int freecommand = dpsoftrast.commandpool.freecommand; + int usedcommands = dpsoftrast.commandpool.usedcommands; + int extra = sizeof(DPSOFTRAST_Command); + if (DPSOFTRAST_DRAW_MAXCOMMANDPOOL - freecommand < size) + extra += DPSOFTRAST_DRAW_MAXCOMMANDPOOL - freecommand; + if (usedcommands > DPSOFTRAST_DRAW_MAXCOMMANDPOOL - (size + extra)) + { + if (dpsoftrast.usethreads) + DPSOFTRAST_Draw_FreeCommandPool(size + extra); + else + DPSOFTRAST_Draw_FlushThreads(); + freecommand = dpsoftrast.commandpool.freecommand; + usedcommands = dpsoftrast.commandpool.usedcommands; + } + if (DPSOFTRAST_DRAW_MAXCOMMANDPOOL - freecommand < size) + { + command = (DPSOFTRAST_Command *) &dpsoftrast.commandpool.commands[freecommand]; + command->opcode = DPSOFTRAST_OPCODE_Reset; + usedcommands += DPSOFTRAST_DRAW_MAXCOMMANDPOOL - freecommand; + freecommand = 0; + } + command = (DPSOFTRAST_Command *) &dpsoftrast.commandpool.commands[freecommand]; + command->opcode = opcode; + command->commandsize = size; + freecommand += size; + if (freecommand >= DPSOFTRAST_DRAW_MAXCOMMANDPOOL) + freecommand = 0; + dpsoftrast.commandpool.freecommand = freecommand; + dpsoftrast.commandpool.usedcommands = usedcommands + size; + return command; +} + +static void DPSOFTRAST_UndoCommand(int size) +{ + int freecommand = dpsoftrast.commandpool.freecommand; + int usedcommands = dpsoftrast.commandpool.usedcommands; + freecommand -= size; + if (freecommand < 0) + freecommand += DPSOFTRAST_DRAW_MAXCOMMANDPOOL; + usedcommands -= size; + dpsoftrast.commandpool.freecommand = freecommand; + dpsoftrast.commandpool.usedcommands = usedcommands; +} + +DEFCOMMAND(1, Viewport, int x; int y; int width; int height;) +static void DPSOFTRAST_Interpret_Viewport(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_Command_Viewport *command) +{ + thread->viewport[0] = command->x; + thread->viewport[1] = command->y; + thread->viewport[2] = command->width; + thread->viewport[3] = command->height; + thread->validate |= DPSOFTRAST_VALIDATE_FB; +} +void DPSOFTRAST_Viewport(int x, int y, int width, int height) +{ + DPSOFTRAST_Command_Viewport *command = DPSOFTRAST_ALLOCATECOMMAND(Viewport); + command->x = x; + command->y = y; + command->width = width; + command->height = height; + + dpsoftrast.viewport[0] = x; + dpsoftrast.viewport[1] = y; + dpsoftrast.viewport[2] = width; + dpsoftrast.viewport[3] = height; + DPSOFTRAST_RecalcViewport(dpsoftrast.viewport, dpsoftrast.fb_viewportcenter, dpsoftrast.fb_viewportscale); +} + +DEFCOMMAND(2, ClearColor, float r; float g; float b; float a;) +static void DPSOFTRAST_Interpret_ClearColor(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_Command_ClearColor *command) +{ + int i, x1, y1, x2, y2, w, h, x, y; + int miny1, maxy1, miny2, maxy2; + int bandy; + unsigned int *p; + unsigned int c; + DPSOFTRAST_Validate(thread, DPSOFTRAST_VALIDATE_FB); + miny1 = thread->miny1; + maxy1 = thread->maxy1; + miny2 = thread->miny2; + maxy2 = thread->maxy2; + x1 = thread->fb_scissor[0]; + y1 = thread->fb_scissor[1]; + x2 = thread->fb_scissor[0] + thread->fb_scissor[2]; + y2 = thread->fb_scissor[1] + thread->fb_scissor[3]; + if (y1 < miny1) y1 = miny1; + if (y2 > maxy2) y2 = maxy2; + w = x2 - x1; + h = y2 - y1; + if (w < 1 || h < 1) + return; + // FIXME: honor fb_colormask? + c = DPSOFTRAST_BGRA8_FROM_RGBA32F(command->r,command->g,command->b,command->a); + for (i = 0;i < 4;i++) + { + if (!dpsoftrast.fb_colorpixels[i]) + continue; + for (y = y1, bandy = min(y2, maxy1); y < y2; bandy = min(y2, maxy2), y = max(y, miny2)) + for (;y < bandy;y++) + { + p = dpsoftrast.fb_colorpixels[i] + y * dpsoftrast.fb_width; + for (x = x1;x < x2;x++) + p[x] = c; + } + } +} +void DPSOFTRAST_ClearColor(float r, float g, float b, float a) +{ + DPSOFTRAST_Command_ClearColor *command = DPSOFTRAST_ALLOCATECOMMAND(ClearColor); + command->r = r; + command->g = g; + command->b = b; + command->a = a; +} + +DEFCOMMAND(3, ClearDepth, float depth;) +static void DPSOFTRAST_Interpret_ClearDepth(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ClearDepth *command) +{ + int x1, y1, x2, y2, w, h, x, y; + int miny1, maxy1, miny2, maxy2; + int bandy; + unsigned int *p; + unsigned int c; + DPSOFTRAST_Validate(thread, DPSOFTRAST_VALIDATE_FB); + miny1 = thread->miny1; + maxy1 = thread->maxy1; + miny2 = thread->miny2; + maxy2 = thread->maxy2; + x1 = thread->fb_scissor[0]; + y1 = thread->fb_scissor[1]; + x2 = thread->fb_scissor[0] + thread->fb_scissor[2]; + y2 = thread->fb_scissor[1] + thread->fb_scissor[3]; + if (y1 < miny1) y1 = miny1; + if (y2 > maxy2) y2 = maxy2; + w = x2 - x1; + h = y2 - y1; + if (w < 1 || h < 1) + return; + c = DPSOFTRAST_DEPTH32_FROM_DEPTH32F(command->depth); + for (y = y1, bandy = min(y2, maxy1); y < y2; bandy = min(y2, maxy2), y = max(y, miny2)) + for (;y < bandy;y++) + { + p = dpsoftrast.fb_depthpixels + y * dpsoftrast.fb_width; + for (x = x1;x < x2;x++) + p[x] = c; + } +} +void DPSOFTRAST_ClearDepth(float d) +{ + DPSOFTRAST_Command_ClearDepth *command = DPSOFTRAST_ALLOCATECOMMAND(ClearDepth); + command->depth = d; +} + +DEFCOMMAND(4, ColorMask, int r; int g; int b; int a;) +static void DPSOFTRAST_Interpret_ColorMask(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ColorMask *command) +{ + thread->colormask[0] = command->r != 0; + thread->colormask[1] = command->g != 0; + thread->colormask[2] = command->b != 0; + thread->colormask[3] = command->a != 0; + thread->fb_colormask = ((-thread->colormask[0]) & 0x00FF0000) | ((-thread->colormask[1]) & 0x0000FF00) | ((-thread->colormask[2]) & 0x000000FF) | ((-thread->colormask[3]) & 0xFF000000); +} +void DPSOFTRAST_ColorMask(int r, int g, int b, int a) +{ + DPSOFTRAST_Command_ColorMask *command = DPSOFTRAST_ALLOCATECOMMAND(ColorMask); + command->r = r; + command->g = g; + command->b = b; + command->a = a; +} + +DEFCOMMAND(5, DepthTest, int enable;) +static void DPSOFTRAST_Interpret_DepthTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_DepthTest *command) +{ + thread->depthtest = command->enable; + thread->validate |= DPSOFTRAST_VALIDATE_DEPTHFUNC; +} +void DPSOFTRAST_DepthTest(int enable) +{ + DPSOFTRAST_Command_DepthTest *command = DPSOFTRAST_ALLOCATECOMMAND(DepthTest); + command->enable = enable; +} + +DEFCOMMAND(6, ScissorTest, int enable;) +static void DPSOFTRAST_Interpret_ScissorTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ScissorTest *command) +{ + thread->scissortest = command->enable; + thread->validate |= DPSOFTRAST_VALIDATE_FB; +} +void DPSOFTRAST_ScissorTest(int enable) +{ + DPSOFTRAST_Command_ScissorTest *command = DPSOFTRAST_ALLOCATECOMMAND(ScissorTest); + command->enable = enable; +} + +DEFCOMMAND(7, Scissor, float x; float y; float width; float height;) +static void DPSOFTRAST_Interpret_Scissor(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_Scissor *command) +{ + thread->scissor[0] = command->x; + thread->scissor[1] = command->y; + thread->scissor[2] = command->width; + thread->scissor[3] = command->height; + thread->validate |= DPSOFTRAST_VALIDATE_FB; +} +void DPSOFTRAST_Scissor(float x, float y, float width, float height) +{ + DPSOFTRAST_Command_Scissor *command = DPSOFTRAST_ALLOCATECOMMAND(Scissor); + command->x = x; + command->y = y; + command->width = width; + command->height = height; +} + +DEFCOMMAND(8, BlendFunc, int sfactor; int dfactor;) +static void DPSOFTRAST_Interpret_BlendFunc(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_BlendFunc *command) +{ + thread->blendfunc[0] = command->sfactor; + thread->blendfunc[1] = command->dfactor; + thread->validate |= DPSOFTRAST_VALIDATE_BLENDFUNC; +} +void DPSOFTRAST_BlendFunc(int sfactor, int dfactor) +{ + DPSOFTRAST_Command_BlendFunc *command = DPSOFTRAST_ALLOCATECOMMAND(BlendFunc); + command->sfactor = sfactor; + command->dfactor = dfactor; +} + +DEFCOMMAND(9, BlendSubtract, int enable;) +static void DPSOFTRAST_Interpret_BlendSubtract(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_BlendSubtract *command) +{ + thread->blendsubtract = command->enable; + thread->validate |= DPSOFTRAST_VALIDATE_BLENDFUNC; +} +void DPSOFTRAST_BlendSubtract(int enable) +{ + DPSOFTRAST_Command_BlendSubtract *command = DPSOFTRAST_ALLOCATECOMMAND(BlendSubtract); + command->enable = enable; +} + +DEFCOMMAND(10, DepthMask, int enable;) +static void DPSOFTRAST_Interpret_DepthMask(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_DepthMask *command) +{ + thread->depthmask = command->enable; +} +void DPSOFTRAST_DepthMask(int enable) +{ + DPSOFTRAST_Command_DepthMask *command = DPSOFTRAST_ALLOCATECOMMAND(DepthMask); + command->enable = enable; +} + +DEFCOMMAND(11, DepthFunc, int func;) +static void DPSOFTRAST_Interpret_DepthFunc(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_DepthFunc *command) +{ + thread->depthfunc = command->func; +} +void DPSOFTRAST_DepthFunc(int func) +{ + DPSOFTRAST_Command_DepthFunc *command = DPSOFTRAST_ALLOCATECOMMAND(DepthFunc); + command->func = func; +} + +DEFCOMMAND(12, DepthRange, float nearval; float farval;) +static void DPSOFTRAST_Interpret_DepthRange(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_DepthRange *command) +{ + thread->depthrange[0] = command->nearval; + thread->depthrange[1] = command->farval; +} +void DPSOFTRAST_DepthRange(float nearval, float farval) +{ + DPSOFTRAST_Command_DepthRange *command = DPSOFTRAST_ALLOCATECOMMAND(DepthRange); + command->nearval = nearval; + command->farval = farval; +} + +DEFCOMMAND(13, PolygonOffset, float alongnormal; float intoview;) +static void DPSOFTRAST_Interpret_PolygonOffset(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_PolygonOffset *command) +{ + thread->polygonoffset[0] = command->alongnormal; + thread->polygonoffset[1] = command->intoview; +} +void DPSOFTRAST_PolygonOffset(float alongnormal, float intoview) +{ + DPSOFTRAST_Command_PolygonOffset *command = DPSOFTRAST_ALLOCATECOMMAND(PolygonOffset); + command->alongnormal = alongnormal; + command->intoview = intoview; +} + +DEFCOMMAND(14, CullFace, int mode;) +static void DPSOFTRAST_Interpret_CullFace(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_CullFace *command) +{ + thread->cullface = command->mode; +} +void DPSOFTRAST_CullFace(int mode) +{ + DPSOFTRAST_Command_CullFace *command = DPSOFTRAST_ALLOCATECOMMAND(CullFace); + command->mode = mode; +} + +void DPSOFTRAST_Color4f(float r, float g, float b, float a) +{ + dpsoftrast.color[0] = r; + dpsoftrast.color[1] = g; + dpsoftrast.color[2] = b; + dpsoftrast.color[3] = a; +} + +void DPSOFTRAST_GetPixelsBGRA(int blockx, int blocky, int blockwidth, int blockheight, unsigned char *outpixels) +{ + int outstride = blockwidth * 4; + int instride = dpsoftrast.fb_width * 4; + int bx1 = blockx; + int by1 = blocky; + int bx2 = blockx + blockwidth; + int by2 = blocky + blockheight; + int bw; + int x; + int y; + unsigned char *inpixels; + unsigned char *b; + unsigned char *o; + DPSOFTRAST_Flush(); + if (bx1 < 0) bx1 = 0; + if (by1 < 0) by1 = 0; + if (bx2 > dpsoftrast.fb_width) bx2 = dpsoftrast.fb_width; + if (by2 > dpsoftrast.fb_height) by2 = dpsoftrast.fb_height; + bw = bx2 - bx1; + inpixels = (unsigned char *)dpsoftrast.fb_colorpixels[0]; + if (dpsoftrast.bigendian) + { + for (y = by1;y < by2;y++) + { + b = (unsigned char *)inpixels + (dpsoftrast.fb_height - 1 - y) * instride + 4 * bx1; + o = (unsigned char *)outpixels + (y - by1) * outstride; + for (x = bx1;x < bx2;x++) + { + o[0] = b[3]; + o[1] = b[2]; + o[2] = b[1]; + o[3] = b[0]; + o += 4; + b += 4; + } + } + } + else + { + for (y = by1;y < by2;y++) + { + b = (unsigned char *)inpixels + (dpsoftrast.fb_height - 1 - y) * instride + 4 * bx1; + o = (unsigned char *)outpixels + (y - by1) * outstride; + memcpy(o, b, bw*4); + } + } + +} +void DPSOFTRAST_CopyRectangleToTexture(int index, int mip, int tx, int ty, int sx, int sy, int width, int height) +{ + int tx1 = tx; + int ty1 = ty; + int tx2 = tx + width; + int ty2 = ty + height; + int sx1 = sx; + int sy1 = sy; + int sx2 = sx + width; + int sy2 = sy + height; + int swidth; + int sheight; + int twidth; + int theight; + int sw; + int sh; + int tw; + int th; + int y; + unsigned int *spixels; + unsigned int *tpixels; + DPSOFTRAST_Texture *texture; + texture = DPSOFTRAST_Texture_GetByIndex(index);if (!texture) return; + if (mip < 0 || mip >= texture->mipmaps) return; + DPSOFTRAST_Flush(); + spixels = dpsoftrast.fb_colorpixels[0]; + swidth = dpsoftrast.fb_width; + sheight = dpsoftrast.fb_height; + tpixels = (unsigned int *)(texture->bytes + texture->mipmap[mip][0]); + twidth = texture->mipmap[mip][2]; + theight = texture->mipmap[mip][3]; + if (tx1 < 0) tx1 = 0; + if (ty1 < 0) ty1 = 0; + if (tx2 > twidth) tx2 = twidth; + if (ty2 > theight) ty2 = theight; + if (sx1 < 0) sx1 = 0; + if (sy1 < 0) sy1 = 0; + if (sx2 > swidth) sx2 = swidth; + if (sy2 > sheight) sy2 = sheight; + tw = tx2 - tx1; + th = ty2 - ty1; + sw = sx2 - sx1; + sh = sy2 - sy1; + if (tw > sw) tw = sw; + if (th > sh) th = sh; + if (tw < 1 || th < 1) + return; + sy1 = sheight - sy1 - th; + ty1 = theight - ty1 - th; + for (y = 0;y < th;y++) + memcpy(tpixels + ((ty1 + y) * twidth + tx1), spixels + ((sy1 + y) * swidth + sx1), tw*4); + if (texture->mipmaps > 1) + DPSOFTRAST_Texture_CalculateMipmaps(index); +} + +DEFCOMMAND(17, SetTexture, int unitnum; DPSOFTRAST_Texture *texture;) +static void DPSOFTRAST_Interpret_SetTexture(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_SetTexture *command) +{ + if (thread->texbound[command->unitnum]) + ATOMIC_DECREMENT(thread->texbound[command->unitnum]->binds); + thread->texbound[command->unitnum] = command->texture; +} +void DPSOFTRAST_SetTexture(int unitnum, int index) +{ + DPSOFTRAST_Command_SetTexture *command; + DPSOFTRAST_Texture *texture; + if (unitnum < 0 || unitnum >= DPSOFTRAST_MAXTEXTUREUNITS) + { + dpsoftrast.errorstring = "DPSOFTRAST_SetTexture: invalid unit number"; + return; + } + texture = DPSOFTRAST_Texture_GetByIndex(index); + if (index && !texture) + { + dpsoftrast.errorstring = "DPSOFTRAST_SetTexture: invalid texture handle"; + return; + } + + command = DPSOFTRAST_ALLOCATECOMMAND(SetTexture); + command->unitnum = unitnum; + command->texture = texture; + + dpsoftrast.texbound[unitnum] = texture; + if (texture) + ATOMIC_ADD(texture->binds, dpsoftrast.numthreads); +} + +void DPSOFTRAST_SetVertexPointer(const float *vertex3f, size_t stride) +{ + dpsoftrast.pointer_vertex3f = vertex3f; + dpsoftrast.stride_vertex = stride; +} +void DPSOFTRAST_SetColorPointer(const float *color4f, size_t stride) +{ + dpsoftrast.pointer_color4f = color4f; + dpsoftrast.pointer_color4ub = NULL; + dpsoftrast.stride_color = stride; +} +void DPSOFTRAST_SetColorPointer4ub(const unsigned char *color4ub, size_t stride) +{ + dpsoftrast.pointer_color4f = NULL; + dpsoftrast.pointer_color4ub = color4ub; + dpsoftrast.stride_color = stride; +} +void DPSOFTRAST_SetTexCoordPointer(int unitnum, int numcomponents, size_t stride, const float *texcoordf) +{ + dpsoftrast.pointer_texcoordf[unitnum] = texcoordf; + dpsoftrast.components_texcoord[unitnum] = numcomponents; + dpsoftrast.stride_texcoord[unitnum] = stride; +} + +DEFCOMMAND(18, SetShader, int mode; int permutation; int exactspecularmath;) +static void DPSOFTRAST_Interpret_SetShader(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_SetShader *command) +{ + thread->shader_mode = command->mode; + thread->shader_permutation = command->permutation; + thread->shader_exactspecularmath = command->exactspecularmath; +} +void DPSOFTRAST_SetShader(int mode, int permutation, int exactspecularmath) +{ + DPSOFTRAST_Command_SetShader *command = DPSOFTRAST_ALLOCATECOMMAND(SetShader); + command->mode = mode; + command->permutation = permutation; + command->exactspecularmath = exactspecularmath; + + dpsoftrast.shader_mode = mode; + dpsoftrast.shader_permutation = permutation; + dpsoftrast.shader_exactspecularmath = exactspecularmath; +} + +DEFCOMMAND(19, Uniform4f, DPSOFTRAST_UNIFORM index; float val[4];) +static void DPSOFTRAST_Interpret_Uniform4f(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_Uniform4f *command) +{ + memcpy(&thread->uniform4f[command->index*4], command->val, sizeof(command->val)); +} +void DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM index, float v0, float v1, float v2, float v3) +{ + DPSOFTRAST_Command_Uniform4f *command = DPSOFTRAST_ALLOCATECOMMAND(Uniform4f); + command->index = index; + command->val[0] = v0; + command->val[1] = v1; + command->val[2] = v2; + command->val[3] = v3; + + dpsoftrast.uniform4f[index*4+0] = v0; + dpsoftrast.uniform4f[index*4+1] = v1; + dpsoftrast.uniform4f[index*4+2] = v2; + dpsoftrast.uniform4f[index*4+3] = v3; +} +void DPSOFTRAST_Uniform4fv(DPSOFTRAST_UNIFORM index, const float *v) +{ + DPSOFTRAST_Command_Uniform4f *command = DPSOFTRAST_ALLOCATECOMMAND(Uniform4f); + command->index = index; + memcpy(command->val, v, sizeof(command->val)); + + memcpy(&dpsoftrast.uniform4f[index*4], v, sizeof(float[4])); +} + +DEFCOMMAND(20, UniformMatrix4f, DPSOFTRAST_UNIFORM index; ALIGN(float val[16]);) +static void DPSOFTRAST_Interpret_UniformMatrix4f(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_UniformMatrix4f *command) +{ + memcpy(&thread->uniform4f[command->index*4], command->val, sizeof(command->val)); +} +void DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM uniform, int arraysize, int transpose, const float *v) +{ +#ifdef SSE_POSSIBLE + int i, index; + for (i = 0, index = (int)uniform;i < arraysize;i++, index += 4, v += 16) + { + __m128 m0, m1, m2, m3; + DPSOFTRAST_Command_UniformMatrix4f *command = DPSOFTRAST_ALLOCATECOMMAND(UniformMatrix4f); + command->index = (DPSOFTRAST_UNIFORM)index; + if (((size_t)v)&(ALIGN_SIZE-1)) + { + m0 = _mm_loadu_ps(v); + m1 = _mm_loadu_ps(v+4); + m2 = _mm_loadu_ps(v+8); + m3 = _mm_loadu_ps(v+12); + } + else + { + m0 = _mm_load_ps(v); + m1 = _mm_load_ps(v+4); + m2 = _mm_load_ps(v+8); + m3 = _mm_load_ps(v+12); + } + if (transpose) + { + __m128 t0, t1, t2, t3; + t0 = _mm_unpacklo_ps(m0, m1); + t1 = _mm_unpacklo_ps(m2, m3); + t2 = _mm_unpackhi_ps(m0, m1); + t3 = _mm_unpackhi_ps(m2, m3); + m0 = _mm_movelh_ps(t0, t1); + m1 = _mm_movehl_ps(t1, t0); + m2 = _mm_movelh_ps(t2, t3); + m3 = _mm_movehl_ps(t3, t2); + } + _mm_store_ps(command->val, m0); + _mm_store_ps(command->val+4, m1); + _mm_store_ps(command->val+8, m2); + _mm_store_ps(command->val+12, m3); + _mm_store_ps(&dpsoftrast.uniform4f[index*4+0], m0); + _mm_store_ps(&dpsoftrast.uniform4f[index*4+4], m1); + _mm_store_ps(&dpsoftrast.uniform4f[index*4+8], m2); + _mm_store_ps(&dpsoftrast.uniform4f[index*4+12], m3); + } +#endif +} + +DEFCOMMAND(21, Uniform1i, DPSOFTRAST_UNIFORM index; int val;) +static void DPSOFTRAST_Interpret_Uniform1i(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_Uniform1i *command) +{ + thread->uniform1i[command->index] = command->val; +} +void DPSOFTRAST_Uniform1i(DPSOFTRAST_UNIFORM index, int i0) +{ + DPSOFTRAST_Command_Uniform1i *command = DPSOFTRAST_ALLOCATECOMMAND(Uniform1i); + command->index = index; + command->val = i0; + + dpsoftrast.uniform1i[command->index] = i0; +} + +DEFCOMMAND(24, ClipPlane, float clipplane[4];) +static void DPSOFTRAST_Interpret_ClipPlane(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_ClipPlane *command) +{ + memcpy(thread->clipplane, command->clipplane, 4*sizeof(float)); + thread->validate |= DPSOFTRAST_VALIDATE_FB; +} +void DPSOFTRAST_ClipPlane(float x, float y, float z, float w) +{ + DPSOFTRAST_Command_ClipPlane *command = DPSOFTRAST_ALLOCATECOMMAND(ClipPlane); + command->clipplane[0] = x; + command->clipplane[1] = y; + command->clipplane[2] = z; + command->clipplane[3] = w; +} + +#ifdef SSE_POSSIBLE +static void DPSOFTRAST_Load4fTo4f(float *dst, const unsigned char *src, int size, int stride) +{ + float *end = dst + size*4; + if ((((size_t)src)|stride)&(ALIGN_SIZE - 1)) // check for alignment + { + while (dst < end) + { + _mm_store_ps(dst, _mm_loadu_ps((const float *)src)); + dst += 4; + src += stride; + } + } + else + { + while (dst < end) + { + _mm_store_ps(dst, _mm_load_ps((const float *)src)); + dst += 4; + src += stride; + } + } +} + +static void DPSOFTRAST_Load3fTo4f(float *dst, const unsigned char *src, int size, int stride) +{ + float *end = dst + size*4; + if (stride == sizeof(float[3])) + { + float *end4 = dst + (size&~3)*4; + if (((size_t)src)&(ALIGN_SIZE - 1)) // check for alignment + { + while (dst < end4) + { + __m128 v1 = _mm_loadu_ps((const float *)src), v2 = _mm_loadu_ps((const float *)src + 4), v3 = _mm_loadu_ps((const float *)src + 8), dv; + dv = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(2, 1, 0, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_shuffle_ps(v1, v2, _MM_SHUFFLE(1, 0, 3, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 4, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 3, 2)); + dv = _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(2, 1, 0, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 8, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_move_ss(v3, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 12, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dst += 16; + src += 4*sizeof(float[3]); + } + } + else + { + while (dst < end4) + { + __m128 v1 = _mm_load_ps((const float *)src), v2 = _mm_load_ps((const float *)src + 4), v3 = _mm_load_ps((const float *)src + 8), dv; + dv = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(2, 1, 0, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_shuffle_ps(v1, v2, _MM_SHUFFLE(1, 0, 3, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 4, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 3, 2)); + dv = _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(2, 1, 0, 3)); + dv = _mm_move_ss(dv, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 8, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dv = _mm_move_ss(v3, _mm_set_ss(1.0f)); + _mm_store_ps(dst + 12, _mm_shuffle_ps(dv, dv, _MM_SHUFFLE(0, 3, 2, 1))); + dst += 16; + src += 4*sizeof(float[3]); + } + } + } + if ((((size_t)src)|stride)&(ALIGN_SIZE - 1)) + { + while (dst < end) + { + __m128 v = _mm_loadu_ps((const float *)src); + v = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 1, 0, 3)); + v = _mm_move_ss(v, _mm_set_ss(1.0f)); + v = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 3, 2, 1)); + _mm_store_ps(dst, v); + dst += 4; + src += stride; + } + } + else + { + while (dst < end) + { + __m128 v = _mm_load_ps((const float *)src); + v = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 1, 0, 3)); + v = _mm_move_ss(v, _mm_set_ss(1.0f)); + v = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 3, 2, 1)); + _mm_store_ps(dst, v); + dst += 4; + src += stride; + } + } +} + +static void DPSOFTRAST_Load2fTo4f(float *dst, const unsigned char *src, int size, int stride) +{ + float *end = dst + size*4; + __m128 v2 = _mm_setr_ps(0.0f, 0.0f, 0.0f, 1.0f); + if (stride == sizeof(float[2])) + { + float *end2 = dst + (size&~1)*4; + if (((size_t)src)&(ALIGN_SIZE - 1)) // check for alignment + { + while (dst < end2) + { + __m128 v = _mm_loadu_ps((const float *)src); + _mm_store_ps(dst, _mm_shuffle_ps(v, v2, _MM_SHUFFLE(3, 2, 1, 0))); + _mm_store_ps(dst + 4, _mm_movehl_ps(v2, v)); + dst += 8; + src += 2*sizeof(float[2]); + } + } + else + { + while (dst < end2) + { + __m128 v = _mm_load_ps((const float *)src); + _mm_store_ps(dst, _mm_shuffle_ps(v, v2, _MM_SHUFFLE(3, 2, 1, 0))); + _mm_store_ps(dst + 4, _mm_movehl_ps(v2, v)); + dst += 8; + src += 2*sizeof(float[2]); + } + } + } + while (dst < end) + { + _mm_store_ps(dst, _mm_loadl_pi(v2, (__m64 *)src)); + dst += 4; + src += stride; + } +} + +static void DPSOFTRAST_Load4bTo4f(float *dst, const unsigned char *src, int size, int stride) +{ + float *end = dst + size*4; + __m128 scale = _mm_set1_ps(1.0f/255.0f); + if (stride == sizeof(unsigned char[4])) + { + float *end4 = dst + (size&~3)*4; + if (((size_t)src)&(ALIGN_SIZE - 1)) // check for alignment + { + while (dst < end4) + { + __m128i v = _mm_loadu_si128((const __m128i *)src), v1 = _mm_unpacklo_epi8(v, _mm_setzero_si128()), v2 = _mm_unpackhi_epi8(v, _mm_setzero_si128()); + _mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v1, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 4, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v1, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 8, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v2, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 12, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v2, _mm_setzero_si128())), scale)); + dst += 16; + src += 4*sizeof(unsigned char[4]); + } + } + else + { + while (dst < end4) + { + __m128i v = _mm_load_si128((const __m128i *)src), v1 = _mm_unpacklo_epi8(v, _mm_setzero_si128()), v2 = _mm_unpackhi_epi8(v, _mm_setzero_si128()); + _mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v1, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 4, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v1, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 8, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v2, _mm_setzero_si128())), scale)); + _mm_store_ps(dst + 12, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v2, _mm_setzero_si128())), scale)); + dst += 16; + src += 4*sizeof(unsigned char[4]); + } + } + } + while (dst < end) + { + __m128i v = _mm_cvtsi32_si128(*(const int *)src); + _mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(_mm_unpacklo_epi8(v, _mm_setzero_si128()), _mm_setzero_si128())), scale)); + dst += 4; + src += stride; + } +} + +static void DPSOFTRAST_Fill4f(float *dst, const float *src, int size) +{ + float *end = dst + 4*size; + __m128 v = _mm_loadu_ps(src); + while (dst < end) + { + _mm_store_ps(dst, v); + dst += 4; + } +} +#endif + +static void DPSOFTRAST_Vertex_Transform(float *out4f, const float *in4f, int numitems, const float *inmatrix16f) +{ +#ifdef SSE_POSSIBLE + static const float identitymatrix[4][4] = {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}; + __m128 m0, m1, m2, m3; + float *end; + if (!memcmp(identitymatrix, inmatrix16f, sizeof(float[16]))) + { + // fast case for identity matrix + if (out4f != in4f) memcpy(out4f, in4f, numitems * sizeof(float[4])); + return; + } + end = out4f + numitems*4; + m0 = _mm_loadu_ps(inmatrix16f); + m1 = _mm_loadu_ps(inmatrix16f + 4); + m2 = _mm_loadu_ps(inmatrix16f + 8); + m3 = _mm_loadu_ps(inmatrix16f + 12); + if (((size_t)in4f)&(ALIGN_SIZE-1)) // check alignment + { + while (out4f < end) + { + __m128 v = _mm_loadu_ps(in4f); + _mm_store_ps(out4f, + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)), m0), + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)), m1), + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)), m2), + _mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)), m3))))); + out4f += 4; + in4f += 4; + } + } + else + { + while (out4f < end) + { + __m128 v = _mm_load_ps(in4f); + _mm_store_ps(out4f, + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)), m0), + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)), m1), + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)), m2), + _mm_mul_ps(_mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)), m3))))); + out4f += 4; + in4f += 4; + } + } +#endif +} + +#if 0 +static void DPSOFTRAST_Vertex_Copy(float *out4f, const float *in4f, int numitems) +{ + memcpy(out4f, in4f, numitems * sizeof(float[4])); +} +#endif + +#ifdef SSE_POSSIBLE +#define DPSOFTRAST_PROJECTVERTEX(out, in, viewportcenter, viewportscale) \ +{ \ + __m128 p = (in), w = _mm_shuffle_ps(p, p, _MM_SHUFFLE(3, 3, 3, 3)); \ + p = _mm_move_ss(_mm_shuffle_ps(p, p, _MM_SHUFFLE(2, 1, 0, 3)), _mm_set_ss(1.0f)); \ + p = _mm_add_ps(viewportcenter, _mm_div_ps(_mm_mul_ps(viewportscale, p), w)); \ + out = _mm_shuffle_ps(p, p, _MM_SHUFFLE(0, 3, 2, 1)); \ +} + +#define DPSOFTRAST_TRANSFORMVERTEX(out, in, m0, m1, m2, m3) \ +{ \ + __m128 p = (in); \ + out = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(p, p, _MM_SHUFFLE(0, 0, 0, 0)), m0), \ + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(p, p, _MM_SHUFFLE(1, 1, 1, 1)), m1), \ + _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(p, p, _MM_SHUFFLE(2, 2, 2, 2)), m2), \ + _mm_mul_ps(_mm_shuffle_ps(p, p, _MM_SHUFFLE(3, 3, 3, 3)), m3)))); \ +} + +static int DPSOFTRAST_Vertex_BoundY(int *starty, int *endy, const float *minposf, const float *maxposf, const float *inmatrix16f) +{ + int clipmask = 0xFF; + __m128 viewportcenter = _mm_load_ps(dpsoftrast.fb_viewportcenter), viewportscale = _mm_load_ps(dpsoftrast.fb_viewportscale); + __m128 bb[8], clipdist[8], minproj = _mm_set_ss(2.0f), maxproj = _mm_set_ss(-2.0f); + __m128 m0 = _mm_loadu_ps(inmatrix16f), m1 = _mm_loadu_ps(inmatrix16f + 4), m2 = _mm_loadu_ps(inmatrix16f + 8), m3 = _mm_loadu_ps(inmatrix16f + 12); + __m128 minpos = _mm_load_ps(minposf), maxpos = _mm_load_ps(maxposf); + m0 = _mm_shuffle_ps(m0, m0, _MM_SHUFFLE(3, 2, 0, 1)); + m1 = _mm_shuffle_ps(m1, m1, _MM_SHUFFLE(3, 2, 0, 1)); + m2 = _mm_shuffle_ps(m2, m2, _MM_SHUFFLE(3, 2, 0, 1)); + m3 = _mm_shuffle_ps(m3, m3, _MM_SHUFFLE(3, 2, 0, 1)); + #define BBFRONT(k, pos) \ + { \ + DPSOFTRAST_TRANSFORMVERTEX(bb[k], pos, m0, m1, m2, m3); \ + clipdist[k] = _mm_add_ss(_mm_shuffle_ps(bb[k], bb[k], _MM_SHUFFLE(2, 2, 2, 2)), _mm_shuffle_ps(bb[k], bb[k], _MM_SHUFFLE(3, 3, 3, 3))); \ + if (_mm_ucomige_ss(clipdist[k], _mm_setzero_ps())) \ + { \ + __m128 proj; \ + clipmask &= ~(1<= 0 ? DPSOFTRAST_Array_Load(outarray, inarray) : dpsoftrast.post_array4f[outarray]; + DPSOFTRAST_Vertex_Transform(data, data, dpsoftrast.numvertices, inmatrix16f); + return data; +} + +#if 0 +static float *DPSOFTRAST_Array_Project(int outarray, int inarray) +{ +#ifdef SSE_POSSIBLE + float *data = inarray >= 0 ? DPSOFTRAST_Array_Load(outarray, inarray) : dpsoftrast.post_array4f[outarray]; + dpsoftrast.drawclipped = DPSOFTRAST_Vertex_Project(data, dpsoftrast.screencoord4f, &dpsoftrast.drawstarty, &dpsoftrast.drawendy, data, dpsoftrast.numvertices); + return data; +#else + return NULL; +#endif +} +#endif + +static float *DPSOFTRAST_Array_TransformProject(int outarray, int inarray, const float *inmatrix16f) +{ +#ifdef SSE_POSSIBLE + float *data = inarray >= 0 ? DPSOFTRAST_Array_Load(outarray, inarray) : dpsoftrast.post_array4f[outarray]; + dpsoftrast.drawclipped = DPSOFTRAST_Vertex_TransformProject(data, dpsoftrast.screencoord4f, &dpsoftrast.drawstarty, &dpsoftrast.drawendy, data, dpsoftrast.numvertices, inmatrix16f); + return data; +#else + return NULL; +#endif +} + +static void DPSOFTRAST_Draw_Span_Begin(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *zf) +{ + int x; + int startx = span->startx; + int endx = span->endx; + float wslope = triangle->w[0]; + float w = triangle->w[2] + span->x*wslope + span->y*triangle->w[1]; + float endz = 1.0f / (w + wslope * startx); + if (triangle->w[0] == 0) + { + // LordHavoc: fast flat polygons (HUD/menu) + for (x = startx;x < endx;x++) + zf[x] = endz; + return; + } + for (x = startx;x < endx;) + { + int nextsub = x + DPSOFTRAST_DRAW_MAXSUBSPAN, endsub = nextsub - 1; + float z = endz, dz; + if (nextsub >= endx) nextsub = endsub = endx-1; + endz = 1.0f / (w + wslope * nextsub); + dz = x < nextsub ? (endz - z) / (nextsub - x) : 0.0f; + for (; x <= endsub; x++, z += dz) + zf[x] = z; + } +} + +static void DPSOFTRAST_Draw_Span_FinishBGRA8(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, const unsigned char* RESTRICT in4ub) +{ +#ifdef SSE_POSSIBLE + int x; + int startx = span->startx; + int endx = span->endx; + int maskx; + int subx; + const unsigned int * RESTRICT ini = (const unsigned int *)in4ub; + unsigned char * RESTRICT pixelmask = span->pixelmask; + unsigned int * RESTRICT pixeli = (unsigned int *)dpsoftrast.fb_colorpixels[0]; + if (!pixeli) + return; + pixeli += span->y * dpsoftrast.fb_width + span->x; + // handle alphatest now (this affects depth writes too) + if (thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) + for (x = startx;x < endx;x++) + if (in4ub[x*4+3] < 128) + pixelmask[x] = false; + // LordHavoc: clear pixelmask for some pixels in alphablend cases, this + // helps sprites, text and hud artwork + switch(thread->fb_blendmode) + { + case DPSOFTRAST_BLENDMODE_ALPHA: + case DPSOFTRAST_BLENDMODE_ADDALPHA: + case DPSOFTRAST_BLENDMODE_SUBALPHA: + maskx = startx; + for (x = startx;x < endx;x++) + { + if (in4ub[x*4+3] >= 1) + { + startx = x; + for (;;) + { + while (++x < endx && in4ub[x*4+3] >= 1) ; + maskx = x; + if (x >= endx) break; + ++x; + while (++x < endx && in4ub[x*4+3] < 1) pixelmask[x] = false; + if (x >= endx) break; + } + break; + } + } + endx = maskx; + break; + case DPSOFTRAST_BLENDMODE_OPAQUE: + case DPSOFTRAST_BLENDMODE_ADD: + case DPSOFTRAST_BLENDMODE_INVMOD: + case DPSOFTRAST_BLENDMODE_MUL: + case DPSOFTRAST_BLENDMODE_MUL2: + case DPSOFTRAST_BLENDMODE_PSEUDOALPHA: + case DPSOFTRAST_BLENDMODE_INVADD: + break; + } + // put some special values at the end of the mask to ensure the loops end + pixelmask[endx] = 1; + pixelmask[endx+1] = 0; + // LordHavoc: use a double loop to identify subspans, this helps the + // optimized copy/blend loops to perform at their best, most triangles + // have only one run of pixels, and do the search using wide reads... + x = startx; + while (x < endx) + { + // if this pixel is masked off, it's probably not alone... + if (!pixelmask[x]) + { + x++; +#if 1 + if (x + 8 < endx) + { + // the 4-item search must be aligned or else it stalls badly + if ((x & 3) && !pixelmask[x]) + { + if(pixelmask[x]) goto endmasked; + x++; + if (x & 3) + { + if(pixelmask[x]) goto endmasked; + x++; + if (x & 3) + { + if(pixelmask[x]) goto endmasked; + x++; + } + } + } + while (*(unsigned int *)&pixelmask[x] == 0x00000000) + x += 4; + } +#endif + for (;!pixelmask[x];x++) + ; + // rather than continue the loop, just check the end variable + if (x >= endx) + break; + } + endmasked: + // find length of subspan + subx = x + 1; +#if 1 + if (subx + 8 < endx) + { + if (subx & 3) + { + if(!pixelmask[subx]) goto endunmasked; + subx++; + if (subx & 3) + { + if(!pixelmask[subx]) goto endunmasked; + subx++; + if (subx & 3) + { + if(!pixelmask[subx]) goto endunmasked; + subx++; + } + } + } + while (*(unsigned int *)&pixelmask[subx] == 0x01010101) + subx += 4; + } +#endif + for (;pixelmask[subx];subx++) + ; + // the checks can overshoot, so make sure to clip it... + if (subx > endx) + subx = endx; + endunmasked: + // now that we know the subspan length... process! + switch(thread->fb_blendmode) + { + case DPSOFTRAST_BLENDMODE_OPAQUE: +#if 0 + if (subx - x >= 16) + { + memcpy(pixeli + x, ini + x, (subx - x) * sizeof(pixeli[x])); + x = subx; + } + else +#elif 1 + while (x + 16 <= subx) + { + _mm_storeu_si128((__m128i *)&pixeli[x], _mm_loadu_si128((const __m128i *)&ini[x])); + _mm_storeu_si128((__m128i *)&pixeli[x+4], _mm_loadu_si128((const __m128i *)&ini[x+4])); + _mm_storeu_si128((__m128i *)&pixeli[x+8], _mm_loadu_si128((const __m128i *)&ini[x+8])); + _mm_storeu_si128((__m128i *)&pixeli[x+12], _mm_loadu_si128((const __m128i *)&ini[x+12])); + x += 16; + } +#endif + { + while (x + 4 <= subx) + { + _mm_storeu_si128((__m128i *)&pixeli[x], _mm_loadu_si128((const __m128i *)&ini[x])); + x += 4; + } + if (x + 2 <= subx) + { + pixeli[x] = ini[x]; + pixeli[x+1] = ini[x+1]; + x += 2; + } + if (x < subx) + { + pixeli[x] = ini[x]; + x++; + } + } + break; + case DPSOFTRAST_BLENDMODE_ALPHA: + #define FINISHBLEND(blend2, blend1) \ + for (;x + 1 < subx;x += 2) \ + { \ + __m128i src, dst; \ + src = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ini[x]), _mm_setzero_si128()); \ + dst = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&pixeli[x]), _mm_setzero_si128()); \ + blend2; \ + _mm_storel_epi64((__m128i *)&pixeli[x], _mm_packus_epi16(dst, dst)); \ + } \ + if (x < subx) \ + { \ + __m128i src, dst; \ + src = _mm_unpacklo_epi8(_mm_cvtsi32_si128(ini[x]), _mm_setzero_si128()); \ + dst = _mm_unpacklo_epi8(_mm_cvtsi32_si128(pixeli[x]), _mm_setzero_si128()); \ + blend1; \ + pixeli[x] = _mm_cvtsi128_si32(_mm_packus_epi16(dst, dst)); \ + x++; \ + } + FINISHBLEND({ + __m128i blend = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(dst, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(src, dst), 4), _mm_slli_epi16(blend, 4))); + }, { + __m128i blend = _mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(dst, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(src, dst), 4), _mm_slli_epi16(blend, 4))); + }); + break; + case DPSOFTRAST_BLENDMODE_ADDALPHA: + FINISHBLEND({ + __m128i blend = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(src, blend), 8)); + }, { + __m128i blend = _mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(src, blend), 8)); + }); + break; + case DPSOFTRAST_BLENDMODE_ADD: + FINISHBLEND({ dst = _mm_add_epi16(src, dst); }, { dst = _mm_add_epi16(src, dst); }); + break; + case DPSOFTRAST_BLENDMODE_INVMOD: + FINISHBLEND({ + dst = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(dst, src), 8)); + }, { + dst = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(dst, src), 8)); + }); + break; + case DPSOFTRAST_BLENDMODE_MUL: + FINISHBLEND({ dst = _mm_srli_epi16(_mm_mullo_epi16(src, dst), 8); }, { dst = _mm_srli_epi16(_mm_mullo_epi16(src, dst), 8); }); + break; + case DPSOFTRAST_BLENDMODE_MUL2: + FINISHBLEND({ dst = _mm_srli_epi16(_mm_mullo_epi16(src, dst), 7); }, { dst = _mm_srli_epi16(_mm_mullo_epi16(src, dst), 7); }); + break; + case DPSOFTRAST_BLENDMODE_SUBALPHA: + FINISHBLEND({ + __m128i blend = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(src, blend), 8)); + }, { + __m128i blend = _mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(src, blend), 8)); + }); + break; + case DPSOFTRAST_BLENDMODE_PSEUDOALPHA: + FINISHBLEND({ + __m128i blend = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(src, _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(dst, blend), 8))); + }, { + __m128i blend = _mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)); + dst = _mm_add_epi16(src, _mm_sub_epi16(dst, _mm_srli_epi16(_mm_mullo_epi16(dst, blend), 8))); + }); + break; + case DPSOFTRAST_BLENDMODE_INVADD: + FINISHBLEND({ + dst = _mm_add_epi16(dst, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_set1_epi16(255), dst), 4), _mm_slli_epi16(src, 4))); + }, { + dst = _mm_add_epi16(dst, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_set1_epi16(255), dst), 4), _mm_slli_epi16(src, 4))); + }); + break; + } + } +#endif +} + +static void DPSOFTRAST_Texture2DBGRA8(DPSOFTRAST_Texture *texture, int mip, float x, float y, unsigned char c[4]) + // warning: this is SLOW, only use if the optimized per-span functions won't do +{ + const unsigned char * RESTRICT pixelbase; + const unsigned char * RESTRICT pixel[4]; + int width = texture->mipmap[mip][2], height = texture->mipmap[mip][3]; + int wrapmask[2] = { width-1, height-1 }; + pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*width; + if(texture->filter & DPSOFTRAST_TEXTURE_FILTER_LINEAR) + { + unsigned int tc[2] = { x * (width<<12) - 2048, y * (height<<12) - 2048}; + unsigned int frac[2] = { tc[0]&0xFFF, tc[1]&0xFFF }; + unsigned int ifrac[2] = { 0x1000 - frac[0], 0x1000 - frac[1] }; + unsigned int lerp[4] = { ifrac[0]*ifrac[1], frac[0]*ifrac[1], ifrac[0]*frac[1], frac[0]*frac[1] }; + int tci[2] = { tc[0]>>12, tc[1]>>12 }; + int tci1[2] = { tci[0] + 1, tci[1] + 1 }; + if (texture->flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + tci[0] = tci[0] >= 0 ? (tci[0] <= wrapmask[0] ? tci[0] : wrapmask[0]) : 0; + tci[1] = tci[1] >= 0 ? (tci[1] <= wrapmask[1] ? tci[1] : wrapmask[1]) : 0; + tci1[0] = tci1[0] >= 0 ? (tci1[0] <= wrapmask[0] ? tci1[0] : wrapmask[0]) : 0; + tci1[1] = tci1[1] >= 0 ? (tci1[1] <= wrapmask[1] ? tci1[1] : wrapmask[1]) : 0; + } + else + { + tci[0] &= wrapmask[0]; + tci[1] &= wrapmask[1]; + tci1[0] &= wrapmask[0]; + tci1[1] &= wrapmask[1]; + } + pixel[0] = pixelbase + 4 * (tci[0] - tci[1]*width); + pixel[1] = pixelbase + 4 * (tci[0] - tci[1]*width); + pixel[2] = pixelbase + 4 * (tci[0] - tci1[1]*width); + pixel[3] = pixelbase + 4 * (tci[0] - tci1[1]*width); + c[0] = (pixel[0][0]*lerp[0]+pixel[1][0]*lerp[1]+pixel[2][0]*lerp[2]+pixel[3][0]*lerp[3])>>24; + c[1] = (pixel[0][1]*lerp[0]+pixel[1][1]*lerp[1]+pixel[2][1]*lerp[2]+pixel[3][1]*lerp[3])>>24; + c[2] = (pixel[0][2]*lerp[0]+pixel[1][2]*lerp[1]+pixel[2][2]*lerp[2]+pixel[3][2]*lerp[3])>>24; + c[3] = (pixel[0][3]*lerp[0]+pixel[1][3]*lerp[1]+pixel[2][3]*lerp[2]+pixel[3][3]*lerp[3])>>24; + } + else + { + int tci[2] = { x * width, y * height }; + if (texture->flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + tci[0] = tci[0] >= 0 ? (tci[0] <= wrapmask[0] ? tci[0] : wrapmask[0]) : 0; + tci[1] = tci[1] >= 0 ? (tci[1] <= wrapmask[1] ? tci[1] : wrapmask[1]) : 0; + } + else + { + tci[0] &= wrapmask[0]; + tci[1] &= wrapmask[1]; + } + pixel[0] = pixelbase + 4 * (tci[0] - tci[1]*width); + c[0] = pixel[0][0]; + c[1] = pixel[0][1]; + c[2] = pixel[0][2]; + c[3] = pixel[0][3]; + } +} + +#if 0 +static void DPSOFTRAST_Draw_Span_Texture2DVarying(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float * RESTRICT out4f, int texunitindex, int arrayindex, const float * RESTRICT zf) +{ + int x; + int startx = span->startx; + int endx = span->endx; + int flags; + float c[4]; + float data[4]; + float slope[4]; + float tc[2], endtc[2]; + float tcscale[2]; + unsigned int tci[2]; + unsigned int tci1[2]; + unsigned int tcimin[2]; + unsigned int tcimax[2]; + int tciwrapmask[2]; + int tciwidth; + int filter; + int mip; + const unsigned char * RESTRICT pixelbase; + const unsigned char * RESTRICT pixel[4]; + DPSOFTRAST_Texture *texture = thread->texbound[texunitindex]; + // if no texture is bound, just fill it with white + if (!texture) + { + for (x = startx;x < endx;x++) + { + out4f[x*4+0] = 1.0f; + out4f[x*4+1] = 1.0f; + out4f[x*4+2] = 1.0f; + out4f[x*4+3] = 1.0f; + } + return; + } + mip = triangle->mip[texunitindex]; + pixelbase = (unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*texture->mipmap[mip][2]; + // if this mipmap of the texture is 1 pixel, just fill it with that color + if (texture->mipmap[mip][1] == 4) + { + c[0] = texture->bytes[2] * (1.0f/255.0f); + c[1] = texture->bytes[1] * (1.0f/255.0f); + c[2] = texture->bytes[0] * (1.0f/255.0f); + c[3] = texture->bytes[3] * (1.0f/255.0f); + for (x = startx;x < endx;x++) + { + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } + return; + } + filter = texture->filter & DPSOFTRAST_TEXTURE_FILTER_LINEAR; + DPSOFTRAST_CALCATTRIB4F(triangle, span, data, slope, arrayindex); + flags = texture->flags; + tcscale[0] = texture->mipmap[mip][2]; + tcscale[1] = texture->mipmap[mip][3]; + tciwidth = -texture->mipmap[mip][2]; + tcimin[0] = 0; + tcimin[1] = 0; + tcimax[0] = texture->mipmap[mip][2]-1; + tcimax[1] = texture->mipmap[mip][3]-1; + tciwrapmask[0] = texture->mipmap[mip][2]-1; + tciwrapmask[1] = texture->mipmap[mip][3]-1; + endtc[0] = (data[0] + slope[0]*startx) * zf[startx] * tcscale[0]; + endtc[1] = (data[1] + slope[1]*startx) * zf[startx] * tcscale[1]; + if (filter) + { + endtc[0] -= 0.5f; + endtc[1] -= 0.5f; + } + for (x = startx;x < endx;) + { + unsigned int subtc[2]; + unsigned int substep[2]; + float subscale = 4096.0f/DPSOFTRAST_DRAW_MAXSUBSPAN; + int nextsub = x + DPSOFTRAST_DRAW_MAXSUBSPAN, endsub = nextsub - 1; + if (nextsub >= endx) + { + nextsub = endsub = endx-1; + if (x < nextsub) subscale = 4096.0f / (nextsub - x); + } + tc[0] = endtc[0]; + tc[1] = endtc[1]; + endtc[0] = (data[0] + slope[0]*nextsub) * zf[nextsub] * tcscale[0]; + endtc[1] = (data[1] + slope[1]*nextsub) * zf[nextsub] * tcscale[1]; + if (filter) + { + endtc[0] -= 0.5f; + endtc[1] -= 0.5f; + } + substep[0] = (endtc[0] - tc[0]) * subscale; + substep[1] = (endtc[1] - tc[1]) * subscale; + subtc[0] = tc[0] * (1<<12); + subtc[1] = tc[1] * (1<<12); + if (filter) + { + if (flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + for (; x <= endsub; x++, subtc[0] += substep[0], subtc[1] += substep[1]) + { + unsigned int frac[2] = { subtc[0]&0xFFF, subtc[1]&0xFFF }; + unsigned int ifrac[2] = { 0x1000 - frac[0], 0x1000 - frac[1] }; + unsigned int lerp[4] = { ifrac[0]*ifrac[1], frac[0]*ifrac[1], ifrac[0]*frac[1], frac[0]*frac[1] }; + tci[0] = subtc[0]>>12; + tci[1] = subtc[1]>>12; + tci1[0] = tci[0] + 1; + tci1[1] = tci[1] + 1; + tci[0] = tci[0] >= tcimin[0] ? (tci[0] <= tcimax[0] ? tci[0] : tcimax[0]) : tcimin[0]; + tci[1] = tci[1] >= tcimin[1] ? (tci[1] <= tcimax[1] ? tci[1] : tcimax[1]) : tcimin[1]; + tci1[0] = tci1[0] >= tcimin[0] ? (tci1[0] <= tcimax[0] ? tci1[0] : tcimax[0]) : tcimin[0]; + tci1[1] = tci1[1] >= tcimin[1] ? (tci1[1] <= tcimax[1] ? tci1[1] : tcimax[1]) : tcimin[1]; + pixel[0] = pixelbase + 4 * (tci[1]*tciwidth+tci[0]); + pixel[1] = pixelbase + 4 * (tci[1]*tciwidth+tci1[0]); + pixel[2] = pixelbase + 4 * (tci1[1]*tciwidth+tci[0]); + pixel[3] = pixelbase + 4 * (tci1[1]*tciwidth+tci1[0]); + c[0] = (pixel[0][2]*lerp[0]+pixel[1][2]*lerp[1]+pixel[2][2]*lerp[2]+pixel[3][2]*lerp[3]) * (1.0f / 0xFF000000); + c[1] = (pixel[0][1]*lerp[0]+pixel[1][1]*lerp[1]+pixel[2][1]*lerp[2]+pixel[3][1]*lerp[3]) * (1.0f / 0xFF000000); + c[2] = (pixel[0][0]*lerp[0]+pixel[1][0]*lerp[1]+pixel[2][0]*lerp[2]+pixel[3][0]*lerp[3]) * (1.0f / 0xFF000000); + c[3] = (pixel[0][3]*lerp[0]+pixel[1][3]*lerp[1]+pixel[2][3]*lerp[2]+pixel[3][3]*lerp[3]) * (1.0f / 0xFF000000); + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } + } + else + { + for (; x <= endsub; x++, subtc[0] += substep[0], subtc[1] += substep[1]) + { + unsigned int frac[2] = { subtc[0]&0xFFF, subtc[1]&0xFFF }; + unsigned int ifrac[2] = { 0x1000 - frac[0], 0x1000 - frac[1] }; + unsigned int lerp[4] = { ifrac[0]*ifrac[1], frac[0]*ifrac[1], ifrac[0]*frac[1], frac[0]*frac[1] }; + tci[0] = subtc[0]>>12; + tci[1] = subtc[1]>>12; + tci1[0] = tci[0] + 1; + tci1[1] = tci[1] + 1; + tci[0] &= tciwrapmask[0]; + tci[1] &= tciwrapmask[1]; + tci1[0] &= tciwrapmask[0]; + tci1[1] &= tciwrapmask[1]; + pixel[0] = pixelbase + 4 * (tci[1]*tciwidth+tci[0]); + pixel[1] = pixelbase + 4 * (tci[1]*tciwidth+tci1[0]); + pixel[2] = pixelbase + 4 * (tci1[1]*tciwidth+tci[0]); + pixel[3] = pixelbase + 4 * (tci1[1]*tciwidth+tci1[0]); + c[0] = (pixel[0][2]*lerp[0]+pixel[1][2]*lerp[1]+pixel[2][2]*lerp[2]+pixel[3][2]*lerp[3]) * (1.0f / 0xFF000000); + c[1] = (pixel[0][1]*lerp[0]+pixel[1][1]*lerp[1]+pixel[2][1]*lerp[2]+pixel[3][1]*lerp[3]) * (1.0f / 0xFF000000); + c[2] = (pixel[0][0]*lerp[0]+pixel[1][0]*lerp[1]+pixel[2][0]*lerp[2]+pixel[3][0]*lerp[3]) * (1.0f / 0xFF000000); + c[3] = (pixel[0][3]*lerp[0]+pixel[1][3]*lerp[1]+pixel[2][3]*lerp[2]+pixel[3][3]*lerp[3]) * (1.0f / 0xFF000000); + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } + } + } + else if (flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + for (; x <= endsub; x++, subtc[0] += substep[0], subtc[1] += substep[1]) + { + tci[0] = subtc[0]>>12; + tci[1] = subtc[1]>>12; + tci[0] = tci[0] >= tcimin[0] ? (tci[0] <= tcimax[0] ? tci[0] : tcimax[0]) : tcimin[0]; + tci[1] = tci[1] >= tcimin[1] ? (tci[1] <= tcimax[1] ? tci[1] : tcimax[1]) : tcimin[1]; + pixel[0] = pixelbase + 4 * (tci[1]*tciwidth+tci[0]); + c[0] = pixel[0][2] * (1.0f / 255.0f); + c[1] = pixel[0][1] * (1.0f / 255.0f); + c[2] = pixel[0][0] * (1.0f / 255.0f); + c[3] = pixel[0][3] * (1.0f / 255.0f); + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } + } + else + { + for (; x <= endsub; x++, subtc[0] += substep[0], subtc[1] += substep[1]) + { + tci[0] = subtc[0]>>12; + tci[1] = subtc[1]>>12; + tci[0] &= tciwrapmask[0]; + tci[1] &= tciwrapmask[1]; + pixel[0] = pixelbase + 4 * (tci[1]*tciwidth+tci[0]); + c[0] = pixel[0][2] * (1.0f / 255.0f); + c[1] = pixel[0][1] * (1.0f / 255.0f); + c[2] = pixel[0][0] * (1.0f / 255.0f); + c[3] = pixel[0][3] * (1.0f / 255.0f); + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } + } + } +} +#endif + +static void DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char * RESTRICT out4ub, int texunitindex, int arrayindex, const float * RESTRICT zf) +{ +#ifdef SSE_POSSIBLE + int x; + int startx = span->startx; + int endx = span->endx; + int flags; + __m128 data, slope, tcscale; + __m128i tcsize, tcmask, tcoffset, tcmax; + __m128 tc, endtc; + __m128i subtc, substep, endsubtc; + int filter; + int mip; + int affine; // LordHavoc: optimized affine texturing case + unsigned int * RESTRICT outi = (unsigned int *)out4ub; + const unsigned char * RESTRICT pixelbase; + DPSOFTRAST_Texture *texture = thread->texbound[texunitindex]; + // if no texture is bound, just fill it with white + if (!texture) + { + memset(out4ub + startx*4, 255, (span->endx - span->startx)*4); + return; + } + mip = triangle->mip[texunitindex]; + pixelbase = (const unsigned char *)texture->bytes + texture->mipmap[mip][0] + texture->mipmap[mip][1] - 4*texture->mipmap[mip][2]; + // if this mipmap of the texture is 1 pixel, just fill it with that color + if (texture->mipmap[mip][1] == 4) + { + unsigned int k = *((const unsigned int *)pixelbase); + for (x = startx;x < endx;x++) + outi[x] = k; + return; + } + affine = zf[startx] == zf[endx-1]; + filter = texture->filter & DPSOFTRAST_TEXTURE_FILTER_LINEAR; + DPSOFTRAST_CALCATTRIB(triangle, span, data, slope, arrayindex); + flags = texture->flags; + tcsize = _mm_shuffle_epi32(_mm_loadu_si128((const __m128i *)&texture->mipmap[mip][0]), _MM_SHUFFLE(3, 2, 3, 2)); + tcmask = _mm_sub_epi32(tcsize, _mm_set1_epi32(1)); + tcscale = _mm_cvtepi32_ps(tcsize); + data = _mm_mul_ps(_mm_movelh_ps(data, data), tcscale); + slope = _mm_mul_ps(_mm_movelh_ps(slope, slope), tcscale); + endtc = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(startx))), _mm_load1_ps(&zf[startx])); + if (filter) + endtc = _mm_sub_ps(endtc, _mm_set1_ps(0.5f)); + endsubtc = _mm_cvtps_epi32(_mm_mul_ps(endtc, _mm_set1_ps(65536.0f))); + tcoffset = _mm_add_epi32(_mm_slli_epi32(_mm_sub_epi32(_mm_setzero_si128(), _mm_shuffle_epi32(tcsize, _MM_SHUFFLE(0, 0, 0, 0))), 18), _mm_set1_epi32(4)); + tcmax = _mm_packs_epi32(tcmask, tcmask); + for (x = startx;x < endx;) + { + int nextsub = x + DPSOFTRAST_DRAW_MAXSUBSPAN, endsub = nextsub - 1; + __m128 subscale = _mm_set1_ps(65536.0f/DPSOFTRAST_DRAW_MAXSUBSPAN); + if (nextsub >= endx || affine) + { + nextsub = endsub = endx-1; + if (x < nextsub) subscale = _mm_set1_ps(65536.0f / (nextsub - x)); + } + tc = endtc; + subtc = endsubtc; + endtc = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(nextsub))), _mm_load1_ps(&zf[nextsub])); + if (filter) + endtc = _mm_sub_ps(endtc, _mm_set1_ps(0.5f)); + substep = _mm_cvtps_epi32(_mm_mul_ps(_mm_sub_ps(endtc, tc), subscale)); + endsubtc = _mm_cvtps_epi32(_mm_mul_ps(endtc, _mm_set1_ps(65536.0f))); + subtc = _mm_unpacklo_epi64(subtc, _mm_add_epi32(subtc, substep)); + substep = _mm_slli_epi32(substep, 1); + if (filter) + { + __m128i tcrange = _mm_srai_epi32(_mm_unpacklo_epi64(subtc, _mm_add_epi32(endsubtc, substep)), 16); + if (_mm_movemask_epi8(_mm_andnot_si128(_mm_cmplt_epi32(tcrange, _mm_setzero_si128()), _mm_cmplt_epi32(tcrange, tcmask))) == 0xFFFF) + { + int stride = _mm_cvtsi128_si32(tcoffset)>>16; + for (; x + 1 <= endsub; x += 2, subtc = _mm_add_epi32(subtc, substep)) + { + const unsigned char * RESTRICT ptr1, * RESTRICT ptr2; + __m128i tci = _mm_shufflehi_epi16(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(3, 1, 3, 1)), pix1, pix2, pix3, pix4, fracm; + tci = _mm_madd_epi16(tci, tcoffset); + ptr1 = pixelbase + _mm_cvtsi128_si32(tci); + ptr2 = pixelbase + _mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2))); + pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)ptr1), _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(ptr1 + stride)), _mm_setzero_si128()); + pix3 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)ptr2), _mm_setzero_si128()); + pix4 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(ptr2 + stride)), _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix3 = _mm_add_epi16(pix3, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix3), 1), + _mm_shuffle_epi32(_mm_shufflehi_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(3, 2, 3, 2)))); + pix2 = _mm_unpacklo_epi64(pix1, pix3); + pix4 = _mm_unpackhi_epi64(pix1, pix3); + pix2 = _mm_add_epi16(pix2, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix2), 1), + _mm_shufflehi_epi16(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)), _MM_SHUFFLE(0, 0, 0, 0)))); + _mm_storel_epi64((__m128i *)&outi[x], _mm_packus_epi16(pix2, _mm_shufflelo_epi16(pix2, _MM_SHUFFLE(3, 2, 3, 2)))); + } + if (x <= endsub) + { + const unsigned char * RESTRICT ptr1; + __m128i tci = _mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), pix1, pix2, fracm; + tci = _mm_madd_epi16(tci, tcoffset); + ptr1 = pixelbase + _mm_cvtsi128_si32(tci); + pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)ptr1), _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(ptr1 + stride)), _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix2 = _mm_shuffle_epi32(pix1, _MM_SHUFFLE(3, 2, 3, 2)); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)))); + outi[x] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + x++; + } + } + else if (flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + for (; x + 1 <= endsub; x += 2, subtc = _mm_add_epi32(subtc, substep)) + { + __m128i tci = _mm_shuffle_epi32(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(1, 0, 1, 0)), pix1, pix2, pix3, pix4, fracm; + tci = _mm_min_epi16(_mm_max_epi16(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), _mm_setzero_si128()), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix1 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + tci = _mm_shuffle_epi32(_mm_shufflehi_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(3, 2, 3, 2)); + tci = _mm_and_si128(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix3 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix4 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix3 = _mm_add_epi16(pix3, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix3), 1), + _mm_shuffle_epi32(_mm_shufflehi_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(3, 2, 3, 2)))); + pix2 = _mm_unpacklo_epi64(pix1, pix3); + pix4 = _mm_unpackhi_epi64(pix1, pix3); + pix2 = _mm_add_epi16(pix2, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix2), 1), + _mm_shufflehi_epi16(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)), _MM_SHUFFLE(0, 0, 0, 0)))); + _mm_storel_epi64((__m128i *)&outi[x], _mm_packus_epi16(pix2, _mm_shufflelo_epi16(pix2, _MM_SHUFFLE(3, 2, 3, 2)))); + } + if (x <= endsub) + { + __m128i tci = _mm_shuffle_epi32(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(1, 0, 1, 0)), pix1, pix2, fracm; + tci = _mm_min_epi16(_mm_max_epi16(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), _mm_setzero_si128()), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix1 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix2 = _mm_shuffle_epi32(pix1, _MM_SHUFFLE(3, 2, 3, 2)); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)))); + outi[x] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + x++; + } + } + else + { + for (; x + 1 <= endsub; x += 2, subtc = _mm_add_epi32(subtc, substep)) + { + __m128i tci = _mm_shuffle_epi32(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(1, 0, 1, 0)), pix1, pix2, pix3, pix4, fracm; + tci = _mm_and_si128(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix1 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + tci = _mm_shuffle_epi32(_mm_shufflehi_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(3, 2, 3, 2)); + tci = _mm_and_si128(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix3 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix4 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix3 = _mm_add_epi16(pix3, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix3), 1), + _mm_shuffle_epi32(_mm_shufflehi_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(3, 2, 3, 2)))); + pix2 = _mm_unpacklo_epi64(pix1, pix3); + pix4 = _mm_unpackhi_epi64(pix1, pix3); + pix2 = _mm_add_epi16(pix2, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix4, pix2), 1), + _mm_shufflehi_epi16(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)), _MM_SHUFFLE(0, 0, 0, 0)))); + _mm_storel_epi64((__m128i *)&outi[x], _mm_packus_epi16(pix2, _mm_shufflelo_epi16(pix2, _MM_SHUFFLE(3, 2, 3, 2)))); + } + if (x <= endsub) + { + __m128i tci = _mm_shuffle_epi32(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(1, 0, 1, 0)), pix1, pix2, fracm; + tci = _mm_and_si128(_mm_add_epi16(tci, _mm_setr_epi32(0, 1, 0x10000, 0x10001)), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + pix1 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(1, 1, 1, 1)))])), + _mm_setzero_si128()); + pix2 = _mm_unpacklo_epi8(_mm_unpacklo_epi32(_mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]), + _mm_cvtsi32_si128(*(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(3, 3, 3, 3)))])), + _mm_setzero_si128()); + fracm = _mm_srli_epi16(subtc, 1); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shuffle_epi32(_mm_shufflelo_epi16(fracm, _MM_SHUFFLE(2, 2, 2, 2)), _MM_SHUFFLE(1, 0, 1, 0)))); + pix2 = _mm_shuffle_epi32(pix1, _MM_SHUFFLE(3, 2, 3, 2)); + pix1 = _mm_add_epi16(pix1, + _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 1), + _mm_shufflelo_epi16(fracm, _MM_SHUFFLE(0, 0, 0, 0)))); + outi[x] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + x++; + } + } + } + else + { + if (flags & DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE) + { + for (; x + 1 <= endsub; x += 2, subtc = _mm_add_epi32(subtc, substep)) + { + __m128i tci = _mm_shufflehi_epi16(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(3, 1, 3, 1)); + tci = _mm_min_epi16(_mm_max_epi16(tci, _mm_setzero_si128()), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + outi[x] = *(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]; + outi[x+1] = *(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]; + } + if (x <= endsub) + { + __m128i tci = _mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)); + tci =_mm_min_epi16(_mm_max_epi16(tci, _mm_setzero_si128()), tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + outi[x] = *(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]; + x++; + } + } + else + { + for (; x + 1 <= endsub; x += 2, subtc = _mm_add_epi32(subtc, substep)) + { + __m128i tci = _mm_shufflehi_epi16(_mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)), _MM_SHUFFLE(3, 1, 3, 1)); + tci = _mm_and_si128(tci, tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + outi[x] = *(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]; + outi[x+1] = *(const int *)&pixelbase[_mm_cvtsi128_si32(_mm_shuffle_epi32(tci, _MM_SHUFFLE(2, 2, 2, 2)))]; + } + if (x <= endsub) + { + __m128i tci = _mm_shufflelo_epi16(subtc, _MM_SHUFFLE(3, 1, 3, 1)); + tci = _mm_and_si128(tci, tcmax); + tci = _mm_madd_epi16(tci, tcoffset); + outi[x] = *(const int *)&pixelbase[_mm_cvtsi128_si32(tci)]; + x++; + } + } + } + } +#endif +} + +static void DPSOFTRAST_Draw_Span_TextureCubeVaryingBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char * RESTRICT out4ub, int texunitindex, int arrayindex, const float * RESTRICT zf) +{ + // TODO: IMPLEMENT + memset(out4ub + span->startx*4, 255, (span->startx - span->endx)*4); +} + +static float DPSOFTRAST_SampleShadowmap(const float *vector) +{ + // TODO: IMPLEMENT + return 1.0f; +} + +#if 0 +static void DPSOFTRAST_Draw_Span_MultiplyVarying(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *in4f, int arrayindex, const float *zf) +{ + int x; + int startx = span->startx; + int endx = span->endx; + float c[4]; + float data[4]; + float slope[4]; + float z; + DPSOFTRAST_CALCATTRIB4F(triangle, span, data, slope, arrayindex); + for (x = startx;x < endx;x++) + { + z = zf[x]; + c[0] = (data[0] + slope[0]*x) * z; + c[1] = (data[1] + slope[1]*x) * z; + c[2] = (data[2] + slope[2]*x) * z; + c[3] = (data[3] + slope[3]*x) * z; + out4f[x*4+0] = in4f[x*4+0] * c[0]; + out4f[x*4+1] = in4f[x*4+1] * c[1]; + out4f[x*4+2] = in4f[x*4+2] * c[2]; + out4f[x*4+3] = in4f[x*4+3] * c[3]; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_Varying(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, int arrayindex, const float *zf) +{ + int x; + int startx = span->startx; + int endx = span->endx; + float c[4]; + float data[4]; + float slope[4]; + float z; + DPSOFTRAST_CALCATTRIB4F(triangle, span, data, slope, arrayindex); + for (x = startx;x < endx;x++) + { + z = zf[x]; + c[0] = (data[0] + slope[0]*x) * z; + c[1] = (data[1] + slope[1]*x) * z; + c[2] = (data[2] + slope[2]*x) * z; + c[3] = (data[3] + slope[3]*x) * z; + out4f[x*4+0] = c[0]; + out4f[x*4+1] = c[1]; + out4f[x*4+2] = c[2]; + out4f[x*4+3] = c[3]; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_AddBloom(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *ina4f, const float *inb4f, const float *subcolor) +{ + int x, startx = span->startx, endx = span->endx; + float c[4], localcolor[4]; + localcolor[0] = subcolor[0]; + localcolor[1] = subcolor[1]; + localcolor[2] = subcolor[2]; + localcolor[3] = subcolor[3]; + for (x = startx;x < endx;x++) + { + c[0] = inb4f[x*4+0] - localcolor[0];if (c[0] < 0.0f) c[0] = 0.0f; + c[1] = inb4f[x*4+1] - localcolor[1];if (c[1] < 0.0f) c[1] = 0.0f; + c[2] = inb4f[x*4+2] - localcolor[2];if (c[2] < 0.0f) c[2] = 0.0f; + c[3] = inb4f[x*4+3] - localcolor[3];if (c[3] < 0.0f) c[3] = 0.0f; + out4f[x*4+0] = ina4f[x*4+0] + c[0]; + out4f[x*4+1] = ina4f[x*4+1] + c[1]; + out4f[x*4+2] = ina4f[x*4+2] + c[2]; + out4f[x*4+3] = ina4f[x*4+3] + c[3]; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_MultiplyBuffers(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *ina4f, const float *inb4f) +{ + int x, startx = span->startx, endx = span->endx; + for (x = startx;x < endx;x++) + { + out4f[x*4+0] = ina4f[x*4+0] * inb4f[x*4+0]; + out4f[x*4+1] = ina4f[x*4+1] * inb4f[x*4+1]; + out4f[x*4+2] = ina4f[x*4+2] * inb4f[x*4+2]; + out4f[x*4+3] = ina4f[x*4+3] * inb4f[x*4+3]; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_AddBuffers(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *ina4f, const float *inb4f) +{ + int x, startx = span->startx, endx = span->endx; + for (x = startx;x < endx;x++) + { + out4f[x*4+0] = ina4f[x*4+0] + inb4f[x*4+0]; + out4f[x*4+1] = ina4f[x*4+1] + inb4f[x*4+1]; + out4f[x*4+2] = ina4f[x*4+2] + inb4f[x*4+2]; + out4f[x*4+3] = ina4f[x*4+3] + inb4f[x*4+3]; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_MixBuffers(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *ina4f, const float *inb4f) +{ + int x, startx = span->startx, endx = span->endx; + float a, b; + for (x = startx;x < endx;x++) + { + a = 1.0f - inb4f[x*4+3]; + b = inb4f[x*4+3]; + out4f[x*4+0] = ina4f[x*4+0] * a + inb4f[x*4+0] * b; + out4f[x*4+1] = ina4f[x*4+1] * a + inb4f[x*4+1] * b; + out4f[x*4+2] = ina4f[x*4+2] * a + inb4f[x*4+2] * b; + out4f[x*4+3] = ina4f[x*4+3] * a + inb4f[x*4+3] * b; + } +} +#endif + +#if 0 +static void DPSOFTRAST_Draw_Span_MixUniformColor(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, float *out4f, const float *in4f, const float *color) +{ + int x, startx = span->startx, endx = span->endx; + float localcolor[4], ilerp, lerp; + localcolor[0] = color[0]; + localcolor[1] = color[1]; + localcolor[2] = color[2]; + localcolor[3] = color[3]; + ilerp = 1.0f - localcolor[3]; + lerp = localcolor[3]; + for (x = startx;x < endx;x++) + { + out4f[x*4+0] = in4f[x*4+0] * ilerp + localcolor[0] * lerp; + out4f[x*4+1] = in4f[x*4+1] * ilerp + localcolor[1] * lerp; + out4f[x*4+2] = in4f[x*4+2] * ilerp + localcolor[2] * lerp; + out4f[x*4+3] = in4f[x*4+3] * ilerp + localcolor[3] * lerp; + } +} +#endif + + + +static void DPSOFTRAST_Draw_Span_MultiplyVaryingBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *in4ub, int arrayindex, const float *zf) +{ +#ifdef SSE_POSSIBLE + int x; + int startx = span->startx; + int endx = span->endx; + __m128 data, slope; + __m128 mod, endmod; + __m128i submod, substep, endsubmod; + DPSOFTRAST_CALCATTRIB(triangle, span, data, slope, arrayindex); + data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(3, 0, 1, 2)); + slope = _mm_shuffle_ps(slope, slope, _MM_SHUFFLE(3, 0, 1, 2)); + endmod = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(startx))), _mm_load1_ps(&zf[startx])); + endsubmod = _mm_cvtps_epi32(_mm_mul_ps(endmod, _mm_set1_ps(256.0f))); + for (x = startx; x < endx;) + { + int nextsub = x + DPSOFTRAST_DRAW_MAXSUBSPAN, endsub = nextsub - 1; + __m128 subscale = _mm_set1_ps(256.0f/DPSOFTRAST_DRAW_MAXSUBSPAN); + if (nextsub >= endx) + { + nextsub = endsub = endx-1; + if (x < nextsub) subscale = _mm_set1_ps(256.0f / (nextsub - x)); + } + mod = endmod; + submod = endsubmod; + endmod = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(nextsub))), _mm_load1_ps(&zf[nextsub])); + substep = _mm_cvtps_epi32(_mm_mul_ps(_mm_sub_ps(endmod, mod), subscale)); + endsubmod = _mm_cvtps_epi32(_mm_mul_ps(endmod, _mm_set1_ps(256.0f))); + submod = _mm_packs_epi32(submod, _mm_add_epi32(submod, substep)); + substep = _mm_packs_epi32(substep, substep); + for (; x + 1 <= endsub; x += 2, submod = _mm_add_epi16(submod, substep)) + { + __m128i pix = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_loadl_epi64((const __m128i *)&in4ub[x*4])); + pix = _mm_mulhi_epu16(pix, submod); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix, pix)); + } + if (x <= endsub) + { + __m128i pix = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&in4ub[x*4])); + pix = _mm_mulhi_epu16(pix, submod); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + x++; + } + } +#endif +} + +static void DPSOFTRAST_Draw_Span_VaryingBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, int arrayindex, const float *zf) +{ +#ifdef SSE_POSSIBLE + int x; + int startx = span->startx; + int endx = span->endx; + __m128 data, slope; + __m128 mod, endmod; + __m128i submod, substep, endsubmod; + DPSOFTRAST_CALCATTRIB(triangle, span, data, slope, arrayindex); + data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(3, 0, 1, 2)); + slope = _mm_shuffle_ps(slope, slope, _MM_SHUFFLE(3, 0, 1, 2)); + endmod = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(startx))), _mm_load1_ps(&zf[startx])); + endsubmod = _mm_cvtps_epi32(_mm_mul_ps(endmod, _mm_set1_ps(4095.0f))); + for (x = startx; x < endx;) + { + int nextsub = x + DPSOFTRAST_DRAW_MAXSUBSPAN, endsub = nextsub - 1; + __m128 subscale = _mm_set1_ps(4095.0f/DPSOFTRAST_DRAW_MAXSUBSPAN); + if (nextsub >= endx) + { + nextsub = endsub = endx-1; + if (x < nextsub) subscale = _mm_set1_ps(4095.0f / (nextsub - x)); + } + mod = endmod; + submod = endsubmod; + endmod = _mm_mul_ps(_mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(nextsub))), _mm_load1_ps(&zf[nextsub])); + substep = _mm_cvtps_epi32(_mm_mul_ps(_mm_sub_ps(endmod, mod), subscale)); + endsubmod = _mm_cvtps_epi32(_mm_mul_ps(endmod, _mm_set1_ps(4095.0f))); + submod = _mm_packs_epi32(submod, _mm_add_epi32(submod, substep)); + substep = _mm_packs_epi32(substep, substep); + for (; x + 1 <= endsub; x += 2, submod = _mm_add_epi16(submod, substep)) + { + __m128i pix = _mm_srai_epi16(submod, 4); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix, pix)); + } + if (x <= endsub) + { + __m128i pix = _mm_srai_epi16(submod, 4); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + x++; + } + } +#endif +} + +static void DPSOFTRAST_Draw_Span_AddBloomBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *ina4ub, const unsigned char *inb4ub, const float *subcolor) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + __m128i localcolor = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_loadu_ps(subcolor), _mm_set1_ps(255.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + localcolor = _mm_packs_epi32(localcolor, localcolor); + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&inb4ub[x*4]), _mm_setzero_si128()); + pix1 = _mm_add_epi16(pix1, _mm_subs_epu16(pix2, localcolor)); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix1, pix1)); + } + if (x < endx) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&inb4ub[x*4]), _mm_setzero_si128()); + pix1 = _mm_add_epi16(pix1, _mm_subs_epu16(pix2, localcolor)); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + } +#endif +} + +static void DPSOFTRAST_Draw_Span_MultiplyBuffersBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *ina4ub, const unsigned char *inb4ub) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_loadl_epi64((const __m128i *)&inb4ub[x*4])); + pix1 = _mm_mulhi_epu16(pix1, pix2); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix1, pix1)); + } + if (x < endx) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&inb4ub[x*4])); + pix1 = _mm_mulhi_epu16(pix1, pix2); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + } +#endif +} + +static void DPSOFTRAST_Draw_Span_AddBuffersBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *ina4ub, const unsigned char *inb4ub) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&inb4ub[x*4]), _mm_setzero_si128()); + pix1 = _mm_add_epi16(pix1, pix2); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix1, pix1)); + } + if (x < endx) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&inb4ub[x*4]), _mm_setzero_si128()); + pix1 = _mm_add_epi16(pix1, pix2); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + } +#endif +} + +#if 0 +static void DPSOFTRAST_Draw_Span_TintedAddBuffersBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *ina4ub, const unsigned char *inb4ub, const float *inbtintbgra) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + __m128i tint = _mm_cvtps_epi32(_mm_mul_ps(_mm_loadu_ps(inbtintbgra), _mm_set1_ps(256.0f))); + tint = _mm_packs_epi32(tint, tint); + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_loadl_epi64((const __m128i *)&inb4ub[x*4])); + pix1 = _mm_add_epi16(pix1, _mm_mulhi_epu16(tint, pix2)); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix1, pix1)); + } + if (x < endx) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&inb4ub[x*4])); + pix1 = _mm_add_epi16(pix1, _mm_mulhi_epu16(tint, pix2)); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + } +#endif +} +#endif + +static void DPSOFTRAST_Draw_Span_MixBuffersBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *ina4ub, const unsigned char *inb4ub) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&inb4ub[x*4]), _mm_setzero_si128()); + __m128i blend = _mm_shufflehi_epi16(_mm_shufflelo_epi16(pix2, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)); + pix1 = _mm_add_epi16(pix1, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 4), _mm_slli_epi16(blend, 4))); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix1, pix1)); + } + if (x < endx) + { + __m128i pix1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&ina4ub[x*4]), _mm_setzero_si128()); + __m128i pix2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&inb4ub[x*4]), _mm_setzero_si128()); + __m128i blend = _mm_shufflelo_epi16(pix2, _MM_SHUFFLE(3, 3, 3, 3)); + pix1 = _mm_add_epi16(pix1, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(pix2, pix1), 4), _mm_slli_epi16(blend, 4))); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix1, pix1)); + } +#endif +} + +static void DPSOFTRAST_Draw_Span_MixUniformColorBGRA8(const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span, unsigned char *out4ub, const unsigned char *in4ub, const float *color) +{ +#ifdef SSE_POSSIBLE + int x, startx = span->startx, endx = span->endx; + __m128i localcolor = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_loadu_ps(color), _mm_set1_ps(255.0f))), _MM_SHUFFLE(3, 0, 1, 2)), blend; + localcolor = _mm_packs_epi32(localcolor, localcolor); + blend = _mm_slli_epi16(_mm_shufflehi_epi16(_mm_shufflelo_epi16(localcolor, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3)), 4); + for (x = startx;x+2 <= endx;x+=2) + { + __m128i pix = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)&in4ub[x*4]), _mm_setzero_si128()); + pix = _mm_add_epi16(pix, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(localcolor, pix), 4), blend)); + _mm_storel_epi64((__m128i *)&out4ub[x*4], _mm_packus_epi16(pix, pix)); + } + if (x < endx) + { + __m128i pix = _mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int *)&in4ub[x*4]), _mm_setzero_si128()); + pix = _mm_add_epi16(pix, _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(localcolor, pix), 4), blend)); + *(int *)&out4ub[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + } +#endif +} + + + +static void DPSOFTRAST_VertexShader_Generic(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_COLOR, DPSOFTRAST_ARRAY_COLOR); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0); + if (dpsoftrast.shader_permutation & SHADERPERMUTATION_SPECULAR) + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD1); +} + +static void DPSOFTRAST_PixelShader_Generic(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_lightmapbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_DIFFUSE) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_FIRST, 2, buffer_z); + DPSOFTRAST_Draw_Span_MultiplyVaryingBGRA8(triangle, span, buffer_FragColorbgra8, buffer_texture_colorbgra8, 1, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_SPECULAR) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_SECOND, 2, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + // multiply + DPSOFTRAST_Draw_Span_MultiplyBuffersBGRA8(triangle, span, buffer_FragColorbgra8, buffer_FragColorbgra8, buffer_texture_lightmapbgra8); + } + else if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + // add + DPSOFTRAST_Draw_Span_AddBuffersBGRA8(triangle, span, buffer_FragColorbgra8, buffer_FragColorbgra8, buffer_texture_lightmapbgra8); + } + else if (thread->shader_permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) + { + // alphablend + DPSOFTRAST_Draw_Span_MixBuffersBGRA8(triangle, span, buffer_FragColorbgra8, buffer_FragColorbgra8, buffer_texture_lightmapbgra8); + } + } + } + else + DPSOFTRAST_Draw_Span_VaryingBGRA8(triangle, span, buffer_FragColorbgra8, 1, buffer_z); + if(thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) + { + int x; + for (x = span->startx;x < span->endx;x++) + buffer_FragColorbgra8[x*4+3] = buffer_FragColorbgra8[x*4+3] * thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]; + } + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_PostProcess(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD4); +} + +static void DPSOFTRAST_PixelShader_PostProcess(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + // TODO: optimize!! at the very least there is no reason to use texture sampling on the frame texture + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_FragColorbgra8, GL20TU_FIRST, 2, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_BLOOM) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_SECOND, 3, buffer_z); + DPSOFTRAST_Draw_Span_AddBloomBGRA8(triangle, span, buffer_FragColorbgra8, buffer_FragColorbgra8, buffer_texture_colorbgra8, thread->uniform4f + DPSOFTRAST_UNIFORM_BloomColorSubtract * 4); + } + DPSOFTRAST_Draw_Span_MixUniformColorBGRA8(triangle, span, buffer_FragColorbgra8, buffer_FragColorbgra8, thread->uniform4f + DPSOFTRAST_UNIFORM_ViewTintColor * 4); + if (thread->shader_permutation & SHADERPERMUTATION_SATURATION) + { + // TODO: implement saturation + } + if (thread->shader_permutation & SHADERPERMUTATION_GAMMARAMPS) + { + // TODO: implement gammaramps + } + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_Depth_Or_Shadow(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); +} + +static void DPSOFTRAST_PixelShader_Depth_Or_Shadow(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + // this is never called (because colormask is off when this shader is used) + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + memset(buffer_FragColorbgra8 + span->startx*4, 0, (span->endx - span->startx)*4); + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_FlatColor(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); +} + +static void DPSOFTRAST_PixelShader_FlatColor(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ +#ifdef SSE_POSSIBLE + unsigned char * RESTRICT pixelmask = span->pixelmask; + unsigned char * RESTRICT pixel = (unsigned char *)dpsoftrast.fb_colorpixels[0] + (span->y * dpsoftrast.fb_width + span->x) * 4; + int x, startx = span->startx, endx = span->endx; + __m128i Color_Ambientm; + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, 2, buffer_z); + if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE) + pixel = buffer_FragColorbgra8; + Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Ambientm = _mm_or_si128(Color_Ambientm, _mm_setr_epi32(0, 0, 0, (int)(thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]*255.0f))); + Color_Ambientm = _mm_packs_epi32(Color_Ambientm, Color_Ambientm); + for (x = startx;x < endx;x++) + { + __m128i color, pix; + if (x + 4 <= endx && *(const unsigned int *)&pixelmask[x] == 0x01010101) + { + __m128i pix2; + color = _mm_loadu_si128((const __m128i *)&buffer_texture_colorbgra8[x*4]); + pix = _mm_mulhi_epu16(Color_Ambientm, _mm_unpacklo_epi8(_mm_setzero_si128(), color)); + pix2 = _mm_mulhi_epu16(Color_Ambientm, _mm_unpackhi_epi8(_mm_setzero_si128(), color)); + _mm_storeu_si128((__m128i *)&pixel[x*4], _mm_packus_epi16(pix, pix2)); + x += 3; + continue; + } + if (!pixelmask[x]) + continue; + color = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_colorbgra8[x*4])); + pix = _mm_mulhi_epu16(Color_Ambientm, color); + *(int *)&pixel[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + } + if (pixel == buffer_FragColorbgra8) + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +#endif +} + + + +static void DPSOFTRAST_VertexShader_VertexColor(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_COLOR, DPSOFTRAST_ARRAY_COLOR); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); +} + +static void DPSOFTRAST_PixelShader_VertexColor(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ +#ifdef SSE_POSSIBLE + unsigned char * RESTRICT pixelmask = span->pixelmask; + unsigned char * RESTRICT pixel = (unsigned char *)dpsoftrast.fb_colorpixels[0] + (span->y * dpsoftrast.fb_width + span->x) * 4; + int x, startx = span->startx, endx = span->endx; + __m128i Color_Ambientm, Color_Diffusem; + __m128 data, slope; + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + int arrayindex = DPSOFTRAST_ARRAY_COLOR; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, 2, buffer_z); + if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE) + pixel = buffer_FragColorbgra8; + Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Ambientm = _mm_or_si128(Color_Ambientm, _mm_setr_epi32(0, 0, 0, (int)(thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]*255.0f))); + Color_Ambientm = _mm_packs_epi32(Color_Ambientm, Color_Ambientm); + Color_Diffusem = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4]), _mm_set1_ps(4096.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Diffusem = _mm_and_si128(Color_Diffusem, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Diffusem = _mm_packs_epi32(Color_Diffusem, Color_Diffusem); + DPSOFTRAST_CALCATTRIB(triangle, span, data, slope, arrayindex); + data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(3, 0, 1, 2)); + slope = _mm_shuffle_ps(slope, slope, _MM_SHUFFLE(3, 0, 1, 2)); + data = _mm_add_ps(data, _mm_mul_ps(slope, _mm_set1_ps(startx))); + data = _mm_mul_ps(data, _mm_set1_ps(4096.0f)); + slope = _mm_mul_ps(slope, _mm_set1_ps(4096.0f)); + for (x = startx;x < endx;x++, data = _mm_add_ps(data, slope)) + { + __m128i color, mod, pix; + if (x + 4 <= endx && *(const unsigned int *)&pixelmask[x] == 0x01010101) + { + __m128i pix2, mod2; + __m128 z = _mm_loadu_ps(&buffer_z[x]); + color = _mm_loadu_si128((const __m128i *)&buffer_texture_colorbgra8[x*4]); + mod = _mm_cvtps_epi32(_mm_mul_ps(data, _mm_shuffle_ps(z, z, _MM_SHUFFLE(0, 0, 0, 0)))); + data = _mm_add_ps(data, slope); + mod = _mm_packs_epi32(mod, _mm_cvtps_epi32(_mm_mul_ps(data, _mm_shuffle_ps(z, z, _MM_SHUFFLE(1, 1, 1, 1))))); + data = _mm_add_ps(data, slope); + mod2 = _mm_cvtps_epi32(_mm_mul_ps(data, _mm_shuffle_ps(z, z, _MM_SHUFFLE(2, 2, 2, 2)))); + data = _mm_add_ps(data, slope); + mod2 = _mm_packs_epi32(mod2, _mm_cvtps_epi32(_mm_mul_ps(data, _mm_shuffle_ps(z, z, _MM_SHUFFLE(3, 3, 3, 3))))); + pix = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, mod), Color_Ambientm), + _mm_unpacklo_epi8(_mm_setzero_si128(), color)); + pix2 = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, mod2), Color_Ambientm), + _mm_unpackhi_epi8(_mm_setzero_si128(), color)); + _mm_storeu_si128((__m128i *)&pixel[x*4], _mm_packus_epi16(pix, pix2)); + x += 3; + continue; + } + if (!pixelmask[x]) + continue; + color = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_colorbgra8[x*4])); + mod = _mm_cvtps_epi32(_mm_mul_ps(data, _mm_load1_ps(&buffer_z[x]))); + mod = _mm_packs_epi32(mod, mod); + pix = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(mod, Color_Diffusem), Color_Ambientm), color); + *(int *)&pixel[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + } + if (pixel == buffer_FragColorbgra8) + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +#endif +} + + + +static void DPSOFTRAST_VertexShader_Lightmap(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4); +} + +static void DPSOFTRAST_PixelShader_Lightmap(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ +#ifdef SSE_POSSIBLE + unsigned char * RESTRICT pixelmask = span->pixelmask; + unsigned char * RESTRICT pixel = (unsigned char *)dpsoftrast.fb_colorpixels[0] + (span->y * dpsoftrast.fb_width + span->x) * 4; + int x, startx = span->startx, endx = span->endx; + __m128i Color_Ambientm, Color_Diffusem, Color_Glowm, Color_AmbientGlowm; + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_lightmapbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_glowbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + if ((thread->shader_permutation & SHADERPERMUTATION_ALPHAKILL) || thread->fb_blendmode != DPSOFTRAST_BLENDMODE_OPAQUE) + pixel = buffer_FragColorbgra8; + Color_Ambientm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Ambientm = _mm_and_si128(Color_Ambientm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Ambientm = _mm_or_si128(Color_Ambientm, _mm_setr_epi32(0, 0, 0, (int)(thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]*255.0f))); + Color_Ambientm = _mm_packs_epi32(Color_Ambientm, Color_Ambientm); + Color_Diffusem = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Diffusem = _mm_and_si128(Color_Diffusem, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Diffusem = _mm_packs_epi32(Color_Diffusem, Color_Diffusem); + if (thread->shader_permutation & SHADERPERMUTATION_GLOW) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_glowbgra8, GL20TU_GLOW, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + Color_Glowm = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(&thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4]), _mm_set1_ps(256.0f))), _MM_SHUFFLE(3, 0, 1, 2)); + Color_Glowm = _mm_and_si128(Color_Glowm, _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0)); + Color_Glowm = _mm_packs_epi32(Color_Glowm, Color_Glowm); + Color_AmbientGlowm = _mm_unpacklo_epi64(Color_Ambientm, Color_Glowm); + for (x = startx;x < endx;x++) + { + __m128i color, lightmap, glow, pix; + if (x + 4 <= endx && *(const unsigned int *)&pixelmask[x] == 0x01010101) + { + __m128i pix2; + color = _mm_loadu_si128((const __m128i *)&buffer_texture_colorbgra8[x*4]); + lightmap = _mm_loadu_si128((const __m128i *)&buffer_texture_lightmapbgra8[x*4]); + glow = _mm_loadu_si128((const __m128i *)&buffer_texture_glowbgra8[x*4]); + pix = _mm_add_epi16(_mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, _mm_unpacklo_epi8(_mm_setzero_si128(), lightmap)), Color_Ambientm), + _mm_unpacklo_epi8(_mm_setzero_si128(), color)), + _mm_mulhi_epu16(Color_Glowm, _mm_unpacklo_epi8(_mm_setzero_si128(), glow))); + pix2 = _mm_add_epi16(_mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, _mm_unpackhi_epi8(_mm_setzero_si128(), lightmap)), Color_Ambientm), + _mm_unpackhi_epi8(_mm_setzero_si128(), color)), + _mm_mulhi_epu16(Color_Glowm, _mm_unpackhi_epi8(_mm_setzero_si128(), glow))); + _mm_storeu_si128((__m128i *)&pixel[x*4], _mm_packus_epi16(pix, pix2)); + x += 3; + continue; + } + if (!pixelmask[x]) + continue; + color = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_colorbgra8[x*4])); + lightmap = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_lightmapbgra8[x*4])); + glow = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_glowbgra8[x*4])); + pix = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, lightmap), Color_AmbientGlowm), _mm_unpacklo_epi64(color, glow)); + pix = _mm_add_epi16(pix, _mm_shuffle_epi32(pix, _MM_SHUFFLE(3, 2, 3, 2))); + *(int *)&pixel[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + } + } + else + { + for (x = startx;x < endx;x++) + { + __m128i color, lightmap, pix; + if (x + 4 <= endx && *(const unsigned int *)&pixelmask[x] == 0x01010101) + { + __m128i pix2; + color = _mm_loadu_si128((const __m128i *)&buffer_texture_colorbgra8[x*4]); + lightmap = _mm_loadu_si128((const __m128i *)&buffer_texture_lightmapbgra8[x*4]); + pix = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, _mm_unpacklo_epi8(_mm_setzero_si128(), lightmap)), Color_Ambientm), + _mm_unpacklo_epi8(_mm_setzero_si128(), color)); + pix2 = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(Color_Diffusem, _mm_unpackhi_epi8(_mm_setzero_si128(), lightmap)), Color_Ambientm), + _mm_unpackhi_epi8(_mm_setzero_si128(), color)); + _mm_storeu_si128((__m128i *)&pixel[x*4], _mm_packus_epi16(pix, pix2)); + x += 3; + continue; + } + if (!pixelmask[x]) + continue; + color = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_colorbgra8[x*4])); + lightmap = _mm_unpacklo_epi8(_mm_setzero_si128(), _mm_cvtsi32_si128(*(const int *)&buffer_texture_lightmapbgra8[x*4])); + pix = _mm_mulhi_epu16(_mm_add_epi16(_mm_mulhi_epu16(lightmap, Color_Diffusem), Color_Ambientm), color); + *(int *)&pixel[x*4] = _mm_cvtsi128_si32(_mm_packus_epi16(pix, pix)); + } + } + if (pixel == buffer_FragColorbgra8) + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +#endif +} + + +void DPSOFTRAST_VertexShader_LightDirection(void); +void DPSOFTRAST_PixelShader_LightDirection(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span); + +static void DPSOFTRAST_VertexShader_FakeLight(void) +{ + DPSOFTRAST_VertexShader_LightDirection(); +} + +static void DPSOFTRAST_PixelShader_FakeLight(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + DPSOFTRAST_PixelShader_LightDirection(thread, triangle, span); +} + + + +static void DPSOFTRAST_VertexShader_LightDirectionMap_ModelSpace(void) +{ + DPSOFTRAST_VertexShader_LightDirection(); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4); +} + +static void DPSOFTRAST_PixelShader_LightDirectionMap_ModelSpace(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + DPSOFTRAST_PixelShader_LightDirection(thread, triangle, span); +} + + + +static void DPSOFTRAST_VertexShader_LightDirectionMap_TangentSpace(void) +{ + DPSOFTRAST_VertexShader_LightDirection(); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4); +} + +static void DPSOFTRAST_PixelShader_LightDirectionMap_TangentSpace(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + DPSOFTRAST_PixelShader_LightDirection(thread, triangle, span); +} + + + +void DPSOFTRAST_VertexShader_LightDirection(void) +{ + int i; + int numvertices = dpsoftrast.numvertices; + float LightDir[4]; + float LightVector[4]; + float EyePosition[4]; + float EyeVectorModelSpace[4]; + float EyeVector[4]; + float position[4]; + float svector[4]; + float tvector[4]; + float normal[4]; + LightDir[0] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightDir*4+0]; + LightDir[1] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightDir*4+1]; + LightDir[2] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightDir*4+2]; + LightDir[3] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightDir*4+3]; + EyePosition[0] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+0]; + EyePosition[1] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+1]; + EyePosition[2] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+2]; + EyePosition[3] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+3]; + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD3); + for (i = 0;i < numvertices;i++) + { + position[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+0]; + position[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+1]; + position[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+2]; + svector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+0]; + svector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+1]; + svector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+2]; + tvector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+0]; + tvector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+1]; + tvector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+2]; + normal[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+0]; + normal[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+1]; + normal[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+2]; + LightVector[0] = svector[0] * LightDir[0] + svector[1] * LightDir[1] + svector[2] * LightDir[2]; + LightVector[1] = tvector[0] * LightDir[0] + tvector[1] * LightDir[1] + tvector[2] * LightDir[2]; + LightVector[2] = normal[0] * LightDir[0] + normal[1] * LightDir[1] + normal[2] * LightDir[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD5][i*4+0] = LightVector[0]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD5][i*4+1] = LightVector[1]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD5][i*4+2] = LightVector[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD5][i*4+3] = 0.0f; + EyeVectorModelSpace[0] = EyePosition[0] - position[0]; + EyeVectorModelSpace[1] = EyePosition[1] - position[1]; + EyeVectorModelSpace[2] = EyePosition[2] - position[2]; + EyeVector[0] = svector[0] * EyeVectorModelSpace[0] + svector[1] * EyeVectorModelSpace[1] + svector[2] * EyeVectorModelSpace[2]; + EyeVector[1] = tvector[0] * EyeVectorModelSpace[0] + tvector[1] * EyeVectorModelSpace[1] + tvector[2] * EyeVectorModelSpace[2]; + EyeVector[2] = normal[0] * EyeVectorModelSpace[0] + normal[1] * EyeVectorModelSpace[1] + normal[2] * EyeVectorModelSpace[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+0] = EyeVector[0]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+1] = EyeVector[1]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+2] = EyeVector[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+3] = 0.0f; + } + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, -1, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); +} + +#define DPSOFTRAST_Min(a,b) ((a) < (b) ? (a) : (b)) +#define DPSOFTRAST_Max(a,b) ((a) > (b) ? (a) : (b)) +#define DPSOFTRAST_Vector3Dot(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +#define DPSOFTRAST_Vector3LengthSquared(v) (DPSOFTRAST_Vector3Dot((v),(v))) +#define DPSOFTRAST_Vector3Length(v) (sqrt(DPSOFTRAST_Vector3LengthSquared(v))) +#define DPSOFTRAST_Vector3Normalize(v)\ +do\ +{\ + float len = sqrt(DPSOFTRAST_Vector3Dot(v,v));\ + if (len)\ + {\ + len = 1.0f / len;\ + v[0] *= len;\ + v[1] *= len;\ + v[2] *= len;\ + }\ +}\ +while(0) + +void DPSOFTRAST_PixelShader_LightDirection(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_normalbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_glossbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_glowbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_pantsbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_shirtbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_deluxemapbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_lightmapbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + int x, startx = span->startx, endx = span->endx; + float Color_Ambient[4], Color_Diffuse[4], Color_Specular[4], Color_Glow[4], Color_Pants[4], Color_Shirt[4], LightColor[4]; + float LightVectordata[4]; + float LightVectorslope[4]; + float EyeVectordata[4]; + float EyeVectorslope[4]; + float VectorSdata[4]; + float VectorSslope[4]; + float VectorTdata[4]; + float VectorTslope[4]; + float VectorRdata[4]; + float VectorRslope[4]; + float z; + float diffusetex[4]; + float glosstex[4]; + float surfacenormal[4]; + float lightnormal[4]; + float lightnormal_modelspace[4]; + float eyenormal[4]; + float specularnormal[4]; + float diffuse; + float specular; + float SpecularPower; + int d[4]; + Color_Glow[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+0]; + Color_Glow[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+1]; + Color_Glow[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+2]; + Color_Glow[3] = 0.0f; + Color_Ambient[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+0]; + Color_Ambient[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+1]; + Color_Ambient[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+2]; + Color_Ambient[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]; + Color_Pants[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+0]; + Color_Pants[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+1]; + Color_Pants[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+2]; + Color_Pants[3] = 0.0f; + Color_Shirt[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+0]; + Color_Shirt[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+1]; + Color_Shirt[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+2]; + Color_Shirt[3] = 0.0f; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_pantsbgra8, GL20TU_PANTS, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_shirtbgra8, GL20TU_SHIRT, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + } + if (thread->shader_permutation & SHADERPERMUTATION_GLOW) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_glowbgra8, GL20TU_GLOW, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + } + if (thread->shader_permutation & SHADERPERMUTATION_SPECULAR) + { + Color_Diffuse[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+0]; + Color_Diffuse[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+1]; + Color_Diffuse[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+2]; + Color_Diffuse[3] = 0.0f; + LightColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+0]; + LightColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+1]; + LightColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+2]; + LightColor[3] = 0.0f; + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + Color_Specular[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+0]; + Color_Specular[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+1]; + Color_Specular[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+2]; + Color_Specular[3] = 0.0f; + SpecularPower = thread->uniform4f[DPSOFTRAST_UNIFORM_SpecularPower*4+0] * (1.0f / 255.0f); + DPSOFTRAST_CALCATTRIB4F(triangle, span, EyeVectordata, EyeVectorslope, DPSOFTRAST_ARRAY_TEXCOORD6); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_glossbgra8, GL20TU_GLOSS, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + + if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE) + { + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorSdata, VectorSslope, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorTdata, VectorTslope, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorRdata, VectorRslope, DPSOFTRAST_ARRAY_TEXCOORD3); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_deluxemapbgra8, GL20TU_DELUXEMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + } + else if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_deluxemapbgra8, GL20TU_DELUXEMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + } + else if(thread->shader_mode == SHADERMODE_FAKELIGHT) + { + // nothing of this needed + } + else + { + DPSOFTRAST_CALCATTRIB4F(triangle, span, LightVectordata, LightVectorslope, DPSOFTRAST_ARRAY_TEXCOORD5); + } + + for (x = startx;x < endx;x++) + { + z = buffer_z[x]; + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + diffusetex[0] += buffer_texture_pantsbgra8[x*4+0] * Color_Pants[0] + buffer_texture_shirtbgra8[x*4+0] * Color_Shirt[0]; + diffusetex[1] += buffer_texture_pantsbgra8[x*4+1] * Color_Pants[1] + buffer_texture_shirtbgra8[x*4+1] * Color_Shirt[1]; + diffusetex[2] += buffer_texture_pantsbgra8[x*4+2] * Color_Pants[2] + buffer_texture_shirtbgra8[x*4+2] * Color_Shirt[2]; + diffusetex[3] += buffer_texture_pantsbgra8[x*4+3] * Color_Pants[3] + buffer_texture_shirtbgra8[x*4+3] * Color_Shirt[3]; + } + glosstex[0] = buffer_texture_glossbgra8[x*4+0]; + glosstex[1] = buffer_texture_glossbgra8[x*4+1]; + glosstex[2] = buffer_texture_glossbgra8[x*4+2]; + glosstex[3] = buffer_texture_glossbgra8[x*4+3]; + surfacenormal[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + surfacenormal[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + surfacenormal[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(surfacenormal); + + if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE) + { + // myhalf3 lightnormal_modelspace = myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"; + lightnormal_modelspace[0] = buffer_texture_deluxemapbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + lightnormal_modelspace[1] = buffer_texture_deluxemapbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + lightnormal_modelspace[2] = buffer_texture_deluxemapbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + + // lightnormal.x = dot(lightnormal_modelspace, myhalf3(VectorS));\n" + lightnormal[0] = lightnormal_modelspace[0] * (VectorSdata[0] + VectorSslope[0] * x) + + lightnormal_modelspace[1] * (VectorSdata[1] + VectorSslope[1] * x) + + lightnormal_modelspace[2] * (VectorSdata[2] + VectorSslope[2] * x); + + // lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n" + lightnormal[1] = lightnormal_modelspace[0] * (VectorTdata[0] + VectorTslope[0] * x) + + lightnormal_modelspace[1] * (VectorTdata[1] + VectorTslope[1] * x) + + lightnormal_modelspace[2] * (VectorTdata[2] + VectorTslope[2] * x); + + // lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\n" + lightnormal[2] = lightnormal_modelspace[0] * (VectorRdata[0] + VectorRslope[0] * x) + + lightnormal_modelspace[1] * (VectorRdata[1] + VectorRslope[1] * x) + + lightnormal_modelspace[2] * (VectorRdata[2] + VectorRslope[2] * x); + + // lightnormal = normalize(lightnormal); // VectorS/T/R are not always perfectly normalized, and EXACTSPECULARMATH is very picky about this\n" + DPSOFTRAST_Vector3Normalize(lightnormal); + + // myhalf3 lightcolor = myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\n"; + { + float f = 1.0f / (256.0f * max(0.25f, lightnormal[2])); + LightColor[0] = buffer_texture_lightmapbgra8[x*4+0] * f; + LightColor[1] = buffer_texture_lightmapbgra8[x*4+1] * f; + LightColor[2] = buffer_texture_lightmapbgra8[x*4+2] * f; + } + } + else if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE) + { + lightnormal[0] = buffer_texture_deluxemapbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + lightnormal[1] = buffer_texture_deluxemapbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + lightnormal[2] = buffer_texture_deluxemapbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + { + float f = 1.0f / 256.0f; + LightColor[0] = buffer_texture_lightmapbgra8[x*4+0] * f; + LightColor[1] = buffer_texture_lightmapbgra8[x*4+1] * f; + LightColor[2] = buffer_texture_lightmapbgra8[x*4+2] * f; + } + } + else if(thread->shader_mode == SHADERMODE_FAKELIGHT) + { + lightnormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + lightnormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + lightnormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + + LightColor[0] = 1.0; + LightColor[1] = 1.0; + LightColor[2] = 1.0; + } + else + { + lightnormal[0] = (LightVectordata[0] + LightVectorslope[0]*x) * z; + lightnormal[1] = (LightVectordata[1] + LightVectorslope[1]*x) * z; + lightnormal[2] = (LightVectordata[2] + LightVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + } + + diffuse = DPSOFTRAST_Vector3Dot(surfacenormal, lightnormal);if (diffuse < 0.0f) diffuse = 0.0f; + + if(thread->shader_exactspecularmath) + { + // reflect lightnormal at surfacenormal, take the negative of that + // i.e. we want (2*dot(N, i) * N - I) for N=surfacenormal, I=lightnormal + float f; + f = DPSOFTRAST_Vector3Dot(lightnormal, surfacenormal); + specularnormal[0] = 2*f*surfacenormal[0] - lightnormal[0]; + specularnormal[1] = 2*f*surfacenormal[1] - lightnormal[1]; + specularnormal[2] = 2*f*surfacenormal[2] - lightnormal[2]; + + // dot of this and normalize(EyeVectorFogDepth.xyz) + eyenormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + eyenormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + eyenormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(eyenormal); + + specular = DPSOFTRAST_Vector3Dot(eyenormal, specularnormal);if (specular < 0.0f) specular = 0.0f; + } + else + { + eyenormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + eyenormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + eyenormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(eyenormal); + + specularnormal[0] = lightnormal[0] + eyenormal[0]; + specularnormal[1] = lightnormal[1] + eyenormal[1]; + specularnormal[2] = lightnormal[2] + eyenormal[2]; + DPSOFTRAST_Vector3Normalize(specularnormal); + + specular = DPSOFTRAST_Vector3Dot(surfacenormal, specularnormal);if (specular < 0.0f) specular = 0.0f; + } + specular = pow(specular, 1.0f + SpecularPower * glosstex[3]); + + if (thread->shader_permutation & SHADERPERMUTATION_GLOW) + { + d[0] = (int)(buffer_texture_glowbgra8[x*4+0] * Color_Glow[0] + diffusetex[0] * Color_Ambient[0] + (diffusetex[0] * Color_Diffuse[0] * diffuse + glosstex[0] * Color_Specular[0] * specular) * LightColor[0]);if (d[0] > 255) d[0] = 255; + d[1] = (int)(buffer_texture_glowbgra8[x*4+1] * Color_Glow[1] + diffusetex[1] * Color_Ambient[1] + (diffusetex[1] * Color_Diffuse[1] * diffuse + glosstex[1] * Color_Specular[1] * specular) * LightColor[1]);if (d[1] > 255) d[1] = 255; + d[2] = (int)(buffer_texture_glowbgra8[x*4+2] * Color_Glow[2] + diffusetex[2] * Color_Ambient[2] + (diffusetex[2] * Color_Diffuse[2] * diffuse + glosstex[2] * Color_Specular[2] * specular) * LightColor[2]);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * Color_Ambient[3]);if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)( diffusetex[0] * Color_Ambient[0] + (diffusetex[0] * Color_Diffuse[0] * diffuse + glosstex[0] * Color_Specular[0] * specular) * LightColor[0]);if (d[0] > 255) d[0] = 255; + d[1] = (int)( diffusetex[1] * Color_Ambient[1] + (diffusetex[1] * Color_Diffuse[1] * diffuse + glosstex[1] * Color_Specular[1] * specular) * LightColor[1]);if (d[1] > 255) d[1] = 255; + d[2] = (int)( diffusetex[2] * Color_Ambient[2] + (diffusetex[2] * Color_Diffuse[2] * diffuse + glosstex[2] * Color_Specular[2] * specular) * LightColor[2]);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * Color_Ambient[3]);if (d[3] > 255) d[3] = 255; + } + + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + else if (thread->shader_permutation & SHADERPERMUTATION_DIFFUSE) + { + Color_Diffuse[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+0]; + Color_Diffuse[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+1]; + Color_Diffuse[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+2]; + Color_Diffuse[3] = 0.0f; + LightColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+0]; + LightColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+1]; + LightColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+2]; + LightColor[3] = 0.0f; + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + + if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE) + { + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorSdata, VectorSslope, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorTdata, VectorTslope, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_CALCATTRIB4F(triangle, span, VectorRdata, VectorRslope, DPSOFTRAST_ARRAY_TEXCOORD3); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_deluxemapbgra8, GL20TU_DELUXEMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + } + else if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_lightmapbgra8, GL20TU_LIGHTMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_deluxemapbgra8, GL20TU_DELUXEMAP, DPSOFTRAST_ARRAY_TEXCOORD4, buffer_z); + } + else if(thread->shader_mode == SHADERMODE_FAKELIGHT) + { + DPSOFTRAST_CALCATTRIB4F(triangle, span, EyeVectordata, EyeVectorslope, DPSOFTRAST_ARRAY_TEXCOORD6); + } + else + { + DPSOFTRAST_CALCATTRIB4F(triangle, span, LightVectordata, LightVectorslope, DPSOFTRAST_ARRAY_TEXCOORD5); + } + + for (x = startx;x < endx;x++) + { + z = buffer_z[x]; + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + surfacenormal[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + surfacenormal[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + surfacenormal[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(surfacenormal); + + if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE) + { + // myhalf3 lightnormal_modelspace = myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"; + lightnormal_modelspace[0] = buffer_texture_deluxemapbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + lightnormal_modelspace[1] = buffer_texture_deluxemapbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + lightnormal_modelspace[2] = buffer_texture_deluxemapbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + + // lightnormal.x = dot(lightnormal_modelspace, myhalf3(VectorS));\n" + lightnormal[0] = lightnormal_modelspace[0] * (VectorSdata[0] + VectorSslope[0] * x) + + lightnormal_modelspace[1] * (VectorSdata[1] + VectorSslope[1] * x) + + lightnormal_modelspace[2] * (VectorSdata[2] + VectorSslope[2] * x); + + // lightnormal.y = dot(lightnormal_modelspace, myhalf3(VectorT));\n" + lightnormal[1] = lightnormal_modelspace[0] * (VectorTdata[0] + VectorTslope[0] * x) + + lightnormal_modelspace[1] * (VectorTdata[1] + VectorTslope[1] * x) + + lightnormal_modelspace[2] * (VectorTdata[2] + VectorTslope[2] * x); + + // lightnormal.z = dot(lightnormal_modelspace, myhalf3(VectorR));\n" + lightnormal[2] = lightnormal_modelspace[0] * (VectorRdata[0] + VectorRslope[0] * x) + + lightnormal_modelspace[1] * (VectorRdata[1] + VectorRslope[1] * x) + + lightnormal_modelspace[2] * (VectorRdata[2] + VectorRslope[2] * x); + + // lightnormal = normalize(lightnormal); // VectorS/T/R are not always perfectly normalized, and EXACTSPECULARMATH is very picky about this\n" + DPSOFTRAST_Vector3Normalize(lightnormal); + + // myhalf3 lightcolor = myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\n"; + { + float f = 1.0f / (256.0f * max(0.25f, lightnormal[2])); + LightColor[0] = buffer_texture_lightmapbgra8[x*4+0] * f; + LightColor[1] = buffer_texture_lightmapbgra8[x*4+1] * f; + LightColor[2] = buffer_texture_lightmapbgra8[x*4+2] * f; + } + } + else if(thread->shader_mode == SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE) + { + lightnormal[0] = buffer_texture_deluxemapbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + lightnormal[1] = buffer_texture_deluxemapbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + lightnormal[2] = buffer_texture_deluxemapbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + { + float f = 1.0f / 256.0f; + LightColor[0] = buffer_texture_lightmapbgra8[x*4+0] * f; + LightColor[1] = buffer_texture_lightmapbgra8[x*4+1] * f; + LightColor[2] = buffer_texture_lightmapbgra8[x*4+2] * f; + } + } + else if(thread->shader_mode == SHADERMODE_FAKELIGHT) + { + lightnormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + lightnormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + lightnormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + + LightColor[0] = 1.0; + LightColor[1] = 1.0; + LightColor[2] = 1.0; + } + else + { + lightnormal[0] = (LightVectordata[0] + LightVectorslope[0]*x) * z; + lightnormal[1] = (LightVectordata[1] + LightVectorslope[1]*x) * z; + lightnormal[2] = (LightVectordata[2] + LightVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + } + + diffuse = DPSOFTRAST_Vector3Dot(surfacenormal, lightnormal);if (diffuse < 0.0f) diffuse = 0.0f; + if (thread->shader_permutation & SHADERPERMUTATION_GLOW) + { + d[0] = (int)(buffer_texture_glowbgra8[x*4+0] * Color_Glow[0] + diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse * LightColor[0]));if (d[0] > 255) d[0] = 255; + d[1] = (int)(buffer_texture_glowbgra8[x*4+1] * Color_Glow[1] + diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse * LightColor[1]));if (d[1] > 255) d[1] = 255; + d[2] = (int)(buffer_texture_glowbgra8[x*4+2] * Color_Glow[2] + diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse * LightColor[2]));if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * (Color_Ambient[3] ));if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)( + diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse * LightColor[0]));if (d[0] > 255) d[0] = 255; + d[1] = (int)( + diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse * LightColor[1]));if (d[1] > 255) d[1] = 255; + d[2] = (int)( + diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse * LightColor[2]));if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * (Color_Ambient[3] ));if (d[3] > 255) d[3] = 255; + } + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + else + { + for (x = startx;x < endx;x++) + { + // z = buffer_z[x]; + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + + if (thread->shader_permutation & SHADERPERMUTATION_GLOW) + { + d[0] = (int)(buffer_texture_glowbgra8[x*4+0] * Color_Glow[0] + diffusetex[0] * Color_Ambient[0]);if (d[0] > 255) d[0] = 255; + d[1] = (int)(buffer_texture_glowbgra8[x*4+1] * Color_Glow[1] + diffusetex[1] * Color_Ambient[1]);if (d[1] > 255) d[1] = 255; + d[2] = (int)(buffer_texture_glowbgra8[x*4+2] * Color_Glow[2] + diffusetex[2] * Color_Ambient[2]);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * Color_Ambient[3]);if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)( diffusetex[0] * Color_Ambient[0]);if (d[0] > 255) d[0] = 255; + d[1] = (int)( diffusetex[1] * Color_Ambient[1]);if (d[1] > 255) d[1] = 255; + d[2] = (int)( diffusetex[2] * Color_Ambient[2]);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] * Color_Ambient[3]);if (d[3] > 255) d[3] = 255; + } + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_LightSource(void) +{ + int i; + int numvertices = dpsoftrast.numvertices; + float LightPosition[4]; + float LightVector[4]; + float LightVectorModelSpace[4]; + float EyePosition[4]; + float EyeVectorModelSpace[4]; + float EyeVector[4]; + float position[4]; + float svector[4]; + float tvector[4]; + float normal[4]; + LightPosition[0] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightPosition*4+0]; + LightPosition[1] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightPosition*4+1]; + LightPosition[2] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightPosition*4+2]; + LightPosition[3] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_LightPosition*4+3]; + EyePosition[0] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+0]; + EyePosition[1] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+1]; + EyePosition[2] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+2]; + EyePosition[3] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+3]; + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD3); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD4); + for (i = 0;i < numvertices;i++) + { + position[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+0]; + position[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+1]; + position[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+2]; + svector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+0]; + svector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+1]; + svector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+2]; + tvector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+0]; + tvector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+1]; + tvector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+2]; + normal[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+0]; + normal[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+1]; + normal[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+2]; + LightVectorModelSpace[0] = LightPosition[0] - position[0]; + LightVectorModelSpace[1] = LightPosition[1] - position[1]; + LightVectorModelSpace[2] = LightPosition[2] - position[2]; + LightVector[0] = svector[0] * LightVectorModelSpace[0] + svector[1] * LightVectorModelSpace[1] + svector[2] * LightVectorModelSpace[2]; + LightVector[1] = tvector[0] * LightVectorModelSpace[0] + tvector[1] * LightVectorModelSpace[1] + tvector[2] * LightVectorModelSpace[2]; + LightVector[2] = normal[0] * LightVectorModelSpace[0] + normal[1] * LightVectorModelSpace[1] + normal[2] * LightVectorModelSpace[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+0] = LightVector[0]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+1] = LightVector[1]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+2] = LightVector[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+3] = 0.0f; + EyeVectorModelSpace[0] = EyePosition[0] - position[0]; + EyeVectorModelSpace[1] = EyePosition[1] - position[1]; + EyeVectorModelSpace[2] = EyePosition[2] - position[2]; + EyeVector[0] = svector[0] * EyeVectorModelSpace[0] + svector[1] * EyeVectorModelSpace[1] + svector[2] * EyeVectorModelSpace[2]; + EyeVector[1] = tvector[0] * EyeVectorModelSpace[0] + tvector[1] * EyeVectorModelSpace[1] + tvector[2] * EyeVectorModelSpace[2]; + EyeVector[2] = normal[0] * EyeVectorModelSpace[0] + normal[1] * EyeVectorModelSpace[1] + normal[2] * EyeVectorModelSpace[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+0] = EyeVector[0]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+1] = EyeVector[1]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+2] = EyeVector[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+3] = 0.0f; + } + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, -1, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelToLightM1); +} + +static void DPSOFTRAST_PixelShader_LightSource(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ +#ifdef SSE_POSSIBLE + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_texture_colorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_normalbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_glossbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_cubebgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_pantsbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_texture_shirtbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + int x, startx = span->startx, endx = span->endx; + float Color_Ambient[4], Color_Diffuse[4], Color_Specular[4], /*Color_Glow[4],*/ Color_Pants[4], Color_Shirt[4], LightColor[4]; + float CubeVectordata[4]; + float CubeVectorslope[4]; + float LightVectordata[4]; + float LightVectorslope[4]; + float EyeVectordata[4]; + float EyeVectorslope[4]; + float z; + float diffusetex[4]; + float glosstex[4]; + float surfacenormal[4]; + float lightnormal[4]; + float eyenormal[4]; + float specularnormal[4]; + float diffuse; + float specular; + float SpecularPower; + float CubeVector[4]; + float attenuation; + int d[4]; +#if 0 + Color_Glow[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+0]; + Color_Glow[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+1]; + Color_Glow[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Glow*4+2]; + Color_Glow[3] = 0.0f; +#endif + Color_Ambient[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+0]; + Color_Ambient[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+1]; + Color_Ambient[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Ambient*4+2]; + Color_Ambient[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_Alpha*4+0]; + Color_Diffuse[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+0]; + Color_Diffuse[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+1]; + Color_Diffuse[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Diffuse*4+2]; + Color_Diffuse[3] = 0.0f; + Color_Specular[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+0]; + Color_Specular[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+1]; + Color_Specular[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Specular*4+2]; + Color_Specular[3] = 0.0f; + Color_Pants[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+0]; + Color_Pants[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+1]; + Color_Pants[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Pants*4+2]; + Color_Pants[3] = 0.0f; + Color_Shirt[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+0]; + Color_Shirt[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+1]; + Color_Shirt[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_Color_Shirt*4+2]; + Color_Shirt[3] = 0.0f; + LightColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+0]; + LightColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+1]; + LightColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_LightColor*4+2]; + LightColor[3] = 0.0f; + SpecularPower = thread->uniform4f[DPSOFTRAST_UNIFORM_SpecularPower*4+0] * (1.0f / 255.0f); + DPSOFTRAST_CALCATTRIB4F(triangle, span, LightVectordata, LightVectorslope, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_CALCATTRIB4F(triangle, span, EyeVectordata, EyeVectorslope, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_CALCATTRIB4F(triangle, span, CubeVectordata, CubeVectorslope, DPSOFTRAST_ARRAY_TEXCOORD3); + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + memset(buffer_FragColorbgra8 + startx*4, 0, (endx-startx)*4); // clear first, because we skip writing black pixels, and there are a LOT of them... + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_colorbgra8, GL20TU_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_pantsbgra8, GL20TU_PANTS, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_shirtbgra8, GL20TU_SHIRT, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + } + if (thread->shader_permutation & SHADERPERMUTATION_CUBEFILTER) + DPSOFTRAST_Draw_Span_TextureCubeVaryingBGRA8(triangle, span, buffer_texture_cubebgra8, GL20TU_CUBE, DPSOFTRAST_ARRAY_TEXCOORD3, buffer_z); + if (thread->shader_permutation & SHADERPERMUTATION_SPECULAR) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_glossbgra8, GL20TU_GLOSS, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + for (x = startx;x < endx;x++) + { + z = buffer_z[x]; + CubeVector[0] = (CubeVectordata[0] + CubeVectorslope[0]*x) * z; + CubeVector[1] = (CubeVectordata[1] + CubeVectorslope[1]*x) * z; + CubeVector[2] = (CubeVectordata[2] + CubeVectorslope[2]*x) * z; + attenuation = 1.0f - DPSOFTRAST_Vector3LengthSquared(CubeVector); + if (attenuation < 0.01f) + continue; + if (thread->shader_permutation & SHADERPERMUTATION_SHADOWMAP2D) + { + attenuation *= DPSOFTRAST_SampleShadowmap(CubeVector); + if (attenuation < 0.01f) + continue; + } + + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + diffusetex[0] += buffer_texture_pantsbgra8[x*4+0] * Color_Pants[0] + buffer_texture_shirtbgra8[x*4+0] * Color_Shirt[0]; + diffusetex[1] += buffer_texture_pantsbgra8[x*4+1] * Color_Pants[1] + buffer_texture_shirtbgra8[x*4+1] * Color_Shirt[1]; + diffusetex[2] += buffer_texture_pantsbgra8[x*4+2] * Color_Pants[2] + buffer_texture_shirtbgra8[x*4+2] * Color_Shirt[2]; + diffusetex[3] += buffer_texture_pantsbgra8[x*4+3] * Color_Pants[3] + buffer_texture_shirtbgra8[x*4+3] * Color_Shirt[3]; + } + glosstex[0] = buffer_texture_glossbgra8[x*4+0]; + glosstex[1] = buffer_texture_glossbgra8[x*4+1]; + glosstex[2] = buffer_texture_glossbgra8[x*4+2]; + glosstex[3] = buffer_texture_glossbgra8[x*4+3]; + surfacenormal[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + surfacenormal[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + surfacenormal[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(surfacenormal); + + lightnormal[0] = (LightVectordata[0] + LightVectorslope[0]*x) * z; + lightnormal[1] = (LightVectordata[1] + LightVectorslope[1]*x) * z; + lightnormal[2] = (LightVectordata[2] + LightVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + + diffuse = DPSOFTRAST_Vector3Dot(surfacenormal, lightnormal);if (diffuse < 0.0f) diffuse = 0.0f; + + if(thread->shader_exactspecularmath) + { + // reflect lightnormal at surfacenormal, take the negative of that + // i.e. we want (2*dot(N, i) * N - I) for N=surfacenormal, I=lightnormal + float f; + f = DPSOFTRAST_Vector3Dot(lightnormal, surfacenormal); + specularnormal[0] = 2*f*surfacenormal[0] - lightnormal[0]; + specularnormal[1] = 2*f*surfacenormal[1] - lightnormal[1]; + specularnormal[2] = 2*f*surfacenormal[2] - lightnormal[2]; + + // dot of this and normalize(EyeVectorFogDepth.xyz) + eyenormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + eyenormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + eyenormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(eyenormal); + + specular = DPSOFTRAST_Vector3Dot(eyenormal, specularnormal);if (specular < 0.0f) specular = 0.0f; + } + else + { + eyenormal[0] = (EyeVectordata[0] + EyeVectorslope[0]*x) * z; + eyenormal[1] = (EyeVectordata[1] + EyeVectorslope[1]*x) * z; + eyenormal[2] = (EyeVectordata[2] + EyeVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(eyenormal); + + specularnormal[0] = lightnormal[0] + eyenormal[0]; + specularnormal[1] = lightnormal[1] + eyenormal[1]; + specularnormal[2] = lightnormal[2] + eyenormal[2]; + DPSOFTRAST_Vector3Normalize(specularnormal); + + specular = DPSOFTRAST_Vector3Dot(surfacenormal, specularnormal);if (specular < 0.0f) specular = 0.0f; + } + specular = pow(specular, 1.0f + SpecularPower * glosstex[3]); + + if (thread->shader_permutation & SHADERPERMUTATION_CUBEFILTER) + { + // scale down the attenuation to account for the cubefilter multiplying everything by 255 + attenuation *= (1.0f / 255.0f); + d[0] = (int)((diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse) + glosstex[0] * Color_Specular[0] * specular) * LightColor[0] * buffer_texture_cubebgra8[x*4+0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse) + glosstex[1] * Color_Specular[1] * specular) * LightColor[1] * buffer_texture_cubebgra8[x*4+1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse) + glosstex[2] * Color_Specular[2] * specular) * LightColor[2] * buffer_texture_cubebgra8[x*4+2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)((diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse) + glosstex[0] * Color_Specular[0] * specular) * LightColor[0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse) + glosstex[1] * Color_Specular[1] * specular) * LightColor[1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse) + glosstex[2] * Color_Specular[2] * specular) * LightColor[2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + else if (thread->shader_permutation & SHADERPERMUTATION_DIFFUSE) + { + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + for (x = startx;x < endx;x++) + { + z = buffer_z[x]; + CubeVector[0] = (CubeVectordata[0] + CubeVectorslope[0]*x) * z; + CubeVector[1] = (CubeVectordata[1] + CubeVectorslope[1]*x) * z; + CubeVector[2] = (CubeVectordata[2] + CubeVectorslope[2]*x) * z; + attenuation = 1.0f - DPSOFTRAST_Vector3LengthSquared(CubeVector); + if (attenuation < 0.01f) + continue; + if (thread->shader_permutation & SHADERPERMUTATION_SHADOWMAP2D) + { + attenuation *= DPSOFTRAST_SampleShadowmap(CubeVector); + if (attenuation < 0.01f) + continue; + } + + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + diffusetex[0] += buffer_texture_pantsbgra8[x*4+0] * Color_Pants[0] + buffer_texture_shirtbgra8[x*4+0] * Color_Shirt[0]; + diffusetex[1] += buffer_texture_pantsbgra8[x*4+1] * Color_Pants[1] + buffer_texture_shirtbgra8[x*4+1] * Color_Shirt[1]; + diffusetex[2] += buffer_texture_pantsbgra8[x*4+2] * Color_Pants[2] + buffer_texture_shirtbgra8[x*4+2] * Color_Shirt[2]; + diffusetex[3] += buffer_texture_pantsbgra8[x*4+3] * Color_Pants[3] + buffer_texture_shirtbgra8[x*4+3] * Color_Shirt[3]; + } + surfacenormal[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + surfacenormal[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + surfacenormal[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(surfacenormal); + + lightnormal[0] = (LightVectordata[0] + LightVectorslope[0]*x) * z; + lightnormal[1] = (LightVectordata[1] + LightVectorslope[1]*x) * z; + lightnormal[2] = (LightVectordata[2] + LightVectorslope[2]*x) * z; + DPSOFTRAST_Vector3Normalize(lightnormal); + + diffuse = DPSOFTRAST_Vector3Dot(surfacenormal, lightnormal);if (diffuse < 0.0f) diffuse = 0.0f; + if (thread->shader_permutation & SHADERPERMUTATION_CUBEFILTER) + { + // scale down the attenuation to account for the cubefilter multiplying everything by 255 + attenuation *= (1.0f / 255.0f); + d[0] = (int)((diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse)) * LightColor[0] * buffer_texture_cubebgra8[x*4+0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse)) * LightColor[1] * buffer_texture_cubebgra8[x*4+1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse)) * LightColor[2] * buffer_texture_cubebgra8[x*4+2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)((diffusetex[0] * (Color_Ambient[0] + Color_Diffuse[0] * diffuse)) * LightColor[0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1] + Color_Diffuse[1] * diffuse)) * LightColor[1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2] + Color_Diffuse[2] * diffuse)) * LightColor[2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + else + { + for (x = startx;x < endx;x++) + { + z = buffer_z[x]; + CubeVector[0] = (CubeVectordata[0] + CubeVectorslope[0]*x) * z; + CubeVector[1] = (CubeVectordata[1] + CubeVectorslope[1]*x) * z; + CubeVector[2] = (CubeVectordata[2] + CubeVectorslope[2]*x) * z; + attenuation = 1.0f - DPSOFTRAST_Vector3LengthSquared(CubeVector); + if (attenuation < 0.01f) + continue; + if (thread->shader_permutation & SHADERPERMUTATION_SHADOWMAP2D) + { + attenuation *= DPSOFTRAST_SampleShadowmap(CubeVector); + if (attenuation < 0.01f) + continue; + } + + diffusetex[0] = buffer_texture_colorbgra8[x*4+0]; + diffusetex[1] = buffer_texture_colorbgra8[x*4+1]; + diffusetex[2] = buffer_texture_colorbgra8[x*4+2]; + diffusetex[3] = buffer_texture_colorbgra8[x*4+3]; + if (thread->shader_permutation & SHADERPERMUTATION_COLORMAPPING) + { + diffusetex[0] += buffer_texture_pantsbgra8[x*4+0] * Color_Pants[0] + buffer_texture_shirtbgra8[x*4+0] * Color_Shirt[0]; + diffusetex[1] += buffer_texture_pantsbgra8[x*4+1] * Color_Pants[1] + buffer_texture_shirtbgra8[x*4+1] * Color_Shirt[1]; + diffusetex[2] += buffer_texture_pantsbgra8[x*4+2] * Color_Pants[2] + buffer_texture_shirtbgra8[x*4+2] * Color_Shirt[2]; + diffusetex[3] += buffer_texture_pantsbgra8[x*4+3] * Color_Pants[3] + buffer_texture_shirtbgra8[x*4+3] * Color_Shirt[3]; + } + if (thread->shader_permutation & SHADERPERMUTATION_CUBEFILTER) + { + // scale down the attenuation to account for the cubefilter multiplying everything by 255 + attenuation *= (1.0f / 255.0f); + d[0] = (int)((diffusetex[0] * (Color_Ambient[0])) * LightColor[0] * buffer_texture_cubebgra8[x*4+0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1])) * LightColor[1] * buffer_texture_cubebgra8[x*4+1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2])) * LightColor[2] * buffer_texture_cubebgra8[x*4+2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + else + { + d[0] = (int)((diffusetex[0] * (Color_Ambient[0])) * LightColor[0] * attenuation);if (d[0] > 255) d[0] = 255; + d[1] = (int)((diffusetex[1] * (Color_Ambient[1])) * LightColor[1] * attenuation);if (d[1] > 255) d[1] = 255; + d[2] = (int)((diffusetex[2] * (Color_Ambient[2])) * LightColor[2] * attenuation);if (d[2] > 255) d[2] = 255; + d[3] = (int)( diffusetex[3] );if (d[3] > 255) d[3] = 255; + } + buffer_FragColorbgra8[x*4+0] = d[0]; + buffer_FragColorbgra8[x*4+1] = d[1]; + buffer_FragColorbgra8[x*4+2] = d[2]; + buffer_FragColorbgra8[x*4+3] = d[3]; + } + } + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +#endif +} + + + +static void DPSOFTRAST_VertexShader_Refraction(void) +{ + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); +} + +static void DPSOFTRAST_PixelShader_Refraction(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + //float z; + int x, startx = span->startx, endx = span->endx; + + // texture reads + unsigned char buffer_texture_normalbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + + // varyings + float ModelViewProjectionPositiondata[4]; + float ModelViewProjectionPositionslope[4]; + + // uniforms + float ScreenScaleRefractReflect[2]; + float ScreenCenterRefractReflect[2]; + float DistortScaleRefractReflect[2]; + float RefractColor[4]; + + DPSOFTRAST_Texture *texture = thread->texbound[GL20TU_REFRACTION]; + if(!texture) return; + + // read textures + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + + // read varyings + DPSOFTRAST_CALCATTRIB4F(triangle, span, ModelViewProjectionPositiondata, ModelViewProjectionPositionslope, DPSOFTRAST_ARRAY_TEXCOORD4); + + // read uniforms + ScreenScaleRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+0]; + ScreenScaleRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+1]; + ScreenCenterRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+0]; + ScreenCenterRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+1]; + DistortScaleRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+0]; + DistortScaleRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+1]; + RefractColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+2]; + RefractColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+1]; + RefractColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+0]; + RefractColor[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+3]; + + // do stuff + for (x = startx;x < endx;x++) + { + float SafeScreenTexCoord[2]; + float ScreenTexCoord[2]; + float v[3]; + float iw; + unsigned char c[4]; + + //z = buffer_z[x]; + + // " vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n" + iw = 1.0f / (ModelViewProjectionPositiondata[3] + ModelViewProjectionPositionslope[3]*x); // / z + + // " vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n" + SafeScreenTexCoord[0] = (ModelViewProjectionPositiondata[0] + ModelViewProjectionPositionslope[0]*x) * iw * ScreenScaleRefractReflect[0] + ScreenCenterRefractReflect[0]; // * z (disappears) + SafeScreenTexCoord[1] = (ModelViewProjectionPositiondata[1] + ModelViewProjectionPositionslope[1]*x) * iw * ScreenScaleRefractReflect[1] + ScreenCenterRefractReflect[1]; // * z (disappears) + + // " vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.zw;\n" + v[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + v[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + v[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(v); + ScreenTexCoord[0] = SafeScreenTexCoord[0] + v[0] * DistortScaleRefractReflect[0]; + ScreenTexCoord[1] = SafeScreenTexCoord[1] + v[1] * DistortScaleRefractReflect[1]; + + // " dp_FragColor = vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord).rgb, 1.0) * RefractColor;\n" + DPSOFTRAST_Texture2DBGRA8(texture, 0, ScreenTexCoord[0], ScreenTexCoord[1], c); + + buffer_FragColorbgra8[x*4+0] = c[0] * RefractColor[0]; + buffer_FragColorbgra8[x*4+1] = c[1] * RefractColor[1]; + buffer_FragColorbgra8[x*4+2] = c[2] * RefractColor[2]; + buffer_FragColorbgra8[x*4+3] = min(RefractColor[3] * 256, 255); + } + + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_Water(void) +{ + int i; + int numvertices = dpsoftrast.numvertices; + float EyePosition[4]; + float EyeVectorModelSpace[4]; + float EyeVector[4]; + float position[4]; + float svector[4]; + float tvector[4]; + float normal[4]; + EyePosition[0] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+0]; + EyePosition[1] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+1]; + EyePosition[2] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+2]; + EyePosition[3] = dpsoftrast.uniform4f[DPSOFTRAST_UNIFORM_EyePosition*4+3]; + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD1); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD2); + DPSOFTRAST_Array_Load(DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD3); + for (i = 0;i < numvertices;i++) + { + position[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+0]; + position[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+1]; + position[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION][i*4+2]; + svector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+0]; + svector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+1]; + svector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD1][i*4+2]; + tvector[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+0]; + tvector[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+1]; + tvector[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD2][i*4+2]; + normal[0] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+0]; + normal[1] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+1]; + normal[2] = dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD3][i*4+2]; + EyeVectorModelSpace[0] = EyePosition[0] - position[0]; + EyeVectorModelSpace[1] = EyePosition[1] - position[1]; + EyeVectorModelSpace[2] = EyePosition[2] - position[2]; + EyeVector[0] = svector[0] * EyeVectorModelSpace[0] + svector[1] * EyeVectorModelSpace[1] + svector[2] * EyeVectorModelSpace[2]; + EyeVector[1] = tvector[0] * EyeVectorModelSpace[0] + tvector[1] * EyeVectorModelSpace[1] + tvector[2] * EyeVectorModelSpace[2]; + EyeVector[2] = normal[0] * EyeVectorModelSpace[0] + normal[1] * EyeVectorModelSpace[1] + normal[2] * EyeVectorModelSpace[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+0] = EyeVector[0]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+1] = EyeVector[1]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+2] = EyeVector[2]; + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_TEXCOORD6][i*4+3] = 0.0f; + } + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, -1, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); + DPSOFTRAST_Array_Transform(DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD0, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_TexMatrixM1); +} + + +static void DPSOFTRAST_PixelShader_Water(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + // float z; + int x, startx = span->startx, endx = span->endx; + + // texture reads + unsigned char buffer_texture_normalbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + + // varyings + float ModelViewProjectionPositiondata[4]; + float ModelViewProjectionPositionslope[4]; + float EyeVectordata[4]; + float EyeVectorslope[4]; + + // uniforms + float ScreenScaleRefractReflect[4]; + float ScreenCenterRefractReflect[4]; + float DistortScaleRefractReflect[4]; + float RefractColor[4]; + float ReflectColor[4]; + float ReflectFactor; + float ReflectOffset; + + DPSOFTRAST_Texture *texture_refraction = thread->texbound[GL20TU_REFRACTION]; + DPSOFTRAST_Texture *texture_reflection = thread->texbound[GL20TU_REFLECTION]; + if(!texture_refraction || !texture_reflection) return; + + // read textures + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + DPSOFTRAST_Draw_Span_Texture2DVaryingBGRA8(thread, triangle, span, buffer_texture_normalbgra8, GL20TU_NORMAL, DPSOFTRAST_ARRAY_TEXCOORD0, buffer_z); + + // read varyings + DPSOFTRAST_CALCATTRIB4F(triangle, span, ModelViewProjectionPositiondata, ModelViewProjectionPositionslope, DPSOFTRAST_ARRAY_TEXCOORD4); + DPSOFTRAST_CALCATTRIB4F(triangle, span, EyeVectordata, EyeVectorslope, DPSOFTRAST_ARRAY_TEXCOORD6); + + // read uniforms + ScreenScaleRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+0]; + ScreenScaleRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+1]; + ScreenScaleRefractReflect[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+2]; + ScreenScaleRefractReflect[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect*4+3]; + ScreenCenterRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+0]; + ScreenCenterRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+1]; + ScreenCenterRefractReflect[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+2]; + ScreenCenterRefractReflect[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect*4+3]; + DistortScaleRefractReflect[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+0]; + DistortScaleRefractReflect[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+1]; + DistortScaleRefractReflect[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+2]; + DistortScaleRefractReflect[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_DistortScaleRefractReflect*4+3]; + RefractColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+2]; + RefractColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+1]; + RefractColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+0]; + RefractColor[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_RefractColor*4+3]; + ReflectColor[0] = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectColor*4+2]; + ReflectColor[1] = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectColor*4+1]; + ReflectColor[2] = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectColor*4+0]; + ReflectColor[3] = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectColor*4+3]; + ReflectFactor = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectFactor*4+0]; + ReflectOffset = thread->uniform4f[DPSOFTRAST_UNIFORM_ReflectOffset*4+0]; + + // do stuff + for (x = startx;x < endx;x++) + { + float SafeScreenTexCoord[4]; + float ScreenTexCoord[4]; + float v[3]; + float iw; + unsigned char c1[4]; + unsigned char c2[4]; + float Fresnel; + + // z = buffer_z[x]; + + // " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n" + iw = 1.0f / (ModelViewProjectionPositiondata[3] + ModelViewProjectionPositionslope[3]*x); // / z + + // " vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" + SafeScreenTexCoord[0] = (ModelViewProjectionPositiondata[0] + ModelViewProjectionPositionslope[0]*x) * iw * ScreenScaleRefractReflect[0] + ScreenCenterRefractReflect[0]; // * z (disappears) + SafeScreenTexCoord[1] = (ModelViewProjectionPositiondata[1] + ModelViewProjectionPositionslope[1]*x) * iw * ScreenScaleRefractReflect[1] + ScreenCenterRefractReflect[1]; // * z (disappears) + SafeScreenTexCoord[2] = (ModelViewProjectionPositiondata[0] + ModelViewProjectionPositionslope[0]*x) * iw * ScreenScaleRefractReflect[2] + ScreenCenterRefractReflect[2]; // * z (disappears) + SafeScreenTexCoord[3] = (ModelViewProjectionPositiondata[1] + ModelViewProjectionPositionslope[1]*x) * iw * ScreenScaleRefractReflect[3] + ScreenCenterRefractReflect[3]; // * z (disappears) + + // " vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * DistortScaleRefractReflect;\n" + v[0] = buffer_texture_normalbgra8[x*4+2] * (1.0f / 128.0f) - 1.0f; + v[1] = buffer_texture_normalbgra8[x*4+1] * (1.0f / 128.0f) - 1.0f; + v[2] = buffer_texture_normalbgra8[x*4+0] * (1.0f / 128.0f) - 1.0f; + DPSOFTRAST_Vector3Normalize(v); + ScreenTexCoord[0] = SafeScreenTexCoord[0] + v[0] * DistortScaleRefractReflect[0]; + ScreenTexCoord[1] = SafeScreenTexCoord[1] + v[1] * DistortScaleRefractReflect[1]; + ScreenTexCoord[2] = SafeScreenTexCoord[2] + v[0] * DistortScaleRefractReflect[2]; + ScreenTexCoord[3] = SafeScreenTexCoord[3] + v[1] * DistortScaleRefractReflect[3]; + + // " float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n" + v[0] = (EyeVectordata[0] + EyeVectorslope[0] * x); // * z (disappears) + v[1] = (EyeVectordata[1] + EyeVectorslope[1] * x); // * z (disappears) + v[2] = (EyeVectordata[2] + EyeVectorslope[2] * x); // * z (disappears) + DPSOFTRAST_Vector3Normalize(v); + Fresnel = 1.0f - v[2]; + Fresnel = min(1.0f, Fresnel); + Fresnel = Fresnel * Fresnel * ReflectFactor + ReflectOffset; + + // " dp_FragColor = vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord).rgb, 1.0) * RefractColor;\n" + // " dp_FragColor = mix(vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * RefractColor, vec4(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n" + DPSOFTRAST_Texture2DBGRA8(texture_refraction, 0, ScreenTexCoord[0], ScreenTexCoord[1], c1); + DPSOFTRAST_Texture2DBGRA8(texture_reflection, 0, ScreenTexCoord[2], ScreenTexCoord[3], c2); + + buffer_FragColorbgra8[x*4+0] = (c1[0] * RefractColor[0]) * (1.0f - Fresnel) + (c2[0] * ReflectColor[0]) * Fresnel; + buffer_FragColorbgra8[x*4+1] = (c1[1] * RefractColor[1]) * (1.0f - Fresnel) + (c2[1] * ReflectColor[1]) * Fresnel; + buffer_FragColorbgra8[x*4+2] = (c1[2] * RefractColor[2]) * (1.0f - Fresnel) + (c2[2] * ReflectColor[2]) * Fresnel; + buffer_FragColorbgra8[x*4+3] = min(( RefractColor[3] * (1.0f - Fresnel) + ReflectColor[3] * Fresnel) * 256, 255); + } + + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_DeferredGeometry(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); +} + +static void DPSOFTRAST_PixelShader_DeferredGeometry(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + // TODO: IMPLEMENT + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + memset(buffer_FragColorbgra8 + span->startx*4, 0, (span->endx - span->startx)*4); + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +static void DPSOFTRAST_VertexShader_DeferredLightSource(void) +{ + DPSOFTRAST_Array_TransformProject(DPSOFTRAST_ARRAY_POSITION, DPSOFTRAST_ARRAY_POSITION, dpsoftrast.uniform4f + 4*DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1); +} + +static void DPSOFTRAST_PixelShader_DeferredLightSource(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span) +{ + // TODO: IMPLEMENT + float buffer_z[DPSOFTRAST_DRAW_MAXSPANLENGTH]; + unsigned char buffer_FragColorbgra8[DPSOFTRAST_DRAW_MAXSPANLENGTH*4]; + DPSOFTRAST_Draw_Span_Begin(thread, triangle, span, buffer_z); + memset(buffer_FragColorbgra8 + span->startx*4, 0, (span->endx - span->startx)*4); + DPSOFTRAST_Draw_Span_FinishBGRA8(thread, triangle, span, buffer_FragColorbgra8); +} + + + +typedef struct DPSOFTRAST_ShaderModeInfo_s +{ + int lodarrayindex; + void (*Vertex)(void); + void (*Span)(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Triangle * RESTRICT triangle, const DPSOFTRAST_State_Span * RESTRICT span); + unsigned char arrays[DPSOFTRAST_ARRAY_TOTAL]; + unsigned char texunits[DPSOFTRAST_MAXTEXTUREUNITS]; +} +DPSOFTRAST_ShaderModeInfo; + +static const DPSOFTRAST_ShaderModeInfo DPSOFTRAST_ShaderModeTable[SHADERMODE_COUNT] = +{ + {2, DPSOFTRAST_VertexShader_Generic, DPSOFTRAST_PixelShader_Generic, {DPSOFTRAST_ARRAY_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, ~0}, {GL20TU_FIRST, GL20TU_SECOND, ~0}}, + {2, DPSOFTRAST_VertexShader_PostProcess, DPSOFTRAST_PixelShader_PostProcess, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, ~0}, {GL20TU_FIRST, GL20TU_SECOND, ~0}}, + {2, DPSOFTRAST_VertexShader_Depth_Or_Shadow, DPSOFTRAST_PixelShader_Depth_Or_Shadow, {~0}, {~0}}, + {2, DPSOFTRAST_VertexShader_FlatColor, DPSOFTRAST_PixelShader_FlatColor, {DPSOFTRAST_ARRAY_TEXCOORD0, ~0}, {GL20TU_COLOR, ~0}}, + {2, DPSOFTRAST_VertexShader_VertexColor, DPSOFTRAST_PixelShader_VertexColor, {DPSOFTRAST_ARRAY_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, ~0}, {GL20TU_COLOR, ~0}}, + {2, DPSOFTRAST_VertexShader_Lightmap, DPSOFTRAST_PixelShader_Lightmap, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD4, ~0}, {GL20TU_COLOR, GL20TU_LIGHTMAP, GL20TU_GLOW, ~0}}, + {2, DPSOFTRAST_VertexShader_FakeLight, DPSOFTRAST_PixelShader_FakeLight, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD5, DPSOFTRAST_ARRAY_TEXCOORD6, ~0}, {GL20TU_COLOR, GL20TU_PANTS, GL20TU_SHIRT, GL20TU_GLOW, GL20TU_NORMAL, GL20TU_GLOSS, ~0}}, + {2, DPSOFTRAST_VertexShader_LightDirectionMap_ModelSpace, DPSOFTRAST_PixelShader_LightDirectionMap_ModelSpace, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD5, DPSOFTRAST_ARRAY_TEXCOORD6, ~0}, {GL20TU_COLOR, GL20TU_PANTS, GL20TU_SHIRT, GL20TU_GLOW, GL20TU_NORMAL, GL20TU_GLOSS, GL20TU_LIGHTMAP, GL20TU_DELUXEMAP, ~0}}, + {2, DPSOFTRAST_VertexShader_LightDirectionMap_TangentSpace, DPSOFTRAST_PixelShader_LightDirectionMap_TangentSpace, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD5, DPSOFTRAST_ARRAY_TEXCOORD6, ~0}, {GL20TU_COLOR, GL20TU_PANTS, GL20TU_SHIRT, GL20TU_GLOW, GL20TU_NORMAL, GL20TU_GLOSS, GL20TU_LIGHTMAP, GL20TU_DELUXEMAP, ~0}}, + {2, DPSOFTRAST_VertexShader_Lightmap, DPSOFTRAST_PixelShader_Lightmap, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD4, ~0}, {GL20TU_COLOR, GL20TU_LIGHTMAP, GL20TU_GLOW, ~0}}, + {2, DPSOFTRAST_VertexShader_VertexColor, DPSOFTRAST_PixelShader_VertexColor, {DPSOFTRAST_ARRAY_COLOR, DPSOFTRAST_ARRAY_TEXCOORD0, ~0}, {GL20TU_COLOR, ~0}}, + {2, DPSOFTRAST_VertexShader_LightDirection, DPSOFTRAST_PixelShader_LightDirection, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD5, DPSOFTRAST_ARRAY_TEXCOORD6, ~0}, {GL20TU_COLOR, GL20TU_PANTS, GL20TU_SHIRT, GL20TU_GLOW, GL20TU_NORMAL, GL20TU_GLOSS, ~0}}, + {2, DPSOFTRAST_VertexShader_LightSource, DPSOFTRAST_PixelShader_LightSource, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD4, ~0}, {GL20TU_COLOR, GL20TU_PANTS, GL20TU_SHIRT, GL20TU_GLOW, GL20TU_NORMAL, GL20TU_GLOSS, GL20TU_CUBE, ~0}}, + {2, DPSOFTRAST_VertexShader_Refraction, DPSOFTRAST_PixelShader_Refraction, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD4, ~0}, {GL20TU_NORMAL, GL20TU_REFRACTION, ~0}}, + {2, DPSOFTRAST_VertexShader_Water, DPSOFTRAST_PixelShader_Water, {DPSOFTRAST_ARRAY_TEXCOORD0, DPSOFTRAST_ARRAY_TEXCOORD1, DPSOFTRAST_ARRAY_TEXCOORD2, DPSOFTRAST_ARRAY_TEXCOORD3, DPSOFTRAST_ARRAY_TEXCOORD4, DPSOFTRAST_ARRAY_TEXCOORD6, ~0}, {GL20TU_NORMAL, GL20TU_REFLECTION, GL20TU_REFRACTION, ~0}}, + {2, DPSOFTRAST_VertexShader_DeferredGeometry, DPSOFTRAST_PixelShader_DeferredGeometry, {~0}}, + {2, DPSOFTRAST_VertexShader_DeferredLightSource, DPSOFTRAST_PixelShader_DeferredLightSource, {~0}}, +}; + +static void DPSOFTRAST_Draw_DepthTest(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_State_Span *span) +{ + int x; + int startx; + int endx; + unsigned int *depthpixel; + int depth; + int depthslope; + unsigned int d; + unsigned char *pixelmask; + depthpixel = dpsoftrast.fb_depthpixels + span->y * dpsoftrast.fb_width + span->x; + startx = span->startx; + endx = span->endx; + depth = span->depthbase; + depthslope = span->depthslope; + pixelmask = thread->pixelmaskarray; + if (thread->depthtest && dpsoftrast.fb_depthpixels) + { + switch(thread->fb_depthfunc) + { + default: + case GL_ALWAYS: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = true; break; + case GL_LESS: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] < d; break; + case GL_LEQUAL: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] <= d; break; + case GL_EQUAL: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] == d; break; + case GL_GEQUAL: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] >= d; break; + case GL_GREATER: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = depthpixel[x] > d; break; + case GL_NEVER: for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) pixelmask[x] = false; break; + } + while (startx < endx && !pixelmask[startx]) + startx++; + while (endx > startx && !pixelmask[endx-1]) + endx--; + } + else + { + // no depth testing means we're just dealing with color... + memset(pixelmask + startx, 1, endx - startx); + } + span->pixelmask = pixelmask; + span->startx = startx; + span->endx = endx; +} + +static void DPSOFTRAST_Draw_DepthWrite(const DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_State_Span *span) +{ + int x, d, depth, depthslope, startx, endx; + const unsigned char *pixelmask; + unsigned int *depthpixel; + if (thread->depthmask && thread->depthtest && dpsoftrast.fb_depthpixels) + { + depth = span->depthbase; + depthslope = span->depthslope; + pixelmask = span->pixelmask; + startx = span->startx; + endx = span->endx; + depthpixel = dpsoftrast.fb_depthpixels + span->y * dpsoftrast.fb_width + span->x; + for (x = startx, d = depth + depthslope*startx;x < endx;x++, d += depthslope) + if (pixelmask[x]) + depthpixel[x] = d; + } +} + +static void DPSOFTRAST_Draw_ProcessSpans(DPSOFTRAST_State_Thread *thread) +{ + int i; + DPSOFTRAST_State_Triangle *triangle; + DPSOFTRAST_State_Span *span; + for (i = 0; i < thread->numspans; i++) + { + span = &thread->spans[i]; + triangle = &thread->triangles[span->triangle]; + DPSOFTRAST_Draw_DepthTest(thread, span); + if (span->startx >= span->endx) + continue; + // run pixel shader if appropriate + // do this before running depthmask code, to allow the pixelshader + // to clear pixelmask values for alpha testing + if (dpsoftrast.fb_colorpixels[0] && thread->fb_colormask) + DPSOFTRAST_ShaderModeTable[thread->shader_mode].Span(thread, triangle, span); + DPSOFTRAST_Draw_DepthWrite(thread, span); + } + thread->numspans = 0; +} + +DEFCOMMAND(22, Draw, int datasize; int starty; int endy; ATOMIC_COUNTER refcount; int clipped; int firstvertex; int numvertices; int numtriangles; float *arrays; int *element3i; unsigned short *element3s;) + +static void DPSOFTRAST_Interpret_Draw(DPSOFTRAST_State_Thread *thread, DPSOFTRAST_Command_Draw *command) +{ +#ifdef SSE_POSSIBLE + int cullface = thread->cullface; + int minx, maxx, miny, maxy; + int miny1, maxy1, miny2, maxy2; + __m128i fbmin, fbmax; + __m128 viewportcenter, viewportscale; + int firstvertex = command->firstvertex; + int numvertices = command->numvertices; + int numtriangles = command->numtriangles; + const int *element3i = command->element3i; + const unsigned short *element3s = command->element3s; + int clipped = command->clipped; + int i; + int j; + int k; + int y; + int e[3]; + __m128i screeny; + int starty, endy, bandy; + int numpoints; + int clipcase; + float clipdist[4]; + float clip0origin, clip0slope; + int clip0dir; + __m128 triangleedge1, triangleedge2, trianglenormal; + __m128 clipfrac[3]; + __m128 screen[4]; + DPSOFTRAST_State_Triangle *triangle; + DPSOFTRAST_Texture *texture; + DPSOFTRAST_ValidateQuick(thread, DPSOFTRAST_VALIDATE_DRAW); + miny = thread->fb_scissor[1]; + maxy = thread->fb_scissor[1] + thread->fb_scissor[3]; + miny1 = bound(miny, thread->miny1, maxy); + maxy1 = bound(miny, thread->maxy1, maxy); + miny2 = bound(miny, thread->miny2, maxy); + maxy2 = bound(miny, thread->maxy2, maxy); + if ((command->starty >= maxy1 || command->endy <= miny1) && (command->starty >= maxy2 || command->endy <= miny2)) + { + if (!ATOMIC_DECREMENT(command->refcount)) + { + if (command->commandsize <= DPSOFTRAST_ALIGNCOMMAND(sizeof(DPSOFTRAST_Command_Draw))) + MM_FREE(command->arrays); + } + return; + } + minx = thread->fb_scissor[0]; + maxx = thread->fb_scissor[0] + thread->fb_scissor[2]; + fbmin = _mm_setr_epi16(minx, miny1, minx, miny1, minx, miny1, minx, miny1); + fbmax = _mm_sub_epi16(_mm_setr_epi16(maxx, maxy2, maxx, maxy2, maxx, maxy2, maxx, maxy2), _mm_set1_epi16(1)); + viewportcenter = _mm_load_ps(thread->fb_viewportcenter); + viewportscale = _mm_load_ps(thread->fb_viewportscale); + screen[3] = _mm_setzero_ps(); + clipfrac[0] = clipfrac[1] = clipfrac[2] = _mm_setzero_ps(); + for (i = 0;i < numtriangles;i++) + { + const float *screencoord4f = command->arrays; + const float *arrays = screencoord4f + numvertices*4; + + // generate the 3 edges of this triangle + // generate spans for the triangle - switch based on left split or right split classification of triangle + if (element3s) + { + e[0] = element3s[i*3+0] - firstvertex; + e[1] = element3s[i*3+1] - firstvertex; + e[2] = element3s[i*3+2] - firstvertex; + } + else if (element3i) + { + e[0] = element3i[i*3+0] - firstvertex; + e[1] = element3i[i*3+1] - firstvertex; + e[2] = element3i[i*3+2] - firstvertex; + } + else + { + e[0] = i*3+0; + e[1] = i*3+1; + e[2] = i*3+2; + } + +#define SKIPBACKFACE \ + triangleedge1 = _mm_sub_ps(screen[0], screen[1]); \ + triangleedge2 = _mm_sub_ps(screen[2], screen[1]); \ + /* store normal in 2, 0, 1 order instead of 0, 1, 2 as it requires fewer shuffles and leaves z component accessible as scalar */ \ + trianglenormal = _mm_sub_ss(_mm_mul_ss(triangleedge1, _mm_shuffle_ps(triangleedge2, triangleedge2, _MM_SHUFFLE(3, 0, 2, 1))), \ + _mm_mul_ss(_mm_shuffle_ps(triangleedge1, triangleedge1, _MM_SHUFFLE(3, 0, 2, 1)), triangleedge2)); \ + switch(cullface) \ + { \ + case GL_BACK: \ + if (_mm_ucomilt_ss(trianglenormal, _mm_setzero_ps())) \ + continue; \ + break; \ + case GL_FRONT: \ + if (_mm_ucomigt_ss(trianglenormal, _mm_setzero_ps())) \ + continue; \ + break; \ + } + +#define CLIPPEDVERTEXLERP(k,p1, p2) \ + clipfrac[p1] = _mm_set1_ps(clipdist[p1] / (clipdist[p1] - clipdist[p2])); \ + { \ + __m128 v1 = _mm_load_ps(&arrays[e[p1]*4]), v2 = _mm_load_ps(&arrays[e[p2]*4]); \ + DPSOFTRAST_PROJECTVERTEX(screen[k], _mm_add_ps(v1, _mm_mul_ps(_mm_sub_ps(v2, v1), clipfrac[p1])), viewportcenter, viewportscale); \ + } +#define CLIPPEDVERTEXCOPY(k,p1) \ + screen[k] = _mm_load_ps(&screencoord4f[e[p1]*4]); + +#define GENATTRIBCOPY(attrib, p1) \ + attrib = _mm_load_ps(&arrays[e[p1]*4]); +#define GENATTRIBLERP(attrib, p1, p2) \ + { \ + __m128 v1 = _mm_load_ps(&arrays[e[p1]*4]), v2 = _mm_load_ps(&arrays[e[p2]*4]); \ + attrib = _mm_add_ps(v1, _mm_mul_ps(_mm_sub_ps(v2, v1), clipfrac[p1])); \ + } +#define GENATTRIBS(attrib0, attrib1, attrib2) \ + switch(clipcase) \ + { \ + default: \ + case 0: GENATTRIBCOPY(attrib0, 0); GENATTRIBCOPY(attrib1, 1); GENATTRIBCOPY(attrib2, 2); break; \ + case 1: GENATTRIBCOPY(attrib0, 0); GENATTRIBCOPY(attrib1, 1); GENATTRIBLERP(attrib2, 1, 2); break; \ + case 2: GENATTRIBCOPY(attrib0, 0); GENATTRIBLERP(attrib1, 0, 1); GENATTRIBLERP(attrib2, 1, 2); break; \ + case 3: GENATTRIBCOPY(attrib0, 0); GENATTRIBLERP(attrib1, 0, 1); GENATTRIBLERP(attrib2, 2, 0); break; \ + case 4: GENATTRIBLERP(attrib0, 0, 1); GENATTRIBCOPY(attrib1, 1); GENATTRIBCOPY(attrib2, 2); break; \ + case 5: GENATTRIBLERP(attrib0, 0, 1); GENATTRIBCOPY(attrib1, 1); GENATTRIBLERP(attrib2, 1, 2); break; \ + case 6: GENATTRIBLERP(attrib0, 1, 2); GENATTRIBCOPY(attrib1, 2); GENATTRIBLERP(attrib2, 2, 0); break; \ + } + + if (! clipped) + goto notclipped; + + // calculate distance from nearplane + clipdist[0] = arrays[e[0]*4+2] + arrays[e[0]*4+3]; + clipdist[1] = arrays[e[1]*4+2] + arrays[e[1]*4+3]; + clipdist[2] = arrays[e[2]*4+2] + arrays[e[2]*4+3]; + if (clipdist[0] >= 0.0f) + { + if (clipdist[1] >= 0.0f) + { + if (clipdist[2] >= 0.0f) + { + notclipped: + // triangle is entirely in front of nearplane + CLIPPEDVERTEXCOPY(0,0); CLIPPEDVERTEXCOPY(1,1); CLIPPEDVERTEXCOPY(2,2); + SKIPBACKFACE; + numpoints = 3; + clipcase = 0; + } + else + { + CLIPPEDVERTEXCOPY(0,0); CLIPPEDVERTEXCOPY(1,1); CLIPPEDVERTEXLERP(2,1,2); CLIPPEDVERTEXLERP(3,2,0); + SKIPBACKFACE; + numpoints = 4; + clipcase = 1; + } + } + else + { + if (clipdist[2] >= 0.0f) + { + CLIPPEDVERTEXCOPY(0,0); CLIPPEDVERTEXLERP(1,0,1); CLIPPEDVERTEXLERP(2,1,2); CLIPPEDVERTEXCOPY(3,2); + SKIPBACKFACE; + numpoints = 4; + clipcase = 2; + } + else + { + CLIPPEDVERTEXCOPY(0,0); CLIPPEDVERTEXLERP(1,0,1); CLIPPEDVERTEXLERP(2,2,0); + SKIPBACKFACE; + numpoints = 3; + clipcase = 3; + } + } + } + else if (clipdist[1] >= 0.0f) + { + if (clipdist[2] >= 0.0f) + { + CLIPPEDVERTEXLERP(0,0,1); CLIPPEDVERTEXCOPY(1,1); CLIPPEDVERTEXCOPY(2,2); CLIPPEDVERTEXLERP(3,2,0); + SKIPBACKFACE; + numpoints = 4; + clipcase = 4; + } + else + { + CLIPPEDVERTEXLERP(0,0,1); CLIPPEDVERTEXCOPY(1,1); CLIPPEDVERTEXLERP(2,1,2); + SKIPBACKFACE; + numpoints = 3; + clipcase = 5; + } + } + else if (clipdist[2] >= 0.0f) + { + CLIPPEDVERTEXLERP(0,1,2); CLIPPEDVERTEXCOPY(1,2); CLIPPEDVERTEXLERP(2,2,0); + SKIPBACKFACE; + numpoints = 3; + clipcase = 6; + } + else continue; // triangle is entirely behind nearplane + + { + // calculate integer y coords for triangle points + __m128i screeni = _mm_packs_epi32(_mm_cvttps_epi32(_mm_movelh_ps(screen[0], screen[1])), _mm_cvttps_epi32(_mm_movelh_ps(screen[2], numpoints > 3 ? screen[3] : screen[2]))), + screenir = _mm_shuffle_epi32(screeni, _MM_SHUFFLE(1, 0, 3, 2)), + screenmin = _mm_min_epi16(screeni, screenir), + screenmax = _mm_max_epi16(screeni, screenir); + screenmin = _mm_min_epi16(screenmin, _mm_shufflelo_epi16(screenmin, _MM_SHUFFLE(1, 0, 3, 2))); + screenmax = _mm_max_epi16(screenmax, _mm_shufflelo_epi16(screenmax, _MM_SHUFFLE(1, 0, 3, 2))); + screenmin = _mm_max_epi16(screenmin, fbmin); + screenmax = _mm_min_epi16(screenmax, fbmax); + // skip offscreen triangles + if (_mm_cvtsi128_si32(_mm_cmplt_epi16(screenmax, screenmin))) + continue; + starty = _mm_extract_epi16(screenmin, 1); + endy = _mm_extract_epi16(screenmax, 1)+1; + if (starty >= maxy1 && endy <= miny2) + continue; + screeny = _mm_srai_epi32(screeni, 16); + } + + triangle = &thread->triangles[thread->numtriangles]; + + // calculate attribute plans for triangle data... + // okay, this triangle is going to produce spans, we'd better project + // the interpolants now (this is what gives perspective texturing), + // this consists of simply multiplying all arrays by the W coord + // (which is basically 1/Z), which will be undone per-pixel + // (multiplying by Z again) to get the perspective-correct array + // values + { + __m128 attribuvslope, attribuxslope, attribuyslope, attribvxslope, attribvyslope, attriborigin, attribedge1, attribedge2, attribxslope, attribyslope, w0, w1, w2, x1, y1; + __m128 mipedgescale, mipdensity; + attribuvslope = _mm_div_ps(_mm_movelh_ps(triangleedge1, triangleedge2), _mm_shuffle_ps(trianglenormal, trianglenormal, _MM_SHUFFLE(0, 0, 0, 0))); + attribuxslope = _mm_shuffle_ps(attribuvslope, attribuvslope, _MM_SHUFFLE(3, 3, 3, 3)); + attribuyslope = _mm_shuffle_ps(attribuvslope, attribuvslope, _MM_SHUFFLE(2, 2, 2, 2)); + attribvxslope = _mm_shuffle_ps(attribuvslope, attribuvslope, _MM_SHUFFLE(1, 1, 1, 1)); + attribvyslope = _mm_shuffle_ps(attribuvslope, attribuvslope, _MM_SHUFFLE(0, 0, 0, 0)); + w0 = _mm_shuffle_ps(screen[0], screen[0], _MM_SHUFFLE(3, 3, 3, 3)); + w1 = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(3, 3, 3, 3)); + w2 = _mm_shuffle_ps(screen[2], screen[2], _MM_SHUFFLE(3, 3, 3, 3)); + attribedge1 = _mm_sub_ss(w0, w1); + attribedge2 = _mm_sub_ss(w2, w1); + attribxslope = _mm_sub_ss(_mm_mul_ss(attribuxslope, attribedge1), _mm_mul_ss(attribvxslope, attribedge2)); + attribyslope = _mm_sub_ss(_mm_mul_ss(attribvyslope, attribedge2), _mm_mul_ss(attribuyslope, attribedge1)); + x1 = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(0, 0, 0, 0)); + y1 = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(1, 1, 1, 1)); + attriborigin = _mm_sub_ss(w1, _mm_add_ss(_mm_mul_ss(attribxslope, x1), _mm_mul_ss(attribyslope, y1))); + _mm_store_ss(&triangle->w[0], attribxslope); + _mm_store_ss(&triangle->w[1], attribyslope); + _mm_store_ss(&triangle->w[2], attriborigin); + + clip0origin = 0; + clip0slope = 0; + clip0dir = 0; + if(thread->fb_clipplane[0] || thread->fb_clipplane[1] || thread->fb_clipplane[2]) + { + float cliporigin, clipxslope, clipyslope; + attriborigin = _mm_shuffle_ps(screen[1], screen[1], _MM_SHUFFLE(2, 2, 2, 2)); + attribedge1 = _mm_sub_ss(_mm_shuffle_ps(screen[0], screen[0], _MM_SHUFFLE(2, 2, 2, 2)), attriborigin); + attribedge2 = _mm_sub_ss(_mm_shuffle_ps(screen[2], screen[2], _MM_SHUFFLE(2, 2, 2, 2)), attriborigin); + attribxslope = _mm_sub_ss(_mm_mul_ss(attribuxslope, attribedge1), _mm_mul_ss(attribvxslope, attribedge2)); + attribyslope = _mm_sub_ss(_mm_mul_ss(attribvyslope, attribedge2), _mm_mul_ss(attribuyslope, attribedge1)); + attriborigin = _mm_sub_ss(attriborigin, _mm_add_ss(_mm_mul_ss(attribxslope, x1), _mm_mul_ss(attribyslope, y1))); + cliporigin = _mm_cvtss_f32(attriborigin)*thread->fb_clipplane[2] + thread->fb_clipplane[3]; + clipxslope = thread->fb_clipplane[0] + _mm_cvtss_f32(attribxslope)*thread->fb_clipplane[2]; + clipyslope = thread->fb_clipplane[1] + _mm_cvtss_f32(attribyslope)*thread->fb_clipplane[2]; + if(clipxslope != 0) + { + clip0origin = -cliporigin/clipxslope; + clip0slope = -clipyslope/clipxslope; + clip0dir = clipxslope > 0 ? 1 : -1; + } + else if(clipyslope > 0) + { + clip0origin = dpsoftrast.fb_width*floor(cliporigin/clipyslope); + clip0slope = dpsoftrast.fb_width; + clip0dir = -1; + } + else if(clipyslope < 0) + { + clip0origin = dpsoftrast.fb_width*ceil(cliporigin/clipyslope); + clip0slope = -dpsoftrast.fb_width; + clip0dir = -1; + } + else if(clip0origin < 0) continue; + } + + mipedgescale = _mm_setzero_ps(); + for (j = 0;j < DPSOFTRAST_ARRAY_TOTAL; j++) + { + __m128 attrib0, attrib1, attrib2; + k = DPSOFTRAST_ShaderModeTable[thread->shader_mode].arrays[j]; + if (k >= DPSOFTRAST_ARRAY_TOTAL) + break; + arrays += numvertices*4; + GENATTRIBS(attrib0, attrib1, attrib2); + attriborigin = _mm_mul_ps(attrib1, w1); + attribedge1 = _mm_sub_ps(_mm_mul_ps(attrib0, w0), attriborigin); + attribedge2 = _mm_sub_ps(_mm_mul_ps(attrib2, w2), attriborigin); + attribxslope = _mm_sub_ps(_mm_mul_ps(attribuxslope, attribedge1), _mm_mul_ps(attribvxslope, attribedge2)); + attribyslope = _mm_sub_ps(_mm_mul_ps(attribvyslope, attribedge2), _mm_mul_ps(attribuyslope, attribedge1)); + attriborigin = _mm_sub_ps(attriborigin, _mm_add_ps(_mm_mul_ps(attribxslope, x1), _mm_mul_ps(attribyslope, y1))); + _mm_storeu_ps(triangle->attribs[k][0], attribxslope); + _mm_storeu_ps(triangle->attribs[k][1], attribyslope); + _mm_storeu_ps(triangle->attribs[k][2], attriborigin); + if (k == DPSOFTRAST_ShaderModeTable[thread->shader_mode].lodarrayindex) + { + mipedgescale = _mm_movelh_ps(triangleedge1, triangleedge2); + mipedgescale = _mm_mul_ps(mipedgescale, mipedgescale); + mipedgescale = _mm_rsqrt_ps(_mm_add_ps(mipedgescale, _mm_shuffle_ps(mipedgescale, mipedgescale, _MM_SHUFFLE(2, 3, 0, 1)))); + mipedgescale = _mm_mul_ps(_mm_sub_ps(_mm_movelh_ps(attrib0, attrib2), _mm_movelh_ps(attrib1, attrib1)), mipedgescale); + } + } + + memset(triangle->mip, 0, sizeof(triangle->mip)); + for (j = 0;j < DPSOFTRAST_MAXTEXTUREUNITS;j++) + { + int texunit = DPSOFTRAST_ShaderModeTable[thread->shader_mode].texunits[j]; + if (texunit >= DPSOFTRAST_MAXTEXTUREUNITS) + break; + texture = thread->texbound[texunit]; + if (texture && texture->filter > DPSOFTRAST_TEXTURE_FILTER_LINEAR) + { + mipdensity = _mm_mul_ps(mipedgescale, _mm_cvtepi32_ps(_mm_shuffle_epi32(_mm_loadl_epi64((const __m128i *)&texture->mipmap[0][2]), _MM_SHUFFLE(1, 0, 1, 0)))); + mipdensity = _mm_mul_ps(mipdensity, mipdensity); + mipdensity = _mm_add_ps(mipdensity, _mm_shuffle_ps(mipdensity, mipdensity, _MM_SHUFFLE(2, 3, 0, 1))); + mipdensity = _mm_min_ss(mipdensity, _mm_shuffle_ps(mipdensity, mipdensity, _MM_SHUFFLE(2, 2, 2, 2))); + // this will be multiplied in the texturing routine by the texture resolution + y = _mm_cvtss_si32(mipdensity); + if (y > 0) + { + y = (int)(log((float)y)*0.5f/M_LN2); + if (y > texture->mipmaps - 1) + y = texture->mipmaps - 1; + triangle->mip[texunit] = y; + } + } + } + } + + for (y = starty, bandy = min(endy, maxy1); y < endy; bandy = min(endy, maxy2), y = max(y, miny2)) + for (; y < bandy;) + { + __m128 xcoords, xslope; + __m128i ycc = _mm_cmpgt_epi32(_mm_set1_epi32(y), screeny); + int yccmask = _mm_movemask_epi8(ycc); + int edge0p, edge0n, edge1p, edge1n; + int nexty; + float w, wslope; + float clip0; + if (numpoints == 4) + { + switch(yccmask) + { + default: + case 0xFFFF: /*0000*/ y = endy; continue; + case 0xFFF0: /*1000*/ edge0p = 3;edge0n = 0;edge1p = 1;edge1n = 0;break; + case 0xFF0F: /*0100*/ edge0p = 0;edge0n = 1;edge1p = 2;edge1n = 1;break; + case 0xFF00: /*1100*/ edge0p = 3;edge0n = 0;edge1p = 2;edge1n = 1;break; + case 0xF0FF: /*0010*/ edge0p = 1;edge0n = 2;edge1p = 3;edge1n = 2;break; + case 0xF0F0: /*1010*/ edge0p = 1;edge0n = 2;edge1p = 3;edge1n = 2;break; // concave - nonsense + case 0xF00F: /*0110*/ edge0p = 0;edge0n = 1;edge1p = 3;edge1n = 2;break; + case 0xF000: /*1110*/ edge0p = 3;edge0n = 0;edge1p = 3;edge1n = 2;break; + case 0x0FFF: /*0001*/ edge0p = 2;edge0n = 3;edge1p = 0;edge1n = 3;break; + case 0x0FF0: /*1001*/ edge0p = 2;edge0n = 3;edge1p = 1;edge1n = 0;break; + case 0x0F0F: /*0101*/ edge0p = 2;edge0n = 3;edge1p = 2;edge1n = 1;break; // concave - nonsense + case 0x0F00: /*1101*/ edge0p = 2;edge0n = 3;edge1p = 2;edge1n = 1;break; + case 0x00FF: /*0011*/ edge0p = 1;edge0n = 2;edge1p = 0;edge1n = 3;break; + case 0x00F0: /*1011*/ edge0p = 1;edge0n = 2;edge1p = 1;edge1n = 0;break; + case 0x000F: /*0111*/ edge0p = 0;edge0n = 1;edge1p = 0;edge1n = 3;break; + case 0x0000: /*1111*/ y++; continue; + } + } + else + { + switch(yccmask) + { + default: + case 0xFFFF: /*000*/ y = endy; continue; + case 0xFFF0: /*100*/ edge0p = 2;edge0n = 0;edge1p = 1;edge1n = 0;break; + case 0xFF0F: /*010*/ edge0p = 0;edge0n = 1;edge1p = 2;edge1n = 1;break; + case 0xFF00: /*110*/ edge0p = 2;edge0n = 0;edge1p = 2;edge1n = 1;break; + case 0x00FF: /*001*/ edge0p = 1;edge0n = 2;edge1p = 0;edge1n = 2;break; + case 0x00F0: /*101*/ edge0p = 1;edge0n = 2;edge1p = 1;edge1n = 0;break; + case 0x000F: /*011*/ edge0p = 0;edge0n = 1;edge1p = 0;edge1n = 2;break; + case 0x0000: /*111*/ y++; continue; + } + } + ycc = _mm_max_epi16(_mm_srli_epi16(ycc, 1), screeny); + ycc = _mm_min_epi16(ycc, _mm_shuffle_epi32(ycc, _MM_SHUFFLE(1, 0, 3, 2))); + ycc = _mm_min_epi16(ycc, _mm_shuffle_epi32(ycc, _MM_SHUFFLE(2, 3, 0, 1))); + nexty = _mm_extract_epi16(ycc, 0); + if (nexty >= bandy) nexty = bandy-1; + xslope = _mm_sub_ps(_mm_movelh_ps(screen[edge0n], screen[edge1n]), _mm_movelh_ps(screen[edge0p], screen[edge1p])); + xslope = _mm_div_ps(xslope, _mm_shuffle_ps(xslope, xslope, _MM_SHUFFLE(3, 3, 1, 1))); + xcoords = _mm_add_ps(_mm_movelh_ps(screen[edge0p], screen[edge1p]), + _mm_mul_ps(xslope, _mm_sub_ps(_mm_set1_ps(y), _mm_shuffle_ps(screen[edge0p], screen[edge1p], _MM_SHUFFLE(1, 1, 1, 1))))); + xcoords = _mm_add_ps(xcoords, _mm_set1_ps(0.5f)); + if (_mm_ucomigt_ss(xcoords, _mm_shuffle_ps(xcoords, xcoords, _MM_SHUFFLE(1, 0, 3, 2)))) + { + xcoords = _mm_shuffle_ps(xcoords, xcoords, _MM_SHUFFLE(1, 0, 3, 2)); + xslope = _mm_shuffle_ps(xslope, xslope, _MM_SHUFFLE(1, 0, 3, 2)); + } + clip0 = clip0origin + (y+0.5f)*clip0slope + 0.5f; + for(; y <= nexty; y++, xcoords = _mm_add_ps(xcoords, xslope), clip0 += clip0slope) + { + int startx, endx, offset; + startx = _mm_cvtss_si32(xcoords); + endx = _mm_cvtss_si32(_mm_movehl_ps(xcoords, xcoords)); + if (startx < minx) startx = minx; + if (endx > maxx) endx = maxx; + if (startx >= endx) continue; + + if (clip0dir) + { + if (clip0dir > 0) + { + if (startx < clip0) + { + if(endx <= clip0) continue; + startx = (int)clip0; + } + } + else if (endx > clip0) + { + if(startx >= clip0) continue; + endx = (int)clip0; + } + } + + for (offset = startx; offset < endx;offset += DPSOFTRAST_DRAW_MAXSPANLENGTH) + { + DPSOFTRAST_State_Span *span = &thread->spans[thread->numspans]; + span->triangle = thread->numtriangles; + span->x = offset; + span->y = y; + span->startx = 0; + span->endx = min(endx - offset, DPSOFTRAST_DRAW_MAXSPANLENGTH); + if (span->startx >= span->endx) + continue; + wslope = triangle->w[0]; + w = triangle->w[2] + span->x*wslope + span->y*triangle->w[1]; + span->depthslope = (int)(wslope*DPSOFTRAST_DEPTHSCALE); + span->depthbase = (int)(w*DPSOFTRAST_DEPTHSCALE - DPSOFTRAST_DEPTHOFFSET*(thread->polygonoffset[1] + fabs(wslope)*thread->polygonoffset[0])); + if (++thread->numspans >= DPSOFTRAST_DRAW_MAXSPANS) + DPSOFTRAST_Draw_ProcessSpans(thread); + } + } + } + + if (++thread->numtriangles >= DPSOFTRAST_DRAW_MAXTRIANGLES) + { + DPSOFTRAST_Draw_ProcessSpans(thread); + thread->numtriangles = 0; + } + } + + if (!ATOMIC_DECREMENT(command->refcount)) + { + if (command->commandsize <= DPSOFTRAST_ALIGNCOMMAND(sizeof(DPSOFTRAST_Command_Draw))) + MM_FREE(command->arrays); + } + + if (thread->numspans > 0 || thread->numtriangles > 0) + { + DPSOFTRAST_Draw_ProcessSpans(thread); + thread->numtriangles = 0; + } +#endif +} + +static DPSOFTRAST_Command_Draw *DPSOFTRAST_Draw_AllocateDrawCommand(int firstvertex, int numvertices, int numtriangles, const int *element3i, const unsigned short *element3s) +{ + int i; + int j; + int commandsize = DPSOFTRAST_ALIGNCOMMAND(sizeof(DPSOFTRAST_Command_Draw)); + int datasize = 2*numvertices*sizeof(float[4]); + DPSOFTRAST_Command_Draw *command; + unsigned char *data; + for (i = 0; i < DPSOFTRAST_ARRAY_TOTAL; i++) + { + j = DPSOFTRAST_ShaderModeTable[dpsoftrast.shader_mode].arrays[i]; + if (j >= DPSOFTRAST_ARRAY_TOTAL) + break; + datasize += numvertices*sizeof(float[4]); + } + if (element3s) + datasize += numtriangles*sizeof(unsigned short[3]); + else if (element3i) + datasize += numtriangles*sizeof(int[3]); + datasize = DPSOFTRAST_ALIGNCOMMAND(datasize); + if (commandsize + datasize > DPSOFTRAST_DRAW_MAXCOMMANDSIZE) + { + command = (DPSOFTRAST_Command_Draw *) DPSOFTRAST_AllocateCommand(DPSOFTRAST_OPCODE_Draw, commandsize); + data = (unsigned char *)MM_CALLOC(datasize, 1); + } + else + { + command = (DPSOFTRAST_Command_Draw *) DPSOFTRAST_AllocateCommand(DPSOFTRAST_OPCODE_Draw, commandsize + datasize); + data = (unsigned char *)command + commandsize; + } + command->firstvertex = firstvertex; + command->numvertices = numvertices; + command->numtriangles = numtriangles; + command->arrays = (float *)data; + memset(dpsoftrast.post_array4f, 0, sizeof(dpsoftrast.post_array4f)); + dpsoftrast.firstvertex = firstvertex; + dpsoftrast.numvertices = numvertices; + dpsoftrast.screencoord4f = (float *)data; + data += numvertices*sizeof(float[4]); + dpsoftrast.post_array4f[DPSOFTRAST_ARRAY_POSITION] = (float *)data; + data += numvertices*sizeof(float[4]); + for (i = 0; i < DPSOFTRAST_ARRAY_TOTAL; i++) + { + j = DPSOFTRAST_ShaderModeTable[dpsoftrast.shader_mode].arrays[i]; + if (j >= DPSOFTRAST_ARRAY_TOTAL) + break; + dpsoftrast.post_array4f[j] = (float *)data; + data += numvertices*sizeof(float[4]); + } + command->element3i = NULL; + command->element3s = NULL; + if (element3s) + { + command->element3s = (unsigned short *)data; + memcpy(command->element3s, element3s, numtriangles*sizeof(unsigned short[3])); + } + else if (element3i) + { + command->element3i = (int *)data; + memcpy(command->element3i, element3i, numtriangles*sizeof(int[3])); + } + return command; +} + +void DPSOFTRAST_DrawTriangles(int firstvertex, int numvertices, int numtriangles, const int *element3i, const unsigned short *element3s) +{ + DPSOFTRAST_Command_Draw *command = DPSOFTRAST_Draw_AllocateDrawCommand(firstvertex, numvertices, numtriangles, element3i, element3s); + DPSOFTRAST_ShaderModeTable[dpsoftrast.shader_mode].Vertex(); + command->starty = bound(0, dpsoftrast.drawstarty, dpsoftrast.fb_height); + command->endy = bound(0, dpsoftrast.drawendy, dpsoftrast.fb_height); + if (command->starty >= command->endy) + { + if (command->commandsize <= DPSOFTRAST_ALIGNCOMMAND(sizeof(DPSOFTRAST_Command_Draw))) + MM_FREE(command->arrays); + DPSOFTRAST_UndoCommand(command->commandsize); + return; + } + command->clipped = dpsoftrast.drawclipped; + command->refcount = dpsoftrast.numthreads; + + if (dpsoftrast.usethreads) + { + int i; + DPSOFTRAST_Draw_SyncCommands(); + for (i = 0; i < dpsoftrast.numthreads; i++) + { + DPSOFTRAST_State_Thread *thread = &dpsoftrast.threads[i]; + if (((command->starty < thread->maxy1 && command->endy > thread->miny1) || (command->starty < thread->maxy2 && command->endy > thread->miny2)) && thread->starving) + Thread_CondSignal(thread->drawcond); + } + } + else + { + DPSOFTRAST_Draw_FlushThreads(); + } +} + +DEFCOMMAND(23, SetRenderTargets, int width; int height;) +static void DPSOFTRAST_Interpret_SetRenderTargets(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_Command_SetRenderTargets *command) +{ + thread->validate |= DPSOFTRAST_VALIDATE_FB; +} +void DPSOFTRAST_SetRenderTargets(int width, int height, unsigned int *depthpixels, unsigned int *colorpixels0, unsigned int *colorpixels1, unsigned int *colorpixels2, unsigned int *colorpixels3) +{ + DPSOFTRAST_Command_SetRenderTargets *command; + if (width != dpsoftrast.fb_width || height != dpsoftrast.fb_height || depthpixels != dpsoftrast.fb_depthpixels || + colorpixels0 != dpsoftrast.fb_colorpixels[0] || colorpixels1 != dpsoftrast.fb_colorpixels[1] || + colorpixels2 != dpsoftrast.fb_colorpixels[2] || colorpixels3 != dpsoftrast.fb_colorpixels[3]) + DPSOFTRAST_Flush(); + dpsoftrast.fb_width = width; + dpsoftrast.fb_height = height; + dpsoftrast.fb_depthpixels = depthpixels; + dpsoftrast.fb_colorpixels[0] = colorpixels0; + dpsoftrast.fb_colorpixels[1] = colorpixels1; + dpsoftrast.fb_colorpixels[2] = colorpixels2; + dpsoftrast.fb_colorpixels[3] = colorpixels3; + DPSOFTRAST_RecalcViewport(dpsoftrast.viewport, dpsoftrast.fb_viewportcenter, dpsoftrast.fb_viewportscale); + command = DPSOFTRAST_ALLOCATECOMMAND(SetRenderTargets); + command->width = width; + command->height = height; +} + +static void DPSOFTRAST_Draw_InterpretCommands(DPSOFTRAST_State_Thread *thread, int endoffset) +{ + int commandoffset = thread->commandoffset; + while (commandoffset != endoffset) + { + DPSOFTRAST_Command *command = (DPSOFTRAST_Command *)&dpsoftrast.commandpool.commands[commandoffset]; + switch (command->opcode) + { +#define INTERPCOMMAND(name) \ + case DPSOFTRAST_OPCODE_##name : \ + DPSOFTRAST_Interpret_##name (thread, (DPSOFTRAST_Command_##name *)command); \ + commandoffset += DPSOFTRAST_ALIGNCOMMAND(sizeof( DPSOFTRAST_Command_##name )); \ + if (commandoffset >= DPSOFTRAST_DRAW_MAXCOMMANDPOOL) \ + commandoffset = 0; \ + break; + INTERPCOMMAND(Viewport) + INTERPCOMMAND(ClearColor) + INTERPCOMMAND(ClearDepth) + INTERPCOMMAND(ColorMask) + INTERPCOMMAND(DepthTest) + INTERPCOMMAND(ScissorTest) + INTERPCOMMAND(Scissor) + INTERPCOMMAND(BlendFunc) + INTERPCOMMAND(BlendSubtract) + INTERPCOMMAND(DepthMask) + INTERPCOMMAND(DepthFunc) + INTERPCOMMAND(DepthRange) + INTERPCOMMAND(PolygonOffset) + INTERPCOMMAND(CullFace) + INTERPCOMMAND(SetTexture) + INTERPCOMMAND(SetShader) + INTERPCOMMAND(Uniform4f) + INTERPCOMMAND(UniformMatrix4f) + INTERPCOMMAND(Uniform1i) + INTERPCOMMAND(SetRenderTargets) + INTERPCOMMAND(ClipPlane) + + case DPSOFTRAST_OPCODE_Draw: + DPSOFTRAST_Interpret_Draw(thread, (DPSOFTRAST_Command_Draw *)command); + commandoffset += command->commandsize; + if (commandoffset >= DPSOFTRAST_DRAW_MAXCOMMANDPOOL) + commandoffset = 0; + thread->commandoffset = commandoffset; + break; + + case DPSOFTRAST_OPCODE_Reset: + commandoffset = 0; + break; + } + } + thread->commandoffset = commandoffset; +} + +static int DPSOFTRAST_Draw_Thread(void *data) +{ + DPSOFTRAST_State_Thread *thread = (DPSOFTRAST_State_Thread *)data; + while(thread->index >= 0) + { + if (thread->commandoffset != dpsoftrast.drawcommand) + { + DPSOFTRAST_Draw_InterpretCommands(thread, dpsoftrast.drawcommand); + } + else + { + Thread_LockMutex(thread->drawmutex); + if (thread->commandoffset == dpsoftrast.drawcommand && thread->index >= 0) + { + if (thread->waiting) Thread_CondSignal(thread->waitcond); + thread->starving = true; + Thread_CondWait(thread->drawcond, thread->drawmutex); + thread->starving = false; + } + Thread_UnlockMutex(thread->drawmutex); + } + } + return 0; +} + +static void DPSOFTRAST_Draw_FlushThreads(void) +{ + DPSOFTRAST_State_Thread *thread; + int i; + DPSOFTRAST_Draw_SyncCommands(); + if (dpsoftrast.usethreads) + { + for (i = 0; i < dpsoftrast.numthreads; i++) + { + thread = &dpsoftrast.threads[i]; + if (thread->commandoffset != dpsoftrast.drawcommand) + { + Thread_LockMutex(thread->drawmutex); + if (thread->commandoffset != dpsoftrast.drawcommand && thread->starving) + Thread_CondSignal(thread->drawcond); + Thread_UnlockMutex(thread->drawmutex); + } + } + for (i = 0; i < dpsoftrast.numthreads; i++) + { + thread = &dpsoftrast.threads[i]; + if (thread->commandoffset != dpsoftrast.drawcommand) + { + Thread_LockMutex(thread->drawmutex); + if (thread->commandoffset != dpsoftrast.drawcommand) + { + thread->waiting = true; + Thread_CondWait(thread->waitcond, thread->drawmutex); + thread->waiting = false; + } + Thread_UnlockMutex(thread->drawmutex); + } + } + } + else + { + for (i = 0; i < dpsoftrast.numthreads; i++) + { + thread = &dpsoftrast.threads[i]; + if (thread->commandoffset != dpsoftrast.drawcommand) + DPSOFTRAST_Draw_InterpretCommands(thread, dpsoftrast.drawcommand); + } + } + dpsoftrast.commandpool.usedcommands = 0; +} + +void DPSOFTRAST_Flush(void) +{ + DPSOFTRAST_Draw_FlushThreads(); +} + +void DPSOFTRAST_Finish(void) +{ + DPSOFTRAST_Flush(); +} + +int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsigned int *colorpixels, unsigned int *depthpixels) +{ + int i; + union + { + int i; + unsigned char b[4]; + } + u; + u.i = 1; + memset(&dpsoftrast, 0, sizeof(dpsoftrast)); + dpsoftrast.bigendian = u.b[3]; + dpsoftrast.fb_width = width; + dpsoftrast.fb_height = height; + dpsoftrast.fb_depthpixels = depthpixels; + dpsoftrast.fb_colorpixels[0] = colorpixels; + dpsoftrast.fb_colorpixels[1] = NULL; + dpsoftrast.fb_colorpixels[1] = NULL; + dpsoftrast.fb_colorpixels[1] = NULL; + dpsoftrast.viewport[0] = 0; + dpsoftrast.viewport[1] = 0; + dpsoftrast.viewport[2] = dpsoftrast.fb_width; + dpsoftrast.viewport[3] = dpsoftrast.fb_height; + DPSOFTRAST_RecalcViewport(dpsoftrast.viewport, dpsoftrast.fb_viewportcenter, dpsoftrast.fb_viewportscale); + dpsoftrast.texture_firstfree = 1; + dpsoftrast.texture_end = 1; + dpsoftrast.texture_max = 0; + dpsoftrast.color[0] = 1; + dpsoftrast.color[1] = 1; + dpsoftrast.color[2] = 1; + dpsoftrast.color[3] = 1; + dpsoftrast.usethreads = numthreads > 0 && Thread_HasThreads(); + dpsoftrast.interlace = dpsoftrast.usethreads ? bound(0, interlace, 1) : 0; + dpsoftrast.numthreads = dpsoftrast.usethreads ? bound(1, numthreads, 64) : 1; + dpsoftrast.threads = (DPSOFTRAST_State_Thread *)MM_CALLOC(dpsoftrast.numthreads, sizeof(DPSOFTRAST_State_Thread)); + for (i = 0; i < dpsoftrast.numthreads; i++) + { + DPSOFTRAST_State_Thread *thread = &dpsoftrast.threads[i]; + thread->index = i; + thread->cullface = GL_BACK; + thread->colormask[0] = 1; + thread->colormask[1] = 1; + thread->colormask[2] = 1; + thread->colormask[3] = 1; + thread->blendfunc[0] = GL_ONE; + thread->blendfunc[1] = GL_ZERO; + thread->depthmask = true; + thread->depthtest = true; + thread->depthfunc = GL_LEQUAL; + thread->scissortest = false; + thread->viewport[0] = 0; + thread->viewport[1] = 0; + thread->viewport[2] = dpsoftrast.fb_width; + thread->viewport[3] = dpsoftrast.fb_height; + thread->scissor[0] = 0; + thread->scissor[1] = 0; + thread->scissor[2] = dpsoftrast.fb_width; + thread->scissor[3] = dpsoftrast.fb_height; + thread->depthrange[0] = 0; + thread->depthrange[1] = 1; + thread->polygonoffset[0] = 0; + thread->polygonoffset[1] = 0; + thread->clipplane[0] = 0; + thread->clipplane[1] = 0; + thread->clipplane[2] = 0; + thread->clipplane[3] = 1; + + thread->numspans = 0; + thread->numtriangles = 0; + thread->commandoffset = 0; + thread->waiting = false; + thread->starving = false; + + thread->validate = -1; + DPSOFTRAST_Validate(thread, -1); + + if (dpsoftrast.usethreads) + { + thread->waitcond = Thread_CreateCond(); + thread->drawcond = Thread_CreateCond(); + thread->drawmutex = Thread_CreateMutex(); + thread->thread = Thread_CreateThread(DPSOFTRAST_Draw_Thread, thread); + } + } + return 0; +} + +void DPSOFTRAST_Shutdown(void) +{ + int i; + if (dpsoftrast.usethreads && dpsoftrast.numthreads > 0) + { + DPSOFTRAST_State_Thread *thread; + for (i = 0; i < dpsoftrast.numthreads; i++) + { + thread = &dpsoftrast.threads[i]; + Thread_LockMutex(thread->drawmutex); + thread->index = -1; + Thread_CondSignal(thread->drawcond); + Thread_UnlockMutex(thread->drawmutex); + Thread_WaitThread(thread->thread, 0); + Thread_DestroyCond(thread->waitcond); + Thread_DestroyCond(thread->drawcond); + Thread_DestroyMutex(thread->drawmutex); + } + } + for (i = 0;i < dpsoftrast.texture_end;i++) + if (dpsoftrast.texture[i].bytes) + MM_FREE(dpsoftrast.texture[i].bytes); + if (dpsoftrast.texture) + free(dpsoftrast.texture); + if (dpsoftrast.threads) + MM_FREE(dpsoftrast.threads); + memset(&dpsoftrast, 0, sizeof(dpsoftrast)); +} + diff --git a/app/jni/dpsoftrast.h b/app/jni/dpsoftrast.h new file mode 100644 index 0000000..5bda9f3 --- /dev/null +++ b/app/jni/dpsoftrast.h @@ -0,0 +1,327 @@ + +#ifndef DPSOFTRAST_H +#define DPSOFTRAST_H + +#include + +#define DPSOFTRAST_MAXMIPMAPS 16 +#define DPSOFTRAST_TEXTURE_MAXSIZE (1<<(DPSOFTRAST_MAXMIPMAPS - 1)) +#define DPSOFTRAST_MAXTEXTUREUNITS 16 +#define DPSOFTRAST_MAXTEXCOORDARRAYS 8 + +// type of pixels in texture (some of these are converted to BGRA8 on update) +#define DPSOFTRAST_TEXTURE_FORMAT_BGRA8 0 +#define DPSOFTRAST_TEXTURE_FORMAT_DEPTH 1 +#define DPSOFTRAST_TEXTURE_FORMAT_RGBA8 2 +#define DPSOFTRAST_TEXTURE_FORMAT_ALPHA8 3 +#define DPSOFTRAST_TEXTURE_FORMAT_RGBA16F 4 +#define DPSOFTRAST_TEXTURE_FORMAT_RGBA32F 5 +#define DPSOFTRAST_TEXTURE_FORMAT_COMPAREMASK 0x0F + +// modifier flags for texture (can not be changed after creation) +#define DPSOFTRAST_TEXTURE_FLAG_MIPMAP 0x10 +#define DPSOFTRAST_TEXTURE_FLAG_CUBEMAP 0x20 +#define DPSOFTRAST_TEXTURE_FLAG_USEALPHA 0x40 +#define DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE 0x80 + +typedef enum DPSOFTRAST_TEXTURE_FILTER_e +{ + DPSOFTRAST_TEXTURE_FILTER_NEAREST = 0, + DPSOFTRAST_TEXTURE_FILTER_LINEAR = 1, + DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE = 2, + DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE = 3, +} +DPSOFTRAST_TEXTURE_FILTER; + +int DPSOFTRAST_Init(int width, int height, int numthreads, int interlace, unsigned int *colorpixels, unsigned int *depthpixels); +void DPSOFTRAST_Shutdown(void); +void DPSOFTRAST_Flush(void); +void DPSOFTRAST_Finish(void); + +int DPSOFTRAST_Texture_New(int flags, int width, int height, int depth); +void DPSOFTRAST_Texture_Free(int index); +void DPSOFTRAST_Texture_UpdatePartial(int index, int mip, const unsigned char *pixels, int blockx, int blocky, int blockwidth, int blockheight); +void DPSOFTRAST_Texture_UpdateFull(int index, const unsigned char *pixels); +int DPSOFTRAST_Texture_GetWidth(int index, int mip); +int DPSOFTRAST_Texture_GetHeight(int index, int mip); +int DPSOFTRAST_Texture_GetDepth(int index, int mip); +unsigned char *DPSOFTRAST_Texture_GetPixelPointer(int index, int mip); +void DPSOFTRAST_Texture_Filter(int index, DPSOFTRAST_TEXTURE_FILTER filter); + +void DPSOFTRAST_SetRenderTargets(int width, int height, unsigned int *depthpixels, unsigned int *colorpixels0, unsigned int *colorpixels1, unsigned int *colorpixels2, unsigned int *colorpixels3); +void DPSOFTRAST_Viewport(int x, int y, int width, int height); +void DPSOFTRAST_ClearColor(float r, float g, float b, float a); +void DPSOFTRAST_ClearDepth(float d); +void DPSOFTRAST_ColorMask(int r, int g, int b, int a); +void DPSOFTRAST_DepthTest(int enable); +void DPSOFTRAST_ScissorTest(int enable); +void DPSOFTRAST_Scissor(float x, float y, float width, float height); +void DPSOFTRAST_ClipPlane(float x, float y, float z, float w); + +void DPSOFTRAST_BlendFunc(int smodulate, int dmodulate); +void DPSOFTRAST_BlendSubtract(int enable); +void DPSOFTRAST_DepthMask(int enable); +void DPSOFTRAST_DepthFunc(int comparemode); +void DPSOFTRAST_DepthRange(float range0, float range1); +void DPSOFTRAST_PolygonOffset(float alongnormal, float intoview); +void DPSOFTRAST_CullFace(int mode); +void DPSOFTRAST_Color4f(float r, float g, float b, float a); +void DPSOFTRAST_GetPixelsBGRA(int blockx, int blocky, int blockwidth, int blockheight, unsigned char *outpixels); +void DPSOFTRAST_CopyRectangleToTexture(int index, int mip, int tx, int ty, int sx, int sy, int width, int height); +void DPSOFTRAST_SetTexture(int unitnum, int index); + +void DPSOFTRAST_SetVertexPointer(const float *vertex3f, size_t stride); +void DPSOFTRAST_SetColorPointer(const float *color4f, size_t stride); +void DPSOFTRAST_SetColorPointer4ub(const unsigned char *color4ub, size_t stride); +void DPSOFTRAST_SetTexCoordPointer(int unitnum, int numcomponents, size_t stride, const float *texcoordf); + +typedef enum gl20_texunit_e +{ + // postprocess shaders, and generic shaders: + GL20TU_FIRST = 0, + GL20TU_SECOND = 1, + GL20TU_GAMMARAMPS = 2, + // standard material properties + GL20TU_NORMAL = 0, + GL20TU_COLOR = 1, + GL20TU_GLOSS = 2, + GL20TU_GLOW = 3, + // material properties for a second material + GL20TU_SECONDARY_NORMAL = 4, + GL20TU_SECONDARY_COLOR = 5, + GL20TU_SECONDARY_GLOSS = 6, + GL20TU_SECONDARY_GLOW = 7, + // material properties for a colormapped material + // conflicts with secondary material + GL20TU_PANTS = 4, + GL20TU_SHIRT = 7, + // fog fade in the distance + GL20TU_FOGMASK = 8, + // compiled ambient lightmap and deluxemap + GL20TU_LIGHTMAP = 9, + GL20TU_DELUXEMAP = 10, + // refraction, used by water shaders + GL20TU_REFRACTION = 3, + // reflection, used by water shaders, also with normal material rendering + // conflicts with secondary material + GL20TU_REFLECTION = 7, + // rtlight attenuation (distance fade) and cubemap filter (projection texturing) + // conflicts with lightmap/deluxemap + GL20TU_ATTENUATION = 9, + GL20TU_CUBE = 10, + GL20TU_SHADOWMAP2D = 15, + GL20TU_CUBEPROJECTION = 12, + // rtlight prepass data (screenspace depth and normalmap) +// GL20TU_UNUSED1 = 13, + GL20TU_SCREENNORMALMAP = 14, + // lightmap prepass data (screenspace diffuse and specular from lights) + GL20TU_SCREENDIFFUSE = 11, + GL20TU_SCREENSPECULAR = 12, + // fake reflections + GL20TU_REFLECTMASK = 5, + GL20TU_REFLECTCUBE = 6, + GL20TU_FOGHEIGHTTEXTURE = 14 +} +gl20_texunit; + +typedef enum glsl_attrib_e +{ + GLSLATTRIB_POSITION = 0, + GLSLATTRIB_COLOR = 1, + GLSLATTRIB_TEXCOORD0 = 2, + GLSLATTRIB_TEXCOORD1 = 3, + GLSLATTRIB_TEXCOORD2 = 4, + GLSLATTRIB_TEXCOORD3 = 5, + GLSLATTRIB_TEXCOORD4 = 6, + GLSLATTRIB_TEXCOORD5 = 7, + GLSLATTRIB_TEXCOORD6 = 8, + GLSLATTRIB_TEXCOORD7 = 9, +} +glsl_attrib; + +// this enum selects which of the glslshadermodeinfo entries should be used +typedef enum shadermode_e +{ + SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture + SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess) + SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only + SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp) + SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp) + SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp) + SHADERMODE_FAKELIGHT, ///< (fakelight) modulate texture by "fake" lighting (no lightmaps, no nothing) + SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap) + SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap) + SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP, // forced deluxemapping for lightmapped surfaces + SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR, // forced deluxemapping for vertexlit surfaces + SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp) + SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight) + SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass) + SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass) + SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers + SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers + SHADERMODE_COUNT +} +shadermode_t; + +typedef enum shaderpermutation_e +{ + SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading + SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp) + SHADERPERMUTATION_VIEWTINT = 1<<2, ///< view tint (postprocessing only), use vertex colors (generic only) + SHADERPERMUTATION_COLORMAPPING = 1<<3, ///< indicates this is a colormapped skin + SHADERPERMUTATION_SATURATION = 1<<4, ///< saturation (postprocessing only) + SHADERPERMUTATION_FOGINSIDE = 1<<5, ///< tint the color by fog color or black if using additive blend mode + SHADERPERMUTATION_FOGOUTSIDE = 1<<6, ///< tint the color by fog color or black if using additive blend mode + SHADERPERMUTATION_FOGHEIGHTTEXTURE = 1<<7, ///< fog color and density determined by texture mapped on vertical axis + SHADERPERMUTATION_FOGALPHAHACK = 1<<8, ///< fog color and density determined by texture mapped on vertical axis + SHADERPERMUTATION_GAMMARAMPS = 1<<9, ///< gamma (postprocessing only) + SHADERPERMUTATION_CUBEFILTER = 1<<10, ///< (lightsource) use cubemap light filter + SHADERPERMUTATION_GLOW = 1<<11, ///< (lightmap) blend in an additive glow texture + SHADERPERMUTATION_BLOOM = 1<<12, ///< bloom (postprocessing only) + SHADERPERMUTATION_SPECULAR = 1<<13, ///< (lightsource or deluxemapping) render specular effects + SHADERPERMUTATION_POSTPROCESSING = 1<<14, ///< user defined postprocessing (postprocessing only) + SHADERPERMUTATION_REFLECTION = 1<<15, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface + SHADERPERMUTATION_OFFSETMAPPING = 1<<16, ///< adjust texcoords to roughly simulate a displacement mapped surface + SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<17, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) + SHADERPERMUTATION_SHADOWMAP2D = 1<<18, ///< (lightsource) use shadowmap texture as light filter + SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<19, ///< (lightsource) use virtual shadow depth cube texture for shadowmap indexing + SHADERPERMUTATION_SHADOWMAPORTHO = 1<<20, ///< (lightsource) use orthographic shadowmap projection + SHADERPERMUTATION_DEFERREDLIGHTMAP = 1<<21, ///< (lightmap) read Texture_ScreenDiffuse/Specular textures and add them on top of lightmapping + SHADERPERMUTATION_ALPHAKILL = 1<<22, ///< (deferredgeometry) discard pixel if diffuse texture alpha below 0.5, (generic) apply global alpha + SHADERPERMUTATION_REFLECTCUBE = 1<<23, ///< fake reflections using global cubemap (not HDRI light probe) + SHADERPERMUTATION_NORMALMAPSCROLLBLEND = 1<<24, ///< (water) counter-direction normalmaps scrolling + SHADERPERMUTATION_BOUNCEGRID = 1<<25, ///< (lightmap) use Texture_BounceGrid as an additional source of ambient light + SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL = 1<<26, ///< (lightmap) use 16-component pixels in bouncegrid texture for directional lighting rather than standard 4-component + SHADERPERMUTATION_TRIPPY = 1<<27, ///< use trippy vertex shader effect + SHADERPERMUTATION_DEPTHRGB = 1<<28, ///< read/write depth values in RGB color coded format for older hardware without depth samplers + SHADERPERMUTATION_ALPHAGEN_VERTEX = 1<<29, ///< alphaGen vertex + SHADERPERMUTATION_SKELETAL = 1<<30, ///< (skeletal models) use skeletal matrices to deform vertices (gpu-skinning) + SHADERPERMUTATION_COUNT = 31 ///< size of shaderpermutationinfo array +} +shaderpermutation_t; + +typedef enum DPSOFTRAST_UNIFORM_e +{ + DPSOFTRAST_UNIFORM_Texture_First, + DPSOFTRAST_UNIFORM_Texture_Second, + DPSOFTRAST_UNIFORM_Texture_GammaRamps, + DPSOFTRAST_UNIFORM_Texture_Normal, + DPSOFTRAST_UNIFORM_Texture_Color, + DPSOFTRAST_UNIFORM_Texture_Gloss, + DPSOFTRAST_UNIFORM_Texture_Glow, + DPSOFTRAST_UNIFORM_Texture_SecondaryNormal, + DPSOFTRAST_UNIFORM_Texture_SecondaryColor, + DPSOFTRAST_UNIFORM_Texture_SecondaryGloss, + DPSOFTRAST_UNIFORM_Texture_SecondaryGlow, + DPSOFTRAST_UNIFORM_Texture_Pants, + DPSOFTRAST_UNIFORM_Texture_Shirt, + DPSOFTRAST_UNIFORM_Texture_FogHeightTexture, + DPSOFTRAST_UNIFORM_Texture_FogMask, + DPSOFTRAST_UNIFORM_Texture_Lightmap, + DPSOFTRAST_UNIFORM_Texture_Deluxemap, + DPSOFTRAST_UNIFORM_Texture_Attenuation, + DPSOFTRAST_UNIFORM_Texture_Cube, + DPSOFTRAST_UNIFORM_Texture_Refraction, + DPSOFTRAST_UNIFORM_Texture_Reflection, + DPSOFTRAST_UNIFORM_Texture_ShadowMap2D, + DPSOFTRAST_UNIFORM_Texture_CubeProjection, + DPSOFTRAST_UNIFORM_Texture_ScreenNormalMap, + DPSOFTRAST_UNIFORM_Texture_ScreenDiffuse, + DPSOFTRAST_UNIFORM_Texture_ScreenSpecular, + DPSOFTRAST_UNIFORM_Texture_ReflectMask, + DPSOFTRAST_UNIFORM_Texture_ReflectCube, + DPSOFTRAST_UNIFORM_Alpha, + DPSOFTRAST_UNIFORM_BloomBlur_Parameters, + DPSOFTRAST_UNIFORM_ClientTime, + DPSOFTRAST_UNIFORM_Color_Ambient, + DPSOFTRAST_UNIFORM_Color_Diffuse, + DPSOFTRAST_UNIFORM_Color_Specular, + DPSOFTRAST_UNIFORM_Color_Glow, + DPSOFTRAST_UNIFORM_Color_Pants, + DPSOFTRAST_UNIFORM_Color_Shirt, + DPSOFTRAST_UNIFORM_DeferredColor_Ambient, + DPSOFTRAST_UNIFORM_DeferredColor_Diffuse, + DPSOFTRAST_UNIFORM_DeferredColor_Specular, + DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, + DPSOFTRAST_UNIFORM_DeferredMod_Specular, + DPSOFTRAST_UNIFORM_DistortScaleRefractReflect, + DPSOFTRAST_UNIFORM_EyePosition, + DPSOFTRAST_UNIFORM_FogColor, + DPSOFTRAST_UNIFORM_FogHeightFade, + DPSOFTRAST_UNIFORM_FogPlane, + DPSOFTRAST_UNIFORM_FogPlaneViewDist, + DPSOFTRAST_UNIFORM_FogRangeRecip, + DPSOFTRAST_UNIFORM_LightColor, + DPSOFTRAST_UNIFORM_LightDir, + DPSOFTRAST_UNIFORM_LightPosition, + DPSOFTRAST_UNIFORM_OffsetMapping_ScaleSteps, + DPSOFTRAST_UNIFORM_PixelSize, + DPSOFTRAST_UNIFORM_ReflectColor, + DPSOFTRAST_UNIFORM_ReflectFactor, + DPSOFTRAST_UNIFORM_ReflectOffset, + DPSOFTRAST_UNIFORM_RefractColor, + DPSOFTRAST_UNIFORM_Saturation, + DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, + DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect, + DPSOFTRAST_UNIFORM_ScreenToDepth, + DPSOFTRAST_UNIFORM_ShadowMap_Parameters, + DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, + DPSOFTRAST_UNIFORM_SpecularPower, + DPSOFTRAST_UNIFORM_UserVec1, + DPSOFTRAST_UNIFORM_UserVec2, + DPSOFTRAST_UNIFORM_UserVec3, + DPSOFTRAST_UNIFORM_UserVec4, + DPSOFTRAST_UNIFORM_ViewTintColor, + DPSOFTRAST_UNIFORM_ViewToLightM1, + DPSOFTRAST_UNIFORM_ViewToLightM2, + DPSOFTRAST_UNIFORM_ViewToLightM3, + DPSOFTRAST_UNIFORM_ViewToLightM4, + DPSOFTRAST_UNIFORM_ModelToLightM1, + DPSOFTRAST_UNIFORM_ModelToLightM2, + DPSOFTRAST_UNIFORM_ModelToLightM3, + DPSOFTRAST_UNIFORM_ModelToLightM4, + DPSOFTRAST_UNIFORM_TexMatrixM1, + DPSOFTRAST_UNIFORM_TexMatrixM2, + DPSOFTRAST_UNIFORM_TexMatrixM3, + DPSOFTRAST_UNIFORM_TexMatrixM4, + DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, + DPSOFTRAST_UNIFORM_BackgroundTexMatrixM2, + DPSOFTRAST_UNIFORM_BackgroundTexMatrixM3, + DPSOFTRAST_UNIFORM_BackgroundTexMatrixM4, + DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, + DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM2, + DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM3, + DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM4, + DPSOFTRAST_UNIFORM_ModelViewMatrixM1, + DPSOFTRAST_UNIFORM_ModelViewMatrixM2, + DPSOFTRAST_UNIFORM_ModelViewMatrixM3, + DPSOFTRAST_UNIFORM_ModelViewMatrixM4, + DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, + DPSOFTRAST_UNIFORM_ModelToReflectCubeM1, + DPSOFTRAST_UNIFORM_ModelToReflectCubeM2, + DPSOFTRAST_UNIFORM_ModelToReflectCubeM3, + DPSOFTRAST_UNIFORM_ModelToReflectCubeM4, + DPSOFTRAST_UNIFORM_ShadowMapMatrixM1, + DPSOFTRAST_UNIFORM_ShadowMapMatrixM2, + DPSOFTRAST_UNIFORM_ShadowMapMatrixM3, + DPSOFTRAST_UNIFORM_ShadowMapMatrixM4, + DPSOFTRAST_UNIFORM_BloomColorSubtract, + DPSOFTRAST_UNIFORM_NormalmapScrollBlend, + DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, + DPSOFTRAST_UNIFORM_OffsetMapping_Bias, + DPSOFTRAST_UNIFORM_TOTAL +} +DPSOFTRAST_UNIFORM; + +void DPSOFTRAST_SetShader(int mode, int permutation, int exactspecularmath); +#define DPSOFTRAST_Uniform1f(index, v0) DPSOFTRAST_Uniform4f(index, v0, 0, 0, 0) +#define DPSOFTRAST_Uniform2f(index, v0, v1) DPSOFTRAST_Uniform4f(index, v0, v1, 0, 0) +#define DPSOFTRAST_Uniform3f(index, v0, v1, v2) DPSOFTRAST_Uniform4f(index, v0, v1, v2, 0) +void DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM index, float v0, float v1, float v2, float v3); +void DPSOFTRAST_Uniform4fv(DPSOFTRAST_UNIFORM index, const float *v); +void DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM index, int arraysize, int transpose, const float *v); +void DPSOFTRAST_Uniform1i(DPSOFTRAST_UNIFORM index, int i0); + +void DPSOFTRAST_DrawTriangles(int firstvertex, int numvertices, int numtriangles, const int *element3i, const unsigned short *element3s); + +#endif // DPSOFTRAST_H diff --git a/app/jni/dpvsimpledecode.c b/app/jni/dpvsimpledecode.c new file mode 100644 index 0000000..ed89260 --- /dev/null +++ b/app/jni/dpvsimpledecode.c @@ -0,0 +1,656 @@ +#include "quakedef.h" +#include "dpvsimpledecode.h" + +#define HZREADERROR_OK 0 +#define HZREADERROR_EOF 1 +#define HZREADERROR_MALLOCFAILED 2 + +//#define HZREADBLOCKSIZE 16000 +#define HZREADBLOCKSIZE 1048576 + +typedef struct hz_bitstream_read_s +{ + qfile_t *file; + int endoffile; +} +hz_bitstream_read_t; + +typedef struct hz_bitstream_readblock_s +{ + struct hz_bitstream_readblock_s *next; + unsigned int size; + unsigned char data[HZREADBLOCKSIZE]; +} +hz_bitstream_readblock_t; + +typedef struct hz_bitstream_readblocks_s +{ + hz_bitstream_readblock_t *blocks; + hz_bitstream_readblock_t *current; + unsigned int position; + unsigned int store; + int count; +} +hz_bitstream_readblocks_t; + +static hz_bitstream_read_t *hz_bitstream_read_open(char *filename) +{ + qfile_t *file; + hz_bitstream_read_t *stream; + if ((file = FS_OpenVirtualFile(filename, false))) + { + stream = (hz_bitstream_read_t *)Z_Malloc(sizeof(hz_bitstream_read_t)); + memset(stream, 0, sizeof(*stream)); + stream->file = file; + return stream; + } + else + return NULL; +} + +static void hz_bitstream_read_close(hz_bitstream_read_t *stream) +{ + if (stream) + { + FS_Close(stream->file); + Z_Free(stream); + } +} + +static hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void) +{ + hz_bitstream_readblocks_t *blocks; + blocks = (hz_bitstream_readblocks_t *)Z_Malloc(sizeof(hz_bitstream_readblocks_t)); + if (blocks == NULL) + return NULL; + memset(blocks, 0, sizeof(hz_bitstream_readblocks_t)); + return blocks; +} + +static void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks) +{ + hz_bitstream_readblock_t *b, *n; + if (blocks == NULL) + return; + for (b = blocks->blocks;b;b = n) + { + n = b->next; + Z_Free(b); + } + Z_Free(blocks); +} + +static void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks) +{ + blocks->store = 0; + blocks->count = 0; +} + +static int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstream_read_t *stream, unsigned int size) +{ + int s; + hz_bitstream_readblock_t *b, *p; + s = size; + p = NULL; + b = blocks->blocks; + while (s > 0) + { + if (b == NULL) + { + b = (hz_bitstream_readblock_t *)Z_Malloc(sizeof(hz_bitstream_readblock_t)); + if (b == NULL) + return HZREADERROR_MALLOCFAILED; + b->next = NULL; + b->size = 0; + if (p != NULL) + p->next = b; + else + blocks->blocks = b; + } + if (s > HZREADBLOCKSIZE) + b->size = HZREADBLOCKSIZE; + else + b->size = s; + s -= b->size; + if (FS_Read(stream->file, b->data, b->size) != (fs_offset_t)b->size) + { + stream->endoffile = 1; + break; + } + p = b; + b = b->next; + } + while (b) + { + b->size = 0; + b = b->next; + } + blocks->current = blocks->blocks; + blocks->position = 0; + hz_bitstream_read_flushbits(blocks); + if (stream->endoffile) + return HZREADERROR_EOF; + return HZREADERROR_OK; +} + +static unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks) +{ + while (blocks->current != NULL && blocks->position >= blocks->current->size) + { + blocks->position = 0; + blocks->current = blocks->current->next; + } + if (blocks->current == NULL) + return 0; + return blocks->current->data[blocks->position++]; +} + +static int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks) +{ + if (!blocks->count) + { + blocks->count += 8; + blocks->store <<= 8; + blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF; + } + blocks->count--; + return (blocks->store >> blocks->count) & 1; +} + +static unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, int size) +{ + unsigned int num = 0; + // we can only handle about 24 bits at a time safely + // (there might be up to 7 bits more than we need in the bit store) + if (size > 24) + { + size -= 8; + num |= hz_bitstream_read_bits(blocks, 8) << size; + } + while (blocks->count < size) + { + blocks->count += 8; + blocks->store <<= 8; + blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF; + } + blocks->count -= size; + num |= (blocks->store >> blocks->count) & ((1 << size) - 1); + return num; +} + +static unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks) +{ + return hz_bitstream_read_blocks_getbyte(blocks); +} + +static unsigned int hz_bitstream_read_short(hz_bitstream_readblocks_t *blocks) +{ + return (hz_bitstream_read_byte(blocks) << 8) + | (hz_bitstream_read_byte(blocks)); +} + +static unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *blocks) +{ + return (hz_bitstream_read_byte(blocks) << 24) + | (hz_bitstream_read_byte(blocks) << 16) + | (hz_bitstream_read_byte(blocks) << 8) + | (hz_bitstream_read_byte(blocks)); +} + +static void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size) +{ + unsigned char *out; + out = (unsigned char *)outdata; + while (size--) + *out++ = hz_bitstream_read_byte(blocks); +} + +#define BLOCKSIZE 8 + +typedef struct dpvsimpledecodestream_s +{ + hz_bitstream_read_t *bitstream; + hz_bitstream_readblocks_t *framedatablocks; + + int error; + + double info_framerate; + unsigned int info_frames; + + unsigned int info_imagewidth; + unsigned int info_imageheight; + unsigned int info_imagebpp; + unsigned int info_imageRloss; + unsigned int info_imageRmask; + unsigned int info_imageRshift; + unsigned int info_imageGloss; + unsigned int info_imageGmask; + unsigned int info_imageGshift; + unsigned int info_imageBloss; + unsigned int info_imageBmask; + unsigned int info_imageBshift; + unsigned int info_imagesize; + double info_aspectratio; + + // current video frame (needed because of delta compression) + int videoframenum; + // current video frame data (needed because of delta compression) + unsigned int *videopixels; + + // channel the sound file is being played on + int sndchan; +} +dpvsimpledecodestream_t; + +static int dpvsimpledecode_setpixelformat(dpvsimpledecodestream_t *s, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel) +{ + int Rshift, Rbits, Gshift, Gbits, Bshift, Bbits; + if (!Rmask) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK; + return s->error; + } + if (!Gmask) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK; + return s->error; + } + if (!Bmask) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK; + return s->error; + } + if (Rmask & Gmask || Rmask & Bmask || Gmask & Bmask) + { + s->error = DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP; + return s->error; + } + switch (bytesperpixel) + { + case 2: + if ((Rmask | Gmask | Bmask) > 65536) + { + s->error = DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP; + return s->error; + } + break; + case 4: + break; + default: + s->error = DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP; + return s->error; + } + for (Rshift = 0;!(Rmask & 1);Rshift++, Rmask >>= 1); + for (Gshift = 0;!(Gmask & 1);Gshift++, Gmask >>= 1); + for (Bshift = 0;!(Bmask & 1);Bshift++, Bmask >>= 1); + if (((Rmask + 1) & Rmask) != 0) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK; + return s->error; + } + if (((Gmask + 1) & Gmask) != 0) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK; + return s->error; + } + if (((Bmask + 1) & Bmask) != 0) + { + s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK; + return s->error; + } + for (Rbits = 0;Rmask & 1;Rbits++, Rmask >>= 1); + for (Gbits = 0;Gmask & 1;Gbits++, Gmask >>= 1); + for (Bbits = 0;Bmask & 1;Bbits++, Bmask >>= 1); + if (Rbits > 8) + { + Rshift += (Rbits - 8); + Rbits = 8; + } + if (Gbits > 8) + { + Gshift += (Gbits - 8); + Gbits = 8; + } + if (Bbits > 8) + { + Bshift += (Bbits - 8); + Bbits = 8; + } + s->info_imagebpp = bytesperpixel; + s->info_imageRloss = 16 + (8 - Rbits); + s->info_imageGloss = 8 + (8 - Gbits); + s->info_imageBloss = 0 + (8 - Bbits); + s->info_imageRmask = (1 << Rbits) - 1; + s->info_imageGmask = (1 << Gbits) - 1; + s->info_imageBmask = (1 << Bbits) - 1; + s->info_imageRshift = Rshift; + s->info_imageGshift = Gshift; + s->info_imageBshift = Bshift; + s->info_imagesize = s->info_imagewidth * s->info_imageheight * s->info_imagebpp; + return s->error; +} + +// opening and closing streams + +// opens a stream +void *dpvsimpledecode_open(clvideo_t *video, char *filename, const char **errorstring) +{ + dpvsimpledecodestream_t *s; + char t[8], *wavename; + if (errorstring != NULL) + *errorstring = NULL; + s = (dpvsimpledecodestream_t *)Z_Malloc(sizeof(dpvsimpledecodestream_t)); + if (s != NULL) + { + s->bitstream = hz_bitstream_read_open(filename); + if (s->bitstream != NULL) + { + // check file identification + s->framedatablocks = hz_bitstream_read_blocks_new(); + if (s->framedatablocks != NULL) + { + hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8); + hz_bitstream_read_bytes(s->framedatablocks, t, 8); + if (!memcmp(t, "DPVideo", 8)) + { + // check version number + hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 2); + if (hz_bitstream_read_short(s->framedatablocks) == 1) + { + hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 12); + s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks); + s->info_imageheight = hz_bitstream_read_short(s->framedatablocks); + s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0); + s->info_aspectratio = (double)s->info_imagewidth / (double)s->info_imageheight; + + if (s->info_framerate > 0.0) + { + s->videopixels = (unsigned int *)Z_Malloc(s->info_imagewidth * s->info_imageheight * sizeof(*s->videopixels)); + if (s->videopixels != NULL) + { + size_t namelen; + + namelen = strlen(filename) + 10; + wavename = (char *)Z_Malloc(namelen); + if (wavename) + { + sfx_t* sfx; + + FS_StripExtension(filename, wavename, namelen); + strlcat(wavename, ".wav", namelen); + sfx = S_PrecacheSound (wavename, false, false); + if (sfx != NULL) + s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0); + else + s->sndchan = -1; + Z_Free(wavename); + } + // all is well... + // set the module functions + s->videoframenum = -10000; + video->close = dpvsimpledecode_close; + video->getwidth = dpvsimpledecode_getwidth; + video->getheight = dpvsimpledecode_getheight; + video->getframerate = dpvsimpledecode_getframerate; + video->decodeframe = dpvsimpledecode_video; + video->getaspectratio = dpvsimpledecode_getaspectratio; + + return s; + } + else if (errorstring != NULL) + *errorstring = "unable to allocate video image buffer"; + } + else if (errorstring != NULL) + *errorstring = "error in video info chunk"; + } + else if (errorstring != NULL) + *errorstring = "read error"; + } + else if (errorstring != NULL) + *errorstring = "not a dpvideo file"; + hz_bitstream_read_blocks_free(s->framedatablocks); + } + else if (errorstring != NULL) + *errorstring = "unable to allocate memory for reading buffer"; + hz_bitstream_read_close(s->bitstream); + } + else if (errorstring != NULL) + *errorstring = "unable to open file"; + Z_Free(s); + } + else if (errorstring != NULL) + *errorstring = "unable to allocate memory for stream info structure"; + return NULL; +} + +// closes a stream +void dpvsimpledecode_close(void *stream) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + if (s == NULL) + return; + if (s->videopixels) + Z_Free(s->videopixels); + if (s->sndchan != -1) + S_StopChannel (s->sndchan, true, true); + if (s->framedatablocks) + hz_bitstream_read_blocks_free(s->framedatablocks); + if (s->bitstream) + hz_bitstream_read_close(s->bitstream); + Z_Free(s); +} + +// utilitarian functions + +// returns the current error number for the stream, and resets the error +// number to DPVSIMPLEDECODEERROR_NONE +// if the supplied string pointer variable is not NULL, it will be set to the +// error message +int dpvsimpledecode_error(void *stream, const char **errorstring) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + int e; + e = s->error; + s->error = 0; + if (errorstring) + { + switch (e) + { + case DPVSIMPLEDECODEERROR_NONE: + *errorstring = "no error"; + break; + case DPVSIMPLEDECODEERROR_EOF: + *errorstring = "end of file reached (this is not an error)"; + break; + case DPVSIMPLEDECODEERROR_READERROR: + *errorstring = "read error (corrupt or incomplete file)"; + break; + case DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL: + *errorstring = "sound buffer is too small for decoding frame (please allocate it as large as dpvsimpledecode_getneededsoundbufferlength suggests)"; + break; + case DPVSIMPLEDECODEERROR_INVALIDRMASK: + *errorstring = "invalid red bits mask"; + break; + case DPVSIMPLEDECODEERROR_INVALIDGMASK: + *errorstring = "invalid green bits mask"; + break; + case DPVSIMPLEDECODEERROR_INVALIDBMASK: + *errorstring = "invalid blue bits mask"; + break; + case DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP: + *errorstring = "color bit masks overlap"; + break; + case DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP: + *errorstring = "color masks too big for specified bytes per pixel"; + break; + case DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP: + *errorstring = "unsupported bytes per pixel (must be 2 for 16bit, or 4 for 32bit)"; + break; + default: + *errorstring = "unknown error"; + break; + } + } + return e; +} + +// returns the width of the image data +unsigned int dpvsimpledecode_getwidth(void *stream) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + return s->info_imagewidth; +} + +// returns the height of the image data +unsigned int dpvsimpledecode_getheight(void *stream) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + return s->info_imageheight; +} + +// returns the framerate of the stream +double dpvsimpledecode_getframerate(void *stream) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + return s->info_framerate; +} + +// return aspect ratio of the stream +double dpvsimpledecode_getaspectratio(void *stream) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + return s->info_aspectratio; +} + +static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow) +{ + unsigned int a, x, y, width, height; + unsigned int Rloss, Rmask, Rshift, Gloss, Gmask, Gshift, Bloss, Bmask, Bshift; + unsigned int *in; + + width = s->info_imagewidth; + height = s->info_imageheight; + + Rloss = s->info_imageRloss; + Rmask = s->info_imageRmask; + Rshift = s->info_imageRshift; + Gloss = s->info_imageGloss; + Gmask = s->info_imageGmask; + Gshift = s->info_imageGshift; + Bloss = s->info_imageBloss; + Bmask = s->info_imageBmask; + Bshift = s->info_imageBshift; + + in = s->videopixels; + if (s->info_imagebpp == 4) + { + unsigned int *outrow; + for (y = 0;y < height;y++) + { + outrow = (unsigned int *)((unsigned char *)imagedata + y * imagebytesperrow); + for (x = 0;x < width;x++) + { + a = *in++; + outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift); + } + } + } + else + { + unsigned short *outrow; + for (y = 0;y < height;y++) + { + outrow = (unsigned short *)((unsigned char *)imagedata + y * imagebytesperrow); + if (Rloss == 19 && Gloss == 10 && Bloss == 3 && Rshift == 11 && Gshift == 5 && Bshift == 0) + { + // optimized + for (x = 0;x < width;x++) + { + a = *in++; + outrow[x] = ((a >> 8) & 0xF800) | ((a >> 5) & 0x07E0) | ((a >> 3) & 0x001F); + } + } + else + { + for (x = 0;x < width;x++) + { + a = *in++; + outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift); + } + } + } + } + return s->error; +} + +static int dpvsimpledecode_decompressimage(dpvsimpledecodestream_t *s) +{ + int i, a, b, colors, g, x1, y1, bw, bh, width, height, palettebits; + unsigned int palette[256], *outrow, *out; + g = BLOCKSIZE; + width = s->info_imagewidth; + height = s->info_imageheight; + for (y1 = 0;y1 < height;y1 += g) + { + outrow = s->videopixels + y1 * width; + bh = g; + if (y1 + bh > height) + bh = height - y1; + for (x1 = 0;x1 < width;x1 += g) + { + out = outrow + x1; + bw = g; + if (x1 + bw > width) + bw = width - x1; + if (hz_bitstream_read_bit(s->framedatablocks)) + { + // updated block + palettebits = hz_bitstream_read_bits(s->framedatablocks, 3); + colors = 1 << palettebits; + for (i = 0;i < colors;i++) + palette[i] = hz_bitstream_read_bits(s->framedatablocks, 24); + if (palettebits) + { + for (b = 0;b < bh;b++, out += width) + for (a = 0;a < bw;a++) + out[a] = palette[hz_bitstream_read_bits(s->framedatablocks, palettebits)]; + } + else + { + for (b = 0;b < bh;b++, out += width) + for (a = 0;a < bw;a++) + out[a] = palette[0]; + } + } + } + } + return s->error; +} + +// decodes a video frame to the supplied output pixels +int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow) +{ + dpvsimpledecodestream_t *s = (dpvsimpledecodestream_t *)stream; + unsigned int framedatasize; + char t[4]; + s->error = DPVSIMPLEDECODEERROR_NONE; + if (dpvsimpledecode_setpixelformat(s, Rmask, Gmask, Bmask, bytesperpixel)) + return s->error; + + hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8); + hz_bitstream_read_bytes(s->framedatablocks, t, 4); + if (memcmp(t, "VID0", 4)) + { + if (t[0] == 0) + return (s->error = DPVSIMPLEDECODEERROR_EOF); + else + return (s->error = DPVSIMPLEDECODEERROR_READERROR); + } + framedatasize = hz_bitstream_read_int(s->framedatablocks); + hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, framedatasize); + if (dpvsimpledecode_decompressimage(s)) + return s->error; + + dpvsimpledecode_convertpixels(s, imagedata, imagebytesperrow); + return s->error; +} diff --git a/app/jni/dpvsimpledecode.h b/app/jni/dpvsimpledecode.h new file mode 100644 index 0000000..0b0ac35 --- /dev/null +++ b/app/jni/dpvsimpledecode.h @@ -0,0 +1,49 @@ + +#ifndef DPVSIMPLEDECODE_H +#define DPVSIMPLEDECODE_H + +#include "cl_video.h" + +#define DPVSIMPLEDECODEERROR_NONE 0 +#define DPVSIMPLEDECODEERROR_EOF 1 +#define DPVSIMPLEDECODEERROR_READERROR 2 +#define DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL 3 +#define DPVSIMPLEDECODEERROR_INVALIDRMASK 4 +#define DPVSIMPLEDECODEERROR_INVALIDGMASK 5 +#define DPVSIMPLEDECODEERROR_INVALIDBMASK 6 +#define DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP 7 +#define DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP 8 +#define DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP 9 + +// opening and closing streams + +// opens a stream +void *dpvsimpledecode_open(clvideo_t *video, char *filename, const char **errorstring); + +// closes a stream +void dpvsimpledecode_close(void *stream); + +// utilitarian functions + +// returns the current error number for the stream, and resets the error +// number to DPVDECODEERROR_NONE +// if the supplied string pointer variable is not NULL, it will be set to the +// error message +int dpvsimpledecode_error(void *stream, const char **errorstring); + +// returns the width of the image data +unsigned int dpvsimpledecode_getwidth(void *stream); + +// returns the height of the image data +unsigned int dpvsimpledecode_getheight(void *stream); + +// returns the framerate of the stream +double dpvsimpledecode_getframerate(void *stream); + +// returns aspect ratio of the stream +double dpvsimpledecode_getaspectratio(void *stream); + +// decodes a video frame to the supplied output pixels +int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow); + +#endif diff --git a/app/jni/draw.h b/app/jni/draw.h new file mode 100644 index 0000000..316a696 --- /dev/null +++ b/app/jni/draw.h @@ -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. + +*/ + +// draw.h -- these are the only functions outside the refresh allowed +// to touch the vid buffer + +#ifndef DRAW_H +#define DRAW_H + +// FIXME: move this stuff to cl_screen +typedef struct cachepic_s +{ + // size of pic + int width, height; + // this flag indicates that it should be loaded and unloaded on demand + int autoload; + // texture flags to upload with + int texflags; + // texture may be freed after a while + int lastusedframe; + // renderer texture to use + rtexture_t *tex; + // used for hash lookups + struct cachepic_s *chain; + // flags - CACHEPICFLAG_NEWPIC for example + unsigned int flags; + // has alpha? + qboolean hasalpha; + // name of pic + char name[MAX_QPATH]; + // allow to override/free the texture + qboolean allow_free_tex; +} +cachepic_t; + +typedef enum cachepicflags_e +{ + CACHEPICFLAG_NOTPERSISTENT = 1, + CACHEPICFLAG_QUIET = 2, + CACHEPICFLAG_NOCOMPRESSION = 4, + CACHEPICFLAG_NOCLAMP = 8, + CACHEPICFLAG_NEWPIC = 16, // disables matching texflags check, because a pic created with Draw_NewPic should not be subject to that + CACHEPICFLAG_MIPMAP = 32, + CACHEPICFLAG_NEAREST = 64 // force nearest filtering instead of linear +} +cachepicflags_t; + +void Draw_Init (void); +void Draw_Frame (void); +cachepic_t *Draw_CachePic_Flags (const char *path, unsigned int cachepicflags); +cachepic_t *Draw_CachePic (const char *path); // standard function with no options, used throughout engine +// create or update a pic's image +cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels); +// free the texture memory used by a pic +void Draw_FreePic(const char *picname); + +// a triangle mesh.. +// each vertex is 3 floats +// each texcoord is 2 floats +// each color is 4 floats +typedef struct drawqueuemesh_s +{ + rtexture_t *texture; + int num_triangles; + int num_vertices; + int *data_element3i; + unsigned short *data_element3s; + float *data_vertex3f; + float *data_texcoord2f; + float *data_color4f; +} +drawqueuemesh_t; + +enum drawqueue_drawflag_e { +DRAWFLAG_NORMAL, +DRAWFLAG_ADDITIVE, +DRAWFLAG_MODULATE, +DRAWFLAG_2XMODULATE, +DRAWFLAG_SCREEN, +DRAWFLAG_NUMFLAGS, +DRAWFLAG_MASK = 0xFF, // ONLY R_BeginPolygon() +DRAWFLAG_MIPMAP = 0x100, // ONLY R_BeginPolygon() +DRAWFLAG_NOGAMMA = 0x200 // ONLY R_DrawQSuperPic() +}; +#define DRAWFLAGS_BLEND 0xFF /* this matches all blending flags */ + +typedef struct ft2_settings_s +{ + float scale, voffset; + // cvar parameters (only read on loadfont command) + int antialias, hinting; + float outline, blur, shadowx, shadowy, shadowz; +} ft2_settings_t; + +#define MAX_FONT_SIZES 16 +#define MAX_FONT_FALLBACKS 3 +typedef struct dp_font_s +{ + rtexture_t *tex; + float width_of[256]; // width_of[0] == max width of any char; 1.0f is base width (1/16 of texture width); therefore, all widths have to be <= 1 (does not include scale) + float maxwidth; // precalculated max width of the font (includes scale) + char texpath[MAX_QPATH]; + char title[MAX_QPATH]; + + int req_face; // requested face index, usually 0 + float req_sizes[MAX_FONT_SIZES]; // sizes to render the font with, 0 still defaults to 16 (backward compatibility when loadfont doesn't get a size parameter) and -1 = disabled + char fallbacks[MAX_FONT_FALLBACKS][MAX_QPATH]; + int fallback_faces[MAX_FONT_FALLBACKS]; + struct ft2_font_s *ft2; + + ft2_settings_t settings; +} +dp_font_t; + +typedef struct dp_fonts_s +{ + dp_font_t *f; + int maxsize; +} +dp_fonts_t; +extern dp_fonts_t dp_fonts; + +#define MAX_FONTS 16 // fonts at the start +#define FONTS_EXPAND 8 // fonts grow when no free slots +#define FONT_DEFAULT (&dp_fonts.f[0]) // should be fixed width +#define FONT_CONSOLE (&dp_fonts.f[1]) // REALLY should be fixed width (ls!) +#define FONT_SBAR (&dp_fonts.f[2]) // must be fixed width +#define FONT_NOTIFY (&dp_fonts.f[3]) // free +#define FONT_CHAT (&dp_fonts.f[4]) // free +#define FONT_CENTERPRINT (&dp_fonts.f[5]) // free +#define FONT_INFOBAR (&dp_fonts.f[6]) // free +#define FONT_MENU (&dp_fonts.f[7]) // should be fixed width +#define FONT_USER(i) (&dp_fonts.f[8+i]) // userdefined fonts +#define MAX_USERFONTS (dp_fonts.maxsize - 8) + +// shared color tag printing constants +#define STRING_COLOR_TAG '^' +#define STRING_COLOR_DEFAULT 7 +#define STRING_COLOR_DEFAULT_STR "^7" +#define STRING_COLOR_RGB_TAG_CHAR 'x' +#define STRING_COLOR_RGB_TAG "^x" + +// all of these functions will set r_defdef.draw2dstage if not in 2D rendering mode (and of course prepare for 2D rendering in that case) + +// draw an image (or a filled rectangle if pic == NULL) +void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags); +// draw a rotated image +void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, float org_x, float org_y, float angle, float red, float green, float blue, float alpha, int flags); +// draw a filled rectangle (slightly faster than DrawQ_Pic with pic = NULL) +void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags); +// draw a text string, +// with optional color tag support, +// returns final unclipped x coordinate +// if outcolor is provided the initial color is read from it, and it is updated at the end with the new value at the end of the text (not at the end of the clipped part) +// the color is tinted by the provided base color +// if r_textshadow is not zero, an additional instance of the text is drawn first at an offset with an inverted shade of gray (black text produces a white shadow, brightly colored text produces a black shadow) +extern float DrawQ_Color[4]; +float DrawQ_String(float x, float y, const char *text, size_t maxlen, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt); +float DrawQ_String_Scale(float x, float y, const char *text, size_t maxlen, float sizex, float sizey, float scalex, float scaley, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt); +float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt); +float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth); +float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth); +float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth); +// draw a very fancy pic (per corner texcoord/color control), the order is tl, tr, bl, br +void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags); +// draw a triangle mesh +void DrawQ_Mesh(drawqueuemesh_t *mesh, int flags, qboolean hasalpha); +// set the clipping area +void DrawQ_SetClipArea(float x, float y, float width, float height); +// reset the clipping area +void DrawQ_ResetClipArea(void); +// draw a line +void DrawQ_Line(float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags); +// draw a lot of lines (call R_Mesh_PrepareVertices_Generic first) +void DrawQ_Lines(float width, int numlines, int flags, qboolean hasalpha); +// draw a line loop +void DrawQ_LineLoop(drawqueuemesh_t *mesh, int flags); +// resets r_refdef.draw2dstage +void DrawQ_Finish(void); +void DrawQ_ProcessDrawFlag(int flags, qboolean alpha); // sets GL_DepthMask and GL_BlendFunc +void DrawQ_RecalcView(void); // use this when changing r_refdef.view.* from e.g. csqc + +rtexture_t *Draw_GetPicTexture(cachepic_t *pic); + +void R_DrawGamma(void); + +extern rtexturepool_t *drawtexturepool; // used by ft2.c + +#endif + diff --git a/app/jni/filematch.c b/app/jni/filematch.c new file mode 100644 index 0000000..9971167 --- /dev/null +++ b/app/jni/filematch.c @@ -0,0 +1,204 @@ + +#ifdef WIN32 +#include +#else +#include +#endif + +#include "quakedef.h" + +// LordHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such... + +int matchpattern(const char *in, const char *pattern, int caseinsensitive) +{ + return matchpattern_with_separator(in, pattern, caseinsensitive, "/\\:", false); +} + +// wildcard_least_one: if true * matches 1 or more characters +// if false * matches 0 or more characters +int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qboolean wildcard_least_one) +{ + int c1, c2; + while (*pattern) + { + switch (*pattern) + { + case 0: + return 1; // end of pattern + case '?': // match any single character + if (*in == 0 || strchr(separators, *in)) + return 0; // no match + in++; + pattern++; + break; + case '*': // match anything until following string + if(wildcard_least_one) + { + if (*in == 0 || strchr(separators, *in)) + return 0; // no match + in++; + } + pattern++; + while (*in) + { + if (strchr(separators, *in)) + break; + // see if pattern matches at this offset + if (matchpattern_with_separator(in, pattern, caseinsensitive, separators, wildcard_least_one)) + return 1; + // nope, advance to next offset + in++; + } + break; + default: + if (*in != *pattern) + { + if (!caseinsensitive) + return 0; // no match + c1 = *in; + if (c1 >= 'A' && c1 <= 'Z') + c1 += 'a' - 'A'; + c2 = *pattern; + if (c2 >= 'A' && c2 <= 'Z') + c2 += 'a' - 'A'; + if (c1 != c2) + return 0; // no match + } + in++; + pattern++; + break; + } + } + if (*in) + return 0; // reached end of pattern but not end of input + return 1; // success +} + +// a little strings system +void stringlistinit(stringlist_t *list) +{ + memset(list, 0, sizeof(*list)); +} + +void stringlistfreecontents(stringlist_t *list) +{ + int i; + for (i = 0;i < list->numstrings;i++) + { + if (list->strings[i]) + Z_Free(list->strings[i]); + list->strings[i] = NULL; + } + list->numstrings = 0; + list->maxstrings = 0; + if (list->strings) + Z_Free(list->strings); + list->strings = NULL; +} + +void stringlistappend(stringlist_t *list, const char *text) +{ + size_t textlen; + char **oldstrings; + + if (list->numstrings >= list->maxstrings) + { + oldstrings = list->strings; + list->maxstrings += 4096; + list->strings = (char **) Z_Malloc(list->maxstrings * sizeof(*list->strings)); + if (list->numstrings) + memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings)); + if (oldstrings) + Z_Free(oldstrings); + } + textlen = strlen(text) + 1; + list->strings[list->numstrings] = (char *) Z_Malloc(textlen); + memcpy(list->strings[list->numstrings], text, textlen); + list->numstrings++; +} + +static int stringlistsort_cmp(const void *a, const void *b) +{ + return strcasecmp(*(const char **)a, *(const char **)b); +} + +void stringlistsort(stringlist_t *list, qboolean uniq) +{ + int i, j; + if(list->numstrings < 1) + return; + qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp); + if(uniq) + { + // i: the item to read + // j: the item last written + for (i = 1, j = 0; i < list->numstrings; ++i) + { + char *save; + if(!strcasecmp(list->strings[i], list->strings[j])) + continue; + ++j; + save = list->strings[j]; + list->strings[j] = list->strings[i]; + list->strings[i] = save; + } + for(i = j+1; i < list->numstrings; ++i) + { + if (list->strings[i]) + Z_Free(list->strings[i]); + } + list->numstrings = j+1; + } +} + +// operating system specific code +static void adddirentry(stringlist_t *list, const char *path, const char *name) +{ + if (strcmp(name, ".") && strcmp(name, "..")) + { + char temp[MAX_OSPATH]; + dpsnprintf( temp, sizeof( temp ), "%s%s", path, name ); + stringlistappend(list, temp); + } +} +#ifdef WIN32 +void listdirectory(stringlist_t *list, const char *basepath, const char *path) +{ + int i; + char pattern[4096], *c; + WIN32_FIND_DATA n_file; + HANDLE hFile; + strlcpy (pattern, basepath, sizeof(pattern)); + strlcat (pattern, path, sizeof (pattern)); + strlcat (pattern, "*", sizeof (pattern)); + // ask for the directory listing handle + hFile = FindFirstFile(pattern, &n_file); + if(hFile == INVALID_HANDLE_VALUE) + return; + do { + adddirentry(list, path, n_file.cFileName); + } while (FindNextFile(hFile, &n_file) != 0); + FindClose(hFile); + + // convert names to lowercase because windows does not care, but pattern matching code often does + for (i = 0;i < list->numstrings;i++) + for (c = list->strings[i];*c;c++) + if (*c >= 'A' && *c <= 'Z') + *c += 'a' - 'A'; +} +#else +void listdirectory(stringlist_t *list, const char *basepath, const char *path) +{ + char fullpath[MAX_OSPATH]; + DIR *dir; + struct dirent *ent; + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, *path ? path : "./"); + dir = opendir(fullpath); + if (!dir) + return; + while ((ent = readdir(dir))) + adddirentry(list, path, ent->d_name); + closedir(dir); +} +#endif + diff --git a/app/jni/fractalnoise.c b/app/jni/fractalnoise.c new file mode 100644 index 0000000..5d68d19 --- /dev/null +++ b/app/jni/fractalnoise.c @@ -0,0 +1,226 @@ + +#include "quakedef.h" + +void fractalnoise(unsigned char *noise, int size, int startgrid) +{ + int x, y, g, g2, amplitude, min, max, size1 = size - 1, sizepower, gridpower; + int *noisebuf; +#define n(x,y) noisebuf[((y)&size1)*size+((x)&size1)] + + for (sizepower = 0;(1 << sizepower) < size;sizepower++); + if (size != (1 << sizepower)) + { + Con_Printf("fractalnoise: size must be power of 2\n"); + return; + } + + for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++); + if (startgrid != (1 << gridpower)) + { + Con_Printf("fractalnoise: grid must be power of 2\n"); + return; + } + + startgrid = bound(0, startgrid, size); + + amplitude = 0xFFFF; // this gets halved before use + noisebuf = (int *)Mem_Alloc(tempmempool, size*size*sizeof(int)); + memset(noisebuf, 0, size*size*sizeof(int)); + + for (g2 = startgrid;g2;g2 >>= 1) + { + // brownian motion (at every smaller level there is random behavior) + amplitude >>= 1; + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + n(x,y) += (rand()&litude); + + g = g2 >> 1; + if (g) + { + // subdivide, diamond-square algorithm (really this has little to do with squares) + // diamond + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2; + // square + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + { + n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2; + n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2; + } + } + } + // find range of noise values + min = max = 0; + for (y = 0;y < size;y++) + for (x = 0;x < size;x++) + { + if (n(x,y) < min) min = n(x,y); + if (n(x,y) > max) max = n(x,y); + } + max -= min; + max++; + // normalize noise and copy to output + for (y = 0;y < size;y++) + for (x = 0;x < size;x++) + *noise++ = (unsigned char) (((n(x,y) - min) * 256) / max); + Mem_Free(noisebuf); +#undef n +} + +// unnormalized, used for explosions mainly, does not allocate/free memory (hence the name quick) +void fractalnoisequick(unsigned char *noise, int size, int startgrid) +{ + int x, y, g, g2, amplitude, size1 = size - 1, sizepower, gridpower; +#define n(x,y) noise[((y)&size1)*size+((x)&size1)] + + for (sizepower = 0;(1 << sizepower) < size;sizepower++); + if (size != (1 << sizepower)) + { + Con_Printf("fractalnoise: size must be power of 2\n"); + return; + } + + for (gridpower = 0;(1 << gridpower) < startgrid;gridpower++); + if (startgrid != (1 << gridpower)) + { + Con_Printf("fractalnoise: grid must be power of 2\n"); + return; + } + + startgrid = bound(0, startgrid, size); + + amplitude = 255; // this gets halved before use + memset(noise, 0, size*size); + + for (g2 = startgrid;g2;g2 >>= 1) + { + // brownian motion (at every smaller level there is random behavior) + amplitude >>= 1; + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + n(x,y) += (rand()&litude); + + g = g2 >> 1; + if (g) + { + // subdivide, diamond-square algorithm (really this has little to do with squares) + // diamond + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + n(x+g,y+g) = (unsigned char) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x,y+g2) + (int) n(x+g2,y+g2)) >> 2); + // square + for (y = 0;y < size;y += g2) + for (x = 0;x < size;x += g2) + { + n(x+g,y) = (unsigned char) (((int) n(x,y) + (int) n(x+g2,y) + (int) n(x+g,y-g) + (int) n(x+g,y+g)) >> 2); + n(x,y+g) = (unsigned char) (((int) n(x,y) + (int) n(x,y+g2) + (int) n(x-g,y+g) + (int) n(x+g,y+g)) >> 2); + } + } + } +#undef n +} + +#define NOISE_SIZE 256 +#define NOISE_MASK 255 +float noise4f(float x, float y, float z, float w) +{ + int i; + int index[4][2]; + float frac[4][2]; + float v[4]; + static float noisetable[NOISE_SIZE]; + static int r[NOISE_SIZE]; + // LordHavoc: this is inspired by code I saw in Quake3, however I think my + // version is much cleaner and substantially faster as well + // + // the following changes were made: + // 1. for the permutation indexing (r[] array in this code) I substituted + // the ^ operator (which never overflows) for the original addition and + // masking code, this should not have any effect on quality. + // 2. removed the outermost randomization array lookup. + // (it really wasn't necessary, it's fine if X indexes the array + // directly without permutation indexing) + // 3. reimplemented the blending using frac[] arrays rather than a macro. + // (the original macro read one parameter twice - not good) + // 4. cleaned up the code by using 4 nested loops to make it read nicer + // (but then I unrolled it completely for speed, it still looks nicer). + if (!noisetable[0]) + { + // noisetable is a random-ish series of float values in +/- 1 range + for (i = 0;i < NOISE_SIZE;i++) + noisetable[i] = (rand() / (double)RAND_MAX) * 2 - 1; + // r is a remapping table to make each dimension of the index have different indexing behavior + for (i = 0;i < NOISE_SIZE;i++) + r[i] = (int)(rand() * (double)NOISE_SIZE / ((double)RAND_MAX + 1)) & NOISE_MASK; + // that & is only needed if RAND_MAX is > the range of double, which isn't the case on most platforms + } + frac[0][1] = x - floor(x);index[0][0] = ((int)floor(x)) & NOISE_MASK; + frac[1][1] = y - floor(y);index[1][0] = ((int)floor(y)) & NOISE_MASK; + frac[2][1] = z - floor(z);index[2][0] = ((int)floor(z)) & NOISE_MASK; + frac[3][1] = w - floor(w);index[3][0] = ((int)floor(w)) & NOISE_MASK; + for (i = 0;i < 4;i++) + frac[i][0] = 1 - frac[i][1]; + for (i = 0;i < 4;i++) + index[i][1] = (index[i][0] < NOISE_SIZE - 1) ? (index[i][0] + 1) : 0; +#if 1 + // short version + v[0] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]); + v[1] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]); + v[2] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]); + v[3] = frac[1][0] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]) + frac[1][1] * (frac[0][0] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]] + frac[0][1] * noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]); + return frac[3][0] * (frac[2][0] * v[0] + frac[2][1] * v[1]) + frac[3][1] * (frac[2][0] * v[2] + frac[2][1] * v[3]); +#elif 1 + // longer version + v[ 0] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]]; + v[ 1] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]; + v[ 2] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]]; + v[ 3] = noisetable[r[r[r[index[3][0]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]; + v[ 4] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]]; + v[ 5] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]; + v[ 6] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]]; + v[ 7] = noisetable[r[r[r[index[3][0]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]; + v[ 8] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][0]]; + v[ 9] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][0]] ^ index[0][1]]; + v[10] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][0]]; + v[11] = noisetable[r[r[r[index[3][1]] ^ index[2][0]] ^ index[1][1]] ^ index[0][1]]; + v[12] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][0]]; + v[13] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][0]] ^ index[0][1]]; + v[14] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][0]]; + v[15] = noisetable[r[r[r[index[3][1]] ^ index[2][1]] ^ index[1][1]] ^ index[0][1]]; + v[16] = frac[0][0] * v[ 0] + frac[0][1] * v[ 1]; + v[17] = frac[0][0] * v[ 2] + frac[0][1] * v[ 3]; + v[18] = frac[0][0] * v[ 4] + frac[0][1] * v[ 5]; + v[19] = frac[0][0] * v[ 6] + frac[0][1] * v[ 7]; + v[20] = frac[0][0] * v[ 8] + frac[0][1] * v[ 9]; + v[21] = frac[0][0] * v[10] + frac[0][1] * v[11]; + v[22] = frac[0][0] * v[12] + frac[0][1] * v[13]; + v[23] = frac[0][0] * v[14] + frac[0][1] * v[15]; + v[24] = frac[1][0] * v[16] + frac[1][1] * v[17]; + v[25] = frac[1][0] * v[18] + frac[1][1] * v[19]; + v[26] = frac[1][0] * v[20] + frac[1][1] * v[21]; + v[27] = frac[1][0] * v[22] + frac[1][1] * v[23]; + v[28] = frac[2][0] * v[24] + frac[2][1] * v[25]; + v[29] = frac[2][0] * v[26] + frac[2][1] * v[27]; + return frac[3][0] * v[28] + frac[3][1] * v[29]; +#else + // the algorithm... + for (l = 0;l < 2;l++) + { + for (k = 0;k < 2;k++) + { + for (j = 0;j < 2;j++) + { + for (i = 0;i < 2;i++) + v[l][k][j][i] = noisetable[r[r[r[index[l][3]] ^ index[k][2]] ^ index[j][1]] ^ index[i][0]]; + v[l][k][j][2] = frac[0][0] * v[l][k][j][0] + frac[0][1] * v[l][k][j][1]; + } + v[l][k][2][2] = frac[1][0] * v[l][k][0][2] + frac[1][1] * v[l][k][1][2]; + } + v[l][2][2][2] = frac[2][0] * v[l][0][2][2] + frac[2][1] * v[l][1][2][2]; + } + v[2][2][2][2] = frac[3][0] * v[0][2][2][2] + frac[3][1] * v[1][2][2][2]; +#endif +} diff --git a/app/jni/fs.c b/app/jni/fs.c new file mode 100644 index 0000000..be8d70f --- /dev/null +++ b/app/jni/fs.c @@ -0,0 +1,3995 @@ +/* + DarkPlaces file system + + Copyright (C) 2003-2006 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA +*/ + +#ifdef __APPLE__ +// include SDL for IPHONEOS code +# include +# if TARGET_OS_IPHONE +# include +# endif +#endif + +#include +#include + +#ifdef WIN32 +# include +# include +# include +# include +# include +#else +# include +# include +# include +#endif + +#include "quakedef.h" +#include "thread.h" + +#include "fs.h" +#include "wad.h" + +// Win32 requires us to add O_BINARY, but the other OSes don't have it +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +// In case the system doesn't support the O_NONBLOCK flag +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +// largefile support for Win32 +#ifdef WIN32 +#undef lseek +# define lseek _lseeki64 +#endif + +// suppress deprecated warnings +#if _MSC_VER >= 1400 +# define read _read +# define write _write +# define close _close +# define unlink _unlink +# define dup _dup +#endif + +/** \page fs File System + +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 +precaution against having a malicious server instruct clients to write files +over areas they shouldn't. + +*/ + + +/* +============================================================================= + +CONSTANTS + +============================================================================= +*/ + +// Magic numbers of a ZIP file (big-endian format) +#define ZIP_DATA_HEADER 0x504B0304 // "PK\3\4" +#define ZIP_CDIR_HEADER 0x504B0102 // "PK\1\2" +#define ZIP_END_HEADER 0x504B0506 // "PK\5\6" + +// Other constants for ZIP files +#define ZIP_MAX_COMMENTS_SIZE ((unsigned short)0xFFFF) +#define ZIP_END_CDIR_SIZE 22 +#define ZIP_CDIR_CHUNK_BASE_SIZE 46 +#define ZIP_LOCAL_CHUNK_BASE_SIZE 30 + +#ifdef LINK_TO_ZLIB +#include + +#define qz_inflate inflate +#define qz_inflateEnd inflateEnd +#define qz_inflateInit2_ inflateInit2_ +#define qz_inflateReset inflateReset +#define qz_deflateInit2_ deflateInit2_ +#define qz_deflateEnd deflateEnd +#define qz_deflate deflate +#define Z_MEMLEVEL_DEFAULT 8 +#else + +// Zlib constants (from zlib.h) +#define Z_SYNC_FLUSH 2 +#define MAX_WBITS 15 +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define ZLIB_VERSION "1.2.3" + +#define Z_BINARY 0 +#define Z_DEFLATED 8 +#define Z_MEMLEVEL_DEFAULT 8 + +#define Z_NULL 0 +#define Z_DEFAULT_COMPRESSION (-1) +#define Z_NO_FLUSH 0 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 + +// Uncomment the following line if the zlib DLL you have still uses +// the 1.1.x series calling convention on Win32 (WINAPI) +//#define ZLIB_USES_WINAPI + + +/* +============================================================================= + +TYPES + +============================================================================= +*/ + +/*! Zlib stream (from zlib.h) + * \warning: some pointers we don't use directly have + * been cast to "void*" for a matter of simplicity + */ +typedef struct +{ + unsigned char *next_in; ///< next input byte + unsigned int avail_in; ///< number of bytes available at next_in + unsigned long total_in; ///< total nb of input bytes read so far + + unsigned char *next_out; ///< next output byte should be put there + unsigned int avail_out; ///< remaining free space at next_out + unsigned long total_out; ///< total nb of bytes output so far + + char *msg; ///< last error message, NULL if no error + void *state; ///< not visible by applications + + void *zalloc; ///< used to allocate the internal state + void *zfree; ///< used to free the internal state + void *opaque; ///< private data object passed to zalloc and zfree + + int data_type; ///< best guess about the data type: ascii or binary + unsigned long adler; ///< adler32 value of the uncompressed data + unsigned long reserved; ///< reserved for future use +} z_stream; +#endif + + +/// inside a package (PAK or PK3) +#define QFILE_FLAG_PACKED (1 << 0) +/// file is compressed using the deflate algorithm (PK3 only) +#define QFILE_FLAG_DEFLATED (1 << 1) +/// file is actually already loaded data +#define QFILE_FLAG_DATA (1 << 2) +/// real file will be removed on close +#define QFILE_FLAG_REMOVE (1 << 3) + +#define FILE_BUFF_SIZE 2048 +typedef struct +{ + z_stream zstream; + size_t comp_length; ///< length of the compressed file + size_t in_ind, in_len; ///< input buffer current index and length + size_t in_position; ///< position in the compressed file + unsigned char input [FILE_BUFF_SIZE]; +} ztoolkit_t; + +struct qfile_s +{ + int flags; + int handle; ///< file descriptor + fs_offset_t real_length; ///< uncompressed file size (for files opened in "read" mode) + fs_offset_t position; ///< current position in the file + fs_offset_t offset; ///< offset into the package (0 if external file) + int ungetc; ///< single stored character from ungetc, cleared to EOF when read + + // Contents buffer + fs_offset_t buff_ind, buff_len; ///< buffer current index and length + unsigned char buff [FILE_BUFF_SIZE]; + + ztoolkit_t* ztk; ///< For zipped files. + + const unsigned char *data; ///< For data files. + + const char *filename; ///< Kept around for QFILE_FLAG_REMOVE, unused otherwise +}; + + +// ------ PK3 files on disk ------ // + +// You can get the complete ZIP format description from PKWARE website + +typedef struct pk3_endOfCentralDir_s +{ + unsigned int signature; + unsigned short disknum; + unsigned short cdir_disknum; ///< number of the disk with the start of the central directory + unsigned short localentries; ///< number of entries in the central directory on this disk + unsigned short nbentries; ///< total number of entries in the central directory on this disk + unsigned int cdir_size; ///< size of the central directory + unsigned int cdir_offset; ///< with respect to the starting disk number + unsigned short comment_size; + fs_offset_t prepended_garbage; +} pk3_endOfCentralDir_t; + + +// ------ PAK files on disk ------ // +typedef struct dpackfile_s +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct dpackheader_s +{ + char id[4]; + int dirofs; + int dirlen; +} dpackheader_t; + + +/*! \name Packages in memory + * @{ + */ +/// the offset in packfile_t is the true contents offset +#define PACKFILE_FLAG_TRUEOFFS (1 << 0) +/// file compressed using the deflate algorithm +#define PACKFILE_FLAG_DEFLATED (1 << 1) +/// file is a symbolic link +#define PACKFILE_FLAG_SYMLINK (1 << 2) + +typedef struct packfile_s +{ + char name [MAX_QPATH]; + int flags; + fs_offset_t offset; + fs_offset_t packsize; ///< size in the package + fs_offset_t realsize; ///< real file size (uncompressed) +} packfile_t; + +typedef struct pack_s +{ + char filename [MAX_OSPATH]; + char shortname [MAX_QPATH]; + int handle; + int ignorecase; ///< PK3 ignores case + int numfiles; + qboolean vpack; + packfile_t *files; +} pack_t; +//@} + +/// Search paths for files (including packages) +typedef struct searchpath_s +{ + // only one of filename / pack will be used + char filename[MAX_OSPATH]; + pack_t *pack; + struct searchpath_s *next; +} searchpath_t; + + +/* +============================================================================= + +FUNCTION PROTOTYPES + +============================================================================= +*/ + +void FS_Dir_f(void); +void FS_Ls_f(void); +void FS_Which_f(void); + +static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet); +static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags); + + +/* +============================================================================= + +VARIABLES + +============================================================================= +*/ + +mempool_t *fs_mempool; +void *fs_mutex = NULL; + +searchpath_t *fs_searchpaths = NULL; +const char *const fs_checkgamedir_missing = "missing"; + +#define MAX_FILES_IN_PACK 65536 + +char fs_userdir[MAX_OSPATH]; +char fs_gamedir[MAX_OSPATH]; +char fs_basedir[MAX_OSPATH]; +static pack_t *fs_selfpack = NULL; + +// list of active game directories (empty if not running a mod) +int fs_numgamedirs = 0; +char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH]; + +// list of all gamedirs with modinfo.txt +gamedir_t *fs_all_gamedirs = NULL; +int fs_all_gamedirs_count = 0; + +cvar_t scr_screenshot_name = {CVAR_NORESETTODEFAULTS, "scr_screenshot_name","dp", "prefix name for saved screenshots (changes based on -game commandline, as well as which game mode is running; the date is encoded using strftime escapes)"}; +cvar_t fs_empty_files_in_pack_mark_deletions = {0, "fs_empty_files_in_pack_mark_deletions", "0", "if enabled, empty files in a pak/pk3 count as not existing but cancel the search in further packs, effectively allowing patch pak/pk3 files to 'delete' files"}; +cvar_t cvar_fs_gamedir = {CVAR_READONLY | CVAR_NORESETTODEFAULTS, "fs_gamedir", "", "the list of currently selected gamedirs (use the 'gamedir' command to change this)"}; + + +/* +============================================================================= + +PRIVATE FUNCTIONS - PK3 HANDLING + +============================================================================= +*/ + +#ifndef LINK_TO_ZLIB +// Functions exported from zlib +#if defined(WIN32) && defined(ZLIB_USES_WINAPI) +# define ZEXPORT WINAPI +#else +# define ZEXPORT +#endif + +static int (ZEXPORT *qz_inflate) (z_stream* strm, int flush); +static int (ZEXPORT *qz_inflateEnd) (z_stream* strm); +static int (ZEXPORT *qz_inflateInit2_) (z_stream* strm, int windowBits, const char *version, int stream_size); +static int (ZEXPORT *qz_inflateReset) (z_stream* strm); +static int (ZEXPORT *qz_deflateInit2_) (z_stream* strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size); +static int (ZEXPORT *qz_deflateEnd) (z_stream* strm); +static int (ZEXPORT *qz_deflate) (z_stream* strm, int flush); +#endif + +#define qz_inflateInit2(strm, windowBits) \ + qz_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define qz_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + qz_deflateInit2_((strm), (level), (method), (windowBits), (memLevel), (strategy), ZLIB_VERSION, sizeof(z_stream)) + +#ifndef LINK_TO_ZLIB +// qz_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) + +static dllfunction_t zlibfuncs[] = +{ + {"inflate", (void **) &qz_inflate}, + {"inflateEnd", (void **) &qz_inflateEnd}, + {"inflateInit2_", (void **) &qz_inflateInit2_}, + {"inflateReset", (void **) &qz_inflateReset}, + {"deflateInit2_", (void **) &qz_deflateInit2_}, + {"deflateEnd", (void **) &qz_deflateEnd}, + {"deflate", (void **) &qz_deflate}, + {NULL, NULL} +}; + +/// Handle for Zlib DLL +static dllhandle_t zlib_dll = NULL; +#endif + +#ifdef WIN32 +static HRESULT (WINAPI *qSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath); +static dllfunction_t shfolderfuncs[] = +{ + {"SHGetFolderPathA", (void **) &qSHGetFolderPath}, + {NULL, NULL} +}; +static const char* shfolderdllnames [] = +{ + "shfolder.dll", // IE 4, or Win NT and higher + NULL +}; +static dllhandle_t shfolder_dll = NULL; + +const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}}; +#define qREFKNOWNFOLDERID const GUID * +#define qKF_FLAG_CREATE 0x8000 +#define qKF_FLAG_NO_ALIAS 0x1000 +static HRESULT (WINAPI *qSHGetKnownFolderPath) (qREFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); +static dllfunction_t shell32funcs[] = +{ + {"SHGetKnownFolderPath", (void **) &qSHGetKnownFolderPath}, + {NULL, NULL} +}; +static const char* shell32dllnames [] = +{ + "shell32.dll", // Vista and higher + NULL +}; +static dllhandle_t shell32_dll = NULL; + +static HRESULT (WINAPI *qCoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); +static void (WINAPI *qCoUninitialize)(void); +static void (WINAPI *qCoTaskMemFree)(LPVOID pv); +static dllfunction_t ole32funcs[] = +{ + {"CoInitializeEx", (void **) &qCoInitializeEx}, + {"CoUninitialize", (void **) &qCoUninitialize}, + {"CoTaskMemFree", (void **) &qCoTaskMemFree}, + {NULL, NULL} +}; +static const char* ole32dllnames [] = +{ + "ole32.dll", // 2000 and higher + NULL +}; +static dllhandle_t ole32_dll = NULL; +#endif + +/* +==================== +PK3_CloseLibrary + +Unload the Zlib DLL +==================== +*/ +static void PK3_CloseLibrary (void) +{ +#ifndef LINK_TO_ZLIB + Sys_UnloadLibrary (&zlib_dll); +#endif +} + + +/* +==================== +PK3_OpenLibrary + +Try to load the Zlib DLL +==================== +*/ +static qboolean PK3_OpenLibrary (void) +{ +#ifdef LINK_TO_ZLIB + return true; +#else + const char* dllnames [] = + { +#if defined(WIN32) +# ifdef ZLIB_USES_WINAPI + "zlibwapi.dll", + "zlib.dll", +# else + "zlib1.dll", +# endif +#elif defined(MACOSX) + "libz.dylib", +#else + "libz.so.1", + "libz.so", +#endif + NULL + }; + + // Already loaded? + if (zlib_dll) + return true; + + // Load the DLL + return Sys_LoadLibrary (dllnames, &zlib_dll, zlibfuncs); +#endif +} + +/* +==================== +FS_HasZlib + +See if zlib is available +==================== +*/ +qboolean FS_HasZlib(void) +{ +#ifdef LINK_TO_ZLIB + return true; +#else + PK3_OpenLibrary(); // to be safe + return (zlib_dll != 0); +#endif +} + +/* +==================== +PK3_GetEndOfCentralDir + +Extract the end of the central directory from a PK3 package +==================== +*/ +static qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOfCentralDir_t *eocd) +{ + fs_offset_t filesize, maxsize; + unsigned char *buffer, *ptr; + int ind; + + // Get the package size + filesize = lseek (packhandle, 0, SEEK_END); + if (filesize < ZIP_END_CDIR_SIZE) + return false; + + // Load the end of the file in memory + if (filesize < ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE) + maxsize = filesize; + else + maxsize = ZIP_MAX_COMMENTS_SIZE + ZIP_END_CDIR_SIZE; + buffer = (unsigned char *)Mem_Alloc (tempmempool, maxsize); + lseek (packhandle, filesize - maxsize, SEEK_SET); + if (read (packhandle, buffer, maxsize) != (fs_offset_t) maxsize) + { + Mem_Free (buffer); + return false; + } + + // Look for the end of central dir signature around the end of the file + maxsize -= ZIP_END_CDIR_SIZE; + ptr = &buffer[maxsize]; + ind = 0; + while (BuffBigLong (ptr) != ZIP_END_HEADER) + { + if (ind == maxsize) + { + Mem_Free (buffer); + return false; + } + + ind++; + ptr--; + } + + memcpy (eocd, ptr, ZIP_END_CDIR_SIZE); + eocd->signature = LittleLong (eocd->signature); + eocd->disknum = LittleShort (eocd->disknum); + eocd->cdir_disknum = LittleShort (eocd->cdir_disknum); + eocd->localentries = LittleShort (eocd->localentries); + eocd->nbentries = LittleShort (eocd->nbentries); + eocd->cdir_size = LittleLong (eocd->cdir_size); + eocd->cdir_offset = LittleLong (eocd->cdir_offset); + eocd->comment_size = LittleShort (eocd->comment_size); + eocd->prepended_garbage = filesize - (ind + ZIP_END_CDIR_SIZE) - eocd->cdir_offset - eocd->cdir_size; // this detects "SFX" zip files + eocd->cdir_offset += eocd->prepended_garbage; + + Mem_Free (buffer); + + return true; +} + + +/* +==================== +PK3_BuildFileList + +Extract the file list from a PK3 file +==================== +*/ +static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd) +{ + unsigned char *central_dir, *ptr; + unsigned int ind; + fs_offset_t remaining; + + // Load the central directory in memory + central_dir = (unsigned char *)Mem_Alloc (tempmempool, eocd->cdir_size); + lseek (pack->handle, eocd->cdir_offset, SEEK_SET); + if(read (pack->handle, central_dir, eocd->cdir_size) != (fs_offset_t) eocd->cdir_size) + { + Mem_Free (central_dir); + return -1; + } + + // Extract the files properties + // The parsing is done "by hand" because some fields have variable sizes and + // the constant part isn't 4-bytes aligned, which makes the use of structs difficult + remaining = eocd->cdir_size; + pack->numfiles = 0; + ptr = central_dir; + for (ind = 0; ind < eocd->nbentries; ind++) + { + fs_offset_t namesize, count; + + // Checking the remaining size + if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE) + { + Mem_Free (central_dir); + return -1; + } + remaining -= ZIP_CDIR_CHUNK_BASE_SIZE; + + // Check header + if (BuffBigLong (ptr) != ZIP_CDIR_HEADER) + { + Mem_Free (central_dir); + return -1; + } + + namesize = BuffLittleShort (&ptr[28]); // filename length + + // Check encryption, compression, and attributes + // 1st uint8 : general purpose bit flag + // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?)) + // + // LordHavoc: bit 3 would be a problem if we were scanning the archive + // but is not a problem in the central directory where the values are + // always real. + // + // bit 3 seems to always be set by the standard Mac OSX zip maker + // + // 2nd uint8 : external file attributes + // Check bits 3 (file is a directory) and 5 (file is a volume (?)) + if ((ptr[8] & 0x21) == 0 && (ptr[38] & 0x18) == 0) + { + // Still enough bytes for the name? + if (remaining < namesize || namesize >= (int)sizeof (*pack->files)) + { + Mem_Free (central_dir); + return -1; + } + + // WinZip doesn't use the "directory" attribute, so we need to check the name directly + if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/') + { + char filename [sizeof (pack->files[0].name)]; + fs_offset_t offset, packsize, realsize; + int flags; + + // Extract the name (strip it if necessary) + namesize = min(namesize, (int)sizeof (filename) - 1); + memcpy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize); + filename[namesize] = '\0'; + + if (BuffLittleShort (&ptr[10])) + flags = PACKFILE_FLAG_DEFLATED; + else + flags = 0; + offset = (unsigned int)(BuffLittleLong (&ptr[42]) + eocd->prepended_garbage); + packsize = (unsigned int)BuffLittleLong (&ptr[20]); + realsize = (unsigned int)BuffLittleLong (&ptr[24]); + + switch(ptr[5]) // C_VERSION_MADE_BY_1 + { + case 3: // UNIX_ + case 2: // VMS_ + case 16: // BEOS_ + if((BuffLittleShort(&ptr[40]) & 0120000) == 0120000) + // can't use S_ISLNK here, as this has to compile on non-UNIX too + flags |= PACKFILE_FLAG_SYMLINK; + break; + } + + FS_AddFileToPack (filename, pack, offset, packsize, realsize, flags); + } + } + + // Skip the name, additionnal field, and comment + // 1er uint16 : extra field length + // 2eme uint16 : file comment length + count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]); + ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count; + remaining -= count; + } + + // If the package is empty, central_dir is NULL here + if (central_dir != NULL) + Mem_Free (central_dir); + return pack->numfiles; +} + + +/* +==================== +FS_LoadPackPK3 + +Create a package entry associated with a PK3 file +==================== +*/ +static pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qboolean silent) +{ + pk3_endOfCentralDir_t eocd; + pack_t *pack; + int real_nb_files; + + if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd)) + { + if(!silent) + Con_Printf ("%s is not a PK3 file\n", packfile); + close(packhandle); + return NULL; + } + + // Multi-volume ZIP archives are NOT allowed + if (eocd.disknum != 0 || eocd.cdir_disknum != 0) + { + Con_Printf ("%s is a multi-volume ZIP archive\n", packfile); + close(packhandle); + return NULL; + } + + // We only need to do this test if MAX_FILES_IN_PACK is lesser than 65535 + // since eocd.nbentries is an unsigned 16 bits integer +#if MAX_FILES_IN_PACK < 65535 + if (eocd.nbentries > MAX_FILES_IN_PACK) + { + Con_Printf ("%s contains too many files (%hu)\n", packfile, eocd.nbentries); + close(packhandle); + return NULL; + } +#endif + + // Create a package structure in memory + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); + pack->ignorecase = true; // PK3 ignores case + strlcpy (pack->filename, packfile, sizeof (pack->filename)); + pack->handle = packhandle; + pack->numfiles = eocd.nbentries; + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, eocd.nbentries * sizeof(packfile_t)); + + real_nb_files = PK3_BuildFileList (pack, &eocd); + if (real_nb_files < 0) + { + Con_Printf ("%s is not a valid PK3 file\n", packfile); + close(pack->handle); + Mem_Free(pack); + return NULL; + } + + Con_DPrintf("Added packfile %s (%i files)\n", packfile, real_nb_files); + return pack; +} +static pack_t *FS_LoadPackPK3 (const char *packfile) +{ + int packhandle; + packhandle = FS_SysOpenFD (packfile, "rb", false); + if (packhandle < 0) + return NULL; + return FS_LoadPackPK3FromFD(packfile, packhandle, false); +} + + +/* +==================== +PK3_GetTrueFileOffset + +Find where the true file data offset is +==================== +*/ +static qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) +{ + unsigned char buffer [ZIP_LOCAL_CHUNK_BASE_SIZE]; + fs_offset_t count; + + // Already found? + if (pfile->flags & PACKFILE_FLAG_TRUEOFFS) + return true; + + // Load the local file description + lseek (pack->handle, pfile->offset, SEEK_SET); + count = read (pack->handle, buffer, ZIP_LOCAL_CHUNK_BASE_SIZE); + if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffBigLong (buffer) != ZIP_DATA_HEADER) + { + Con_Printf ("Can't retrieve file %s in package %s\n", pfile->name, pack->filename); + return false; + } + + // Skip name and extra field + pfile->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE; + + pfile->flags |= PACKFILE_FLAG_TRUEOFFS; + return true; +} + + +/* +============================================================================= + +OTHER PRIVATE FUNCTIONS + +============================================================================= +*/ + + +/* +==================== +FS_AddFileToPack + +Add a file to the list of files contained into a package +==================== +*/ +static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, + fs_offset_t offset, fs_offset_t packsize, + fs_offset_t realsize, int flags) +{ + int (*strcmp_funct) (const char* str1, const char* str2); + int left, right, middle; + packfile_t *pfile; + + strcmp_funct = pack->ignorecase ? strcasecmp : strcmp; + + // Look for the slot we should put that file into (binary search) + left = 0; + right = pack->numfiles - 1; + while (left <= right) + { + int diff; + + middle = (left + right) / 2; + diff = strcmp_funct (pack->files[middle].name, name); + + // If we found the file, there's a problem + if (!diff) + Con_Printf ("Package %s contains the file %s several times\n", pack->filename, name); + + // If we're too far in the list + if (diff > 0) + right = middle - 1; + else + left = middle + 1; + } + + // We have to move the right of the list by one slot to free the one we need + pfile = &pack->files[left]; + memmove (pfile + 1, pfile, (pack->numfiles - left) * sizeof (*pfile)); + pack->numfiles++; + + strlcpy (pfile->name, name, sizeof (pfile->name)); + pfile->offset = offset; + pfile->packsize = packsize; + pfile->realsize = realsize; + pfile->flags = flags; + + return pfile; +} + + +/* +============ +FS_CreatePath + +Only used for FS_OpenRealFile. +============ +*/ +void FS_CreatePath (char *path) +{ + char *ofs, save; + + for (ofs = path+1 ; *ofs ; ofs++) + { + if (*ofs == '/' || *ofs == '\\') + { + // create the directory + save = *ofs; + *ofs = 0; + FS_mkdir (path); + *ofs = save; + } + } +} + + +/* +============ +FS_Path_f + +============ +*/ +static void FS_Path_f (void) +{ + searchpath_t *s; + + Con_Print("Current search path:\n"); + for (s=fs_searchpaths ; s ; s=s->next) + { + if (s->pack) + { + if(s->pack->vpack) + Con_Printf("%sdir (virtual pack)\n", s->pack->filename); + else + Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles); + } + else + Con_Printf("%s\n", s->filename); + } +} + + +/* +================= +FS_LoadPackPAK +================= +*/ +/*! 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. + */ +static pack_t *FS_LoadPackPAK (const char *packfile) +{ + dpackheader_t header; + int i, numpackfiles; + int packhandle; + pack_t *pack; + dpackfile_t *info; + + packhandle = FS_SysOpenFD(packfile, "rb", false); + if (packhandle < 0) + return NULL; + if(read (packhandle, (void *)&header, sizeof(header)) != sizeof(header)) + { + Con_Printf ("%s is not a packfile\n", packfile); + close(packhandle); + return NULL; + } + if (memcmp(header.id, "PACK", 4)) + { + Con_Printf ("%s is not a packfile\n", packfile); + close(packhandle); + return NULL; + } + header.dirofs = LittleLong (header.dirofs); + header.dirlen = LittleLong (header.dirlen); + + if (header.dirlen % sizeof(dpackfile_t)) + { + Con_Printf ("%s has an invalid directory size\n", packfile); + close(packhandle); + return NULL; + } + + numpackfiles = header.dirlen / sizeof(dpackfile_t); + + if (numpackfiles > MAX_FILES_IN_PACK) + { + Con_Printf ("%s has %i files\n", packfile, numpackfiles); + close(packhandle); + return NULL; + } + + info = (dpackfile_t *)Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles); + lseek (packhandle, header.dirofs, SEEK_SET); + if(header.dirlen != read (packhandle, (void *)info, header.dirlen)) + { + Con_Printf("%s is an incomplete PAK, not loading\n", packfile); + Mem_Free(info); + close(packhandle); + return NULL; + } + + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); + pack->ignorecase = false; // PAK is case sensitive + strlcpy (pack->filename, packfile, sizeof (pack->filename)); + pack->handle = packhandle; + pack->numfiles = 0; + pack->files = (packfile_t *)Mem_Alloc(fs_mempool, numpackfiles * sizeof(packfile_t)); + + // parse the directory + for (i = 0;i < numpackfiles;i++) + { + fs_offset_t offset = (unsigned int)LittleLong (info[i].filepos); + fs_offset_t size = (unsigned int)LittleLong (info[i].filelen); + + FS_AddFileToPack (info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS); + } + + Mem_Free(info); + + Con_DPrintf("Added packfile %s (%i files)\n", packfile, numpackfiles); + return pack; +} + +/* +==================== +FS_LoadPackVirtual + +Create a package entry associated with a directory file +==================== +*/ +static pack_t *FS_LoadPackVirtual (const char *dirname) +{ + pack_t *pack; + pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof (pack_t)); + pack->vpack = true; + pack->ignorecase = false; + strlcpy (pack->filename, dirname, sizeof(pack->filename)); + pack->handle = -1; + pack->numfiles = -1; + pack->files = NULL; + Con_DPrintf("Added packfile %s (virtual pack)\n", dirname); + return pack; +} + +/* +================ +FS_AddPack_Fullpath +================ +*/ +/*! Adds the given pack to the search path. + * The pack type is autodetected by the file extension. + * + * Returns true if the file was successfully added to the + * search path or if it was already included. + * + * If keep_plain_dirs is set, the pack will be added AFTER the first sequence of + * plain directories. + * + */ +static qboolean FS_AddPack_Fullpath(const char *pakfile, const char *shortname, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + searchpath_t *search; + pack_t *pak = NULL; + const char *ext = FS_FileExtension(pakfile); + size_t l; + + for(search = fs_searchpaths; search; search = search->next) + { + if(search->pack && !strcasecmp(search->pack->filename, pakfile)) + { + if(already_loaded) + *already_loaded = true; + return true; // already loaded + } + } + + if(already_loaded) + *already_loaded = false; + + if(!strcasecmp(ext, "pk3dir")) + pak = FS_LoadPackVirtual (pakfile); + else if(!strcasecmp(ext, "pak")) + pak = FS_LoadPackPAK (pakfile); + else if(!strcasecmp(ext, "pk3")) + pak = FS_LoadPackPK3 (pakfile); + else + Con_Printf("\"%s\" does not have a pack extension\n", pakfile); + + if(pak) + { + strlcpy(pak->shortname, shortname, sizeof(pak->shortname)); + + //Con_DPrintf(" Registered pack with short name %s\n", shortname); + if(keep_plain_dirs) + { + // find the first item whose next one is a pack or NULL + searchpath_t *insertion_point = 0; + if(fs_searchpaths && !fs_searchpaths->pack) + { + insertion_point = fs_searchpaths; + for(;;) + { + if(!insertion_point->next) + break; + if(insertion_point->next->pack) + break; + insertion_point = insertion_point->next; + } + } + // If insertion_point is NULL, this means that either there is no + // item in the list yet, or that the very first item is a pack. In + // that case, we want to insert at the beginning... + if(!insertion_point) + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->next = fs_searchpaths; + fs_searchpaths = search; + } + else + // otherwise we want to append directly after insertion_point. + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->next = insertion_point->next; + insertion_point->next = search; + } + } + else + { + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->next = fs_searchpaths; + fs_searchpaths = search; + } + search->pack = pak; + if(pak->vpack) + { + dpsnprintf(search->filename, sizeof(search->filename), "%s/", pakfile); + // if shortname ends with "pk3dir", strip that suffix to make it just "pk3" + // same goes for the name inside the pack structure + l = strlen(pak->shortname); + if(l >= 7) + if(!strcasecmp(pak->shortname + l - 7, ".pk3dir")) + pak->shortname[l - 3] = 0; + l = strlen(pak->filename); + if(l >= 7) + if(!strcasecmp(pak->filename + l - 7, ".pk3dir")) + pak->filename[l - 3] = 0; + } + return true; + } + else + { + Con_Printf("unable to load pak \"%s\"\n", pakfile); + return false; + } +} + + +/* +================ +FS_AddPack +================ +*/ +/*! Adds the given pack to the search path and searches for it in the game path. + * The pack type is autodetected by the file extension. + * + * Returns true if the file was successfully added to the + * search path or if it was already included. + * + * If keep_plain_dirs is set, the pack will be added AFTER the first sequence of + * plain directories. + */ +qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs) +{ + char fullpath[MAX_OSPATH]; + int index; + searchpath_t *search; + + if(already_loaded) + *already_loaded = false; + + // then find the real name... + search = FS_FindFile(pakfile, &index, true); + if(!search || search->pack) + { + Con_Printf("could not find pak \"%s\"\n", pakfile); + return false; + } + + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", search->filename, pakfile); + + return FS_AddPack_Fullpath(fullpath, pakfile, already_loaded, keep_plain_dirs); +} + + +/* +================ +FS_AddGameDirectory + +Sets fs_gamedir, adds the directory to the head of the path, +then loads and adds pak1.pak pak2.pak ... +================ +*/ +static void FS_AddGameDirectory (const char *dir) +{ + int i; + stringlist_t list; + searchpath_t *search; + + strlcpy (fs_gamedir, dir, sizeof (fs_gamedir)); + + stringlistinit(&list); + listdirectory(&list, "", dir); + stringlistsort(&list, false); + + // add any PAK package in the directory + for (i = 0;i < list.numstrings;i++) + { + if (!strcasecmp(FS_FileExtension(list.strings[i]), "pak")) + { + FS_AddPack_Fullpath(list.strings[i], list.strings[i] + strlen(dir), NULL, false); + } + } + + // add any PK3 package in the directory + for (i = 0;i < list.numstrings;i++) + { + if (!strcasecmp(FS_FileExtension(list.strings[i]), "pk3") || !strcasecmp(FS_FileExtension(list.strings[i]), "pk3dir")) + { + FS_AddPack_Fullpath(list.strings[i], list.strings[i] + strlen(dir), NULL, false); + } + } + + stringlistfreecontents(&list); + + // Add the directory to the search path + // (unpacked files have the priority over packed files) + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + strlcpy (search->filename, dir, sizeof (search->filename)); + search->next = fs_searchpaths; + fs_searchpaths = search; +} + + +/* +================ +FS_AddGameHierarchy +================ +*/ +static void FS_AddGameHierarchy (const char *dir) +{ + char vabuf[1024]; + // Add the common game directory + FS_AddGameDirectory (va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, dir)); + + if (*fs_userdir) + FS_AddGameDirectory(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, dir)); +} + + +/* +============ +FS_FileExtension +============ +*/ +const char *FS_FileExtension (const char *in) +{ + const char *separator, *backslash, *colon, *dot; + + separator = strrchr(in, '/'); + backslash = strrchr(in, '\\'); + if (!separator || separator < backslash) + separator = backslash; + colon = strrchr(in, ':'); + if (!separator || separator < colon) + separator = colon; + + dot = strrchr(in, '.'); + if (dot == NULL || (separator && (dot < separator))) + return ""; + + return dot + 1; +} + + +/* +============ +FS_FileWithoutPath +============ +*/ +const char *FS_FileWithoutPath (const char *in) +{ + const char *separator, *backslash, *colon; + + separator = strrchr(in, '/'); + backslash = strrchr(in, '\\'); + if (!separator || separator < backslash) + separator = backslash; + colon = strrchr(in, ':'); + if (!separator || separator < colon) + separator = colon; + return separator ? separator + 1 : in; +} + + +/* +================ +FS_ClearSearchPath +================ +*/ +static void FS_ClearSearchPath (void) +{ + // unload all packs and directory information, close all pack files + // (if a qfile is still reading a pack it won't be harmed because it used + // dup() to get its own handle already) + while (fs_searchpaths) + { + searchpath_t *search = fs_searchpaths; + fs_searchpaths = search->next; + if (search->pack && search->pack != fs_selfpack) + { + if(!search->pack->vpack) + { + // close the file + close(search->pack->handle); + // free any memory associated with it + if (search->pack->files) + Mem_Free(search->pack->files); + } + Mem_Free(search->pack); + } + Mem_Free(search); + } +} + +static void FS_AddSelfPack(void) +{ + if(fs_selfpack) + { + searchpath_t *search; + search = (searchpath_t *)Mem_Alloc(fs_mempool, sizeof(searchpath_t)); + search->next = fs_searchpaths; + search->pack = fs_selfpack; + fs_searchpaths = search; + } +} + + +/* +================ +FS_Rescan +================ +*/ +void FS_Rescan (void) +{ + int i; + qboolean fs_modified = false; + qboolean reset = false; + char gamedirbuf[MAX_INPUTLINE]; + char vabuf[1024]; + + if (fs_searchpaths) + reset = true; + FS_ClearSearchPath(); + + // automatically activate gamemode for the gamedirs specified + if (reset) + COM_ChangeGameTypeForGameDirs(); + + // add the game-specific paths + // gamedirname1 (typically id1) + FS_AddGameHierarchy (gamedirname1); + // update the com_modname (used for server info) + if (gamedirname2 && gamedirname2[0]) + strlcpy(com_modname, gamedirname2, sizeof(com_modname)); + else + strlcpy(com_modname, gamedirname1, sizeof(com_modname)); + + // add the game-specific path, if any + // (only used for mission packs and the like, which should set fs_modified) + if (gamedirname2 && gamedirname2[0]) + { + fs_modified = true; + FS_AddGameHierarchy (gamedirname2); + } + + // -game + // Adds basedir/gamedir as an override game + // LordHavoc: now supports multiple -game directories + // set the com_modname (reported in server info) + *gamedirbuf = 0; + for (i = 0;i < fs_numgamedirs;i++) + { + fs_modified = true; + FS_AddGameHierarchy (fs_gamedirs[i]); + // update the com_modname (used server info) + strlcpy (com_modname, fs_gamedirs[i], sizeof (com_modname)); + if(i) + strlcat(gamedirbuf, va(vabuf, sizeof(vabuf), " %s", fs_gamedirs[i]), sizeof(gamedirbuf)); + else + strlcpy(gamedirbuf, fs_gamedirs[i], sizeof(gamedirbuf)); + } + Cvar_SetQuick(&cvar_fs_gamedir, gamedirbuf); // so QC or console code can query it + + // add back the selfpack as new first item + FS_AddSelfPack(); + + // set the default screenshot name to either the mod name or the + // gamemode screenshot name + if (strcmp(com_modname, gamedirname1)) + Cvar_SetQuick (&scr_screenshot_name, com_modname); + else + Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname); + + if((i = COM_CheckParm("-modname")) && i < com_argc - 1) + strlcpy(com_modname, com_argv[i+1], sizeof(com_modname)); + + // If "-condebug" is in the command line, remove the previous log file + if (COM_CheckParm ("-condebug") != 0) + unlink (va(vabuf, sizeof(vabuf), "%s/qconsole.log", fs_gamedir)); + + // look for the pop.lmp file and set registered to true if it is found + if (FS_FileExists("gfx/pop.lmp")) + Cvar_Set ("registered", "1"); + switch(gamemode) + { + case GAME_NORMAL: + case GAME_HIPNOTIC: + case GAME_ROGUE: + if (!registered.integer) + { + if (fs_modified) + Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n"); + else + Con_Print("Playing shareware version.\n"); + } + else + Con_Print("Playing registered version.\n"); + break; + case GAME_STEELSTORM: + if (registered.integer) + Con_Print("Playing registered version.\n"); + else + Con_Print("Playing shareware version.\n"); + break; + default: + break; + } + + // unload all wads so that future queries will return the new data + W_UnloadAll(); +} + +static void FS_Rescan_f(void) +{ + FS_Rescan(); +} + +/* +================ +FS_ChangeGameDirs +================ +*/ +extern qboolean vid_opened; +qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean complain, qboolean failmissing) +{ + int i; + const char *p; + + if (fs_numgamedirs == numgamedirs) + { + for (i = 0;i < numgamedirs;i++) + if (strcasecmp(fs_gamedirs[i], gamedirs[i])) + break; + if (i == numgamedirs) + return true; // already using this set of gamedirs, do nothing + } + + if (numgamedirs > MAX_GAMEDIRS) + { + if (complain) + Con_Printf("That is too many gamedirs (%i > %i)\n", numgamedirs, MAX_GAMEDIRS); + return false; // too many gamedirs + } + + for (i = 0;i < numgamedirs;i++) + { + // if string is nasty, reject it + p = FS_CheckGameDir(gamedirs[i]); + if(!p) + { + if (complain) + Con_Printf("Nasty gamedir name rejected: %s\n", gamedirs[i]); + return false; // nasty gamedirs + } + if(p == fs_checkgamedir_missing && failmissing) + { + if (complain) + Con_Printf("Gamedir missing: %s%s/\n", fs_basedir, gamedirs[i]); + return false; // missing gamedirs + } + } + + Host_SaveConfig(); + + fs_numgamedirs = numgamedirs; + for (i = 0;i < fs_numgamedirs;i++) + strlcpy(fs_gamedirs[i], gamedirs[i], sizeof(fs_gamedirs[i])); + + // reinitialize filesystem to detect the new paks + FS_Rescan(); + + if (cls.demoplayback) + { + CL_Disconnect_f(); + cls.demonum = 0; + } + + // unload all sounds so they will be reloaded from the new files as needed + S_UnloadAllSounds_f(); + + // close down the video subsystem, it will start up again when the config finishes... + VID_Stop(); + vid_opened = false; + + // restart the video subsystem after the config is executed + Cbuf_InsertText("\nloadconfig\nvid_restart\n\n"); + + return true; +} + +/* +================ +FS_GameDir_f +================ +*/ +static void FS_GameDir_f (void) +{ + int i; + int numgamedirs; + char gamedirs[MAX_GAMEDIRS][MAX_QPATH]; + + if (Cmd_Argc() < 2) + { + Con_Printf("gamedirs active:"); + for (i = 0;i < fs_numgamedirs;i++) + Con_Printf(" %s", fs_gamedirs[i]); + Con_Printf("\n"); + return; + } + + numgamedirs = Cmd_Argc() - 1; + if (numgamedirs > MAX_GAMEDIRS) + { + Con_Printf("Too many gamedirs (%i > %i)\n", numgamedirs, MAX_GAMEDIRS); + return; + } + + for (i = 0;i < numgamedirs;i++) + strlcpy(gamedirs[i], Cmd_Argv(i+1), sizeof(gamedirs[i])); + + if ((cls.state == ca_connected && !cls.demoplayback) || sv.active) + { + // actually, changing during game would work fine, but would be stupid + Con_Printf("Can not change gamedir while client is connected or server is running!\n"); + return; + } + + // halt demo playback to close the file + CL_Disconnect(); + + FS_ChangeGameDirs(numgamedirs, gamedirs, true, true); +} + +static const char *FS_SysCheckGameDir(const char *gamedir, char *buf, size_t buflength) +{ + qboolean success; + qfile_t *f; + stringlist_t list; + fs_offset_t n; + char vabuf[1024]; + + stringlistinit(&list); + listdirectory(&list, gamedir, ""); + success = list.numstrings > 0; + stringlistfreecontents(&list); + + if(success) + { + f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%smodinfo.txt", gamedir), "r", false); + if(f) + { + n = FS_Read (f, buf, buflength - 1); + if(n >= 0) + buf[n] = 0; + else + *buf = 0; + FS_Close(f); + } + else + *buf = 0; + return buf; + } + + return NULL; +} + +/* +================ +FS_CheckGameDir +================ +*/ +const char *FS_CheckGameDir(const char *gamedir) +{ + const char *ret; + char buf[8192]; + char vabuf[1024]; + + if (FS_CheckNastyPath(gamedir, true)) + return NULL; + + ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_userdir, gamedir), buf, sizeof(buf)); + if(ret) + { + if(!*ret) + { + // get description from basedir + ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, gamedir), buf, sizeof(buf)); + if(ret) + return ret; + return ""; + } + return ret; + } + + ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, gamedir), buf, sizeof(buf)); + if(ret) + return ret; + + return fs_checkgamedir_missing; +} + +static void FS_ListGameDirs(void) +{ + stringlist_t list, list2; + int i; + const char *info; + char vabuf[1024]; + + fs_all_gamedirs_count = 0; + if(fs_all_gamedirs) + Mem_Free(fs_all_gamedirs); + + stringlistinit(&list); + listdirectory(&list, va(vabuf, sizeof(vabuf), "%s/", fs_basedir), ""); + listdirectory(&list, va(vabuf, sizeof(vabuf), "%s/", fs_userdir), ""); + stringlistsort(&list, false); + + stringlistinit(&list2); + for(i = 0; i < list.numstrings; ++i) + { + if(i) + if(!strcmp(list.strings[i-1], list.strings[i])) + continue; + info = FS_CheckGameDir(list.strings[i]); + if(!info) + continue; + if(info == fs_checkgamedir_missing) + continue; + if(!*info) + continue; + stringlistappend(&list2, list.strings[i]); + } + stringlistfreecontents(&list); + + fs_all_gamedirs = (gamedir_t *)Mem_Alloc(fs_mempool, list2.numstrings * sizeof(*fs_all_gamedirs)); + for(i = 0; i < list2.numstrings; ++i) + { + info = FS_CheckGameDir(list2.strings[i]); + // all this cannot happen any more, but better be safe than sorry + if(!info) + continue; + if(info == fs_checkgamedir_missing) + continue; + if(!*info) + continue; + strlcpy(fs_all_gamedirs[fs_all_gamedirs_count].name, list2.strings[i], sizeof(fs_all_gamedirs[fs_all_gamedirs_count].name)); + strlcpy(fs_all_gamedirs[fs_all_gamedirs_count].description, info, sizeof(fs_all_gamedirs[fs_all_gamedirs_count].description)); + ++fs_all_gamedirs_count; + } +} + +/* +#ifdef WIN32 +#pragma comment(lib, "shell32.lib") +#include +#endif +*/ + +/* +================ +FS_Init_SelfPack +================ +*/ +void FS_Init_SelfPack (void) +{ + PK3_OpenLibrary (); + fs_mempool = Mem_AllocPool("file management", 0, NULL); + if(com_selffd >= 0) + { + fs_selfpack = FS_LoadPackPK3FromFD(com_argv[0], com_selffd, true); + if(fs_selfpack) + { + char *buf, *q; + const char *p; + FS_AddSelfPack(); + buf = (char *) FS_LoadFile("darkplaces.opt", tempmempool, true, NULL); + if(buf) + { + const char **new_argv; + int i = 0; + int args_left = 256; + new_argv = (const char **)Mem_Alloc(fs_mempool, sizeof(*com_argv) * (com_argc + args_left + 2)); + if(com_argc == 0) + { + new_argv[0] = "dummy"; + com_argc = 1; + } + else + { + memcpy((char *)(&new_argv[0]), &com_argv[0], sizeof(*com_argv) * com_argc); + } + p = buf; + while(COM_ParseToken_Console(&p)) + { + size_t sz = strlen(com_token) + 1; // shut up clang + if(i >= args_left) + break; + q = (char *)Mem_Alloc(fs_mempool, sz); + strlcpy(q, com_token, sz); + new_argv[com_argc + i] = q; + ++i; + } + new_argv[i+com_argc] = NULL; + com_argv = new_argv; + com_argc = com_argc + i; + } + Mem_Free(buf); + } + } +} + +static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsize) +{ +#if defined(__IPHONEOS__) + if (userdirmode == USERDIRMODE_HOME) + { + // fs_basedir is "" by default, to utilize this you can simply add your gamedir to the Resources in xcode + // fs_userdir stores configurations to the Documents folder of the app + strlcpy(userdir, maxlength, "../Documents/"); + return 1; + } + return -1; + +#elif defined(WIN32) + char *homedir; +#if _MSC_VER >= 1400 + size_t homedirlen; +#endif + TCHAR mydocsdir[MAX_PATH + 1]; + wchar_t *savedgamesdirw; + char savedgamesdir[MAX_OSPATH]; + int fd; + char vabuf[1024]; + + userdir[0] = 0; + switch(userdirmode) + { + default: + return -1; + case USERDIRMODE_NOHOME: + strlcpy(userdir, fs_basedir, userdirsize); + break; + case USERDIRMODE_MYGAMES: + if (!shfolder_dll) + Sys_LoadLibrary(shfolderdllnames, &shfolder_dll, shfolderfuncs); + mydocsdir[0] = 0; + if (qSHGetFolderPath && qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir) == S_OK) + { + dpsnprintf(userdir, userdirsize, "%s/My Games/%s/", mydocsdir, gameuserdirname); + break; + } +#if _MSC_VER >= 1400 + _dupenv_s(&homedir, &homedirlen, "USERPROFILE"); + if(homedir) + { + dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname); + free(homedir); + break; + } +#else + homedir = getenv("USERPROFILE"); + if(homedir) + { + dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname); + break; + } +#endif + return -1; + case USERDIRMODE_SAVEDGAMES: + if (!shell32_dll) + Sys_LoadLibrary(shell32dllnames, &shell32_dll, shell32funcs); + if (!ole32_dll) + Sys_LoadLibrary(ole32dllnames, &ole32_dll, ole32funcs); + if (qSHGetKnownFolderPath && qCoInitializeEx && qCoTaskMemFree && qCoUninitialize) + { + savedgamesdir[0] = 0; + qCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +/* +#ifdef __cplusplus + if (SHGetKnownFolderPath(FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK) +#else + if (SHGetKnownFolderPath(&FOLDERID_SavedGames, KF_FLAG_CREATE | KF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK) +#endif +*/ + if (qSHGetKnownFolderPath(&qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK) + { + memset(savedgamesdir, 0, sizeof(savedgamesdir)); +#if _MSC_VER >= 1400 + wcstombs_s(NULL, savedgamesdir, sizeof(savedgamesdir), savedgamesdirw, sizeof(savedgamesdir)-1); +#else + wcstombs(savedgamesdir, savedgamesdirw, sizeof(savedgamesdir)-1); +#endif + qCoTaskMemFree(savedgamesdirw); + } + qCoUninitialize(); + if (savedgamesdir[0]) + { + dpsnprintf(userdir, userdirsize, "%s/%s/", savedgamesdir, gameuserdirname); + break; + } + } + return -1; + } +#else + int fd; + char *homedir; + char vabuf[1024]; + userdir[0] = 0; + switch(userdirmode) + { + default: + return -1; + case USERDIRMODE_NOHOME: + strlcpy(userdir, fs_basedir, userdirsize); + break; + case USERDIRMODE_HOME: + homedir = NULL;//Android + if(homedir) + { + dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname); + break; + } + return -1; + case USERDIRMODE_SAVEDGAMES: + homedir = NULL;//Android + if(homedir) + { +#ifdef MACOSX + dpsnprintf(userdir, userdirsize, "%s/Library/Application Support/%s/", homedir, gameuserdirname); +#else + // the XDG say some files would need to go in: + // XDG_CONFIG_HOME (or ~/.config/%s/) + // XDG_DATA_HOME (or ~/.local/share/%s/) + // XDG_CACHE_HOME (or ~/.cache/%s/) + // and also search the following global locations if defined: + // XDG_CONFIG_DIRS (normally /etc/xdg/%s/) + // XDG_DATA_DIRS (normally /usr/share/%s/) + // this would be too complicated... + return -1; +#endif + break; + } + return -1; + } +#endif + + +#ifdef WIN32 + // historical behavior... + if (userdirmode == USERDIRMODE_NOHOME && strcmp(gamedirname1, "id1")) + return 0; // don't bother checking if the basedir folder is writable, it's annoying... unless it is Quake on Windows where NOHOME is the default preferred and we have to check for an error case +#endif + + // see if we can write to this path (note: won't create path) +#ifdef WIN32 + // no access() here, we must try to open the file for appending + fd = FS_SysOpenFD(va(vabuf, sizeof(vabuf), "%s%s/config.cfg", userdir, gamedirname1), "a", false); + if(fd >= 0) + close(fd); +#else + // on Unix, we don't need to ACTUALLY attempt to open the file + if(access(va(vabuf, sizeof(vabuf), "%s%s/", userdir, gamedirname1), W_OK | X_OK) >= 0) + fd = 1; + else + fd = 0; +#endif + if(fd >= 0) + { + return 1; // good choice - the path exists and is writable + } + else + { + if (userdirmode == USERDIRMODE_NOHOME) + return -1; // path usually already exists, we lack permissions + else + return 0; // probably good - failed to write but maybe we need to create path + } +} + +/* +================ +FS_Init +================ +*/ +void FS_Init (void) +{ + const char *p; + int i; + + *fs_basedir = 0; + *fs_userdir = 0; + *fs_gamedir = 0; + + // -basedir + // Overrides the system supplied base directory (under GAMENAME) +// COMMANDLINEOPTION: Filesystem: -basedir chooses what base directory the game data is in, inside this there should be a data directory for the game (for example id1) + i = COM_CheckParm ("-basedir"); + if (i && i < com_argc-1) + { + strlcpy (fs_basedir, com_argv[i+1], sizeof (fs_basedir)); + i = (int)strlen (fs_basedir); + if (i > 0 && (fs_basedir[i-1] == '\\' || fs_basedir[i-1] == '/')) + fs_basedir[i-1] = 0; + } + else + { +// If the base directory is explicitly defined by the compilation process +#ifdef DP_FS_BASEDIR + strlcpy(fs_basedir, DP_FS_BASEDIR, sizeof(fs_basedir)); +#elif defined(MACOSX) + // FIXME: is there a better way to find the directory outside the .app, without using Objective-C? + if (strstr(com_argv[0], ".app/")) + { + char *split; + strlcpy(fs_basedir, com_argv[0], sizeof(fs_basedir)); + split = strstr(fs_basedir, ".app/"); + if (split) + { + struct stat statresult; + char vabuf[1024]; + // truncate to just after the .app/ + split[5] = 0; + // see if gamedir exists in Resources + if (stat(va(vabuf, sizeof(vabuf), "%s/Contents/Resources/%s", fs_basedir, gamedirname1), &statresult) == 0) + { + // found gamedir inside Resources, use it + strlcat(fs_basedir, "Contents/Resources/", sizeof(fs_basedir)); + } + else + { + // no gamedir found in Resources, gamedir is probably + // outside the .app, remove .app part of path + while (split > fs_basedir && *split != '/') + split--; + *split = 0; + } + } + } +#endif + } + + // make sure the appending of a path separator won't create an unterminated string + memset(fs_basedir + sizeof(fs_basedir) - 2, 0, 2); + // add a path separator to the end of the basedir if it lacks one + if (fs_basedir[0] && fs_basedir[strlen(fs_basedir) - 1] != '/' && fs_basedir[strlen(fs_basedir) - 1] != '\\') + strlcat(fs_basedir, "/", sizeof(fs_basedir)); + + // Add the personal game directory + if((i = COM_CheckParm("-userdir")) && i < com_argc - 1) + dpsnprintf(fs_userdir, sizeof(fs_userdir), "%s/", com_argv[i+1]); + else if (COM_CheckParm("-nohome")) + *fs_userdir = 0; // user wants roaming installation, no userdir + else + { + int dirmode; + int highestuserdirmode = USERDIRMODE_COUNT - 1; + int preferreduserdirmode = USERDIRMODE_COUNT - 1; + int userdirstatus[USERDIRMODE_COUNT]; +#ifdef WIN32 + // historical behavior... + if (!strcmp(gamedirname1, "id1")) + preferreduserdirmode = USERDIRMODE_NOHOME; +#endif + // check what limitations the user wants to impose + if (COM_CheckParm("-home")) preferreduserdirmode = USERDIRMODE_HOME; + if (COM_CheckParm("-mygames")) preferreduserdirmode = USERDIRMODE_MYGAMES; + if (COM_CheckParm("-savedgames")) preferreduserdirmode = USERDIRMODE_SAVEDGAMES; + // gather the status of the possible userdirs + for (dirmode = 0;dirmode < USERDIRMODE_COUNT;dirmode++) + { + userdirstatus[dirmode] = FS_ChooseUserDir((userdirmode_t)dirmode, fs_userdir, sizeof(fs_userdir)); + if (userdirstatus[dirmode] == 1) + Con_DPrintf("userdir %i = %s (writable)\n", dirmode, fs_userdir); + else if (userdirstatus[dirmode] == 0) + Con_DPrintf("userdir %i = %s (not writable or does not exist)\n", dirmode, fs_userdir); + else + Con_DPrintf("userdir %i (not applicable)\n", dirmode); + } + // some games may prefer writing to basedir, but if write fails we + // have to search for a real userdir... + if (preferreduserdirmode == 0 && userdirstatus[0] < 1) + preferreduserdirmode = highestuserdirmode; + // check for an existing userdir and continue using it if possible... + for (dirmode = USERDIRMODE_COUNT - 1;dirmode > 0;dirmode--) + if (userdirstatus[dirmode] == 1) + break; + // if no existing userdir found, make a new one... + if (dirmode == 0 && preferreduserdirmode > 0) + for (dirmode = preferreduserdirmode;dirmode > 0;dirmode--) + if (userdirstatus[dirmode] >= 0) + break; + // and finally, we picked one... + FS_ChooseUserDir((userdirmode_t)dirmode, fs_userdir, sizeof(fs_userdir)); + Con_DPrintf("userdir %i is the winner\n", dirmode); + } + + // if userdir equal to basedir, clear it to avoid confusion later + if (!strcmp(fs_basedir, fs_userdir)) + fs_userdir[0] = 0; + + FS_ListGameDirs(); + + p = FS_CheckGameDir(gamedirname1); + if(!p || p == fs_checkgamedir_missing) + Con_Printf("WARNING: base gamedir %s%s/ not found!\n", fs_basedir, gamedirname1); + + if(gamedirname2) + { + p = FS_CheckGameDir(gamedirname2); + if(!p || p == fs_checkgamedir_missing) + Con_Printf("WARNING: base gamedir %s%s/ not found!\n", fs_basedir, gamedirname2); + } + + // -game + // Adds basedir/gamedir as an override game + // LordHavoc: now supports multiple -game directories + for (i = 1;i < com_argc && fs_numgamedirs < MAX_GAMEDIRS;i++) + { + if (!com_argv[i]) + continue; + if (!strcmp (com_argv[i], "-game") && i < com_argc-1) + { + i++; + p = FS_CheckGameDir(com_argv[i]); + if(!p) + Sys_Error("Nasty -game name rejected: %s", com_argv[i]); + if(p == fs_checkgamedir_missing) + Con_Printf("WARNING: -game %s%s/ not found!\n", fs_basedir, com_argv[i]); + // add the gamedir to the list of active gamedirs + strlcpy (fs_gamedirs[fs_numgamedirs], com_argv[i], sizeof(fs_gamedirs[fs_numgamedirs])); + fs_numgamedirs++; + } + } + + // generate the searchpath + FS_Rescan(); + + if (Thread_HasThreads()) + fs_mutex = Thread_CreateMutex(); +} + +void FS_Init_Commands(void) +{ + Cvar_RegisterVariable (&scr_screenshot_name); + Cvar_RegisterVariable (&fs_empty_files_in_pack_mark_deletions); + Cvar_RegisterVariable (&cvar_fs_gamedir); + + Cmd_AddCommand ("gamedir", FS_GameDir_f, "changes active gamedir list (can take multiple arguments), not including base directory (example usage: gamedir ctf)"); + Cmd_AddCommand ("fs_rescan", FS_Rescan_f, "rescans filesystem for new pack archives and any other changes"); + Cmd_AddCommand ("path", FS_Path_f, "print searchpath (game directories and archives)"); + Cmd_AddCommand ("dir", FS_Dir_f, "list files in searchpath matching an * filename pattern, one per line"); + Cmd_AddCommand ("ls", FS_Ls_f, "list files in searchpath matching an * filename pattern, multiple per line"); + Cmd_AddCommand ("which", FS_Which_f, "accepts a file name as argument and reports where the file is taken from"); +} + +/* +================ +FS_Shutdown +================ +*/ +void FS_Shutdown (void) +{ + // close all pack files and such + // (hopefully there aren't any other open files, but they'll be cleaned up + // by the OS anyway) + FS_ClearSearchPath(); + Mem_FreePool (&fs_mempool); + PK3_CloseLibrary (); + +#ifdef WIN32 + Sys_UnloadLibrary (&shfolder_dll); + Sys_UnloadLibrary (&shell32_dll); + Sys_UnloadLibrary (&ole32_dll); +#endif + + if (fs_mutex) + Thread_DestroyMutex(fs_mutex); +} + +int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking) +{ + int handle = -1; + int mod, opt; + unsigned int ind; + qboolean dolock = false; + + // Parse the mode string + switch (mode[0]) + { + case 'r': + mod = O_RDONLY; + opt = 0; + break; + case 'w': + mod = O_WRONLY; + opt = O_CREAT | O_TRUNC; + break; + case 'a': + mod = O_WRONLY; + opt = O_CREAT | O_APPEND; + break; + default: + Con_Printf ("FS_SysOpen(%s, %s): invalid mode\n", filepath, mode); + return -1; + } + for (ind = 1; mode[ind] != '\0'; ind++) + { + switch (mode[ind]) + { + case '+': + mod = O_RDWR; + break; + case 'b': + opt |= O_BINARY; + break; + case 'l': + dolock = true; + break; + default: + Con_Printf ("FS_SysOpen(%s, %s): unknown character in mode (%c)\n", + filepath, mode, mode[ind]); + } + } + + if (nonblocking) + opt |= O_NONBLOCK; + + if(COM_CheckParm("-readonly") && mod != O_RDONLY) + return -1; + +#ifdef WIN32 +# if _MSC_VER >= 1400 + _sopen_s(&handle, filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE); +# else + handle = _sopen (filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE); +# endif +#else + handle = open (filepath, mod | opt, 0666); + if(handle >= 0 && dolock) + { + struct flock l; + l.l_type = ((mod == O_RDONLY) ? F_RDLCK : F_WRLCK); + l.l_whence = SEEK_SET; + l.l_start = 0; + l.l_len = 0; + if(fcntl(handle, F_SETLK, &l) == -1) + { + close(handle); + handle = -1; + } + } +#endif + + return handle; +} + +/* +==================== +FS_SysOpen + +Internal function used to create a qfile_t and open the relevant non-packed file on disk +==================== +*/ +qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking) +{ + qfile_t* file; + + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); + file->ungetc = EOF; + file->handle = FS_SysOpenFD(filepath, mode, nonblocking); + if (file->handle < 0) + { + Mem_Free (file); + return NULL; + } + + file->filename = Mem_strdup(fs_mempool, filepath); + + file->real_length = lseek (file->handle, 0, SEEK_END); + + // For files opened in append mode, we start at the end of the file + if (mode[0] == 'a') + file->position = file->real_length; + else + lseek (file->handle, 0, SEEK_SET); + + return file; +} + + +/* +=========== +FS_OpenPackedFile + +Open a packed file using its package file descriptor +=========== +*/ +static qfile_t *FS_OpenPackedFile (pack_t* pack, int pack_ind) +{ + packfile_t *pfile; + int dup_handle; + qfile_t* file; + + pfile = &pack->files[pack_ind]; + + // If we don't have the true offset, get it now + if (! (pfile->flags & PACKFILE_FLAG_TRUEOFFS)) + if (!PK3_GetTrueFileOffset (pfile, pack)) + return NULL; + +#ifndef LINK_TO_ZLIB + // No Zlib DLL = no compressed files + if (!zlib_dll && (pfile->flags & PACKFILE_FLAG_DEFLATED)) + { + Con_Printf("WARNING: can't open the compressed file %s\n" + "You need the Zlib DLL to use compressed files\n", + pfile->name); + return NULL; + } +#endif + + // LordHavoc: lseek affects all duplicates of a handle so we do it before + // the dup() call to avoid having to close the dup_handle on error here + if (lseek (pack->handle, pfile->offset, SEEK_SET) == -1) + { + Con_Printf ("FS_OpenPackedFile: can't lseek to %s in %s (offset: %08x%08x)\n", + pfile->name, pack->filename, (unsigned int)(pfile->offset >> 32), (unsigned int)(pfile->offset)); + return NULL; + } + + dup_handle = dup (pack->handle); + if (dup_handle < 0) + { + Con_Printf ("FS_OpenPackedFile: can't dup package's handle (pack: %s)\n", pack->filename); + return NULL; + } + + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); + memset (file, 0, sizeof (*file)); + file->handle = dup_handle; + file->flags = QFILE_FLAG_PACKED; + file->real_length = pfile->realsize; + file->offset = pfile->offset; + file->position = 0; + file->ungetc = EOF; + + if (pfile->flags & PACKFILE_FLAG_DEFLATED) + { + ztoolkit_t *ztk; + + file->flags |= QFILE_FLAG_DEFLATED; + + // We need some more variables + ztk = (ztoolkit_t *)Mem_Alloc (fs_mempool, sizeof (*ztk)); + + ztk->comp_length = pfile->packsize; + + // Initialize zlib stream + ztk->zstream.next_in = ztk->input; + ztk->zstream.avail_in = 0; + + /* From Zlib's "unzip.c": + * + * windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + if (qz_inflateInit2 (&ztk->zstream, -MAX_WBITS) != Z_OK) + { + Con_Printf ("FS_OpenPackedFile: inflate init error (file: %s)\n", pfile->name); + close(dup_handle); + Mem_Free(file); + return NULL; + } + + ztk->zstream.next_out = file->buff; + ztk->zstream.avail_out = sizeof (file->buff); + + file->ztk = ztk; + } + + return file; +} + +/* +==================== +FS_CheckNastyPath + +Return true if the path should be rejected due to one of the following: +1: path elements that are non-portable +2: path elements that would allow access to files outside the game directory, + or are just not a good idea for a mod to be using. +==================== +*/ +int FS_CheckNastyPath (const char *path, qboolean isgamedir) +{ + // all: never allow an empty path, as for gamedir it would access the parent directory and a non-gamedir path it is just useless + if (!path[0]) + return 2; + + // Windows: don't allow \ in filenames (windows-only), period. + // (on Windows \ is a directory separator, but / is also supported) + if (strstr(path, "\\")) + return 1; // non-portable + + // Mac: don't allow Mac-only filenames - : is a directory separator + // instead of /, but we rely on / working already, so there's no reason to + // support a Mac-only path + // Amiga and Windows: : tries to go to root of drive + if (strstr(path, ":")) + return 1; // non-portable attempt to go to root of drive + + // Amiga: // is parent directory + if (strstr(path, "//")) + return 1; // non-portable attempt to go to parent directory + + // all: don't allow going to parent directory (../ or /../) + if (strstr(path, "..")) + return 2; // attempt to go outside the game directory + + // Windows and UNIXes: don't allow absolute paths + if (path[0] == '/') + return 2; // attempt to go outside the game directory + + // all: don't allow . characters before the last slash (it should only be used in filenames, not path elements), this catches all imaginable cases of ./, ../, .../, etc + if (strchr(path, '.')) + { + if (isgamedir) + { + // gamedir is entirely path elements, so simply forbid . entirely + return 2; + } + if (strchr(path, '.') < strrchr(path, '/')) + return 2; // possible attempt to go outside the game directory + } + + // all: forbid trailing slash on gamedir + if (isgamedir && path[strlen(path)-1] == '/') + return 2; + + // all: forbid leading dot on any filename for any reason + if (strstr(path, "/.")) + return 2; // attempt to go outside the game directory + + // after all these checks we're pretty sure it's a / separated filename + // and won't do much if any harm + return false; +} + + +/* +==================== +FS_FindFile + +Look for a file in the packages and in the filesystem + +Return the searchpath where the file was found (or NULL) +and the file index in the package if relevant +==================== +*/ +static searchpath_t *FS_FindFile (const char *name, int* index, qboolean quiet) +{ + searchpath_t *search; + pack_t *pak; + + // search through the path, one element at a time + for (search = fs_searchpaths;search;search = search->next) + { + // is the element a pak file? + if (search->pack && !search->pack->vpack) + { + int (*strcmp_funct) (const char* str1, const char* str2); + int left, right, middle; + + pak = search->pack; + strcmp_funct = pak->ignorecase ? strcasecmp : strcmp; + + // Look for the file (binary search) + left = 0; + right = pak->numfiles - 1; + while (left <= right) + { + int diff; + + middle = (left + right) / 2; + diff = strcmp_funct (pak->files[middle].name, name); + + // Found it + if (!diff) + { + if (fs_empty_files_in_pack_mark_deletions.integer && pak->files[middle].realsize == 0) + { + // yes, but the first one is empty so we treat it as not being there + if (!quiet && developer_extra.integer) + Con_DPrintf("FS_FindFile: %s is marked as deleted\n", name); + + if (index != NULL) + *index = -1; + return NULL; + } + + if (!quiet && developer_extra.integer) + Con_DPrintf("FS_FindFile: %s in %s\n", + pak->files[middle].name, pak->filename); + + if (index != NULL) + *index = middle; + return search; + } + + // If we're too far in the list + if (diff > 0) + right = middle - 1; + else + left = middle + 1; + } + } + else + { + char netpath[MAX_OSPATH]; + dpsnprintf(netpath, sizeof(netpath), "%s%s", search->filename, name); + if (FS_SysFileExists (netpath)) + { + if (!quiet && developer_extra.integer) + Con_DPrintf("FS_FindFile: %s\n", netpath); + + if (index != NULL) + *index = -1; + return search; + } + } + } + + if (!quiet && developer_extra.integer) + Con_DPrintf("FS_FindFile: can't find %s\n", name); + + if (index != NULL) + *index = -1; + return NULL; +} + + +/* +=========== +FS_OpenReadFile + +Look for a file in the search paths and open it in read-only mode +=========== +*/ +static qfile_t *FS_OpenReadFile (const char *filename, qboolean quiet, qboolean nonblocking, int symlinkLevels) +{ + searchpath_t *search; + int pack_ind; + + search = FS_FindFile (filename, &pack_ind, quiet); + + // Not found? + if (search == NULL) + return NULL; + + // Found in the filesystem? + if (pack_ind < 0) + { + // this works with vpacks, so we are fine + char path [MAX_OSPATH]; + dpsnprintf (path, sizeof (path), "%s%s", search->filename, filename); + return FS_SysOpen (path, "rb", nonblocking); + } + + // So, we found it in a package... + + // Is it a PK3 symlink? + // TODO also handle directory symlinks by parsing the whole structure... + // but heck, file symlinks are good enough for now + if(search->pack->files[pack_ind].flags & PACKFILE_FLAG_SYMLINK) + { + if(symlinkLevels <= 0) + { + Con_Printf("symlink: %s: too many levels of symbolic links\n", filename); + return NULL; + } + else + { + char linkbuf[MAX_QPATH]; + fs_offset_t count; + qfile_t *linkfile = FS_OpenPackedFile (search->pack, pack_ind); + const char *mergeslash; + char *mergestart; + + if(!linkfile) + return NULL; + count = FS_Read(linkfile, linkbuf, sizeof(linkbuf) - 1); + FS_Close(linkfile); + if(count < 0) + return NULL; + linkbuf[count] = 0; + + // Now combine the paths... + mergeslash = strrchr(filename, '/'); + mergestart = linkbuf; + if(!mergeslash) + mergeslash = filename; + while(!strncmp(mergestart, "../", 3)) + { + mergestart += 3; + while(mergeslash > filename) + { + --mergeslash; + if(*mergeslash == '/') + break; + } + } + // Now, mergestart will point to the path to be appended, and mergeslash points to where it should be appended + if(mergeslash == filename) + { + // Either mergeslash == filename, then we just replace the name (done below) + } + else + { + // Or, we append the name after mergeslash; + // or rather, we can also shift the linkbuf so we can put everything up to and including mergeslash first + int spaceNeeded = mergeslash - filename + 1; + int spaceRemoved = mergestart - linkbuf; + if(count - spaceRemoved + spaceNeeded >= MAX_QPATH) + { + Con_DPrintf("symlink: too long path rejected\n"); + return NULL; + } + memmove(linkbuf + spaceNeeded, linkbuf + spaceRemoved, count - spaceRemoved); + memcpy(linkbuf, filename, spaceNeeded); + linkbuf[count - spaceRemoved + spaceNeeded] = 0; + mergestart = linkbuf; + } + if (!quiet && developer_loading.integer) + Con_DPrintf("symlink: %s -> %s\n", filename, mergestart); + if(FS_CheckNastyPath (mergestart, false)) + { + Con_DPrintf("symlink: nasty path %s rejected\n", mergestart); + return NULL; + } + return FS_OpenReadFile(mergestart, quiet, nonblocking, symlinkLevels - 1); + } + } + + return FS_OpenPackedFile (search->pack, pack_ind); +} + + +/* +============================================================================= + +MAIN PUBLIC FUNCTIONS + +============================================================================= +*/ + +/* +==================== +FS_OpenRealFile + +Open a file in the userpath. The syntax is the same as fopen +Used for savegame scanning in menu, and all file writing. +==================== +*/ +qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet) +{ + char real_path [MAX_OSPATH]; + + if (FS_CheckNastyPath(filepath, false)) + { + Con_Printf("FS_OpenRealFile(\"%s\", \"%s\", %s): nasty filename rejected\n", filepath, mode, quiet ? "true" : "false"); + return NULL; + } + + dpsnprintf (real_path, sizeof (real_path), "%s/%s", fs_gamedir, filepath); // this is never a vpack + + // If the file is opened in "write", "append", or "read/write" mode, + // create directories up to the file. + if (mode[0] == 'w' || mode[0] == 'a' || strchr (mode, '+')) + FS_CreatePath (real_path); + return FS_SysOpen (real_path, mode, false); +} + + +/* +==================== +FS_OpenVirtualFile + +Open a file. The syntax is the same as fopen +==================== +*/ +qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet) +{ + qfile_t *result = NULL; + if (FS_CheckNastyPath(filepath, false)) + { + Con_Printf("FS_OpenVirtualFile(\"%s\", %s): nasty filename rejected\n", filepath, quiet ? "true" : "false"); + return NULL; + } + + if (fs_mutex) Thread_LockMutex(fs_mutex); + result = FS_OpenReadFile (filepath, quiet, false, 16); + if (fs_mutex) Thread_UnlockMutex(fs_mutex); + return result; +} + + +/* +==================== +FS_FileFromData + +Open a file. The syntax is the same as fopen +==================== +*/ +qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet) +{ + qfile_t* file; + file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file)); + memset (file, 0, sizeof (*file)); + file->flags = QFILE_FLAG_DATA; + file->ungetc = EOF; + file->real_length = size; + file->data = data; + return file; +} + +/* +==================== +FS_Close + +Close a file +==================== +*/ +int FS_Close (qfile_t* file) +{ + if(file->flags & QFILE_FLAG_DATA) + { + Mem_Free(file); + return 0; + } + + if (close (file->handle)) + return EOF; + + if (file->filename) + { + if (file->flags & QFILE_FLAG_REMOVE) + remove(file->filename); + + Mem_Free((void *) file->filename); + } + + if (file->ztk) + { + qz_inflateEnd (&file->ztk->zstream); + Mem_Free (file->ztk); + } + + Mem_Free (file); + return 0; +} + +void FS_RemoveOnClose(qfile_t* file) +{ + file->flags |= QFILE_FLAG_REMOVE; +} + +/* +==================== +FS_Write + +Write "datasize" bytes into a file +==================== +*/ +fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize) +{ + fs_offset_t result; + + // If necessary, seek to the exact file position we're supposed to be + if (file->buff_ind != file->buff_len) + lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR); + + // Purge cached data + FS_Purge (file); + + // Write the buffer and update the position + result = write (file->handle, data, (fs_offset_t)datasize); + file->position = lseek (file->handle, 0, SEEK_CUR); + if (file->real_length < file->position) + file->real_length = file->position; + + if (result < 0) + return 0; + + return result; +} + + +/* +==================== +FS_Read + +Read up to "buffersize" bytes from a file +==================== +*/ +fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize) +{ + fs_offset_t count, done; + + if (buffersize == 0) + return 0; + + // Get rid of the ungetc character + if (file->ungetc != EOF) + { + ((char*)buffer)[0] = file->ungetc; + buffersize--; + file->ungetc = EOF; + done = 1; + } + else + done = 0; + + if(file->flags & QFILE_FLAG_DATA) + { + size_t left = file->real_length - file->position; + if(buffersize > left) + buffersize = left; + memcpy(buffer, file->data + file->position, buffersize); + file->position += buffersize; + return buffersize; + } + + // First, we copy as many bytes as we can from "buff" + if (file->buff_ind < file->buff_len) + { + count = file->buff_len - file->buff_ind; + count = ((fs_offset_t)buffersize > count) ? count : (fs_offset_t)buffersize; + done += count; + memcpy (buffer, &file->buff[file->buff_ind], count); + file->buff_ind += count; + + buffersize -= count; + if (buffersize == 0) + return done; + } + + // NOTE: at this point, the read buffer is always empty + + // If the file isn't compressed + if (! (file->flags & QFILE_FLAG_DEFLATED)) + { + fs_offset_t nb; + + // We must take care to not read after the end of the file + count = file->real_length - file->position; + + // If we have a lot of data to get, put them directly into "buffer" + if (buffersize > sizeof (file->buff) / 2) + { + if (count > (fs_offset_t)buffersize) + count = (fs_offset_t)buffersize; + lseek (file->handle, file->offset + file->position, SEEK_SET); + nb = read (file->handle, &((unsigned char*)buffer)[done], count); + if (nb > 0) + { + done += nb; + file->position += nb; + + // Purge cached data + FS_Purge (file); + } + } + else + { + if (count > (fs_offset_t)sizeof (file->buff)) + count = (fs_offset_t)sizeof (file->buff); + lseek (file->handle, file->offset + file->position, SEEK_SET); + nb = read (file->handle, file->buff, count); + if (nb > 0) + { + file->buff_len = nb; + file->position += nb; + + // Copy the requested data in "buffer" (as much as we can) + count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; + memcpy (&((unsigned char*)buffer)[done], file->buff, count); + file->buff_ind = count; + done += count; + } + } + + return done; + } + + // If the file is compressed, it's more complicated... + // We cycle through a few operations until we have read enough data + while (buffersize > 0) + { + ztoolkit_t *ztk = file->ztk; + int error; + + // NOTE: at this point, the read buffer is always empty + + // If "input" is also empty, we need to refill it + if (ztk->in_ind == ztk->in_len) + { + // If we are at the end of the file + if (file->position == file->real_length) + return done; + + count = (fs_offset_t)(ztk->comp_length - ztk->in_position); + if (count > (fs_offset_t)sizeof (ztk->input)) + count = (fs_offset_t)sizeof (ztk->input); + lseek (file->handle, file->offset + (fs_offset_t)ztk->in_position, SEEK_SET); + if (read (file->handle, ztk->input, count) != count) + { + Con_Printf ("FS_Read: unexpected end of file\n"); + break; + } + + ztk->in_ind = 0; + ztk->in_len = count; + ztk->in_position += count; + } + + ztk->zstream.next_in = &ztk->input[ztk->in_ind]; + ztk->zstream.avail_in = (unsigned int)(ztk->in_len - ztk->in_ind); + + // Now that we are sure we have compressed data available, we need to determine + // if it's better to inflate it in "file->buff" or directly in "buffer" + + // Inflate the data in "file->buff" + if (buffersize < sizeof (file->buff) / 2) + { + ztk->zstream.next_out = file->buff; + ztk->zstream.avail_out = sizeof (file->buff); + error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH); + if (error != Z_OK && error != Z_STREAM_END) + { + Con_Printf ("FS_Read: Can't inflate file\n"); + break; + } + ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; + + file->buff_len = (fs_offset_t)sizeof (file->buff) - ztk->zstream.avail_out; + file->position += file->buff_len; + + // Copy the requested data in "buffer" (as much as we can) + count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; + memcpy (&((unsigned char*)buffer)[done], file->buff, count); + file->buff_ind = count; + } + + // Else, we inflate directly in "buffer" + else + { + ztk->zstream.next_out = &((unsigned char*)buffer)[done]; + ztk->zstream.avail_out = (unsigned int)buffersize; + error = qz_inflate (&ztk->zstream, Z_SYNC_FLUSH); + if (error != Z_OK && error != Z_STREAM_END) + { + Con_Printf ("FS_Read: Can't inflate file\n"); + break; + } + ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; + + // How much data did it inflate? + count = (fs_offset_t)(buffersize - ztk->zstream.avail_out); + file->position += count; + + // Purge cached data + FS_Purge (file); + } + + done += count; + buffersize -= count; + } + + return done; +} + + +/* +==================== +FS_Print + +Print a string into a file +==================== +*/ +int FS_Print (qfile_t* file, const char *msg) +{ + return (int)FS_Write (file, msg, strlen (msg)); +} + +/* +==================== +FS_Printf + +Print a string into a file +==================== +*/ +int FS_Printf(qfile_t* file, const char* format, ...) +{ + int result; + va_list args; + + va_start (args, format); + result = FS_VPrintf (file, format, args); + va_end (args); + + return result; +} + + +/* +==================== +FS_VPrintf + +Print a string into a file +==================== +*/ +int FS_VPrintf (qfile_t* file, const char* format, va_list ap) +{ + int len; + fs_offset_t buff_size = MAX_INPUTLINE; + char *tempbuff; + + for (;;) + { + tempbuff = (char *)Mem_Alloc (tempmempool, buff_size); + len = dpvsnprintf (tempbuff, buff_size, format, ap); + if (len >= 0 && len < buff_size) + break; + Mem_Free (tempbuff); + buff_size *= 2; + } + + len = write (file->handle, tempbuff, len); + Mem_Free (tempbuff); + + return len; +} + + +/* +==================== +FS_Getc + +Get the next character of a file +==================== +*/ +int FS_Getc (qfile_t* file) +{ + unsigned char c; + + if (FS_Read (file, &c, 1) != 1) + return EOF; + + return c; +} + + +/* +==================== +FS_UnGetc + +Put a character back into the read buffer (only supports one character!) +==================== +*/ +int FS_UnGetc (qfile_t* file, unsigned char c) +{ + // If there's already a character waiting to be read + if (file->ungetc != EOF) + return EOF; + + file->ungetc = c; + return c; +} + + +/* +==================== +FS_Seek + +Move the position index in a file +==================== +*/ +int FS_Seek (qfile_t* file, fs_offset_t offset, int whence) +{ + ztoolkit_t *ztk; + unsigned char* buffer; + fs_offset_t buffersize; + + // Compute the file offset + switch (whence) + { + case SEEK_CUR: + offset += file->position - file->buff_len + file->buff_ind; + break; + + case SEEK_SET: + break; + + case SEEK_END: + offset += file->real_length; + break; + + default: + return -1; + } + if (offset < 0 || offset > file->real_length) + return -1; + + if(file->flags & QFILE_FLAG_DATA) + { + file->position = offset; + return 0; + } + + // If we have the data in our read buffer, we don't need to actually seek + if (file->position - file->buff_len <= offset && offset <= file->position) + { + file->buff_ind = offset + file->buff_len - file->position; + return 0; + } + + // Purge cached data + FS_Purge (file); + + // Unpacked or uncompressed files can seek directly + if (! (file->flags & QFILE_FLAG_DEFLATED)) + { + if (lseek (file->handle, file->offset + offset, SEEK_SET) == -1) + return -1; + file->position = offset; + return 0; + } + + // Seeking in compressed files is more a hack than anything else, + // but we need to support it, so here we go. + ztk = file->ztk; + + // If we have to go back in the file, we need to restart from the beginning + if (offset <= file->position) + { + ztk->in_ind = 0; + ztk->in_len = 0; + ztk->in_position = 0; + file->position = 0; + lseek (file->handle, file->offset, SEEK_SET); + + // Reset the Zlib stream + ztk->zstream.next_in = ztk->input; + ztk->zstream.avail_in = 0; + qz_inflateReset (&ztk->zstream); + } + + // We need a big buffer to force inflating into it directly + buffersize = 2 * sizeof (file->buff); + buffer = (unsigned char *)Mem_Alloc (tempmempool, buffersize); + + // Skip all data until we reach the requested offset + while (offset > file->position) + { + fs_offset_t diff = offset - file->position; + fs_offset_t count, len; + + count = (diff > buffersize) ? buffersize : diff; + len = FS_Read (file, buffer, count); + if (len != count) + { + Mem_Free (buffer); + return -1; + } + } + + Mem_Free (buffer); + return 0; +} + + +/* +==================== +FS_Tell + +Give the current position in a file +==================== +*/ +fs_offset_t FS_Tell (qfile_t* file) +{ + return file->position - file->buff_len + file->buff_ind; +} + + +/* +==================== +FS_FileSize + +Give the total size of a file +==================== +*/ +fs_offset_t FS_FileSize (qfile_t* file) +{ + return file->real_length; +} + + +/* +==================== +FS_Purge + +Erases any buffered input or output data +==================== +*/ +void FS_Purge (qfile_t* file) +{ + file->buff_len = 0; + file->buff_ind = 0; + file->ungetc = EOF; +} + + +/* +============ +FS_LoadFile + +Filename are relative to the quake directory. +Always appends a 0 byte. +============ +*/ +unsigned char *FS_LoadFile (const char *path, mempool_t *pool, qboolean quiet, fs_offset_t *filesizepointer) +{ + qfile_t *file; + unsigned char *buf = NULL; + fs_offset_t filesize = 0; + + file = FS_OpenVirtualFile(path, quiet); + if (file) + { + filesize = file->real_length; + if(filesize < 0) + { + Con_Printf("FS_LoadFile(\"%s\", pool, %s, filesizepointer): trying to open a non-regular file\n", path, quiet ? "true" : "false"); + FS_Close(file); + return NULL; + } + + buf = (unsigned char *)Mem_Alloc (pool, filesize + 1); + buf[filesize] = '\0'; + FS_Read (file, buf, filesize); + FS_Close (file); + if (developer_loadfile.integer) + Con_Printf("loaded file \"%s\" (%u bytes)\n", path, (unsigned int)filesize); + } + + if (filesizepointer) + *filesizepointer = filesize; + return buf; +} + + +/* +============ +FS_WriteFile + +The filename will be prefixed by the current game directory +============ +*/ +qboolean FS_WriteFileInBlocks (const char *filename, const void *const *data, const fs_offset_t *len, size_t count) +{ + qfile_t *file; + size_t i; + fs_offset_t lentotal; + + file = FS_OpenRealFile(filename, "wb", false); + if (!file) + { + Con_Printf("FS_WriteFile: failed on %s\n", filename); + return false; + } + + lentotal = 0; + for(i = 0; i < count; ++i) + lentotal += len[i]; + Con_DPrintf("FS_WriteFile: %s (%u bytes)\n", filename, (unsigned int)lentotal); + for(i = 0; i < count; ++i) + FS_Write (file, data[i], len[i]); + FS_Close (file); + return true; +} + +qboolean FS_WriteFile (const char *filename, const void *data, fs_offset_t len) +{ + return FS_WriteFileInBlocks(filename, &data, &len, 1); +} + + +/* +============================================================================= + +OTHERS PUBLIC FUNCTIONS + +============================================================================= +*/ + +/* +============ +FS_StripExtension +============ +*/ +void FS_StripExtension (const char *in, char *out, size_t size_out) +{ + char *last = NULL; + char currentchar; + + if (size_out == 0) + return; + + while ((currentchar = *in) && size_out > 1) + { + if (currentchar == '.') + last = out; + else if (currentchar == '/' || currentchar == '\\' || currentchar == ':') + last = NULL; + *out++ = currentchar; + in++; + size_out--; + } + if (last) + *last = 0; + else + *out = 0; +} + + +/* +================== +FS_DefaultExtension +================== +*/ +void FS_DefaultExtension (char *path, const char *extension, size_t size_path) +{ + const 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--; + } + + strlcat (path, extension, size_path); +} + + +/* +================== +FS_FileType + +Look for a file in the packages and in the filesystem +================== +*/ +int FS_FileType (const char *filename) +{ + searchpath_t *search; + char fullpath[MAX_OSPATH]; + + search = FS_FindFile (filename, NULL, true); + if(!search) + return FS_FILETYPE_NONE; + + if(search->pack && !search->pack->vpack) + return FS_FILETYPE_FILE; // TODO can't check directories in paks yet, maybe later + + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", search->filename, filename); + return FS_SysFileType(fullpath); +} + + +/* +================== +FS_FileExists + +Look for a file in the packages and in the filesystem +================== +*/ +qboolean FS_FileExists (const char *filename) +{ + return (FS_FindFile (filename, NULL, true) != NULL); +} + + +/* +================== +FS_SysFileExists + +Look for a file in the filesystem only +================== +*/ +int FS_SysFileType (const char *path) +{ +#if WIN32 +// Sajt - some older sdks are missing this define +# ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +# endif + + DWORD result = GetFileAttributes(path); + + if(result == INVALID_FILE_ATTRIBUTES) + return FS_FILETYPE_NONE; + + if(result & FILE_ATTRIBUTE_DIRECTORY) + return FS_FILETYPE_DIRECTORY; + + return FS_FILETYPE_FILE; +#else + struct stat buf; + + if (stat (path,&buf) == -1) + return FS_FILETYPE_NONE; + +#ifndef S_ISDIR +#define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) +#endif + if(S_ISDIR(buf.st_mode)) + return FS_FILETYPE_DIRECTORY; + + return FS_FILETYPE_FILE; +#endif +} + +qboolean FS_SysFileExists (const char *path) +{ + return FS_SysFileType (path) != FS_FILETYPE_NONE; +} + +void FS_mkdir (const char *path) +{ + if(COM_CheckParm("-readonly")) + return; + +#if WIN32 + _mkdir (path); +#else + mkdir (path, 0777); +#endif +} + +/* +=========== +FS_Search + +Allocate and fill a search structure with information on matching filenames. +=========== +*/ +fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet) +{ + fssearch_t *search; + searchpath_t *searchpath; + pack_t *pak; + int i, basepathlength, numfiles, numchars, resultlistindex, dirlistindex; + stringlist_t resultlist; + stringlist_t dirlist; + const char *slash, *backslash, *colon, *separator; + char *basepath; + char temp[MAX_OSPATH]; + + for (i = 0;pattern[i] == '.' || pattern[i] == ':' || pattern[i] == '/' || pattern[i] == '\\';i++) + ; + + if (i > 0) + { + Con_Printf("Don't use punctuation at the beginning of a search pattern!\n"); + return NULL; + } + + stringlistinit(&resultlist); + stringlistinit(&dirlist); + search = NULL; + slash = strrchr(pattern, '/'); + backslash = strrchr(pattern, '\\'); + colon = strrchr(pattern, ':'); + separator = max(slash, backslash); + separator = max(separator, colon); + basepathlength = separator ? (separator + 1 - pattern) : 0; + basepath = (char *)Mem_Alloc (tempmempool, basepathlength + 1); + if (basepathlength) + memcpy(basepath, pattern, basepathlength); + basepath[basepathlength] = 0; + + // search through the path, one element at a time + for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next) + { + // is the element a pak file? + if (searchpath->pack && !searchpath->pack->vpack) + { + // look through all the pak file elements + pak = searchpath->pack; + for (i = 0;i < pak->numfiles;i++) + { + strlcpy(temp, pak->files[i].name, sizeof(temp)); + while (temp[0]) + { + if (matchpattern(temp, (char *)pattern, true)) + { + for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++) + if (!strcmp(resultlist.strings[resultlistindex], temp)) + break; + if (resultlistindex == resultlist.numstrings) + { + stringlistappend(&resultlist, temp); + if (!quiet && developer_loading.integer) + Con_Printf("SearchPackFile: %s : %s\n", pak->filename, temp); + } + } + // strip off one path element at a time until empty + // this way directories are added to the listing if they match the pattern + slash = strrchr(temp, '/'); + backslash = strrchr(temp, '\\'); + colon = strrchr(temp, ':'); + separator = temp; + if (separator < slash) + separator = slash; + if (separator < backslash) + separator = backslash; + if (separator < colon) + separator = colon; + *((char *)separator) = 0; + } + } + } + else + { + stringlist_t matchedSet, foundSet; + const char *start = pattern; + + stringlistinit(&matchedSet); + stringlistinit(&foundSet); + // add a first entry to the set + stringlistappend(&matchedSet, ""); + // iterate through pattern's path + while (*start) + { + const char *asterisk, *wildcard, *nextseparator, *prevseparator; + char subpath[MAX_OSPATH]; + char subpattern[MAX_OSPATH]; + + // find the next wildcard + wildcard = strchr(start, '?'); + asterisk = strchr(start, '*'); + if (asterisk && (!wildcard || asterisk < wildcard)) + { + wildcard = asterisk; + } + + if (wildcard) + { + nextseparator = strchr( wildcard, '/' ); + } + else + { + nextseparator = NULL; + } + + if( !nextseparator ) { + nextseparator = start + strlen( start ); + } + + // prevseparator points past the '/' right before the wildcard and nextseparator at the one following it (or at the end of the string) + // copy everything up except nextseperator + strlcpy(subpattern, pattern, min(sizeof(subpattern), (size_t) (nextseparator - pattern + 1))); + // find the last '/' before the wildcard + prevseparator = strrchr( subpattern, '/' ); + if (!prevseparator) + prevseparator = subpattern; + else + prevseparator++; + // copy everything from start to the previous including the '/' (before the wildcard) + // everything up to start is already included in the path of matchedSet's entries + strlcpy(subpath, start, min(sizeof(subpath), (size_t) ((prevseparator - subpattern) - (start - pattern) + 1))); + + // for each entry in matchedSet try to open the subdirectories specified in subpath + for( dirlistindex = 0 ; dirlistindex < matchedSet.numstrings ; dirlistindex++ ) { + strlcpy( temp, matchedSet.strings[ dirlistindex ], sizeof(temp) ); + strlcat( temp, subpath, sizeof(temp) ); + listdirectory( &foundSet, searchpath->filename, temp ); + } + if( dirlistindex == 0 ) { + break; + } + // reset the current result set + stringlistfreecontents( &matchedSet ); + // match against the pattern + for( dirlistindex = 0 ; dirlistindex < foundSet.numstrings ; dirlistindex++ ) { + const char *direntry = foundSet.strings[ dirlistindex ]; + if (matchpattern(direntry, subpattern, true)) { + stringlistappend( &matchedSet, direntry ); + } + } + stringlistfreecontents( &foundSet ); + + start = nextseparator; + } + + for (dirlistindex = 0;dirlistindex < matchedSet.numstrings;dirlistindex++) + { + const char *temp = matchedSet.strings[dirlistindex]; + if (matchpattern(temp, (char *)pattern, true)) + { + for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++) + if (!strcmp(resultlist.strings[resultlistindex], temp)) + break; + if (resultlistindex == resultlist.numstrings) + { + stringlistappend(&resultlist, temp); + if (!quiet && developer_loading.integer) + Con_Printf("SearchDirFile: %s\n", temp); + } + } + } + stringlistfreecontents( &matchedSet ); + } + } + + if (resultlist.numstrings) + { + stringlistsort(&resultlist, true); + numfiles = resultlist.numstrings; + numchars = 0; + for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++) + numchars += (int)strlen(resultlist.strings[resultlistindex]) + 1; + search = (fssearch_t *)Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *)); + search->filenames = (char **)((char *)search + sizeof(fssearch_t)); + search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *)); + search->numfilenames = (int)numfiles; + numfiles = 0; + numchars = 0; + for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++) + { + size_t textlen; + search->filenames[numfiles] = search->filenamesbuffer + numchars; + textlen = strlen(resultlist.strings[resultlistindex]) + 1; + memcpy(search->filenames[numfiles], resultlist.strings[resultlistindex], textlen); + numfiles++; + numchars += (int)textlen; + } + } + stringlistfreecontents(&resultlist); + + Mem_Free(basepath); + return search; +} + +void FS_FreeSearch(fssearch_t *search) +{ + Z_Free(search); +} + +extern int con_linewidth; +static int FS_ListDirectory(const char *pattern, int oneperline) +{ + int numfiles; + int numcolumns; + int numlines; + int columnwidth; + int linebufpos; + int i, j, k, l; + const char *name; + char linebuf[MAX_INPUTLINE]; + fssearch_t *search; + search = FS_Search(pattern, true, true); + if (!search) + return 0; + numfiles = search->numfilenames; + if (!oneperline) + { + // FIXME: the names could be added to one column list and then + // gradually shifted into the next column if they fit, and then the + // next to make a compact variable width listing but it's a lot more + // complicated... + // find width for columns + columnwidth = 0; + for (i = 0;i < numfiles;i++) + { + l = (int)strlen(search->filenames[i]); + if (columnwidth < l) + columnwidth = l; + } + // count the spacing character + columnwidth++; + // calculate number of columns + numcolumns = con_linewidth / columnwidth; + // don't bother with the column printing if it's only one column + if (numcolumns >= 2) + { + numlines = (numfiles + numcolumns - 1) / numcolumns; + for (i = 0;i < numlines;i++) + { + linebufpos = 0; + for (k = 0;k < numcolumns;k++) + { + l = i * numcolumns + k; + if (l < numfiles) + { + name = search->filenames[l]; + for (j = 0;name[j] && linebufpos + 1 < (int)sizeof(linebuf);j++) + linebuf[linebufpos++] = name[j]; + // space out name unless it's the last on the line + if (k + 1 < numcolumns && l + 1 < numfiles) + for (;j < columnwidth && linebufpos + 1 < (int)sizeof(linebuf);j++) + linebuf[linebufpos++] = ' '; + } + } + linebuf[linebufpos] = 0; + Con_Printf("%s\n", linebuf); + } + } + else + oneperline = true; + } + if (oneperline) + for (i = 0;i < numfiles;i++) + Con_Printf("%s\n", search->filenames[i]); + FS_FreeSearch(search); + return (int)numfiles; +} + +static void FS_ListDirectoryCmd (const char* cmdname, int oneperline) +{ + const char *pattern; + if (Cmd_Argc() >= 3) + { + Con_Printf("usage:\n%s [path/pattern]\n", cmdname); + return; + } + if (Cmd_Argc() == 2) + pattern = Cmd_Argv(1); + else + pattern = "*"; + if (!FS_ListDirectory(pattern, oneperline)) + Con_Print("No files found.\n"); +} + +void FS_Dir_f(void) +{ + FS_ListDirectoryCmd("dir", true); +} + +void FS_Ls_f(void) +{ + FS_ListDirectoryCmd("ls", false); +} + +void FS_Which_f(void) +{ + const char *filename; + int index; + searchpath_t *sp; + if (Cmd_Argc() != 2) + { + Con_Printf("usage:\n%s \n", Cmd_Argv(0)); + return; + } + filename = Cmd_Argv(1); + sp = FS_FindFile(filename, &index, true); + if (!sp) { + Con_Printf("%s isn't anywhere\n", filename); + return; + } + if (sp->pack) + { + if(sp->pack->vpack) + Con_Printf("%s is in virtual package %sdir\n", filename, sp->pack->shortname); + else + Con_Printf("%s is in package %s\n", filename, sp->pack->shortname); + } + else + Con_Printf("%s is file %s%s\n", filename, sp->filename, filename); +} + + +const char *FS_WhichPack(const char *filename) +{ + int index; + searchpath_t *sp = FS_FindFile(filename, &index, true); + if(sp && sp->pack) + return sp->pack->shortname; + else + return 0; +} + +/* +==================== +FS_IsRegisteredQuakePack + +Look for a proof of purchase file file in the requested package + +If it is found, this file should NOT be downloaded. +==================== +*/ +qboolean FS_IsRegisteredQuakePack(const char *name) +{ + searchpath_t *search; + pack_t *pak; + + // search through the path, one element at a time + for (search = fs_searchpaths;search;search = search->next) + { + if (search->pack && !search->pack->vpack && !strcasecmp(FS_FileWithoutPath(search->filename), name)) + // TODO do we want to support vpacks in here too? + { + int (*strcmp_funct) (const char* str1, const char* str2); + int left, right, middle; + + pak = search->pack; + strcmp_funct = pak->ignorecase ? strcasecmp : strcmp; + + // Look for the file (binary search) + left = 0; + right = pak->numfiles - 1; + while (left <= right) + { + int diff; + + middle = (left + right) / 2; + diff = !strcmp_funct (pak->files[middle].name, "gfx/pop.lmp"); + + // Found it + if (!diff) + return true; + + // If we're too far in the list + if (diff > 0) + right = middle - 1; + else + left = middle + 1; + } + + // we found the requested pack but it is not registered quake + return false; + } + } + + return false; +} + +int FS_CRCFile(const char *filename, size_t *filesizepointer) +{ + int crc = -1; + unsigned char *filedata; + fs_offset_t filesize; + if (filesizepointer) + *filesizepointer = 0; + if (!filename || !*filename) + return crc; + filedata = FS_LoadFile(filename, tempmempool, true, &filesize); + if (filedata) + { + if (filesizepointer) + *filesizepointer = filesize; + crc = CRC_Block(filedata, filesize); + Mem_Free(filedata); + } + return crc; +} + +unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool) +{ + z_stream strm; + unsigned char *out = NULL; + unsigned char *tmp; + + *deflated_size = 0; +#ifndef LINK_TO_ZLIB + if(!zlib_dll) + return NULL; +#endif + + memset(&strm, 0, sizeof(strm)); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + if(level < 0) + level = Z_DEFAULT_COMPRESSION; + + if(qz_deflateInit2(&strm, level, Z_DEFLATED, -MAX_WBITS, Z_MEMLEVEL_DEFAULT, Z_BINARY) != Z_OK) + { + Con_Printf("FS_Deflate: deflate init error!\n"); + return NULL; + } + + strm.next_in = (unsigned char*)data; + strm.avail_in = size; + + tmp = (unsigned char *) Mem_Alloc(tempmempool, size); + if(!tmp) + { + Con_Printf("FS_Deflate: not enough memory in tempmempool!\n"); + qz_deflateEnd(&strm); + return NULL; + } + + strm.next_out = tmp; + strm.avail_out = size; + + if(qz_deflate(&strm, Z_FINISH) != Z_STREAM_END) + { + Con_Printf("FS_Deflate: deflate failed!\n"); + qz_deflateEnd(&strm); + Mem_Free(tmp); + return NULL; + } + + if(qz_deflateEnd(&strm) != Z_OK) + { + Con_Printf("FS_Deflate: deflateEnd failed\n"); + Mem_Free(tmp); + return NULL; + } + + if(strm.total_out >= size) + { + Con_Printf("FS_Deflate: deflate is useless on this data!\n"); + Mem_Free(tmp); + return NULL; + } + + out = (unsigned char *) Mem_Alloc(mempool, strm.total_out); + if(!out) + { + Con_Printf("FS_Deflate: not enough memory in target mempool!\n"); + Mem_Free(tmp); + return NULL; + } + + if(deflated_size) + *deflated_size = (size_t)strm.total_out; + + memcpy(out, tmp, strm.total_out); + Mem_Free(tmp); + + return out; +} + +static void AssertBufsize(sizebuf_t *buf, int length) +{ + if(buf->cursize + length > buf->maxsize) + { + int oldsize = buf->maxsize; + unsigned char *olddata; + olddata = buf->data; + buf->maxsize += length; + buf->data = (unsigned char *) Mem_Alloc(tempmempool, buf->maxsize); + if(olddata) + { + memcpy(buf->data, olddata, oldsize); + Mem_Free(olddata); + } + } +} + +unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflated_size, mempool_t *mempool) +{ + int ret; + z_stream strm; + unsigned char *out = NULL; + unsigned char tmp[2048]; + unsigned int have; + sizebuf_t outbuf; + + *inflated_size = 0; +#ifndef LINK_TO_ZLIB + if(!zlib_dll) + return NULL; +#endif + + memset(&outbuf, 0, sizeof(outbuf)); + outbuf.data = (unsigned char *) Mem_Alloc(tempmempool, sizeof(tmp)); + outbuf.maxsize = sizeof(tmp); + + memset(&strm, 0, sizeof(strm)); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + if(qz_inflateInit2(&strm, -MAX_WBITS) != Z_OK) + { + Con_Printf("FS_Inflate: inflate init error!\n"); + Mem_Free(outbuf.data); + return NULL; + } + + strm.next_in = (unsigned char*)data; + strm.avail_in = size; + + do + { + strm.next_out = tmp; + strm.avail_out = sizeof(tmp); + ret = qz_inflate(&strm, Z_NO_FLUSH); + // it either returns Z_OK on progress, Z_STREAM_END on end + // or an error code + switch(ret) + { + case Z_STREAM_END: + case Z_OK: + break; + + case Z_STREAM_ERROR: + Con_Print("FS_Inflate: stream error!\n"); + break; + case Z_DATA_ERROR: + Con_Print("FS_Inflate: data error!\n"); + break; + case Z_MEM_ERROR: + Con_Print("FS_Inflate: mem error!\n"); + break; + case Z_BUF_ERROR: + Con_Print("FS_Inflate: buf error!\n"); + break; + default: + Con_Print("FS_Inflate: unknown error!\n"); + break; + + } + if(ret != Z_OK && ret != Z_STREAM_END) + { + Con_Printf("Error after inflating %u bytes\n", (unsigned)strm.total_in); + Mem_Free(outbuf.data); + qz_inflateEnd(&strm); + return NULL; + } + have = sizeof(tmp) - strm.avail_out; + AssertBufsize(&outbuf, max(have, sizeof(tmp))); + SZ_Write(&outbuf, tmp, have); + } while(ret != Z_STREAM_END); + + qz_inflateEnd(&strm); + + out = (unsigned char *) Mem_Alloc(mempool, outbuf.cursize); + if(!out) + { + Con_Printf("FS_Inflate: not enough memory in target mempool!\n"); + Mem_Free(outbuf.data); + return NULL; + } + + memcpy(out, outbuf.data, outbuf.cursize); + Mem_Free(outbuf.data); + + if(inflated_size) + *inflated_size = (size_t)outbuf.cursize; + + return out; +} diff --git a/app/jni/fs.h b/app/jni/fs.h new file mode 100644 index 0000000..cd1979a --- /dev/null +++ b/app/jni/fs.h @@ -0,0 +1,144 @@ +/* + DarkPlaces file system + + Copyright (C) 2003-2005 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA +*/ + +#ifndef FS_H +#define FS_H + + +// ------ Types ------ // + +typedef struct qfile_s qfile_t; + +#ifdef WIN32 +//typedef long fs_offset_t; // 32bit +typedef __int64 fs_offset_t; ///< 64bit (lots of warnings, and read/write still don't take 64bit on win64) +#else +typedef long long fs_offset_t; +#endif + + + +// ------ Variables ------ // + +extern char fs_gamedir [MAX_OSPATH]; +extern char fs_basedir [MAX_OSPATH]; +extern char fs_userdir [MAX_OSPATH]; + +// list of active game directories (empty if not running a mod) +#define MAX_GAMEDIRS 16 +extern int fs_numgamedirs; +extern char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH]; + + +// ------ Main functions ------ // + +// IMPORTANT: the file path is automatically prefixed by the current game directory for +// each file created by FS_WriteFile, or opened in "write" or "append" mode by FS_OpenRealFile + +qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs); // already_loaded may be NULL if caller does not care +const char *FS_WhichPack(const char *filename); +void FS_CreatePath (char *path); +int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking); // uses absolute path +qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking); // uses absolute path +qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet); +qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet); +qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet); +int FS_Close (qfile_t* file); +void FS_RemoveOnClose(qfile_t* file); +fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize); +fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize); +int FS_Print(qfile_t* file, const char *msg); +int FS_Printf(qfile_t* file, const char* format, ...) DP_FUNC_PRINTF(2); +int FS_VPrintf(qfile_t* file, const char* format, va_list ap); +int FS_Getc (qfile_t* file); +int FS_UnGetc (qfile_t* file, unsigned char c); +int FS_Seek (qfile_t* file, fs_offset_t offset, int whence); +fs_offset_t FS_Tell (qfile_t* file); +fs_offset_t FS_FileSize (qfile_t* file); +void FS_Purge (qfile_t* file); +const char *FS_FileWithoutPath (const char *in); +const char *FS_FileExtension (const char *in); +int FS_CheckNastyPath (const char *path, qboolean isgamedir); + +extern const char *const fs_checkgamedir_missing; // "(missing)" +const char *FS_CheckGameDir(const char *gamedir); // returns NULL if nasty, fs_checkgamedir_missing (exact pointer) if missing + +typedef struct +{ + char name[MAX_OSPATH]; + char description[8192]; +} +gamedir_t; +extern gamedir_t *fs_all_gamedirs; // terminated by entry with empty name +extern int fs_all_gamedirs_count; + +qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean complain, qboolean failmissing); +qboolean FS_IsRegisteredQuakePack(const char *name); +int FS_CRCFile(const char *filename, size_t *filesizepointer); +void FS_Rescan(void); + +typedef struct fssearch_s +{ + int numfilenames; + char **filenames; + // array of filenames + char *filenamesbuffer; +} +fssearch_t; + +fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet); +void FS_FreeSearch(fssearch_t *search); + +unsigned char *FS_LoadFile (const char *path, mempool_t *pool, qboolean quiet, fs_offset_t *filesizepointer); +qboolean FS_WriteFileInBlocks (const char *filename, const void *const *data, const fs_offset_t *len, size_t count); +qboolean FS_WriteFile (const char *filename, const void *data, fs_offset_t len); + + +// ------ Other functions ------ // + +void FS_StripExtension (const char *in, char *out, size_t size_out); +void FS_DefaultExtension (char *path, const char *extension, size_t size_path); + +#define FS_FILETYPE_NONE 0 +#define FS_FILETYPE_FILE 1 +#define FS_FILETYPE_DIRECTORY 2 +int FS_FileType (const char *filename); // the file can be into a package +int FS_SysFileType (const char *filename); // only look for files outside of packages + +qboolean FS_FileExists (const char *filename); // the file can be into a package +qboolean FS_SysFileExists (const char *filename); // only look for files outside of packages + +void FS_mkdir (const char *path); + +unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool); +unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflated_size, mempool_t *mempool); + +qboolean FS_HasZlib(void); + +void FS_Init_SelfPack(void); +void FS_Init(void); +void FS_Shutdown(void); +void FS_Init_Commands(void); + +#endif diff --git a/app/jni/ft2.c b/app/jni/ft2.c new file mode 100644 index 0000000..f55d0e2 --- /dev/null +++ b/app/jni/ft2.c @@ -0,0 +1,1593 @@ +/* FreeType 2 and UTF-8 encoding support for + * DarkPlaces + */ +#include "quakedef.h" + +#include "ft2.h" +#include "ft2_defs.h" +#include "ft2_fontdefs.h" +#include "image.h" + +static int img_fontmap[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // shift+digit line + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // digits + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // caps + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // small + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // specials + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // faces + 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, 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 +}; + +/* +================================================================================ +CVars introduced with the freetype extension +================================================================================ +*/ + +cvar_t r_font_disable_freetype = {CVAR_SAVE, "r_font_disable_freetype", "1", "disable freetype support for fonts entirely"}; +cvar_t r_font_use_alpha_textures = {CVAR_SAVE, "r_font_use_alpha_textures", "0", "use alpha-textures for font rendering, this should safe memory"}; +cvar_t r_font_size_snapping = {CVAR_SAVE, "r_font_size_snapping", "1", "stick to good looking font sizes whenever possible - bad when the mod doesn't support it!"}; +cvar_t r_font_kerning = {CVAR_SAVE, "r_font_kerning", "1", "Use kerning if available"}; +cvar_t r_font_diskcache = {CVAR_SAVE, "r_font_diskcache", "0", "save font textures to disk for future loading rather than generating them every time"}; +cvar_t r_font_compress = {CVAR_SAVE, "r_font_compress", "0", "use texture compression on font textures to save video memory"}; +cvar_t r_font_nonpoweroftwo = {CVAR_SAVE, "r_font_nonpoweroftwo", "1", "use nonpoweroftwo textures for font (saves memory, potentially slower)"}; +cvar_t developer_font = {CVAR_SAVE, "developer_font", "0", "prints debug messages about fonts"}; + +/* +================================================================================ +Function definitions. Taken from the freetype2 headers. +================================================================================ +*/ + + +FT_EXPORT( FT_Error ) +(*qFT_Init_FreeType)( FT_Library *alibrary ); +FT_EXPORT( FT_Error ) +(*qFT_Done_FreeType)( FT_Library library ); +/* +FT_EXPORT( FT_Error ) +(*qFT_New_Face)( FT_Library library, + const char* filepathname, + FT_Long face_index, + FT_Face *aface ); +*/ +FT_EXPORT( FT_Error ) +(*qFT_New_Memory_Face)( FT_Library library, + const FT_Byte* file_base, + FT_Long file_size, + FT_Long face_index, + FT_Face *aface ); +FT_EXPORT( FT_Error ) +(*qFT_Done_Face)( FT_Face face ); +FT_EXPORT( FT_Error ) +(*qFT_Select_Size)( FT_Face face, + FT_Int strike_index ); +FT_EXPORT( FT_Error ) +(*qFT_Request_Size)( FT_Face face, + FT_Size_Request req ); +FT_EXPORT( FT_Error ) +(*qFT_Set_Char_Size)( FT_Face face, + FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution ); +FT_EXPORT( FT_Error ) +(*qFT_Set_Pixel_Sizes)( FT_Face face, + FT_UInt pixel_width, + FT_UInt pixel_height ); +FT_EXPORT( FT_Error ) +(*qFT_Load_Glyph)( FT_Face face, + FT_UInt glyph_index, + FT_Int32 load_flags ); +FT_EXPORT( FT_Error ) +(*qFT_Load_Char)( FT_Face face, + FT_ULong char_code, + FT_Int32 load_flags ); +FT_EXPORT( FT_UInt ) +(*qFT_Get_Char_Index)( FT_Face face, + FT_ULong charcode ); +FT_EXPORT( FT_Error ) +(*qFT_Render_Glyph)( FT_GlyphSlot slot, + FT_Render_Mode render_mode ); +FT_EXPORT( FT_Error ) +(*qFT_Get_Kerning)( FT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph, + FT_UInt kern_mode, + FT_Vector *akerning ); +FT_EXPORT( FT_Error ) +(*qFT_Attach_Stream)( FT_Face face, + FT_Open_Args* parameters ); +/* +================================================================================ +Support for dynamically loading the FreeType2 library +================================================================================ +*/ + +static dllfunction_t ft2funcs[] = +{ + {"FT_Init_FreeType", (void **) &qFT_Init_FreeType}, + {"FT_Done_FreeType", (void **) &qFT_Done_FreeType}, + //{"FT_New_Face", (void **) &qFT_New_Face}, + {"FT_New_Memory_Face", (void **) &qFT_New_Memory_Face}, + {"FT_Done_Face", (void **) &qFT_Done_Face}, + {"FT_Select_Size", (void **) &qFT_Select_Size}, + {"FT_Request_Size", (void **) &qFT_Request_Size}, + {"FT_Set_Char_Size", (void **) &qFT_Set_Char_Size}, + {"FT_Set_Pixel_Sizes", (void **) &qFT_Set_Pixel_Sizes}, + {"FT_Load_Glyph", (void **) &qFT_Load_Glyph}, + {"FT_Load_Char", (void **) &qFT_Load_Char}, + {"FT_Get_Char_Index", (void **) &qFT_Get_Char_Index}, + {"FT_Render_Glyph", (void **) &qFT_Render_Glyph}, + {"FT_Get_Kerning", (void **) &qFT_Get_Kerning}, + {"FT_Attach_Stream", (void **) &qFT_Attach_Stream}, + {NULL, NULL} +}; + +/// Handle for FreeType2 DLL +static dllhandle_t ft2_dll = NULL; + +/// Memory pool for fonts +static mempool_t *font_mempool= NULL; + +/// FreeType library handle +static FT_Library font_ft2lib = NULL; + +#define POSTPROCESS_MAXRADIUS 8 +typedef struct +{ + unsigned char *buf, *buf2; + int bufsize, bufwidth, bufheight, bufpitch; + float blur, outline, shadowx, shadowy, shadowz; + int padding_t, padding_b, padding_l, padding_r, blurpadding_lt, blurpadding_rb, outlinepadding_t, outlinepadding_b, outlinepadding_l, outlinepadding_r; + unsigned char circlematrix[2*POSTPROCESS_MAXRADIUS+1][2*POSTPROCESS_MAXRADIUS+1]; + unsigned char gausstable[2*POSTPROCESS_MAXRADIUS+1]; +} +font_postprocess_t; +static font_postprocess_t pp; + +typedef struct fontfilecache_s +{ + unsigned char *buf; + fs_offset_t len; + int refcount; + char path[MAX_QPATH]; +} +fontfilecache_t; +#define MAX_FONTFILES 8 +static fontfilecache_t fontfiles[MAX_FONTFILES]; +static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer) +{ + int i; + unsigned char *buf; + + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + if(!strcmp(path, fontfiles[i].path)) + { + *filesizepointer = fontfiles[i].len; + ++fontfiles[i].refcount; + return fontfiles[i].buf; + } + } + + buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer); + if(buf) + { + for(i = 0; i < MAX_FONTFILES; ++i) + if(fontfiles[i].refcount <= 0) + { + strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path)); + fontfiles[i].len = *filesizepointer; + fontfiles[i].buf = buf; + fontfiles[i].refcount = 1; + return buf; + } + } + + return buf; +} +static void fontfilecache_Free(const unsigned char *buf) +{ + int i; + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + if(fontfiles[i].buf == buf) + { + if(--fontfiles[i].refcount <= 0) + { + Mem_Free(fontfiles[i].buf); + fontfiles[i].buf = NULL; + } + return; + } + } + // if we get here, it used regular allocation + Mem_Free((void *) buf); +} +static void fontfilecache_FreeAll(void) +{ + int i; + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + Mem_Free(fontfiles[i].buf); + fontfiles[i].buf = NULL; + fontfiles[i].refcount = 0; + } +} + +/* +==================== +Font_CloseLibrary + +Unload the FreeType2 DLL +==================== +*/ +void Font_CloseLibrary (void) +{ + fontfilecache_FreeAll(); + if (font_mempool) + Mem_FreePool(&font_mempool); + if (font_ft2lib && qFT_Done_FreeType) + { + qFT_Done_FreeType(font_ft2lib); + font_ft2lib = NULL; + } + Sys_UnloadLibrary (&ft2_dll); + pp.buf = NULL; +} + +/* +==================== +Font_OpenLibrary + +Try to load the FreeType2 DLL +==================== +*/ +qboolean Font_OpenLibrary (void) +{ + const char* dllnames [] = + { +#if defined(WIN32) + "libfreetype-6.dll", + "freetype6.dll", +#elif defined(MACOSX) + "libfreetype.6.dylib", + "libfreetype.dylib", +#else + "libfreetype.so.6", + "libfreetype.so", +#endif + NULL + }; + + if (r_font_disable_freetype.integer) + return false; + + // Already loaded? + if (ft2_dll) + return true; + + // Load the DLL + if (!Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs)) + return false; + return true; +} + +/* +==================== +Font_Init + +Initialize the freetype2 font subsystem +==================== +*/ + +void font_start(void) +{ + if (!Font_OpenLibrary()) + return; + + if (qFT_Init_FreeType(&font_ft2lib)) + { + Con_Print("ERROR: Failed to initialize the FreeType2 library!\n"); + Font_CloseLibrary(); + return; + } + + font_mempool = Mem_AllocPool("FONT", 0, NULL); + if (!font_mempool) + { + Con_Print("ERROR: Failed to allocate FONT memory pool!\n"); + Font_CloseLibrary(); + return; + } +} + +void font_shutdown(void) +{ + int i; + for (i = 0; i < dp_fonts.maxsize; ++i) + { + if (dp_fonts.f[i].ft2) + { + Font_UnloadFont(dp_fonts.f[i].ft2); + dp_fonts.f[i].ft2 = NULL; + } + } + Font_CloseLibrary(); +} + +void font_newmap(void) +{ +} + +void Font_Init(void) +{ + Cvar_RegisterVariable(&r_font_nonpoweroftwo); + Cvar_RegisterVariable(&r_font_disable_freetype); + Cvar_RegisterVariable(&r_font_use_alpha_textures); + Cvar_RegisterVariable(&r_font_size_snapping); + Cvar_RegisterVariable(&r_font_kerning); + Cvar_RegisterVariable(&r_font_diskcache); + Cvar_RegisterVariable(&r_font_compress); + Cvar_RegisterVariable(&developer_font); + + // let's open it at startup already + Font_OpenLibrary(); +} + +/* +================================================================================ +Implementation of a more or less lazy font loading and rendering code. +================================================================================ +*/ + +#include "ft2_fontdefs.h" + +ft2_font_t *Font_Alloc(void) +{ + if (!ft2_dll) + return NULL; + return (ft2_font_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_t)); +} + +static qboolean Font_Attach(ft2_font_t *font, ft2_attachment_t *attachment) +{ + ft2_attachment_t *na; + + font->attachmentcount++; + na = (ft2_attachment_t*)Mem_Alloc(font_mempool, sizeof(font->attachments[0]) * font->attachmentcount); + if (na == NULL) + return false; + if (font->attachments && font->attachmentcount > 1) + { + memcpy(na, font->attachments, sizeof(font->attachments[0]) * (font->attachmentcount - 1)); + Mem_Free(font->attachments); + } + memcpy(na + sizeof(font->attachments[0]) * (font->attachmentcount - 1), attachment, sizeof(*attachment)); + font->attachments = na; + return true; +} + +float Font_VirtualToRealSize(float sz) +{ + int vh; + //int vw; + int si; + float sn; + if(sz < 0) + return sz; + //vw = ((vid.width > 0) ? vid.width : vid_width.value); + vh = ((vid.height > 0) ? vid.height : vid_height.value); + // now try to scale to our actual size: + sn = sz * vh / vid_conheight.value; + si = (int)sn; + if ( sn - (float)si >= 0.5 ) + ++si; + return si; +} + +float Font_SnapTo(float val, float snapwidth) +{ + return floor(val / snapwidth + 0.5f) * snapwidth; +} + +static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font); +static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only); +qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt) +{ + int s, count, i; + ft2_font_t *ft2, *fbfont, *fb; + char vabuf[1024]; + + ft2 = Font_Alloc(); + if (!ft2) + { + dpfnt->ft2 = NULL; + return false; + } + + // check if a fallback font has been specified, if it has been, and the + // font fails to load, use the image font as main font + for (i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + if (dpfnt->fallbacks[i][0]) + break; + } + + if (!Font_LoadFile(name, dpfnt->req_face, &dpfnt->settings, ft2)) + { + if (i >= MAX_FONT_FALLBACKS) + { + dpfnt->ft2 = NULL; + Mem_Free(ft2); + return false; + } + strlcpy(ft2->name, name, sizeof(ft2->name)); + ft2->image_font = true; + ft2->has_kerning = false; + } + else + { + ft2->image_font = false; + } + + // attempt to load fallback fonts: + fbfont = ft2; + for (i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + if (!dpfnt->fallbacks[i][0]) + break; + if (! (fb = Font_Alloc()) ) + { + Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name); + break; + } + + if (!Font_LoadFile(dpfnt->fallbacks[i], dpfnt->fallback_faces[i], &dpfnt->settings, fb)) + { + if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.tga", dpfnt->fallbacks[i]))) + if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.png", dpfnt->fallbacks[i]))) + if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.jpg", dpfnt->fallbacks[i]))) + if(!FS_FileExists(va(vabuf, sizeof(vabuf), "%s.pcx", dpfnt->fallbacks[i]))) + Con_Printf("Failed to load font %s for fallback %i of font %s\n", dpfnt->fallbacks[i], i, name); + Mem_Free(fb); + continue; + } + count = 0; + for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s) + { + if (Font_LoadSize(fb, Font_VirtualToRealSize(dpfnt->req_sizes[s]), true)) + ++count; + } + if (!count) + { + Con_Printf("Failed to allocate font for fallback %i of font %s\n", i, name); + Font_UnloadFont(fb); + Mem_Free(fb); + break; + } + // at least one size of the fallback font loaded successfully + // link it: + fbfont->next = fb; + fbfont = fb; + } + + if (fbfont == ft2 && ft2->image_font) + { + // no fallbacks were loaded successfully: + dpfnt->ft2 = NULL; + Mem_Free(ft2); + return false; + } + + count = 0; + for (s = 0; s < MAX_FONT_SIZES && dpfnt->req_sizes[s] >= 0; ++s) + { + if (Font_LoadSize(ft2, Font_VirtualToRealSize(dpfnt->req_sizes[s]), false)) + ++count; + } + if (!count) + { + // loading failed for every requested size + Font_UnloadFont(ft2); + Mem_Free(ft2); + dpfnt->ft2 = NULL; + return false; + } + + //Con_Printf("%i sizes loaded\n", count); + dpfnt->ft2 = ft2; + return true; +} + +static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *settings, ft2_font_t *font) +{ + size_t namelen; + char filename[MAX_QPATH]; + int status; + size_t i; + const unsigned char *data; + fs_offset_t datasize; + + memset(font, 0, sizeof(*font)); + + if (!Font_OpenLibrary()) + { + if (!r_font_disable_freetype.integer) + { + Con_Printf("WARNING: can't open load font %s\n" + "You need the FreeType2 DLL to load font files\n", + name); + } + return false; + } + + font->settings = settings; + + namelen = strlen(name); + + // try load direct file + memcpy(filename, name, namelen+1); + data = fontfilecache_LoadFile(filename, false, &datasize); + // try load .ttf + if (!data) + { + memcpy(filename + namelen, ".ttf", 5); + data = fontfilecache_LoadFile(filename, false, &datasize); + } + // try load .otf + if (!data) + { + memcpy(filename + namelen, ".otf", 5); + data = fontfilecache_LoadFile(filename, false, &datasize); + } + // try load .pfb/afm + if (!data) + { + ft2_attachment_t afm; + + memcpy(filename + namelen, ".pfb", 5); + data = fontfilecache_LoadFile(filename, false, &datasize); + + if (data) + { + memcpy(filename + namelen, ".afm", 5); + afm.data = fontfilecache_LoadFile(filename, false, &afm.size); + + if (afm.data) + Font_Attach(font, &afm); + } + } + if (!data) + { + // FS_LoadFile being not-quiet should print an error :) + return false; + } + Con_DPrintf("Loading font %s face %i...\n", filename, _face); + + status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face); + if (status && _face != 0) + { + Con_Printf("Failed to load face %i of %s. Falling back to face 0\n", _face, name); + _face = 0; + status = qFT_New_Memory_Face(font_ft2lib, (FT_Bytes)data, datasize, _face, (FT_Face*)&font->face); + } + font->data = data; + if (status) + { + Con_Printf("ERROR: can't create face for %s\n" + "Error %i\n", // TODO: error strings + name, status); + Font_UnloadFont(font); + return false; + } + + // add the attachments + for (i = 0; i < font->attachmentcount; ++i) + { + FT_Open_Args args; + memset(&args, 0, sizeof(args)); + args.flags = FT_OPEN_MEMORY; + args.memory_base = (const FT_Byte*)font->attachments[i].data; + args.memory_size = font->attachments[i].size; + if (qFT_Attach_Stream((FT_Face)font->face, &args)) + Con_Printf("Failed to add attachment %u to %s\n", (unsigned)i, font->name); + } + + memcpy(font->name, name, namelen+1); + font->image_font = false; + font->has_kerning = !!(((FT_Face)(font->face))->face_flags & FT_FACE_FLAG_KERNING); + return true; +} + +static void Font_Postprocess_Update(ft2_font_t *fnt, int bpp, int w, int h) +{ + int needed, x, y; + float gausstable[2*POSTPROCESS_MAXRADIUS+1]; + qboolean need_gauss = (!pp.buf || pp.blur != fnt->settings->blur || pp.shadowz != fnt->settings->shadowz); + qboolean need_circle = (!pp.buf || pp.outline != fnt->settings->outline || pp.shadowx != fnt->settings->shadowx || pp.shadowy != fnt->settings->shadowy); + pp.blur = fnt->settings->blur; + pp.outline = fnt->settings->outline; + pp.shadowx = fnt->settings->shadowx; + pp.shadowy = fnt->settings->shadowy; + pp.shadowz = fnt->settings->shadowz; + pp.outlinepadding_l = bound(0, ceil(pp.outline - pp.shadowx), POSTPROCESS_MAXRADIUS); + pp.outlinepadding_r = bound(0, ceil(pp.outline + pp.shadowx), POSTPROCESS_MAXRADIUS); + pp.outlinepadding_t = bound(0, ceil(pp.outline - pp.shadowy), POSTPROCESS_MAXRADIUS); + pp.outlinepadding_b = bound(0, ceil(pp.outline + pp.shadowy), POSTPROCESS_MAXRADIUS); + pp.blurpadding_lt = bound(0, ceil(pp.blur - pp.shadowz), POSTPROCESS_MAXRADIUS); + pp.blurpadding_rb = bound(0, ceil(pp.blur + pp.shadowz), POSTPROCESS_MAXRADIUS); + pp.padding_l = pp.blurpadding_lt + pp.outlinepadding_l; + pp.padding_r = pp.blurpadding_rb + pp.outlinepadding_r; + pp.padding_t = pp.blurpadding_lt + pp.outlinepadding_t; + pp.padding_b = pp.blurpadding_rb + pp.outlinepadding_b; + if(need_gauss) + { + float sum = 0; + for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x) + gausstable[POSTPROCESS_MAXRADIUS+x] = (pp.blur > 0 ? exp(-(pow(x + pp.shadowz, 2))/(pp.blur*pp.blur * 2)) : (floor(x + pp.shadowz + 0.5) == 0)); + for(x = -pp.blurpadding_rb; x <= pp.blurpadding_lt; ++x) + sum += gausstable[POSTPROCESS_MAXRADIUS+x]; + for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x) + pp.gausstable[POSTPROCESS_MAXRADIUS+x] = floor(gausstable[POSTPROCESS_MAXRADIUS+x] / sum * 255 + 0.5); + } + if(need_circle) + { + for(y = -POSTPROCESS_MAXRADIUS; y <= POSTPROCESS_MAXRADIUS; ++y) + for(x = -POSTPROCESS_MAXRADIUS; x <= POSTPROCESS_MAXRADIUS; ++x) + { + float d = pp.outline + 1 - sqrt(pow(x + pp.shadowx, 2) + pow(y + pp.shadowy, 2)); + pp.circlematrix[POSTPROCESS_MAXRADIUS+y][POSTPROCESS_MAXRADIUS+x] = (d >= 1) ? 255 : (d <= 0) ? 0 : floor(d * 255 + 0.5); + } + } + pp.bufwidth = w + pp.padding_l + pp.padding_r; + pp.bufheight = h + pp.padding_t + pp.padding_b; + pp.bufpitch = pp.bufwidth; + needed = pp.bufwidth * pp.bufheight; + if(!pp.buf || pp.bufsize < needed * 2) + { + if(pp.buf) + Mem_Free(pp.buf); + pp.bufsize = needed * 4; + pp.buf = (unsigned char *)Mem_Alloc(font_mempool, pp.bufsize); + pp.buf2 = pp.buf + needed; + } +} + +static void Font_Postprocess(ft2_font_t *fnt, unsigned char *imagedata, int pitch, int bpp, int w, int h, int *pad_l, int *pad_r, int *pad_t, int *pad_b) +{ + int x, y; + + // calculate gauss table + Font_Postprocess_Update(fnt, bpp, w, h); + + if(imagedata) + { + // enlarge buffer + // perform operation, not exceeding the passed padding values, + // but possibly reducing them + *pad_l = min(*pad_l, pp.padding_l); + *pad_r = min(*pad_r, pp.padding_r); + *pad_t = min(*pad_t, pp.padding_t); + *pad_b = min(*pad_b, pp.padding_b); + + // outline the font (RGBA only) + if(bpp == 4 && (pp.outline > 0 || pp.blur > 0 || pp.shadowx != 0 || pp.shadowy != 0 || pp.shadowz != 0)) // we can only do this in BGRA + { + // this is like mplayer subtitle rendering + // bbuffer, bitmap buffer: this is our font + // abuffer, alpha buffer: this is pp.buf + // tmp: this is pp.buf2 + + // create outline buffer + memset(pp.buf, 0, pp.bufwidth * pp.bufheight); + for(y = -*pad_t; y < h + *pad_b; ++y) + for(x = -*pad_l; x < w + *pad_r; ++x) + { + int x1 = max(-x, -pp.outlinepadding_r); + int y1 = max(-y, -pp.outlinepadding_b); + int x2 = min(pp.outlinepadding_l, w-1-x); + int y2 = min(pp.outlinepadding_t, h-1-y); + int mx, my; + int cur = 0; + int highest = 0; + for(my = y1; my <= y2; ++my) + for(mx = x1; mx <= x2; ++mx) + { + cur = pp.circlematrix[POSTPROCESS_MAXRADIUS+my][POSTPROCESS_MAXRADIUS+mx] * (int)imagedata[(x+mx) * bpp + pitch * (y+my) + (bpp - 1)]; + if(cur > highest) + highest = cur; + } + pp.buf[((x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t))] = (highest + 128) / 255; + } + + // blur the outline buffer + if(pp.blur > 0 || pp.shadowz != 0) + { + // horizontal blur + for(y = 0; y < pp.bufheight; ++y) + for(x = 0; x < pp.bufwidth; ++x) + { + int x1 = max(-x, -pp.blurpadding_rb); + int x2 = min(pp.blurpadding_lt, pp.bufwidth-1-x); + int mx; + int blurred = 0; + for(mx = x1; mx <= x2; ++mx) + blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+mx] * (int)pp.buf[(x+mx) + pp.bufpitch * y]; + pp.buf2[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255; + } + + // vertical blur + for(y = 0; y < pp.bufheight; ++y) + for(x = 0; x < pp.bufwidth; ++x) + { + int y1 = max(-y, -pp.blurpadding_rb); + int y2 = min(pp.blurpadding_lt, pp.bufheight-1-y); + int my; + int blurred = 0; + for(my = y1; my <= y2; ++my) + blurred += pp.gausstable[POSTPROCESS_MAXRADIUS+my] * (int)pp.buf2[x + pp.bufpitch * (y+my)]; + pp.buf[x + pp.bufpitch * y] = bound(0, blurred, 65025) / 255; + } + } + + // paste the outline below the font + for(y = -*pad_t; y < h + *pad_b; ++y) + for(x = -*pad_l; x < w + *pad_r; ++x) + { + unsigned char outlinealpha = pp.buf[(x + pp.padding_l) + pp.bufpitch * (y + pp.padding_t)]; + if(outlinealpha > 0) + { + unsigned char oldalpha = imagedata[x * bpp + pitch * y + (bpp - 1)]; + // a' = 1 - (1 - a1) (1 - a2) + unsigned char newalpha = 255 - ((255 - (int)outlinealpha) * (255 - (int)oldalpha)) / 255; // this is >= oldalpha + // c' = (a2 c2 - a1 a2 c1 + a1 c1) / a' = (a2 c2 + a1 (1 - a2) c1) / a' + unsigned char oldfactor = (255 * (int)oldalpha) / newalpha; + //unsigned char outlinefactor = ((255 - oldalpha) * (int)outlinealpha) / newalpha; + int i; + for(i = 0; i < bpp-1; ++i) + { + unsigned char c = imagedata[x * bpp + pitch * y + i]; + c = (c * (int)oldfactor) / 255 /* + outlinecolor[i] * (int)outlinefactor */; + imagedata[x * bpp + pitch * y + i] = c; + } + imagedata[x * bpp + pitch * y + (bpp - 1)] = newalpha; + } + //imagedata[x * bpp + pitch * y + (bpp - 1)] |= 0x80; + } + } + } + else if(pitch) + { + // perform operation, not exceeding the passed padding values, + // but possibly reducing them + *pad_l = min(*pad_l, pp.padding_l); + *pad_r = min(*pad_r, pp.padding_r); + *pad_t = min(*pad_t, pp.padding_t); + *pad_b = min(*pad_b, pp.padding_b); + } + else + { + // just calculate parameters + *pad_l = pp.padding_l; + *pad_r = pp.padding_r; + *pad_t = pp.padding_t; + *pad_b = pp.padding_b; + } +} + +static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size); +static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap); +static qboolean Font_LoadSize(ft2_font_t *font, float size, qboolean check_only) +{ + int map_index; + ft2_font_map_t *fmap, temp; + int gpad_l, gpad_r, gpad_t, gpad_b; + + if (!(size > 0.001f && size < 1000.0f)) + size = 0; + + if (!size) + size = 16; + if (size < 2) // bogus sizes are not allowed - and they screw up our allocations + return false; + + for (map_index = 0; map_index < MAX_FONT_SIZES; ++map_index) + { + if (!font->font_maps[map_index]) + break; + // if a similar size has already been loaded, ignore this one + //abs(font->font_maps[map_index]->size - size) < 4 + if (font->font_maps[map_index]->size == size) + return true; + } + + if (map_index >= MAX_FONT_SIZES) + return false; + + if (check_only) { + FT_Face fontface; + if (font->image_font) + fontface = (FT_Face)font->next->face; + else + fontface = (FT_Face)font->face; + return (Font_SearchSize(font, fontface, size) > 0); + } + + Font_Postprocess(font, NULL, 0, 4, size*2, size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b); + + memset(&temp, 0, sizeof(temp)); + temp.size = size; + temp.glyphSize = size*2 + max(gpad_l + gpad_r, gpad_t + gpad_b); + if (!(r_font_nonpoweroftwo.integer && vid.support.arb_texture_non_power_of_two)) + temp.glyphSize = CeilPowerOf2(temp.glyphSize); + temp.sfx = (1.0/64.0)/(double)size; + temp.sfy = (1.0/64.0)/(double)size; + temp.intSize = -1; // negative value: LoadMap must search now :) + if (!Font_LoadMap(font, &temp, 0, &fmap)) + { + Con_Printf("ERROR: can't load the first character map for %s\n" + "This is fatal\n", + font->name); + Font_UnloadFont(font); + return false; + } + font->font_maps[map_index] = temp.next; + + fmap->sfx = temp.sfx; + fmap->sfy = temp.sfy; + + // load the default kerning vector: + if (font->has_kerning) + { + Uchar l, r; + FT_Vector kernvec; + for (l = 0; l < 256; ++l) + { + for (r = 0; r < 256; ++r) + { + FT_ULong ul, ur; + ul = qFT_Get_Char_Index((FT_Face)font->face, l); + ur = qFT_Get_Char_Index((FT_Face)font->face, r); + if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec)) + { + fmap->kerning.kerning[l][r][0] = 0; + fmap->kerning.kerning[l][r][1] = 0; + } + else + { + fmap->kerning.kerning[l][r][0] = Font_SnapTo((kernvec.x / 64.0) / fmap->size, 1 / fmap->size); + fmap->kerning.kerning[l][r][1] = Font_SnapTo((kernvec.y / 64.0) / fmap->size, 1 / fmap->size); + } + } + } + } + return true; +} + +int Font_IndexForSize(ft2_font_t *font, float _fsize, float *outw, float *outh) +{ + int match = -1; + float value = 1000000; + float nval; + int matchsize = -10000; + int m; + float fsize_x, fsize_y; + ft2_font_map_t **maps = font->font_maps; + + fsize_x = fsize_y = _fsize * vid.height / vid_conheight.value; + if(outw && *outw) + fsize_x = *outw * vid.width / vid_conwidth.value; + if(outh && *outh) + fsize_y = *outh * vid.height / vid_conheight.value; + + if (fsize_x < 0) + { + if(fsize_y < 0) + fsize_x = fsize_y = 16; + else + fsize_x = fsize_y; + } + else + { + if(fsize_y < 0) + fsize_y = fsize_x; + } + + for (m = 0; m < MAX_FONT_SIZES; ++m) + { + if (!maps[m]) + continue; + // "round up" to the bigger size if two equally-valued matches exist + nval = 0.5 * (fabs(maps[m]->size - fsize_x) + fabs(maps[m]->size - fsize_y)); + if (match == -1 || nval < value || (nval == value && matchsize < maps[m]->size)) + { + value = nval; + match = m; + matchsize = maps[m]->size; + if (value == 0) // there is no better match + break; + } + } + if (value <= r_font_size_snapping.value) + { + // do NOT keep the aspect for perfect rendering + if (outh) *outh = maps[match]->size * vid_conheight.value / vid.height; + if (outw) *outw = maps[match]->size * vid_conwidth.value / vid.width; + } + return match; +} + +ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index) +{ + if (index < 0 || index >= MAX_FONT_SIZES) + return NULL; + return font->font_maps[index]; +} + +static qboolean Font_SetSize(ft2_font_t *font, float w, float h) +{ + if (font->currenth == h && + ((!w && (!font->currentw || font->currentw == font->currenth)) || // check if w==h when w is not set + font->currentw == w)) // same size has been requested + { + return true; + } + // sorry, but freetype doesn't seem to care about other sizes + w = (int)w; + h = (int)h; + if (font->image_font) + { + if (qFT_Set_Char_Size((FT_Face)font->next->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72)) + return false; + } + else + { + if (qFT_Set_Char_Size((FT_Face)font->face, (FT_F26Dot6)(w*64), (FT_F26Dot6)(h*64), 72, 72)) + return false; + } + font->currentw = w; + font->currenth = h; + return true; +} + +qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy) +{ + ft2_font_map_t *fmap; + if (!font->has_kerning || !r_font_kerning.integer) + return false; + if (map_index < 0 || map_index >= MAX_FONT_SIZES) + return false; + fmap = font->font_maps[map_index]; + if (!fmap) + return false; + if (left < 256 && right < 256) + { + //Con_Printf("%g : %f, %f, %f :: %f\n", (w / (float)fmap->size), w, fmap->size, fmap->intSize, Font_VirtualToRealSize(w)); + // quick-kerning, be aware of the size: scale it + if (outx) *outx = fmap->kerning.kerning[left][right][0];// * (w / (float)fmap->size); + if (outy) *outy = fmap->kerning.kerning[left][right][1];// * (h / (float)fmap->size); + return true; + } + else + { + FT_Vector kernvec; + FT_ULong ul, ur; + + //if (qFT_Set_Pixel_Sizes((FT_Face)font->face, 0, fmap->size)) +#if 0 + if (!Font_SetSize(font, w, h)) + { + // this deserves an error message + Con_Printf("Failed to get kerning for %s\n", font->name); + return false; + } + ul = qFT_Get_Char_Index(font->face, left); + ur = qFT_Get_Char_Index(font->face, right); + if (qFT_Get_Kerning(font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec)) + { + if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size); + if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size); + return true; + } +#endif + if (!Font_SetSize(font, fmap->intSize, fmap->intSize)) + { + // this deserves an error message + Con_Printf("Failed to get kerning for %s\n", font->name); + return false; + } + ul = qFT_Get_Char_Index((FT_Face)font->face, left); + ur = qFT_Get_Char_Index((FT_Face)font->face, right); + if (qFT_Get_Kerning((FT_Face)font->face, ul, ur, FT_KERNING_DEFAULT, &kernvec)) + { + if (outx) *outx = Font_SnapTo(kernvec.x * fmap->sfx, 1 / fmap->size);// * (w / (float)fmap->size); + if (outy) *outy = Font_SnapTo(kernvec.y * fmap->sfy, 1 / fmap->size);// * (h / (float)fmap->size); + return true; + } + return false; + } +} + +qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy) +{ + return Font_GetKerningForMap(font, Font_IndexForSize(font, h, NULL, NULL), w, h, left, right, outx, outy); +} + +static void UnloadMapRec(ft2_font_map_t *map) +{ + if (map->pic) + { + //Draw_FreePic(map->pic); // FIXME: refcounting needed... + map->pic = NULL; + } + if (map->next) + UnloadMapRec(map->next); + Mem_Free(map); +} + +void Font_UnloadFont(ft2_font_t *font) +{ + int i; + + // unload fallbacks + if(font->next) + Font_UnloadFont(font->next); + + if (font->attachments && font->attachmentcount) + { + for (i = 0; i < (int)font->attachmentcount; ++i) { + if (font->attachments[i].data) + fontfilecache_Free(font->attachments[i].data); + } + Mem_Free(font->attachments); + font->attachmentcount = 0; + font->attachments = NULL; + } + for (i = 0; i < MAX_FONT_SIZES; ++i) + { + if (font->font_maps[i]) + { + UnloadMapRec(font->font_maps[i]); + font->font_maps[i] = NULL; + } + } + if (ft2_dll) + { + if (font->face) + { + qFT_Done_Face((FT_Face)font->face); + font->face = NULL; + } + } + if (font->data) { + fontfilecache_Free(font->data); + font->data = NULL; + } +} + +static float Font_SearchSize(ft2_font_t *font, FT_Face fontface, float size) +{ + float intSize = size; + while (1) + { + if (!Font_SetSize(font, intSize, intSize)) + { + Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, size, intSize); + return -1; + } + if ((fontface->size->metrics.height>>6) <= size) + return intSize; + if (intSize < 2) + { + Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, size); + return -1; + } + --intSize; + } +} + +static qboolean Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch, ft2_font_map_t **outmap) +{ + char map_identifier[MAX_QPATH]; + unsigned long mapidx = _ch / FONT_CHARS_PER_MAP; + unsigned char *data = NULL; + FT_ULong ch, mapch; + int status; + int tp; + FT_Int32 load_flags; + int gpad_l, gpad_r, gpad_t, gpad_b; + char vabuf[1024]; + + int pitch; + int gR, gC; // glyph position: row and column + + ft2_font_map_t *map, *next; + ft2_font_t *usefont; + + FT_Face fontface; + + int bytesPerPixel = 4; // change the conversion loop too if you change this! + + if (outmap) + *outmap = NULL; + + if (r_font_use_alpha_textures.integer) + bytesPerPixel = 1; + + if (font->image_font) + fontface = (FT_Face)font->next->face; + else + fontface = (FT_Face)font->face; + + switch(font->settings->antialias) + { + case 0: + switch(font->settings->hinting) + { + case 0: + load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME; + break; + case 1: + case 2: + load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME; + break; + default: + case 3: + load_flags = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME; + break; + } + break; + default: + case 1: + switch(font->settings->hinting) + { + case 0: + load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_TARGET_NORMAL; + break; + case 1: + load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; + break; + case 2: + load_flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL; + break; + default: + case 3: + load_flags = FT_LOAD_TARGET_NORMAL; + break; + } + break; + } + + //status = qFT_Set_Pixel_Sizes((FT_Face)font->face, /*size*/0, mapstart->size); + //if (status) + if (font->image_font && mapstart->intSize < 0) + mapstart->intSize = mapstart->size; + if (mapstart->intSize < 0) + { + /* + mapstart->intSize = mapstart->size; + while (1) + { + if (!Font_SetSize(font, mapstart->intSize, mapstart->intSize)) + { + Con_Printf("ERROR: can't set size for font %s: %f ((%f))\n", font->name, mapstart->size, mapstart->intSize); + return false; + } + if ((fontface->size->metrics.height>>6) <= mapstart->size) + break; + if (mapstart->intSize < 2) + { + Con_Printf("ERROR: no appropriate size found for font %s: %f\n", font->name, mapstart->size); + return false; + } + --mapstart->intSize; + } + */ + if ((mapstart->intSize = Font_SearchSize(font, fontface, mapstart->size)) <= 0) + return false; + Con_DPrintf("Using size: %f for requested size %f\n", mapstart->intSize, mapstart->size); + } + + if (!font->image_font && !Font_SetSize(font, mapstart->intSize, mapstart->intSize)) + { + Con_Printf("ERROR: can't set sizes for font %s: %f\n", font->name, mapstart->size); + return false; + } + + map = (ft2_font_map_t *)Mem_Alloc(font_mempool, sizeof(ft2_font_map_t)); + if (!map) + { + Con_Printf("ERROR: Out of memory when loading fontmap for %s\n", font->name); + return false; + } + + // create a totally unique name for this map, then we will use it to make a unique cachepic_t to avoid redundant textures + dpsnprintf(map_identifier, sizeof(map_identifier), + "%s_cache_%g_%d_%g_%g_%g_%g_%g_%u", + font->name, + (double) mapstart->intSize, + (int) load_flags, + (double) font->settings->blur, + (double) font->settings->outline, + (double) font->settings->shadowx, + (double) font->settings->shadowy, + (double) font->settings->shadowz, + (unsigned) mapidx); + + // create a cachepic_t from the data now, or reuse an existing one + map->pic = Draw_CachePic_Flags(map_identifier, CACHEPICFLAG_QUIET); + if (developer_font.integer) + { + if (map->pic->tex == r_texture_notexture) + Con_Printf("Generating font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize); + else + Con_Printf("Using cached font map %s (size: %.1f MB)\n", map_identifier, mapstart->glyphSize * (256 * 4 / 1048576.0) * mapstart->glyphSize); + } + + Font_Postprocess(font, NULL, 0, bytesPerPixel, mapstart->size*2, mapstart->size*2, &gpad_l, &gpad_r, &gpad_t, &gpad_b); + + // copy over the information + map->size = mapstart->size; + map->intSize = mapstart->intSize; + map->glyphSize = mapstart->glyphSize; + map->sfx = mapstart->sfx; + map->sfy = mapstart->sfy; + + pitch = map->glyphSize * FONT_CHARS_PER_LINE * bytesPerPixel; + if (map->pic->tex == r_texture_notexture) + { + data = (unsigned char *)Mem_Alloc(font_mempool, (FONT_CHAR_LINES * map->glyphSize) * pitch); + if (!data) + { + Con_Printf("ERROR: Failed to allocate memory for font %s size %g\n", font->name, map->size); + Mem_Free(map); + return false; + } + // initialize as white texture with zero alpha + tp = 0; + while (tp < (FONT_CHAR_LINES * map->glyphSize) * pitch) + { + if (bytesPerPixel == 4) + { + data[tp++] = 0xFF; + data[tp++] = 0xFF; + data[tp++] = 0xFF; + } + data[tp++] = 0x00; + } + } + + memset(map->width_of, 0, sizeof(map->width_of)); + + // insert the map + map->start = mapidx * FONT_CHARS_PER_MAP; + next = mapstart; + while(next->next && next->next->start < map->start) + next = next->next; + map->next = next->next; + next->next = map; + + gR = 0; + gC = -1; + for (ch = map->start; + ch < (FT_ULong)map->start + FONT_CHARS_PER_MAP; + ++ch) + { + FT_ULong glyphIndex; + int w, h, x, y; + FT_GlyphSlot glyph; + FT_Bitmap *bmp; + unsigned char *imagedata = NULL, *dst, *src; + glyph_slot_t *mapglyph; + FT_Face face; + int pad_l, pad_r, pad_t, pad_b; + + mapch = ch - map->start; + + if (developer_font.integer) + Con_DPrint("glyphinfo: ------------- GLYPH INFO -----------------\n"); + + ++gC; + if (gC >= FONT_CHARS_PER_LINE) + { + gC -= FONT_CHARS_PER_LINE; + ++gR; + } + + if (data) + { + imagedata = data + gR * pitch * map->glyphSize + gC * map->glyphSize * bytesPerPixel; + imagedata += gpad_t * pitch + gpad_l * bytesPerPixel; + } + //status = qFT_Load_Char(face, ch, FT_LOAD_RENDER); + // we need the glyphIndex + face = (FT_Face)font->face; + usefont = NULL; + if (font->image_font && mapch == ch && img_fontmap[mapch]) + { + map->glyphs[mapch].image = true; + continue; + } + glyphIndex = qFT_Get_Char_Index(face, ch); + if (glyphIndex == 0) + { + // by convention, 0 is the "missing-glyph"-glyph + // try to load from a fallback font + for(usefont = font->next; usefont != NULL; usefont = usefont->next) + { + if (!Font_SetSize(usefont, mapstart->intSize, mapstart->intSize)) + continue; + // try that glyph + face = (FT_Face)usefont->face; + glyphIndex = qFT_Get_Char_Index(face, ch); + if (glyphIndex == 0) + continue; + status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags); + if (status) + continue; + break; + } + if (!usefont) + { + //Con_Printf("failed to load fallback glyph for char %lx from font %s\n", (unsigned long)ch, font->name); + // now we let it use the "missing-glyph"-glyph + face = (FT_Face)font->face; + glyphIndex = 0; + } + } + + if (!usefont) + { + usefont = font; + face = (FT_Face)font->face; + status = qFT_Load_Glyph(face, glyphIndex, FT_LOAD_RENDER | load_flags); + if (status) + { + //Con_Printf("failed to load glyph %lu for %s\n", glyphIndex, font->name); + Con_DPrintf("failed to load glyph for char %lx from font %s\n", (unsigned long)ch, font->name); + continue; + } + } + + glyph = face->glyph; + bmp = &glyph->bitmap; + + w = bmp->width; + h = bmp->rows; + + if (w > (map->glyphSize - gpad_l - gpad_r) || h > (map->glyphSize - gpad_t - gpad_b)) { + Con_Printf("WARNING: Glyph %lu is too big in font %s, size %g: %i x %i\n", ch, font->name, map->size, w, h); + if (w > map->glyphSize) + w = map->glyphSize - gpad_l - gpad_r; + if (h > map->glyphSize) + h = map->glyphSize; + } + + if (imagedata) + { + switch (bmp->pixel_mode) + { + case FT_PIXEL_MODE_MONO: + if (developer_font.integer) + Con_DPrint("glyphinfo: Pixel Mode: MONO\n"); + break; + case FT_PIXEL_MODE_GRAY2: + if (developer_font.integer) + Con_DPrint("glyphinfo: Pixel Mode: GRAY2\n"); + break; + case FT_PIXEL_MODE_GRAY4: + if (developer_font.integer) + Con_DPrint("glyphinfo: Pixel Mode: GRAY4\n"); + break; + case FT_PIXEL_MODE_GRAY: + if (developer_font.integer) + Con_DPrint("glyphinfo: Pixel Mode: GRAY\n"); + break; + default: + if (developer_font.integer) + Con_DPrintf("glyphinfo: Pixel Mode: Unknown: %i\n", bmp->pixel_mode); + Mem_Free(data); + Con_Printf("ERROR: Unrecognized pixel mode for font %s size %f: %i\n", font->name, mapstart->size, bmp->pixel_mode); + return false; + } + for (y = 0; y < h; ++y) + { + dst = imagedata + y * pitch; + src = bmp->buffer + y * bmp->pitch; + + switch (bmp->pixel_mode) + { + case FT_PIXEL_MODE_MONO: + dst += bytesPerPixel - 1; // shift to alpha byte + for (x = 0; x < bmp->width; x += 8) + { + unsigned char ch = *src++; + *dst = 255 * !!((ch & 0x80) >> 7); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x40) >> 6); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x20) >> 5); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x10) >> 4); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x08) >> 3); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x04) >> 2); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x02) >> 1); dst += bytesPerPixel; + *dst = 255 * !!((ch & 0x01) >> 0); dst += bytesPerPixel; + } + break; + case FT_PIXEL_MODE_GRAY2: + dst += bytesPerPixel - 1; // shift to alpha byte + for (x = 0; x < bmp->width; x += 4) + { + unsigned char ch = *src++; + *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel; + *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel; + *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel; + *dst = ( ((ch & 0xA0) >> 6) * 0x55 ); ch <<= 2; dst += bytesPerPixel; + } + break; + case FT_PIXEL_MODE_GRAY4: + dst += bytesPerPixel - 1; // shift to alpha byte + for (x = 0; x < bmp->width; x += 2) + { + unsigned char ch = *src++; + *dst = ( ((ch & 0xF0) >> 4) * 0x11); dst += bytesPerPixel; + *dst = ( ((ch & 0x0F) ) * 0x11); dst += bytesPerPixel; + } + break; + case FT_PIXEL_MODE_GRAY: + // in this case pitch should equal width + for (tp = 0; tp < bmp->pitch; ++tp) + dst[(bytesPerPixel - 1) + tp*bytesPerPixel] = src[tp]; // copy the grey value into the alpha bytes + + //memcpy((void*)dst, (void*)src, bmp->pitch); + //dst += bmp->pitch; + break; + default: + break; + } + } + + pad_l = gpad_l; + pad_r = gpad_r; + pad_t = gpad_t; + pad_b = gpad_b; + Font_Postprocess(font, imagedata, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b); + } + else + { + pad_l = gpad_l; + pad_r = gpad_r; + pad_t = gpad_t; + pad_b = gpad_b; + Font_Postprocess(font, NULL, pitch, bytesPerPixel, w, h, &pad_l, &pad_r, &pad_t, &pad_b); + } + + + // now fill map->glyphs[ch - map->start] + mapglyph = &map->glyphs[mapch]; + + { + // old way + // double advance = (double)glyph->metrics.horiAdvance * map->sfx; + + double bearingX = (glyph->metrics.horiBearingX / 64.0) / map->size; + //double bearingY = (glyph->metrics.horiBearingY >> 6) / map->size; + double advance = (glyph->advance.x / 64.0) / map->size; + //double mWidth = (glyph->metrics.width >> 6) / map->size; + //double mHeight = (glyph->metrics.height >> 6) / map->size; + + mapglyph->txmin = ( (double)(gC * map->glyphSize) + (double)(gpad_l - pad_l) ) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) ); + mapglyph->txmax = mapglyph->txmin + (double)(bmp->width + pad_l + pad_r) / ( (double)(map->glyphSize * FONT_CHARS_PER_LINE) ); + mapglyph->tymin = ( (double)(gR * map->glyphSize) + (double)(gpad_r - pad_r) ) / ( (double)(map->glyphSize * FONT_CHAR_LINES) ); + mapglyph->tymax = mapglyph->tymin + (double)(bmp->rows + pad_t + pad_b) / ( (double)(map->glyphSize * FONT_CHAR_LINES) ); + //mapglyph->vxmin = bearingX; + //mapglyph->vxmax = bearingX + mWidth; + mapglyph->vxmin = (glyph->bitmap_left - pad_l) / map->size; + mapglyph->vxmax = mapglyph->vxmin + (bmp->width + pad_l + pad_r) / map->size; // don't ask + //mapglyph->vymin = -bearingY; + //mapglyph->vymax = mHeight - bearingY; + mapglyph->vymin = (-glyph->bitmap_top - pad_t) / map->size; + mapglyph->vymax = mapglyph->vymin + (bmp->rows + pad_t + pad_b) / map->size; + //Con_Printf("dpi = %f %f (%f %d) %d %d\n", bmp->width / (mapglyph->vxmax - mapglyph->vxmin), bmp->rows / (mapglyph->vymax - mapglyph->vymin), map->size, map->glyphSize, (int)fontface->size->metrics.x_ppem, (int)fontface->size->metrics.y_ppem); + //mapglyph->advance_x = advance * usefont->size; + //mapglyph->advance_x = advance; + mapglyph->advance_x = Font_SnapTo(advance, 1 / map->size); + mapglyph->advance_y = 0; + + if (developer_font.integer) + { + Con_DPrintf("glyphinfo: Glyph: %lu at (%i, %i)\n", (unsigned long)ch, gC, gR); + Con_DPrintf("glyphinfo: %f, %f, %lu\n", bearingX, map->sfx, (unsigned long)glyph->metrics.horiBearingX); + if (ch >= 32 && ch <= 128) + Con_DPrintf("glyphinfo: Character: %c\n", (int)ch); + Con_DPrintf("glyphinfo: Vertex info:\n"); + Con_DPrintf("glyphinfo: X: ( %f -- %f )\n", mapglyph->vxmin, mapglyph->vxmax); + Con_DPrintf("glyphinfo: Y: ( %f -- %f )\n", mapglyph->vymin, mapglyph->vymax); + Con_DPrintf("glyphinfo: Texture info:\n"); + Con_DPrintf("glyphinfo: S: ( %f -- %f )\n", mapglyph->txmin, mapglyph->txmax); + Con_DPrintf("glyphinfo: T: ( %f -- %f )\n", mapglyph->tymin, mapglyph->tymax); + Con_DPrintf("glyphinfo: Advance: %f, %f\n", mapglyph->advance_x, mapglyph->advance_y); + } + } + map->glyphs[mapch].image = false; + } + + if (map->pic->tex == r_texture_notexture) + { + int w = map->glyphSize * FONT_CHARS_PER_LINE; + int h = map->glyphSize * FONT_CHAR_LINES; + rtexture_t *tex; + // abuse the Draw_CachePic system to keep track of this texture + tex = R_LoadTexture2D(drawtexturepool, map_identifier, w, h, data, r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA, TEXF_ALPHA | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0), -1, NULL); + // if tex is NULL for any reason, the pic->tex will remain set to r_texture_notexture + if (tex) + map->pic->tex = tex; + + if (r_font_diskcache.integer >= 1) + { + // swap to BGRA for tga writing... + int s = w * h; + int x; + int b; + for (x = 0;x < s;x++) + { + b = data[x*4+0]; + data[x*4+0] = data[x*4+2]; + data[x*4+2] = b; + } + Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "%s.tga", map_identifier), w, h, data); +#ifndef USE_GLES2 + if (r_font_compress.integer && qglGetCompressedTexImageARB && tex) + R_SaveTextureDDSFile(tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", map_identifier), r_texture_dds_save.integer < 2, true); +#endif + } + } + + if(data) + Mem_Free(data); + + if (map->pic->tex == r_texture_notexture) + { + // if the first try isn't successful, keep it with a broken texture + // otherwise we retry to load it every single frame where ft2 rendering is used + // this would be bad... + // only `data' must be freed + Con_Printf("ERROR: Failed to generate texture for font %s size %f map %lu\n", + font->name, mapstart->size, mapidx); + return false; + } + if (outmap) + *outmap = map; + return true; +} + +qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap) +{ + if (map_index < 0 || map_index >= MAX_FONT_SIZES) + return false; + // the first map must have been loaded already + if (!font->font_maps[map_index]) + return false; + return Font_LoadMap(font, font->font_maps[map_index], _ch, outmap); +} + +ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch) +{ + while (start && start->start + FONT_CHARS_PER_MAP <= ch) + start = start->next; + if (start && start->start > ch) + return NULL; + return start; +} diff --git a/app/jni/ft2.h b/app/jni/ft2.h new file mode 100644 index 0000000..e8110a7 --- /dev/null +++ b/app/jni/ft2.h @@ -0,0 +1,81 @@ +/* Header for FreeType 2 and UTF-8 encoding support for + * DarkPlaces + */ + +#ifndef DP_FREETYPE2_H__ +#define DP_FREETYPE2_H__ + +//#include + +#include "utf8lib.h" + +/* + * From http://www.unicode.org/Public/UNIDATA/Blocks.txt + * + * E000..F8FF; Private Use Area + * F0000..FFFFF; Supplementary Private Use Area-A + * + * We use: + * Range E000 - E0FF + * Contains the non-FreeType2 version of characters. + */ + +typedef struct ft2_font_map_s ft2_font_map_t; +typedef struct ft2_attachment_s ft2_attachment_t; +#define ft2_oldstyle_map ((ft2_font_map_t*)-1) + +typedef float ft2_kernvec[2]; +typedef struct ft2_kerning_s +{ + ft2_kernvec kerning[256][256]; /* kerning[left char][right char] */ +} ft2_kerning_t; + +typedef struct ft2_font_s +{ + char name[64]; + qboolean has_kerning; + // last requested size loaded using Font_SetSize + float currentw; + float currenth; + float ascend; + float descend; + qboolean image_font; // only fallbacks are freetype fonts + + // TODO: clean this up and do not expose everything. + + const unsigned char *data; // FT2 needs it to stay + //fs_offset_t datasize; + void *face; + + // an unordered array of ordered linked lists of glyph maps for a specific size + ft2_font_map_t *font_maps[MAX_FONT_SIZES]; + int num_sizes; + + // attachments + size_t attachmentcount; + ft2_attachment_t *attachments; + + ft2_settings_t *settings; + + // fallback mechanism + struct ft2_font_s *next; +} ft2_font_t; + +void Font_CloseLibrary(void); +void Font_Init(void); +qboolean Font_OpenLibrary(void); +ft2_font_t* Font_Alloc(void); +void Font_UnloadFont(ft2_font_t *font); +// IndexForSize suggests to change the width and height if a font size is in a reasonable range +// for example, you render at a size of 12.4, and a font of size 12 has been loaded +// in such a case, *outw and *outh are set to 12, which is often a good alternative size +int Font_IndexForSize(ft2_font_t *font, float size, float *outw, float *outh); +ft2_font_map_t *Font_MapForIndex(ft2_font_t *font, int index); +qboolean Font_LoadFont(const char *name, dp_font_t *dpfnt); +qboolean Font_GetKerningForSize(ft2_font_t *font, float w, float h, Uchar left, Uchar right, float *outx, float *outy); +qboolean Font_GetKerningForMap(ft2_font_t *font, int map_index, float w, float h, Uchar left, Uchar right, float *outx, float *outy); +float Font_VirtualToRealSize(float sz); +float Font_SnapTo(float val, float snapwidth); +// since this is used on a font_map_t, let's name it FontMap_* +ft2_font_map_t *FontMap_FindForChar(ft2_font_map_t *start, Uchar ch); +#endif // DP_FREETYPE2_H__ diff --git a/app/jni/ft2_defs.h b/app/jni/ft2_defs.h new file mode 100644 index 0000000..c8d38c6 --- /dev/null +++ b/app/jni/ft2_defs.h @@ -0,0 +1,500 @@ +/* FreeType 2 definitions from the freetype header mostly. + */ + +#ifndef FT2_DEFS_H_H__ +#define FT2_DEFS_H_H__ + +#ifdef _MSC_VER +typedef __int32 FT_Int32; +typedef unsigned __int32 FT_UInt32; +#else +# include +typedef int32_t FT_Int32; +typedef uint32_t FT_UInt32; +#endif + +typedef int FT_Error; + +typedef signed char FT_Char; +typedef unsigned char FT_Byte; +typedef const FT_Byte *FT_Bytes; +typedef char FT_String; +typedef signed short FT_Short; +typedef unsigned short FT_UShort; +typedef signed int FT_Int; +typedef unsigned int FT_UInt; +typedef signed long FT_Long; +typedef signed long FT_Fixed; +typedef unsigned long FT_ULong; +typedef void *FT_Pointer; +typedef size_t FT_Offset; +typedef signed long FT_F26Dot6; + +typedef void *FT_Stream; +typedef void *FT_Module; +typedef void *FT_Library; +typedef struct FT_FaceRec_ *FT_Face; +typedef struct FT_CharMapRec_* FT_CharMap; +typedef struct FT_SizeRec_* FT_Size; +typedef struct FT_Size_InternalRec_* FT_Size_Internal; +typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; +typedef struct FT_SubGlyphRec_* FT_SubGlyph; +typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + +// Taken from the freetype headers: +typedef signed long FT_Pos; +typedef struct FT_Vector_ +{ + FT_Pos x; + FT_Pos y; +} FT_Vector; + +typedef struct FT_BBox_ +{ + FT_Pos xMin, yMin; + FT_Pos xMax, yMax; +} FT_BBox; + +typedef enum FT_Pixel_Mode_ +{ + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + FT_PIXEL_MODE_MAX /* do not remove */ +} FT_Pixel_Mode; +typedef enum FT_Render_Mode_ +{ + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + + FT_RENDER_MODE_MAX +} FT_Render_Mode; + +#define ft_pixel_mode_none FT_PIXEL_MODE_NONE +#define ft_pixel_mode_mono FT_PIXEL_MODE_MONO +#define ft_pixel_mode_grays FT_PIXEL_MODE_GRAY +#define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 +#define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + +typedef struct FT_Bitmap_ +{ + int rows; + int width; + int pitch; + unsigned char* buffer; + short num_grays; + char pixel_mode; + char palette_mode; + void* palette; +} FT_Bitmap; + +typedef struct FT_Outline_ +{ + short n_contours; /* number of contours in glyph */ + short n_points; /* number of points in the glyph */ + + FT_Vector* points; /* the outline's points */ + char* tags; /* the points flags */ + short* contours; /* the contour end points */ + + int flags; /* outline masks */ +} FT_Outline; + +#define FT_OUTLINE_NONE 0x0 +#define FT_OUTLINE_OWNER 0x1 +#define FT_OUTLINE_EVEN_ODD_FILL 0x2 +#define FT_OUTLINE_REVERSE_FILL 0x4 +#define FT_OUTLINE_IGNORE_DROPOUTS 0x8 +#define FT_OUTLINE_SMART_DROPOUTS 0x10 +#define FT_OUTLINE_INCLUDE_STUBS 0x20 + +#define FT_OUTLINE_HIGH_PRECISION 0x100 +#define FT_OUTLINE_SINGLE_PASS 0x200 + +#define ft_outline_none FT_OUTLINE_NONE +#define ft_outline_owner FT_OUTLINE_OWNER +#define ft_outline_even_odd_fill FT_OUTLINE_EVEN_ODD_FILL +#define ft_outline_reverse_fill FT_OUTLINE_REVERSE_FILL +#define ft_outline_ignore_dropouts FT_OUTLINE_IGNORE_DROPOUTS +#define ft_outline_high_precision FT_OUTLINE_HIGH_PRECISION +#define ft_outline_single_pass FT_OUTLINE_SINGLE_PASS + +#define FT_CURVE_TAG( flag ) ( flag & 3 ) + +#define FT_CURVE_TAG_ON 1 +#define FT_CURVE_TAG_CONIC 0 +#define FT_CURVE_TAG_CUBIC 2 + +#define FT_CURVE_TAG_TOUCH_X 8 /* reserved for the TrueType hinter */ +#define FT_CURVE_TAG_TOUCH_Y 16 /* reserved for the TrueType hinter */ + +#define FT_CURVE_TAG_TOUCH_BOTH ( FT_CURVE_TAG_TOUCH_X | \ + FT_CURVE_TAG_TOUCH_Y ) + +#define FT_Curve_Tag_On FT_CURVE_TAG_ON +#define FT_Curve_Tag_Conic FT_CURVE_TAG_CONIC +#define FT_Curve_Tag_Cubic FT_CURVE_TAG_CUBIC +#define FT_Curve_Tag_Touch_X FT_CURVE_TAG_TOUCH_X +#define FT_Curve_Tag_Touch_Y FT_CURVE_TAG_TOUCH_Y + +typedef int +(*FT_Outline_MoveToFunc)( const FT_Vector* to, + void* user ); +#define FT_Outline_MoveTo_Func FT_Outline_MoveToFunc + +typedef int +(*FT_Outline_LineToFunc)( const FT_Vector* to, + void* user ); +#define FT_Outline_LineTo_Func FT_Outline_LineToFunc + +typedef int +(*FT_Outline_ConicToFunc)( const FT_Vector* control, + const FT_Vector* to, + void* user ); +#define FT_Outline_ConicTo_Func FT_Outline_ConicToFunc + +typedef int +(*FT_Outline_CubicToFunc)( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user ); +#define FT_Outline_CubicTo_Func FT_Outline_CubicToFunc + +typedef struct FT_Outline_Funcs_ +{ + FT_Outline_MoveToFunc move_to; + FT_Outline_LineToFunc line_to; + FT_Outline_ConicToFunc conic_to; + FT_Outline_CubicToFunc cubic_to; + + int shift; + FT_Pos delta; +} FT_Outline_Funcs; + +#ifndef FT_IMAGE_TAG +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( (unsigned long)_x1 << 24 ) | \ + ( (unsigned long)_x2 << 16 ) | \ + ( (unsigned long)_x3 << 8 ) | \ + (unsigned long)_x4 ) +#endif /* FT_IMAGE_TAG */ + +typedef enum FT_Glyph_Format_ +{ + FT_IMAGE_TAG( FT_GLYPH_FORMAT_NONE, 0, 0, 0, 0 ), + + FT_IMAGE_TAG( FT_GLYPH_FORMAT_COMPOSITE, 'c', 'o', 'm', 'p' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_BITMAP, 'b', 'i', 't', 's' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_OUTLINE, 'o', 'u', 't', 'l' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ) +} FT_Glyph_Format; +#define ft_glyph_format_none FT_GLYPH_FORMAT_NONE +#define ft_glyph_format_composite FT_GLYPH_FORMAT_COMPOSITE +#define ft_glyph_format_bitmap FT_GLYPH_FORMAT_BITMAP +#define ft_glyph_format_outline FT_GLYPH_FORMAT_OUTLINE +#define ft_glyph_format_plotter FT_GLYPH_FORMAT_PLOTTER + +typedef struct FT_Glyph_Metrics_ +{ + FT_Pos width; + FT_Pos height; + + FT_Pos horiBearingX; + FT_Pos horiBearingY; + FT_Pos horiAdvance; + + FT_Pos vertBearingX; + FT_Pos vertBearingY; + FT_Pos vertAdvance; +} FT_Glyph_Metrics; + +#define FT_EXPORT( x ) x + +#define FT_OPEN_MEMORY 0x1 +#define FT_OPEN_STREAM 0x2 +#define FT_OPEN_PATHNAME 0x4 +#define FT_OPEN_DRIVER 0x8 +#define FT_OPEN_PARAMS 0x10 + +typedef struct FT_Parameter_ +{ + FT_ULong tag; + FT_Pointer data; +} FT_Parameter; + +typedef struct FT_Open_Args_ +{ + FT_UInt flags; + const FT_Byte* memory_base; + FT_Long memory_size; + FT_String* pathname; + FT_Stream stream; + FT_Module driver; + FT_Int num_params; + FT_Parameter* params; +} FT_Open_Args; +typedef enum FT_Size_Request_Type_ +{ + FT_SIZE_REQUEST_TYPE_NOMINAL, + FT_SIZE_REQUEST_TYPE_REAL_DIM, + FT_SIZE_REQUEST_TYPE_BBOX, + FT_SIZE_REQUEST_TYPE_CELL, + FT_SIZE_REQUEST_TYPE_SCALES, + + FT_SIZE_REQUEST_TYPE_MAX + +} FT_Size_Request_Type; +typedef struct FT_Size_RequestRec_ +{ + FT_Size_Request_Type type; + FT_Long width; + FT_Long height; + FT_UInt horiResolution; + FT_UInt vertResolution; +} FT_Size_RequestRec; +typedef struct FT_Size_RequestRec_ *FT_Size_Request; + +#define FT_LOAD_DEFAULT 0x0 +#define FT_LOAD_NO_SCALE 0x1 +#define FT_LOAD_NO_HINTING 0x2 +#define FT_LOAD_RENDER 0x4 +#define FT_LOAD_NO_BITMAP 0x8 +#define FT_LOAD_VERTICAL_LAYOUT 0x10 +#define FT_LOAD_FORCE_AUTOHINT 0x20 +#define FT_LOAD_CROP_BITMAP 0x40 +#define FT_LOAD_PEDANTIC 0x80 +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +#define FT_LOAD_NO_RECURSE 0x400 +#define FT_LOAD_IGNORE_TRANSFORM 0x800 +#define FT_LOAD_MONOCHROME 0x1000 +#define FT_LOAD_LINEAR_DESIGN 0x2000 +#define FT_LOAD_NO_AUTOHINT 0x8000U + +#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) + +#define FT_LOAD_TARGET_NORMAL FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL ) +#define FT_LOAD_TARGET_LIGHT FT_LOAD_TARGET_( FT_RENDER_MODE_LIGHT ) +#define FT_LOAD_TARGET_MONO FT_LOAD_TARGET_( FT_RENDER_MODE_MONO ) +#define FT_LOAD_TARGET_LCD FT_LOAD_TARGET_( FT_RENDER_MODE_LCD ) +#define FT_LOAD_TARGET_LCD_V FT_LOAD_TARGET_( FT_RENDER_MODE_LCD_V ) + +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( (FT_UInt32)(a) << 24 ) | \ + ( (FT_UInt32)(b) << 16 ) | \ + ( (FT_UInt32)(c) << 8 ) | \ + (FT_UInt32)(d) ) + +typedef enum FT_Encoding_ +{ + FT_ENC_TAG( FT_ENCODING_NONE, 0, 0, 0, 0 ), + + FT_ENC_TAG( FT_ENCODING_MS_SYMBOL, 's', 'y', 'm', 'b' ), + FT_ENC_TAG( FT_ENCODING_UNICODE, 'u', 'n', 'i', 'c' ), + + FT_ENC_TAG( FT_ENCODING_SJIS, 's', 'j', 'i', 's' ), + FT_ENC_TAG( FT_ENCODING_GB2312, 'g', 'b', ' ', ' ' ), + FT_ENC_TAG( FT_ENCODING_BIG5, 'b', 'i', 'g', '5' ), + FT_ENC_TAG( FT_ENCODING_WANSUNG, 'w', 'a', 'n', 's' ), + FT_ENC_TAG( FT_ENCODING_JOHAB, 'j', 'o', 'h', 'a' ), + + /* for backwards compatibility */ + FT_ENCODING_MS_SJIS = FT_ENCODING_SJIS, + FT_ENCODING_MS_GB2312 = FT_ENCODING_GB2312, + FT_ENCODING_MS_BIG5 = FT_ENCODING_BIG5, + FT_ENCODING_MS_WANSUNG = FT_ENCODING_WANSUNG, + FT_ENCODING_MS_JOHAB = FT_ENCODING_JOHAB, + + FT_ENC_TAG( FT_ENCODING_ADOBE_STANDARD, 'A', 'D', 'O', 'B' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_EXPERT, 'A', 'D', 'B', 'E' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_CUSTOM, 'A', 'D', 'B', 'C' ), + FT_ENC_TAG( FT_ENCODING_ADOBE_LATIN_1, 'l', 'a', 't', '1' ), + + FT_ENC_TAG( FT_ENCODING_OLD_LATIN_2, 'l', 'a', 't', '2' ), + + FT_ENC_TAG( FT_ENCODING_APPLE_ROMAN, 'a', 'r', 'm', 'n' ) +} FT_Encoding; + +#define ft_encoding_none FT_ENCODING_NONE +#define ft_encoding_unicode FT_ENCODING_UNICODE +#define ft_encoding_symbol FT_ENCODING_MS_SYMBOL +#define ft_encoding_latin_1 FT_ENCODING_ADOBE_LATIN_1 +#define ft_encoding_latin_2 FT_ENCODING_OLD_LATIN_2 +#define ft_encoding_sjis FT_ENCODING_SJIS +#define ft_encoding_gb2312 FT_ENCODING_GB2312 +#define ft_encoding_big5 FT_ENCODING_BIG5 +#define ft_encoding_wansung FT_ENCODING_WANSUNG +#define ft_encoding_johab FT_ENCODING_JOHAB + +#define ft_encoding_adobe_standard FT_ENCODING_ADOBE_STANDARD +#define ft_encoding_adobe_expert FT_ENCODING_ADOBE_EXPERT +#define ft_encoding_adobe_custom FT_ENCODING_ADOBE_CUSTOM +#define ft_encoding_apple_roman FT_ENCODING_APPLE_ROMAN + +typedef struct FT_Bitmap_Size_ +{ + FT_Short height; + FT_Short width; + + FT_Pos size; + + FT_Pos x_ppem; + FT_Pos y_ppem; +} FT_Bitmap_Size; + +typedef struct FT_CharMapRec_ +{ + FT_Face face; + FT_Encoding encoding; + FT_UShort platform_id; + FT_UShort encoding_id; +} FT_CharMapRec; + +typedef void (*FT_Generic_Finalizer)(void* object); +typedef struct FT_Generic_ +{ + void* data; + FT_Generic_Finalizer finalizer; +} FT_Generic; + +typedef struct FT_Size_Metrics_ +{ + FT_UShort x_ppem; /* horizontal pixels per EM */ + FT_UShort y_ppem; /* vertical pixels per EM */ + + FT_Fixed x_scale; /* scaling values used to convert font */ + FT_Fixed y_scale; /* units to 26.6 fractional pixels */ + + FT_Pos ascender; /* ascender in 26.6 frac. pixels */ + FT_Pos descender; /* descender in 26.6 frac. pixels */ + FT_Pos height; /* text height in 26.6 frac. pixels */ + FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */ +} FT_Size_Metrics; + +typedef struct FT_SizeRec_ +{ + FT_Face face; /* parent face object */ + FT_Generic generic; /* generic pointer for client uses */ + FT_Size_Metrics metrics; /* size metrics */ + FT_Size_Internal internal; +} FT_SizeRec; + +typedef struct FT_FaceRec_ +{ + FT_Long num_faces; + FT_Long face_index; + + FT_Long face_flags; + FT_Long style_flags; + + FT_Long num_glyphs; + + FT_String* family_name; + FT_String* style_name; + + FT_Int num_fixed_sizes; + FT_Bitmap_Size* available_sizes; + + FT_Int num_charmaps; + FT_CharMap* charmaps; + + FT_Generic generic; + + /*# The following member variables (down to `underline_thickness') */ + /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /*# for bitmap fonts. */ + FT_BBox bbox; + + FT_UShort units_per_EM; + FT_Short ascender; + FT_Short descender; + FT_Short height; + + FT_Short max_advance_width; + FT_Short max_advance_height; + + FT_Short underline_position; + FT_Short underline_thickness; + + FT_GlyphSlot glyph; + FT_Size size; + FT_CharMap charmap; + + /* ft2 private + FT_Driver driver; + FT_Memory memory; + FT_Stream stream; + + FT_ListRec sizes_list; + + FT_Generic autohint; + void* extensions; + + FT_Face_Internal internal; + */ +} FT_FaceRec; + +typedef struct FT_GlyphSlotRec_ +{ + FT_Library library; + FT_Face face; + FT_GlyphSlot next; + FT_UInt reserved; /* retained for binary compatibility */ + FT_Generic generic; + + FT_Glyph_Metrics metrics; + FT_Fixed linearHoriAdvance; + FT_Fixed linearVertAdvance; + FT_Vector advance; + + FT_Glyph_Format format; + + FT_Bitmap bitmap; + FT_Int bitmap_left; + FT_Int bitmap_top; + + FT_Outline outline; + + FT_UInt num_subglyphs; + FT_SubGlyph subglyphs; + + void* control_data; + long control_len; + + FT_Pos lsb_delta; + FT_Pos rsb_delta; + + void* other; + + FT_Slot_Internal internal; +} FT_GlyphSlotRec; + +#define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) +#define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) +#define FT_FACE_FLAG_FIXED_WIDTH ( 1L << 2 ) +#define FT_FACE_FLAG_SFNT ( 1L << 3 ) +#define FT_FACE_FLAG_HORIZONTAL ( 1L << 4 ) +#define FT_FACE_FLAG_VERTICAL ( 1L << 5 ) +#define FT_FACE_FLAG_KERNING ( 1L << 6 ) +#define FT_FACE_FLAG_FAST_GLYPHS ( 1L << 7 ) +#define FT_FACE_FLAG_MULTIPLE_MASTERS ( 1L << 8 ) +#define FT_FACE_FLAG_GLYPH_NAMES ( 1L << 9 ) +#define FT_FACE_FLAG_EXTERNAL_STREAM ( 1L << 10 ) +#define FT_FACE_FLAG_HINTER ( 1L << 11 ) +#define FT_FACE_FLAG_CID_KEYED ( 1L << 12 ) +#define FT_FACE_FLAG_TRICKY ( 1L << 13 ) + +typedef enum FT_Kerning_Mode_ +{ + FT_KERNING_DEFAULT = 0, + FT_KERNING_UNFITTED, + FT_KERNING_UNSCALED +} FT_Kerning_Mode; + +#endif // FT2_DEFS_H_H__ diff --git a/app/jni/ft2_fontdefs.h b/app/jni/ft2_fontdefs.h new file mode 100644 index 0000000..3f08187 --- /dev/null +++ b/app/jni/ft2_fontdefs.h @@ -0,0 +1,64 @@ +#ifndef FT2_PRIVATE_H__ +#define FT2_PRIVATE_H__ + +// anything should work, but I recommend multiples of 8 +// since the texture size should be a power of 2 +#define FONT_CHARS_PER_LINE 16 +#define FONT_CHAR_LINES 16 +#define FONT_CHARS_PER_MAP (FONT_CHARS_PER_LINE * FONT_CHAR_LINES) + +typedef struct glyph_slot_s +{ + qboolean image; + // we keep the quad coords here only currently + // if you need other info, make Font_LoadMapForIndex fill it into this slot + float txmin; // texture coordinate in [0,1] + float txmax; + float tymin; + float tymax; + float vxmin; + float vxmax; + float vymin; + float vymax; + float advance_x; + float advance_y; +} glyph_slot_t; + +struct ft2_font_map_s +{ + Uchar start; + struct ft2_font_map_s *next; + float size; + // the actual size used in the freetype code + // by convention, the requested size is the height of the font's bounding box. + float intSize; + int glyphSize; + + cachepic_t *pic; + qboolean static_tex; + glyph_slot_t glyphs[FONT_CHARS_PER_MAP]; + + // contains the kerning information for the first 256 characters + // for the other characters, we will lookup the kerning information + ft2_kerning_t kerning; + // safes us the trouble of calculating these over and over again + double sfx, sfy; + + // the width_of for the image-font, pixel-snapped for this size + float width_of[256]; +}; + +struct ft2_attachment_s +{ + const unsigned char *data; + fs_offset_t size; +}; + +//qboolean Font_LoadMapForIndex(ft2_font_t *font, Uchar _ch, ft2_font_map_t **outmap); +qboolean Font_LoadMapForIndex(ft2_font_t *font, int map_index, Uchar _ch, ft2_font_map_t **outmap); + +void font_start(void); +void font_shutdown(void); +void font_newmap(void); + +#endif // FT2_PRIVATE_H__ diff --git a/app/jni/gl_backend.c b/app/jni/gl_backend.c new file mode 100644 index 0000000..939a36c --- /dev/null +++ b/app/jni/gl_backend.c @@ -0,0 +1,4867 @@ + +#include "quakedef.h" +#include "cl_collision.h" +#include "dpsoftrast.h" +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +extern D3DCAPS9 vid_d3d9caps; +#endif + +// on GLES we have to use some proper #define's +#ifndef GL_FRAMEBUFFER +#define GL_FRAMEBUFFER 0x8D40 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#endif +#ifndef GL_COLOR_ATTACHMENT1 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#endif +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#endif +//#ifndef GL_VERTEX_ARRAY +//#define GL_VERTEX_ARRAY 0x8074 +//#define GL_COLOR_ARRAY 0x8076 +//#define GL_TEXTURE_COORD_ARRAY 0x8078 +//#endif +#ifndef GL_TEXTURE0 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#endif + +#ifndef GL_TEXTURE_3D +#define GL_TEXTURE_3D 0x806F +#endif +#ifndef GL_TEXTURE_CUBE_MAP +#define GL_TEXTURE_CUBE_MAP 0x8513 +#endif +//#ifndef GL_MODELVIEW +//#define GL_MODELVIEW 0x1700 +//#endif +//#ifndef GL_PROJECTION +//#define GL_PROJECTION 0x1701 +//#endif +//#ifndef GL_DECAL +//#define GL_DECAL 0x2101 +//#endif +//#ifndef GL_INTERPOLATE +//#define GL_INTERPOLATE 0x8575 +//#endif + + +#define MAX_RENDERTARGETS 4 + +cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"}; +cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"}; +cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"}; +cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"}; + +cvar_t r_render = {0, "r_render", "1", "enables rendering 3D views (you want this on!)"}; +cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"}; +cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"}; +cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"}; +cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"}; +cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"}; +cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"}; +cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"}; +cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"}; + +cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"}; +qboolean v_flipped_state = false; + +r_viewport_t gl_viewport; +matrix4x4_t gl_modelmatrix; +matrix4x4_t gl_viewmatrix; +matrix4x4_t gl_modelviewmatrix; +matrix4x4_t gl_projectionmatrix; +matrix4x4_t gl_modelviewprojectionmatrix; +float gl_modelview16f[16]; +float gl_modelviewprojection16f[16]; +qboolean gl_modelmatrixchanged; + +int gl_maxdrawrangeelementsvertices; +int gl_maxdrawrangeelementsindices; + +#ifdef DEBUGGL +int errornumber = 0; + +void GL_PrintError(int errornumber, const char *filename, int linenumber) +{ + switch(errornumber) + { +#ifdef GL_INVALID_ENUM + case GL_INVALID_ENUM: + Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_INVALID_VALUE + case GL_INVALID_VALUE: + Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_INVALID_OPERATION + case GL_INVALID_OPERATION: + Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: + Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: + Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_OUT_OF_MEMORY + case GL_OUT_OF_MEMORY: + Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber); + break; +#endif +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION + case GL_INVALID_FRAMEBUFFER_OPERATION: + Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber); + break; +#endif + default: + Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber); + break; + } +} +#endif + +#define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active"); + +void SCR_ScreenShot_f (void); + +typedef struct gltextureunit_s +{ + int pointer_texcoord_components; + int pointer_texcoord_gltype; + size_t pointer_texcoord_stride; + const void *pointer_texcoord_pointer; + const r_meshbuffer_t *pointer_texcoord_vertexbuffer; + size_t pointer_texcoord_offset; + + rtexture_t *texture; + int t2d, t3d, tcubemap; + int arrayenabled; + int rgbscale, alphascale; + int combine; + int combinergb, combinealpha; + // texmatrixenabled exists only to avoid unnecessary texmatrix compares + int texmatrixenabled; + matrix4x4_t matrix; +} +gltextureunit_t; + +typedef struct gl_state_s +{ + int cullface; + int cullfaceenable; + int blendfunc1; + int blendfunc2; + qboolean blend; + GLboolean depthmask; + int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order) + int depthtest; + int depthfunc; + float depthrange[2]; + float polygonoffset[2]; + int alphatest; + int alphafunc; + float alphafuncvalue; + qboolean alphatocoverage; + int scissortest; + unsigned int unit; + unsigned int clientunit; + gltextureunit_t units[MAX_TEXTUREUNITS]; + float color4f[4]; + int lockrange_first; + int lockrange_count; + int vertexbufferobject; + int elementbufferobject; + int uniformbufferobject; + int framebufferobject; + int defaultframebufferobject; // deal with platforms that use a non-zero default fbo + qboolean pointer_color_enabled; + + int pointer_vertex_components; + int pointer_vertex_gltype; + size_t pointer_vertex_stride; + const void *pointer_vertex_pointer; + const r_meshbuffer_t *pointer_vertex_vertexbuffer; + size_t pointer_vertex_offset; + + int pointer_color_components; + int pointer_color_gltype; + size_t pointer_color_stride; + const void *pointer_color_pointer; + const r_meshbuffer_t *pointer_color_vertexbuffer; + size_t pointer_color_offset; + + void *preparevertices_tempdata; + size_t preparevertices_tempdatamaxsize; + r_vertexgeneric_t *preparevertices_vertexgeneric; + r_vertexmesh_t *preparevertices_vertexmesh; + int preparevertices_numvertices; + + qboolean usevbo_staticvertex; + qboolean usevbo_staticindex; + qboolean usevbo_dynamicvertex; + qboolean usevbo_dynamicindex; + + memexpandablearray_t meshbufferarray; + + qboolean active; + +#ifdef SUPPORTD3D +// rtexture_t *d3drt_depthtexture; +// rtexture_t *d3drt_colortextures[MAX_RENDERTARGETS]; + IDirect3DSurface9 *d3drt_depthsurface; + IDirect3DSurface9 *d3drt_colorsurfaces[MAX_RENDERTARGETS]; + IDirect3DSurface9 *d3drt_backbufferdepthsurface; + IDirect3DSurface9 *d3drt_backbuffercolorsurface; + void *d3dvertexbuffer; + void *d3dvertexdata; + size_t d3dvertexsize; +#endif +} +gl_state_t; + +static gl_state_t gl_state; + +void android_kostyl() +{ +gl_state.pointer_vertex_pointer=0; +gl_state.pointer_color_pointer=0; +} + + +/* +note: here's strip order for a terrain row: +0--1--2--3--4 +|\ |\ |\ |\ | +| \| \| \| \| +A--B--C--D--E +clockwise + +A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E + +*elements++ = i + row; +*elements++ = i; +*elements++ = i + row + 1; +*elements++ = i; +*elements++ = i + 1; +*elements++ = i + row + 1; + + +for (y = 0;y < rows - 1;y++) +{ + for (x = 0;x < columns - 1;x++) + { + i = y * rows + x; + *elements++ = i + columns; + *elements++ = i; + *elements++ = i + columns + 1; + *elements++ = i; + *elements++ = i + 1; + *elements++ = i + columns + 1; + } +} + +alternative: +0--1--2--3--4 +| /| /|\ | /| +|/ |/ | \|/ | +A--B--C--D--E +counterclockwise + +for (y = 0;y < rows - 1;y++) +{ + for (x = 0;x < columns - 1;x++) + { + i = y * rows + x; + *elements++ = i; + *elements++ = i + columns; + *elements++ = i + columns + 1; + *elements++ = i + columns; + *elements++ = i + columns + 1; + *elements++ = i + 1; + } +} +*/ + +int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3]; +unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3]; +int quadelement3i[QUADELEMENTS_MAXQUADS*6]; +unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6]; + +static void GL_VBOStats_f(void) +{ + GL_Mesh_ListVBOs(true); +} + +static void GL_Backend_ResetState(void); + +static void R_Mesh_InitVertexDeclarations(void); +static void R_Mesh_DestroyVertexDeclarations(void); + +static void R_Mesh_SetUseVBO(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo; + gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer && gl_vbo.integer) || vid.forcevbo; + break; + case RENDERPATH_D3D9: + gl_state.usevbo_staticvertex = gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_dynamicvertex = gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer && gl_vbo_dynamicindex.integer && gl_vbo.integer) || vid.forcevbo; + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + gl_state.usevbo_staticvertex = false; + gl_state.usevbo_staticindex = false; + gl_state.usevbo_dynamicvertex = false; + gl_state.usevbo_dynamicindex = false; + break; + case RENDERPATH_GLES2: + gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo; + gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo; + break; + } +} + +static void gl_backend_start(void) +{ + memset(&gl_state, 0, sizeof(gl_state)); + + R_Mesh_InitVertexDeclarations(); + + R_Mesh_SetUseVBO(); + Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128); + + Con_DPrintf("OpenGL backend started.\n"); + + CHECKGLERROR + + GL_Backend_ResetState(); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // fetch current fbo here (default fbo is not 0 on some GLES devices) + if (vid.support.ext_framebuffer_object) + qglGetIntegerv(GL_FRAMEBUFFER_BINDING, &gl_state.defaultframebufferobject); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface); + IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } +} + +static void gl_backend_shutdown(void) +{ + Con_DPrint("OpenGL Backend shutting down\n"); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface); + IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + + if (gl_state.preparevertices_tempdata) + Mem_Free(gl_state.preparevertices_tempdata); + + Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray); + + R_Mesh_DestroyVertexDeclarations(); + + memset(&gl_state, 0, sizeof(gl_state)); +} + +static void gl_backend_newmap(void) +{ +} + +static void gl_backend_devicelost(void) +{ + int i, endindex; + r_meshbuffer_t *buffer; +#ifdef SUPPORTD3D + gl_state.d3dvertexbuffer = NULL; +#endif + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DSurface9_Release(gl_state.d3drt_backbufferdepthsurface); + IDirect3DSurface9_Release(gl_state.d3drt_backbuffercolorsurface); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray); + for (i = 0;i < endindex;i++) + { + buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i); + if (!buffer || !buffer->isdynamic) + continue; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (buffer->devicebuffer) + { + if (buffer->isindexbuffer) + IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer); + else + IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer); + buffer->devicebuffer = NULL; + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + } +} + +static void gl_backend_devicerestored(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_GetDepthStencilSurface(vid_d3d9dev, &gl_state.d3drt_backbufferdepthsurface); + IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, &gl_state.d3drt_backbuffercolorsurface); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } +} + +void gl_backend_init(void) +{ + int i; + + for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++) + { + polygonelement3s[i * 3 + 0] = 0; + polygonelement3s[i * 3 + 1] = i + 1; + polygonelement3s[i * 3 + 2] = i + 2; + } + // elements for rendering a series of quads as triangles + for (i = 0;i < QUADELEMENTS_MAXQUADS;i++) + { + quadelement3s[i * 6 + 0] = i * 4; + quadelement3s[i * 6 + 1] = i * 4 + 1; + quadelement3s[i * 6 + 2] = i * 4 + 2; + quadelement3s[i * 6 + 3] = i * 4; + quadelement3s[i * 6 + 4] = i * 4 + 2; + quadelement3s[i * 6 + 5] = i * 4 + 3; + } + + for (i = 0;i < (POLYGONELEMENTS_MAXPOINTS - 2)*3;i++) + polygonelement3i[i] = polygonelement3s[i]; + for (i = 0;i < QUADELEMENTS_MAXQUADS*6;i++) + quadelement3i[i] = quadelement3s[i]; + + Cvar_RegisterVariable(&r_render); + Cvar_RegisterVariable(&r_renderview); + Cvar_RegisterVariable(&r_waterwarp); + Cvar_RegisterVariable(&gl_polyblend); + Cvar_RegisterVariable(&v_flipped); + Cvar_RegisterVariable(&gl_dither); + Cvar_RegisterVariable(&gl_vbo); + Cvar_RegisterVariable(&gl_vbo_dynamicvertex); + Cvar_RegisterVariable(&gl_vbo_dynamicindex); + Cvar_RegisterVariable(&gl_paranoid); + Cvar_RegisterVariable(&gl_printcheckerror); + + Cvar_RegisterVariable(&gl_mesh_drawrangeelements); + Cvar_RegisterVariable(&gl_mesh_testmanualfeeding); + + Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them"); + + R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored); +} + +void GL_SetMirrorState(qboolean state); + +void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out) +{ + vec4_t temp; + float iw; + Matrix4x4_Transform4 (&v->viewmatrix, in, temp); + Matrix4x4_Transform4 (&v->projectmatrix, temp, out); + iw = 1.0f / out[3]; + out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f; + + // for an odd reason, inverting this is wrong for R_Shadow_ScissorForBBox (we then get badly scissored lights) + //out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f; + out[1] = v->y + (out[1] * iw + 1.0f) * v->height * 0.5f; + + out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f; +} + +void GL_Finish(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglFinish(); + break; + case RENDERPATH_D3D9: + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_Finish(); + break; + } +} + +static int bboxedges[12][2] = +{ + // top + {0, 1}, // +X + {0, 2}, // +Y + {1, 3}, // Y, +X + {2, 3}, // X, +Y + // bottom + {4, 5}, // +X + {4, 6}, // +Y + {5, 7}, // Y, +X + {6, 7}, // X, +Y + // verticals + {0, 4}, // +Z + {1, 5}, // X, +Z + {2, 6}, // Y, +Z + {3, 7}, // XY, +Z +}; + +qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor) +{ + int i, ix1, iy1, ix2, iy2; + float x1, y1, x2, y2; + vec4_t v, v2; + float vertex[20][3]; + int j, k; + vec4_t plane4f; + int numvertices; + float corner[8][4]; + float dist[8]; + int sign[8]; + float f; + + scissor[0] = r_refdef.view.viewport.x; + scissor[1] = r_refdef.view.viewport.y; + scissor[2] = r_refdef.view.viewport.width; + scissor[3] = r_refdef.view.viewport.height; + + // if view is inside the box, just say yes it's visible + if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs)) + return false; + + // transform all corners that are infront of the nearclip plane + VectorNegate(r_refdef.view.frustum[4].normal, plane4f); + plane4f[3] = r_refdef.view.frustum[4].dist; + numvertices = 0; + for (i = 0;i < 8;i++) + { + Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1); + dist[i] = DotProduct4(corner[i], plane4f); + sign[i] = dist[i] > 0; + if (!sign[i]) + { + VectorCopy(corner[i], vertex[numvertices]); + numvertices++; + } + } + // if some points are behind the nearclip, add clipped edge points to make + // sure that the scissor boundary is complete + if (numvertices > 0 && numvertices < 8) + { + // add clipped edge points + for (i = 0;i < 12;i++) + { + j = bboxedges[i][0]; + k = bboxedges[i][1]; + if (sign[j] != sign[k]) + { + f = dist[j] / (dist[j] - dist[k]); + VectorLerp(corner[j], f, corner[k], vertex[numvertices]); + numvertices++; + } + } + } + + // if we have no points to check, it is behind the view plane + if (!numvertices) + return true; + + // if we have some points to transform, check what screen area is covered + x1 = y1 = x2 = y2 = 0; + v[3] = 1.0f; + //Con_Printf("%i vertices to transform...\n", numvertices); + for (i = 0;i < numvertices;i++) + { + VectorCopy(vertex[i], v); + R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2); + //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); + if (i) + { + if (x1 > v2[0]) x1 = v2[0]; + if (x2 < v2[0]) x2 = v2[0]; + if (y1 > v2[1]) y1 = v2[1]; + if (y2 < v2[1]) y2 = v2[1]; + } + else + { + x1 = x2 = v2[0]; + y1 = y2 = v2[1]; + } + } + + // now convert the scissor rectangle to integer screen coordinates + ix1 = (int)(x1 - 1.0f); + //iy1 = vid.height - (int)(y2 - 1.0f); + //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f); + iy1 = (int)(y1 - 1.0f); + ix2 = (int)(x2 + 1.0f); + //iy2 = vid.height - (int)(y1 + 1.0f); + //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f); + iy2 = (int)(y2 + 1.0f); + //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); + + // clamp it to the screen + if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x; + if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y; + if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width; + if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height; + + // if it is inside out, it's not visible + if (ix2 <= ix1 || iy2 <= iy1) + return true; + + // the light area is visible, set up the scissor rectangle + scissor[0] = ix1; + scissor[1] = iy1; + scissor[2] = ix2 - ix1; + scissor[3] = iy2 - iy1; + + // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one + switch(vid.renderpath) + { + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + scissor[1] = vid.height - scissor[1] - scissor[3]; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + } + + return false; +} + + +static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist) +{ + float q[4]; + float d; + float clipPlane[4], v3[3], v4[3]; + float normal[3]; + + // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php + + VectorSet(normal, normalx, normaly, normalz); + Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane); + VectorScale(normal, -dist, v3); + Matrix4x4_Transform(&v->viewmatrix, v3, v4); + // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique + clipPlane[3] = -DotProduct(v4, clipPlane); + +#if 0 +{ + // testing code for comparing results + float clipPlane2[4]; + VectorCopy4(clipPlane, clipPlane2); + R_EntityMatrix(&identitymatrix); + VectorSet(q, normal[0], normal[1], normal[2], -dist); + qglClipPlane(GL_CLIP_PLANE0, q); + qglGetClipPlane(GL_CLIP_PLANE0, q); + VectorCopy4(q, clipPlane); +} +#endif + + // Calculate the clip-space corner point opposite the clipping plane + // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + m[8]) / m[0]; + q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + m[9]) / m[5]; + q[2] = -1.0f; + q[3] = (1.0f + m[10]) / m[14]; + + // Calculate the scaled plane vector + d = 2.0f / DotProduct4(clipPlane, q); + + // Replace the third row of the projection matrix + m[2] = clipPlane[0] * d; + m[6] = clipPlane[1] * d; + m[10] = clipPlane[2] * d + 1.0f; + m[14] = clipPlane[3] * d; +} + +void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float nearclip, float farclip, const float *nearplane) +{ + float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip; + float m[16]; + memset(v, 0, sizeof(*v)); + v->type = R_VIEWPORTTYPE_ORTHO; + v->cameramatrix = *cameramatrix; + v->x = x; + v->y = y; + v->z = 0; + v->width = width; + v->height = height; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[0] = 2/(right - left); + m[5] = 2/(top - bottom); + m[10] = -2/(zFar - zNear); + m[12] = - (right + left)/(right - left); + m[13] = - (top + bottom)/(top - bottom); + m[14] = - (zFar + zNear)/(zFar - zNear); + m[15] = 1; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + m[10] = -1/(zFar - zNear); + m[14] = -zNear/(zFar-zNear); + break; + } + v->screentodepth[0] = -farclip / (farclip - nearclip); + v->screentodepth[1] = farclip * nearclip / (farclip - nearclip); + + Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix); + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); + +#if 0 + { + vec4_t test1; + vec4_t test2; + Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f); + R_Viewport_TransformToScreen(v, test1, test2); + Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]); + } +#endif +} + +void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane) +{ + matrix4x4_t tempmatrix, basematrix; + float m[16]; + memset(v, 0, sizeof(*v)); + + v->type = R_VIEWPORTTYPE_PERSPECTIVE; + v->cameramatrix = *cameramatrix; + v->x = x; + v->y = y; + v->z = 0; + v->width = width; + v->height = height; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[0] = 1.0 / frustumx; + m[5] = 1.0 / frustumy; + m[10] = -(farclip + nearclip) / (farclip - nearclip); + m[11] = -1; + m[14] = -2 * nearclip * farclip / (farclip - nearclip); + v->screentodepth[0] = -farclip / (farclip - nearclip); + v->screentodepth[1] = farclip * nearclip / (farclip - nearclip); + + Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix); + Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0); + Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1); + Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix); + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + if(v_flipped.integer) + { + m[0] = -m[0]; + m[4] = -m[4]; + m[8] = -m[8]; + m[12] = -m[12]; + } + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); +} + +void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, const float *nearplane) +{ + matrix4x4_t tempmatrix, basematrix; + const float nudge = 1.0 - 1.0 / (1<<23); + float m[16]; + memset(v, 0, sizeof(*v)); + + v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP; + v->cameramatrix = *cameramatrix; + v->x = x; + v->y = y; + v->z = 0; + v->width = width; + v->height = height; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[ 0] = 1.0 / frustumx; + m[ 5] = 1.0 / frustumy; + m[10] = -nudge; + m[11] = -1; + m[14] = -2 * nearclip * nudge; + v->screentodepth[0] = (m[10] + 1) * 0.5 - 1; + v->screentodepth[1] = m[14] * -0.5; + + Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix); + Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0); + Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1); + Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix); + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + if(v_flipped.integer) + { + m[0] = -m[0]; + m[4] = -m[4]; + m[8] = -m[8]; + m[12] = -m[12]; + } + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); +} + +float cubeviewmatrix[6][16] = +{ + // standard cubemap projections + { // +X + 0, 0,-1, 0, + 0,-1, 0, 0, + -1, 0, 0, 0, + 0, 0, 0, 1, + }, + { // -X + 0, 0, 1, 0, + 0,-1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 1, + }, + { // +Y + 1, 0, 0, 0, + 0, 0,-1, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + }, + { // -Y + 1, 0, 0, 0, + 0, 0, 1, 0, + 0,-1, 0, 0, + 0, 0, 0, 1, + }, + { // +Z + 1, 0, 0, 0, + 0,-1, 0, 0, + 0, 0,-1, 0, + 0, 0, 0, 1, + }, + { // -Z + -1, 0, 0, 0, + 0,-1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }, +}; +float rectviewmatrix[6][16] = +{ + // sign-preserving cubemap projections + { // +X + 0, 0,-1, 0, + 0, 1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 1, + }, + { // -X + 0, 0, 1, 0, + 0, 1, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 1, + }, + { // +Y + 1, 0, 0, 0, + 0, 0,-1, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + }, + { // -Y + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + }, + { // +Z + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0,-1, 0, + 0, 0, 0, 1, + }, + { // -Z + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }, +}; + +void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane) +{ + matrix4x4_t tempmatrix, basematrix; + float m[16]; + memset(v, 0, sizeof(*v)); + v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE; + v->cameramatrix = *cameramatrix; + v->width = size; + v->height = size; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[0] = m[5] = 1.0f; + m[10] = -(farclip + nearclip) / (farclip - nearclip); + m[11] = -1; + m[14] = -2 * nearclip * farclip / (farclip - nearclip); + + Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]); + Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix); + Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix); + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); +} + +void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane) +{ + matrix4x4_t tempmatrix, basematrix; + float m[16]; + memset(v, 0, sizeof(*v)); + v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE; + v->cameramatrix = *cameramatrix; + v->x = (side & 1) * size; + v->y = (side >> 1) * size; + v->width = size; + v->height = size; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[0] = m[5] = 1.0f * ((float)size - border) / size; + m[10] = -(farclip + nearclip) / (farclip - nearclip); + m[11] = -1; + m[14] = -2 * nearclip * farclip / (farclip - nearclip); + + Matrix4x4_FromArrayFloatGL(&basematrix, rectviewmatrix[side]); + Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix); + Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix); + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: + m[5] *= -1; + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); +} + +void R_SetViewport(const r_viewport_t *v) +{ + float m[16]; + gl_viewport = *v; + + // FIXME: v_flipped_state is evil, this probably breaks somewhere + GL_SetMirrorState(v_flipped.integer && (v->type == R_VIEWPORTTYPE_PERSPECTIVE || v->type == R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP)); + + // copy over the matrices to our state + gl_viewmatrix = v->viewmatrix; + gl_projectionmatrix = v->projectmatrix; + + switch(vid.renderpath) + { + case RENDERPATH_GL13: + case RENDERPATH_GL11: + case RENDERPATH_GLES1: +#ifdef GL_PROJECTION + CHECKGLERROR + qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR + // Load the projection matrix into OpenGL + qglMatrixMode(GL_PROJECTION);CHECKGLERROR + Matrix4x4_ToArrayFloatGL(&gl_projectionmatrix, m); + qglLoadMatrixf(m);CHECKGLERROR + qglMatrixMode(GL_MODELVIEW);CHECKGLERROR +#endif + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DVIEWPORT9 d3dviewport; + d3dviewport.X = gl_viewport.x; + d3dviewport.Y = gl_viewport.y; + d3dviewport.Width = gl_viewport.width; + d3dviewport.Height = gl_viewport.height; + d3dviewport.MinZ = gl_state.depthrange[0]; + d3dviewport.MaxZ = gl_state.depthrange[1]; + IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_Viewport(v->x, v->y, v->width, v->height); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + CHECKGLERROR + qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR + break; + } + + // force an update of the derived matrices + gl_modelmatrixchanged = true; + R_EntityMatrix(&gl_modelmatrix); +} + +void R_GetViewport(r_viewport_t *v) +{ + *v = gl_viewport; +} + +static void GL_BindVBO(int bufferobject) +{ + if (gl_state.vertexbufferobject != bufferobject) + { + gl_state.vertexbufferobject = bufferobject; + CHECKGLERROR + qglBindBufferARB(GL_ARRAY_BUFFER, bufferobject);CHECKGLERROR + } +} + +static void GL_BindEBO(int bufferobject) +{ + if (gl_state.elementbufferobject != bufferobject) + { + gl_state.elementbufferobject = bufferobject; + CHECKGLERROR + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, bufferobject);CHECKGLERROR + } +} + +static void GL_BindUBO(int bufferobject) +{ + if (gl_state.uniformbufferobject != bufferobject) + { + gl_state.uniformbufferobject = bufferobject; + CHECKGLERROR + qglBindBufferARB(GL_UNIFORM_BUFFER, bufferobject);CHECKGLERROR + } +} + +static const GLuint drawbuffers[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}; +int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (vid.support.arb_framebuffer_object) + { + int temp; + GLuint status; + qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR + R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL); + // GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment +#ifdef USE_GLES2 + // FIXME: separate stencil attachment on GLES + if (depthtexture && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR +#else + if (depthtexture && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, depthtexture->glisdepthstencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR +#endif + if (depthtexture && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, /*depthtexture->glisdepthstencil ? GL_DEPTH_STENCIL_ATTACHMENT : */GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR + if (colortexture && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR + if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR + if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR + if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR + if (colortexture && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR + if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR + if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR + if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR + +#ifndef USE_GLES2 + if (colortexture4 && qglDrawBuffersARB) + { + qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture3 && qglDrawBuffersARB) + { + qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture2 && qglDrawBuffersARB) + { + qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture && qglDrawBuffer) + { + qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR + qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR + } + else if (qglDrawBuffer) + { + qglDrawBuffer(GL_NONE);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } +#endif + status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR + if (status != GL_FRAMEBUFFER_COMPLETE) + { + Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status); + gl_state.framebufferobject = 0; // GL unbinds it for us + qglDeleteFramebuffers(1, (GLuint*)&temp); + temp = 0; + } + return temp; + } + else if (vid.support.ext_framebuffer_object) + { + int temp; + GLuint status; + qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR + R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL); + // GL_EXT_framebuffer_object (GL2-class hardware) - no depth stencil attachment, let it break stencil + if (depthtexture && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR + if (depthtexture && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR + if (colortexture && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR + if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR + if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR + if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR + if (colortexture && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR + if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR + if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR + if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR + +#ifndef USE_GLES2 + if (colortexture4 && qglDrawBuffersARB) + { + qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture3 && qglDrawBuffersARB) + { + qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture2 && qglDrawBuffersARB) + { + qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } + else if (colortexture && qglDrawBuffer) + { + qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR + qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR + } + else if (qglDrawBuffer) + { + qglDrawBuffer(GL_NONE);CHECKGLERROR + qglReadBuffer(GL_NONE);CHECKGLERROR + } +#endif + status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR + if (status != GL_FRAMEBUFFER_COMPLETE) + { + Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status); + gl_state.framebufferobject = 0; // GL unbinds it for us + qglDeleteFramebuffers(1, (GLuint*)&temp); + temp = 0; + } + return temp; + } + return 0; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + return 1; + case RENDERPATH_SOFT: + return 1; + } + return 0; +} + +void R_Mesh_DestroyFramebufferObject(int fbo) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (fbo) + { + // GL clears the binding if we delete something bound + if (gl_state.framebufferobject == fbo) + gl_state.framebufferobject = 0; + qglDeleteFramebuffers(1, (GLuint*)&fbo); + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + } +} + +#ifdef SUPPORTD3D +void R_Mesh_SetRenderTargetsD3D9(IDirect3DSurface9 *depthsurface, IDirect3DSurface9 *colorsurface0, IDirect3DSurface9 *colorsurface1, IDirect3DSurface9 *colorsurface2, IDirect3DSurface9 *colorsurface3) +{ + gl_state.framebufferobject = depthsurface != gl_state.d3drt_backbufferdepthsurface || colorsurface0 != gl_state.d3drt_backbuffercolorsurface; + if (gl_state.d3drt_depthsurface != depthsurface) + { + gl_state.d3drt_depthsurface = depthsurface; + IDirect3DDevice9_SetDepthStencilSurface(vid_d3d9dev, gl_state.d3drt_depthsurface); + } + if (gl_state.d3drt_colorsurfaces[0] != colorsurface0) + { + gl_state.d3drt_colorsurfaces[0] = colorsurface0; + IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 0, gl_state.d3drt_colorsurfaces[0]); + } + if (gl_state.d3drt_colorsurfaces[1] != colorsurface1) + { + gl_state.d3drt_colorsurfaces[1] = colorsurface1; + IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 1, gl_state.d3drt_colorsurfaces[1]); + } + if (gl_state.d3drt_colorsurfaces[2] != colorsurface2) + { + gl_state.d3drt_colorsurfaces[2] = colorsurface2; + IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 2, gl_state.d3drt_colorsurfaces[2]); + } + if (gl_state.d3drt_colorsurfaces[3] != colorsurface3) + { + gl_state.d3drt_colorsurfaces[3] = colorsurface3; + IDirect3DDevice9_SetRenderTarget(vid_d3d9dev, 3, gl_state.d3drt_colorsurfaces[3]); + } +} +#endif + +void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4) +{ + unsigned int i; + unsigned int j; + rtexture_t *textures[5]; + Vector4Set(textures, colortexture, colortexture2, colortexture3, colortexture4); + textures[4] = depthtexture; + // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target + for (j = 0;j < 5;j++) + if (textures[j]) + for (i = 0;i < vid.teximageunits;i++) + if (gl_state.units[i].texture == textures[j]) + R_Mesh_TexBind(i, NULL); + // set up framebuffer object or render targets for the active rendering API + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (gl_state.framebufferobject != fbo) + { + gl_state.framebufferobject = fbo; + qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject); + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + // set up the new render targets, a NULL depthtexture intentionally binds nothing + // TODO: optimize: keep surface pointer around in rtexture_t until texture is freed or lost + if (fbo) + { + IDirect3DSurface9 *surfaces[5]; + for (i = 0;i < 5;i++) + { + surfaces[i] = NULL; + if (textures[i]) + { + if (textures[i]->d3dsurface) + surfaces[i] = (IDirect3DSurface9 *)textures[i]->d3dsurface; + else + IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9 *)textures[i]->d3dtexture, 0, &surfaces[i]); + } + } + // set the render targets for real + R_Mesh_SetRenderTargetsD3D9(surfaces[4], surfaces[0], surfaces[1], surfaces[2], surfaces[3]); + // release the texture surface levels (they won't be lost while bound...) + for (i = 0;i < 5;i++) + if (textures[i] && !textures[i]->d3dsurface) + IDirect3DSurface9_Release(surfaces[i]); + } + else + R_Mesh_SetRenderTargetsD3D9(gl_state.d3drt_backbufferdepthsurface, gl_state.d3drt_backbuffercolorsurface, NULL, NULL, NULL); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (fbo) + { + int width, height; + unsigned int *pointers[5]; + memset(pointers, 0, sizeof(pointers)); + for (i = 0;i < 5;i++) + pointers[i] = textures[i] ? (unsigned int *)DPSOFTRAST_Texture_GetPixelPointer(textures[i]->texnum, 0) : NULL; + width = DPSOFTRAST_Texture_GetWidth(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0); + height = DPSOFTRAST_Texture_GetHeight(textures[0] ? textures[0]->texnum : textures[4]->texnum, 0); + DPSOFTRAST_SetRenderTargets(width, height, pointers[4], pointers[0], pointers[1], pointers[2], pointers[3]); + } + else + DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL); + break; + } +} + +#ifdef SUPPORTD3D +static int d3dcmpforglfunc(int f) +{ + switch(f) + { + case GL_NEVER: return D3DCMP_NEVER; + case GL_LESS: return D3DCMP_LESS; + case GL_EQUAL: return D3DCMP_EQUAL; + case GL_LEQUAL: return D3DCMP_LESSEQUAL; + case GL_GREATER: return D3DCMP_GREATER; + case GL_NOTEQUAL: return D3DCMP_NOTEQUAL; + case GL_GEQUAL: return D3DCMP_GREATEREQUAL; + case GL_ALWAYS: return D3DCMP_ALWAYS; + default: Con_DPrintf("Unknown GL_DepthFunc\n");return D3DCMP_ALWAYS; + } +} + +static int d3dstencilopforglfunc(int f) +{ + switch(f) + { + case GL_KEEP: return D3DSTENCILOP_KEEP; + case GL_INCR: return D3DSTENCILOP_INCR; // note: GL_INCR is clamped, D3DSTENCILOP_INCR wraps + case GL_DECR: return D3DSTENCILOP_DECR; // note: GL_DECR is clamped, D3DSTENCILOP_DECR wraps + default: Con_DPrintf("Unknown GL_StencilFunc\n");return D3DSTENCILOP_KEEP; + } +} +#endif + +static void GL_Backend_ResetState(void) +{ + unsigned int i; + gl_state.active = true; + gl_state.depthtest = true; + gl_state.alphatest = false; + gl_state.alphafunc = GL_GEQUAL; + gl_state.alphafuncvalue = 0.5f; + gl_state.alphatocoverage = false; + gl_state.blendfunc1 = GL_ONE; + gl_state.blendfunc2 = GL_ZERO; + gl_state.blend = false; + gl_state.depthmask = GL_TRUE; + gl_state.colormask = 15; + gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1; + gl_state.lockrange_first = 0; + gl_state.lockrange_count = 0; + gl_state.cullface = GL_FRONT; + gl_state.cullfaceenable = false; + gl_state.polygonoffset[0] = 0; + gl_state.polygonoffset[1] = 0; + gl_state.framebufferobject = 0; + gl_state.depthfunc = GL_LEQUAL; + + switch(vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, gl_state.colormask); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f)); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: +#ifdef GL_ALPHA_TEST + CHECKGLERROR + + qglColorMask(1, 1, 1, 1);CHECKGLERROR + qglAlphaFunc(gl_state.alphafunc, gl_state.alphafuncvalue);CHECKGLERROR + qglDisable(GL_ALPHA_TEST);CHECKGLERROR + qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR + qglDisable(GL_BLEND);CHECKGLERROR + qglCullFace(gl_state.cullface);CHECKGLERROR + qglDisable(GL_CULL_FACE);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglEnable(GL_DEPTH_TEST);CHECKGLERROR + qglDepthMask(gl_state.depthmask);CHECKGLERROR + qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]); + + if (vid.support.arb_vertex_buffer_object) + { + qglBindBufferARB(GL_ARRAY_BUFFER, 0); + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + if (vid.support.ext_framebuffer_object) + { + //qglBindRenderbuffer(GL_RENDERBUFFER, 0); + qglBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR + qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR + + qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR + qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR + qglColor4f(1, 1, 1, 1);CHECKGLERROR + + if (vid.support.ext_framebuffer_object) + qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject); + + gl_state.unit = MAX_TEXTUREUNITS; + gl_state.clientunit = MAX_TEXTUREUNITS; + for (i = 0;i < vid.texunits;i++) + { + GL_ActiveTexture(i); + GL_ClientActiveTexture(i); + qglDisable(GL_TEXTURE_2D);CHECKGLERROR + qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR + if (vid.support.ext_texture_3d) + { + qglDisable(GL_TEXTURE_3D);CHECKGLERROR + qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR + } + if (vid.support.arb_texture_cube_map) + { + qglDisable(GL_TEXTURE_CUBE_MAP);CHECKGLERROR + qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR + } + GL_BindVBO(0); + qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR + qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR + qglMatrixMode(GL_TEXTURE);CHECKGLERROR + qglLoadIdentity();CHECKGLERROR + qglMatrixMode(GL_MODELVIEW);CHECKGLERROR + qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR + } + CHECKGLERROR +#endif + break; + case RENDERPATH_SOFT: + DPSOFTRAST_ColorMask(1,1,1,1); + DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2); + DPSOFTRAST_CullFace(gl_state.cullface); + DPSOFTRAST_DepthFunc(gl_state.depthfunc); + DPSOFTRAST_DepthMask(gl_state.depthmask); + DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]); + DPSOFTRAST_SetRenderTargets(vid.width, vid.height, vid.softdepthpixels, vid.softpixels, NULL, NULL, NULL); + DPSOFTRAST_Viewport(0, 0, vid.width, vid.height); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + CHECKGLERROR + qglColorMask(1, 1, 1, 1);CHECKGLERROR + qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR + qglDisable(GL_BLEND);CHECKGLERROR + qglCullFace(gl_state.cullface);CHECKGLERROR + qglDisable(GL_CULL_FACE);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglEnable(GL_DEPTH_TEST);CHECKGLERROR + qglDepthMask(gl_state.depthmask);CHECKGLERROR + qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]); + if (vid.support.arb_vertex_buffer_object) + { + qglBindBufferARB(GL_ARRAY_BUFFER, 0); + qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + } + if (vid.support.ext_framebuffer_object) + qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.defaultframebufferobject); + qglEnableVertexAttribArray(GLSLATTRIB_POSITION); + qglVertexAttribPointer(GLSLATTRIB_POSITION, 3, GL_FLOAT, false, sizeof(float[3]), NULL);CHECKGLERROR + qglDisableVertexAttribArray(GLSLATTRIB_COLOR); + qglVertexAttribPointer(GLSLATTRIB_COLOR, 4, GL_FLOAT, false, sizeof(float[4]), NULL);CHECKGLERROR + qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1); + gl_state.unit = MAX_TEXTUREUNITS; + gl_state.clientunit = MAX_TEXTUREUNITS; + for (i = 0;i < vid.teximageunits;i++) + { + GL_ActiveTexture(i); + qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR + if (vid.support.ext_texture_3d) + { + qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR + } + if (vid.support.arb_texture_cube_map) + { + qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR + } + } + for (i = 0;i < vid.texarrayunits;i++) + { + GL_BindVBO(0); + qglVertexAttribPointer(i+GLSLATTRIB_TEXCOORD0, 2, GL_FLOAT, false, sizeof(float[2]), NULL);CHECKGLERROR + qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR + } + CHECKGLERROR + break; + } +} + +void GL_ActiveTexture(unsigned int num) +{ + if (gl_state.unit != num) + { + gl_state.unit = num; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (1) + { + CHECKGLERROR + glActiveTexture(GL_TEXTURE0 + gl_state.unit); + CHECKGLERROR + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + } + } +} + +void GL_ClientActiveTexture(unsigned int num) +{ + if (gl_state.clientunit != num) + { + gl_state.clientunit = num; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (1) + { + CHECKGLERROR + qglClientActiveTexture(GL_TEXTURE0 + gl_state.clientunit); + CHECKGLERROR + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + break; + } + } +} + +void GL_BlendFunc(int blendfunc1, int blendfunc2) +{ + if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2) + { + qboolean blendenable; + gl_state.blendfunc1 = blendfunc1; + gl_state.blendfunc2 = blendfunc2; + blendenable = (gl_state.blendfunc1 != GL_ONE || gl_state.blendfunc2 != GL_ZERO); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR + if (gl_state.blend != blendenable) + { + gl_state.blend = blendenable; + if (!gl_state.blend) + { + qglDisable(GL_BLEND);CHECKGLERROR + } + else + { + qglEnable(GL_BLEND);CHECKGLERROR + } + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + int i; + int glblendfunc[2]; + D3DBLEND d3dblendfunc[2]; + glblendfunc[0] = gl_state.blendfunc1; + glblendfunc[1] = gl_state.blendfunc2; + for (i = 0;i < 2;i++) + { + switch(glblendfunc[i]) + { + case GL_ZERO: d3dblendfunc[i] = D3DBLEND_ZERO;break; + case GL_ONE: d3dblendfunc[i] = D3DBLEND_ONE;break; + case GL_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_SRCCOLOR;break; + case GL_ONE_MINUS_SRC_COLOR: d3dblendfunc[i] = D3DBLEND_INVSRCCOLOR;break; + case GL_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_SRCALPHA;break; + case GL_ONE_MINUS_SRC_ALPHA: d3dblendfunc[i] = D3DBLEND_INVSRCALPHA;break; + case GL_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_DESTALPHA;break; + case GL_ONE_MINUS_DST_ALPHA: d3dblendfunc[i] = D3DBLEND_INVDESTALPHA;break; + case GL_DST_COLOR: d3dblendfunc[i] = D3DBLEND_DESTCOLOR;break; + case GL_ONE_MINUS_DST_COLOR: d3dblendfunc[i] = D3DBLEND_INVDESTCOLOR;break; + } + } + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SRCBLEND, d3dblendfunc[0]); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DESTBLEND, d3dblendfunc[1]); + if (gl_state.blend != blendenable) + { + gl_state.blend = blendenable; + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ALPHABLENDENABLE, gl_state.blend); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_BlendFunc(gl_state.blendfunc1, gl_state.blendfunc2); + break; + } + } +} + +void GL_DepthMask(int state) +{ + if (gl_state.depthmask != state) + { + gl_state.depthmask = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglDepthMask(gl_state.depthmask);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZWRITEENABLE, gl_state.depthmask); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_DepthMask(gl_state.depthmask); + break; + } + } +} + +void GL_DepthTest(int state) +{ + if (gl_state.depthtest != state) + { + gl_state.depthtest = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + if (gl_state.depthtest) + { + qglEnable(GL_DEPTH_TEST);CHECKGLERROR + } + else + { + qglDisable(GL_DEPTH_TEST);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZENABLE, gl_state.depthtest); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_DepthTest(gl_state.depthtest); + break; + } + } +} + +void GL_DepthFunc(int state) +{ + if (gl_state.depthfunc != state) + { + gl_state.depthfunc = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglDepthFunc(gl_state.depthfunc);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_ZFUNC, d3dcmpforglfunc(gl_state.depthfunc)); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_DepthFunc(gl_state.depthfunc); + break; + } + } +} + +void GL_DepthRange(float nearfrac, float farfrac) +{ + if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac) + { + gl_state.depthrange[0] = nearfrac; + gl_state.depthrange[1] = farfrac; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef USE_GLES2 + qglDepthRangef(gl_state.depthrange[0], gl_state.depthrange[1]); +#else + qglDepthRange(gl_state.depthrange[0], gl_state.depthrange[1]); +#endif + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DVIEWPORT9 d3dviewport; + d3dviewport.X = gl_viewport.x; + d3dviewport.Y = gl_viewport.y; + d3dviewport.Width = gl_viewport.width; + d3dviewport.Height = gl_viewport.height; + d3dviewport.MinZ = gl_state.depthrange[0]; + d3dviewport.MaxZ = gl_state.depthrange[1]; + IDirect3DDevice9_SetViewport(vid_d3d9dev, &d3dviewport); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_DepthRange(gl_state.depthrange[0], gl_state.depthrange[1]); + break; + } + } +} + +void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int frontzfail, int frontzpass, int backfail, int backzfail, int backzpass, int frontcompare, int backcompare, int comparereference, int comparemask) +{ + switch (vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + if (enable) + { + qglEnable(GL_STENCIL_TEST);CHECKGLERROR + } + else + { + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + } + if (vid.support.ati_separate_stencil) + { + qglStencilMask(writemask);CHECKGLERROR + qglStencilOpSeparate(GL_FRONT, frontfail, frontzfail, frontzpass);CHECKGLERROR + qglStencilOpSeparate(GL_BACK, backfail, backzfail, backzpass);CHECKGLERROR + qglStencilFuncSeparate(GL_FRONT, frontcompare, comparereference, comparereference);CHECKGLERROR + qglStencilFuncSeparate(GL_BACK, backcompare, comparereference, comparereference);CHECKGLERROR + } + else if (vid.support.ext_stencil_two_side) + { +#ifdef GL_STENCIL_TEST_TWO_SIDE_EXT + qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR + qglActiveStencilFaceEXT(GL_FRONT);CHECKGLERROR + qglStencilMask(writemask);CHECKGLERROR + qglStencilOp(frontfail, frontzfail, frontzpass);CHECKGLERROR + qglStencilFunc(frontcompare, comparereference, comparemask);CHECKGLERROR + qglActiveStencilFaceEXT(GL_BACK);CHECKGLERROR + qglStencilMask(writemask);CHECKGLERROR + qglStencilOp(backfail, backzfail, backzpass);CHECKGLERROR + qglStencilFunc(backcompare, comparereference, comparemask);CHECKGLERROR +#endif + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(frontfail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(frontzfail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(frontzpass)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(frontcompare)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFAIL, d3dstencilopforglfunc(backfail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILZFAIL, d3dstencilopforglfunc(backzfail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILPASS, d3dstencilopforglfunc(backzpass)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CCW_STENCILFUNC, d3dcmpforglfunc(backcompare)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } +} + +void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask) +{ + switch (vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + if (enable) + { + qglEnable(GL_STENCIL_TEST);CHECKGLERROR + } + else + { + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + } + if (vid.support.ext_stencil_two_side) + { +#ifdef GL_STENCIL_TEST_TWO_SIDE_EXT + qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR +#endif + } + qglStencilMask(writemask);CHECKGLERROR + qglStencilOp(fail, zfail, zpass);CHECKGLERROR + qglStencilFunc(compare, comparereference, comparemask);CHECKGLERROR + CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (vid.support.ati_separate_stencil) + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_TWOSIDEDSTENCILMODE, true); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILENABLE, enable); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILWRITEMASK, writemask); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFAIL, d3dstencilopforglfunc(fail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILZFAIL, d3dstencilopforglfunc(zfail)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILPASS, d3dstencilopforglfunc(zpass)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILFUNC, d3dcmpforglfunc(compare)); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILREF, comparereference); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_STENCILMASK, comparemask); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } +} + +void GL_PolygonOffset(float planeoffset, float depthoffset) +{ + if (gl_state.polygonoffset[0] != planeoffset || gl_state.polygonoffset[1] != depthoffset) + { + gl_state.polygonoffset[0] = planeoffset; + gl_state.polygonoffset[1] = depthoffset; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglPolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SLOPESCALEDEPTHBIAS, gl_state.polygonoffset[0]); + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_DEPTHBIAS, gl_state.polygonoffset[1] * (1.0f / 16777216.0f)); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_PolygonOffset(gl_state.polygonoffset[0], gl_state.polygonoffset[1]); + break; + } + } +} + +void GL_SetMirrorState(qboolean state) +{ + if (v_flipped_state != state) + { + v_flipped_state = state; + if (gl_state.cullface == GL_BACK) + gl_state.cullface = GL_FRONT; + else if (gl_state.cullface == GL_FRONT) + gl_state.cullface = GL_BACK; + else + return; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglCullFace(gl_state.cullface);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, gl_state.cullface == GL_FRONT ? D3DCULL_CCW : D3DCULL_CW); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_CullFace(gl_state.cullface); + break; + } + } +} + +void GL_CullFace(int state) +{ + if(v_flipped_state) + { + if(state == GL_FRONT) + state = GL_BACK; + else if(state == GL_BACK) + state = GL_FRONT; + } + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + + if (state != GL_NONE) + { + if (!gl_state.cullfaceenable) + { + gl_state.cullfaceenable = true; + qglEnable(GL_CULL_FACE);CHECKGLERROR + } + if (gl_state.cullface != state) + { + gl_state.cullface = state; + qglCullFace(gl_state.cullface);CHECKGLERROR + } + } + else + { + if (gl_state.cullfaceenable) + { + gl_state.cullfaceenable = false; + qglDisable(GL_CULL_FACE);CHECKGLERROR + } + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (gl_state.cullface != state) + { + gl_state.cullface = state; + switch(gl_state.cullface) + { + case GL_NONE: + gl_state.cullfaceenable = false; + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_NONE); + break; + case GL_FRONT: + gl_state.cullfaceenable = true; + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CCW); + break; + case GL_BACK: + gl_state.cullfaceenable = true; + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_CULLMODE, D3DCULL_CW); + break; + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (gl_state.cullface != state) + { + gl_state.cullface = state; + gl_state.cullfaceenable = state != GL_NONE ? true : false; + DPSOFTRAST_CullFace(gl_state.cullface); + } + break; + } +} + +void GL_AlphaTest(int state) +{ + if (gl_state.alphatest != state) + { + gl_state.alphatest = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: +#ifdef GL_ALPHA_TEST + // only fixed function uses alpha test, other paths use pixel kill capability in shaders + CHECKGLERROR + if (gl_state.alphatest) + { + qglEnable(GL_ALPHA_TEST);CHECKGLERROR + } + else + { + qglDisable(GL_ALPHA_TEST);CHECKGLERROR + } +#endif + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + break; + } + } +} + +void GL_AlphaToCoverage(qboolean state) +{ + if (gl_state.alphatocoverage != state) + { + gl_state.alphatocoverage = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + case RENDERPATH_GL20: +#ifdef GL_SAMPLE_ALPHA_TO_COVERAGE_ARB + // alpha to coverage turns the alpha value of the pixel into 0%, 25%, 50%, 75% or 100% by masking the multisample fragments accordingly + CHECKGLERROR + if (gl_state.alphatocoverage) + { + qglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR +// qglEnable(GL_MULTISAMPLE_ARB);CHECKGLERROR + } + else + { + qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);CHECKGLERROR +// qglDisable(GL_MULTISAMPLE_ARB);CHECKGLERROR + } +#endif + break; + } + } +} + +void GL_ColorMask(int r, int g, int b, int a) +{ + // NOTE: this matches D3DCOLORWRITEENABLE_RED, GREEN, BLUE, ALPHA + int state = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0) | (a ? 8 : 0); + if (gl_state.colormask != state) + { + gl_state.colormask = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_COLORWRITEENABLE, state); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_ColorMask(r, g, b, a); + break; + } + } +} + +void GL_Color(float cr, float cg, float cb, float ca) +{ + if (gl_state.pointer_color_enabled || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca) + { + gl_state.color4f[0] = cr; + gl_state.color4f[1] = cg; + gl_state.color4f[2] = cb; + gl_state.color4f[3] = ca; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + CHECKGLERROR + qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]); + CHECKGLERROR + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + // no equivalent in D3D + break; + case RENDERPATH_SOFT: + DPSOFTRAST_Color4f(cr, cg, cb, ca); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + qglVertexAttrib4f(GLSLATTRIB_COLOR, cr, cg, cb, ca); + break; + } + } +} + +void GL_Scissor (int x, int y, int width, int height) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglScissor(x, y,width,height); + CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + RECT d3drect; + d3drect.left = x; + d3drect.top = y; + d3drect.right = x + width; + d3drect.bottom = y + height; + IDirect3DDevice9_SetScissorRect(vid_d3d9dev, &d3drect); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_Scissor(x, y, width, height); + break; + } +} + +void GL_ScissorTest(int state) +{ + if (gl_state.scissortest != state) + { + gl_state.scissortest = state; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + if(gl_state.scissortest) + qglEnable(GL_SCISSOR_TEST); + else + qglDisable(GL_SCISSOR_TEST); + CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_SCISSORTESTENABLE, gl_state.scissortest); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_ScissorTest(gl_state.scissortest); + break; + } + } +} + +void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue) +{ + static const float blackcolor[4] = {0, 0, 0, 0}; + // prevent warnings when trying to clear a buffer that does not exist + if (!colorvalue) + colorvalue = blackcolor; + if (!vid.stencil) + { + mask &= ~GL_STENCIL_BUFFER_BIT; + stencilvalue = 0; + } + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + if (mask & GL_COLOR_BUFFER_BIT) + { + qglClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]);CHECKGLERROR + } + if (mask & GL_DEPTH_BUFFER_BIT) + { +#ifdef USE_GLES2 + qglClearDepthf(depthvalue);CHECKGLERROR +#else + qglClearDepth(depthvalue);CHECKGLERROR +#endif + } + if (mask & GL_STENCIL_BUFFER_BIT) + { + qglClearStencil(stencilvalue);CHECKGLERROR + } + qglClear(mask);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_Clear(vid_d3d9dev, 0, NULL, ((mask & GL_COLOR_BUFFER_BIT) ? D3DCLEAR_TARGET : 0) | ((mask & GL_STENCIL_BUFFER_BIT) ? D3DCLEAR_STENCIL : 0) | ((mask & GL_DEPTH_BUFFER_BIT) ? D3DCLEAR_ZBUFFER : 0), D3DCOLOR_COLORVALUE(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]), depthvalue, stencilvalue); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (mask & GL_COLOR_BUFFER_BIT) + DPSOFTRAST_ClearColor(colorvalue[0], colorvalue[1], colorvalue[2], colorvalue[3]); + if (mask & GL_DEPTH_BUFFER_BIT) + DPSOFTRAST_ClearDepth(depthvalue); + break; + } +} + +void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, outpixels);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + // LordHavoc: we can't directly download the backbuffer because it may be + // multisampled, and it may not be lockable, so we blit it to a lockable + // surface of the same dimensions (but without multisample) to resolve the + // multisample buffer to a normal image, and then lock that... + IDirect3DSurface9 *stretchsurface = NULL; + if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &stretchsurface, NULL))) + { + D3DLOCKED_RECT lockedrect; + if (!FAILED(IDirect3DDevice9_StretchRect(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, NULL, stretchsurface, NULL, D3DTEXF_POINT))) + { + if (!FAILED(IDirect3DSurface9_LockRect(stretchsurface, &lockedrect, NULL, D3DLOCK_READONLY))) + { + int line; + unsigned char *row = (unsigned char *)lockedrect.pBits + x * 4 + lockedrect.Pitch * (vid.height - 1 - y); + for (line = 0;line < height;line++, row -= lockedrect.Pitch) + memcpy(outpixels + line * width * 4, row, width * 4); + IDirect3DSurface9_UnlockRect(stretchsurface); + } + } + IDirect3DSurface9_Release(stretchsurface); + } + // code scraps + //IDirect3DSurface9 *syssurface = NULL; + //if (!FAILED(IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &stretchsurface, NULL))) + //if (!FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(vid_d3d9dev, vid.width, vid.height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurface, NULL))) + //IDirect3DDevice9_GetRenderTargetData(vid_d3d9dev, gl_state.d3drt_backbuffercolorsurface, syssurface); + //if (!FAILED(IDirect3DDevice9_GetFrontBufferData(vid_d3d9dev, 0, syssurface))) + //if (!FAILED(IDirect3DSurface9_LockRect(syssurface, &lockedrect, NULL, D3DLOCK_READONLY))) + //IDirect3DSurface9_UnlockRect(syssurface); + //IDirect3DSurface9_Release(syssurface); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_GetPixelsBGRA(x, y, width, height, outpixels); + break; + } +} + +// called at beginning of frame +void R_Mesh_Start(void) +{ + BACKENDACTIVECHECK + R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL); + R_Mesh_SetUseVBO(); + if (gl_printcheckerror.integer && !gl_paranoid.integer) + { + Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n"); + Cvar_SetValueQuick(&gl_paranoid, 1); + } +} + +static qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings) +{ + int shaderobject; + int shadercompiled; + char compilelog[MAX_INPUTLINE]; + shaderobject = qglCreateShader(shadertypeenum);CHECKGLERROR + if (!shaderobject) + return false; + qglShaderSource(shaderobject, numstrings, strings, NULL);CHECKGLERROR + qglCompileShader(shaderobject);CHECKGLERROR + qglGetShaderiv(shaderobject, GL_COMPILE_STATUS, &shadercompiled);CHECKGLERROR + qglGetShaderInfoLog(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR + if (compilelog[0] && ((strstr(compilelog, "error") || strstr(compilelog, "ERROR") || strstr(compilelog, "Error")) || ((strstr(compilelog, "WARNING") || strstr(compilelog, "warning") || strstr(compilelog, "Warning")) && developer.integer) || developer_extra.integer)) + { + int i, j, pretextlines = 0; + for (i = 0;i < numstrings - 1;i++) + for (j = 0;strings[i][j];j++) + if (strings[i][j] == '\n') + pretextlines++; + Con_Printf("%s shader compile log:\n%s\n(line offset for any above warnings/errors: %i)\n", shadertype, compilelog, pretextlines); + } + if (!shadercompiled) + { + qglDeleteShader(shaderobject);CHECKGLERROR + return false; + } + qglAttachShader(programobject, shaderobject);CHECKGLERROR + qglDeleteShader(shaderobject);CHECKGLERROR + return true; +} + +unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int geometrystrings_count, const char **geometrystrings_list, int fragmentstrings_count, const char **fragmentstrings_list) +{ + GLint programlinked; + GLuint programobject = 0; + char linklog[MAX_INPUTLINE]; + CHECKGLERROR + + programobject = qglCreateProgram();CHECKGLERROR + if (!programobject) + return 0; + + qglBindAttribLocation(programobject, GLSLATTRIB_POSITION , "Attrib_Position" ); + qglBindAttribLocation(programobject, GLSLATTRIB_COLOR , "Attrib_Color" ); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD0, "Attrib_TexCoord0"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD1, "Attrib_TexCoord1"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD2, "Attrib_TexCoord2"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD3, "Attrib_TexCoord3"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD4, "Attrib_TexCoord4"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD5, "Attrib_TexCoord5"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD6, "Attrib_SkeletalIndex"); + qglBindAttribLocation(programobject, GLSLATTRIB_TEXCOORD7, "Attrib_SkeletalWeight"); +#ifndef USE_GLES2 + if(vid.support.gl20shaders130) + qglBindFragDataLocation(programobject, 0, "dp_FragColor"); +#endif + + if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER, "vertex", vertexstrings_count, vertexstrings_list)) + goto cleanup; + +#ifdef GL_GEOMETRY_SHADER + if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER, "geometry", geometrystrings_count, geometrystrings_list)) + goto cleanup; +#endif + + if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER, "fragment", fragmentstrings_count, fragmentstrings_list)) + goto cleanup; + + qglLinkProgram(programobject);CHECKGLERROR + qglGetProgramiv(programobject, GL_LINK_STATUS, &programlinked);CHECKGLERROR + qglGetProgramInfoLog(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR + if (linklog[0]) + { + if (strstr(linklog, "error") || strstr(linklog, "ERROR") || strstr(linklog, "Error") || strstr(linklog, "WARNING") || strstr(linklog, "warning") || strstr(linklog, "Warning") || developer_extra.integer) + Con_DPrintf("program link log:\n%s\n", linklog); + // software vertex shader is ok but software fragment shader is WAY + // too slow, fail program if so. + // NOTE: this string might be ATI specific, but that's ok because the + // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a + // software fragment shader due to low instruction and dependent + // texture limits. + if (strstr(linklog, "fragment shader will run in software")) + programlinked = false; + } + if (!programlinked) + goto cleanup; + return programobject; +cleanup: + qglDeleteProgram(programobject);CHECKGLERROR + return 0; +} + +void GL_Backend_FreeProgram(unsigned int prog) +{ + CHECKGLERROR + qglDeleteProgram(prog); + CHECKGLERROR +} + +// renders triangles using vertices from the active arrays +int paranoidblah = 0; +void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, int element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, int element3s_bufferoffset) +{ + unsigned int numelements = numtriangles * 3; + int bufferobject3i; + size_t bufferoffset3i; + int bufferobject3s; + size_t bufferoffset3s; + if (numvertices < 3 || numtriangles < 1) + { + if (numvertices < 0 || numtriangles < 0 || developer_extra.integer) + Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %8x, %8p, %8p, %8x);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3i_indexbuffer, (int)element3i_bufferoffset, (void *)element3s, (void *)element3s_indexbuffer, (int)element3s_bufferoffset); + return; + } + + // adjust the pointers for firsttriangle + if (element3i) + element3i += firsttriangle * 3; + if (element3i_indexbuffer) + element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i); + if (element3s) + element3s += firsttriangle * 3; + if (element3s_indexbuffer) + element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // check if the user specified to ignore static index buffers + if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset))) + { + element3i_indexbuffer = NULL; + element3s_indexbuffer = NULL; + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + } + // upload a dynamic index buffer if needed + if (element3s) + { + if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex) + element3s_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3s), (void *)element3s, R_BUFFERDATA_INDEX16, &element3s_bufferoffset); + } + else if (element3i) + { + if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex) + element3i_indexbuffer = R_BufferData_Store(numelements * sizeof(*element3i), (void *)element3i, R_BUFFERDATA_INDEX32, &element3i_bufferoffset); + } + bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0; + bufferoffset3i = element3i_bufferoffset; + bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0; + bufferoffset3s = element3s_bufferoffset; + r_refdef.stats[r_stat_draws]++; + r_refdef.stats[r_stat_draws_vertices] += numvertices; + r_refdef.stats[r_stat_draws_elements] += numelements; + if (gl_paranoid.integer) + { + unsigned int i; + // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array +#if 0 + unsigned int j, size; + const int *p; + // note: there's no validation done here on buffer objects because it + // is somewhat difficult to get at the data, and gl_paranoid can be + // used without buffer objects if the need arises + // (the data could be gotten using glMapBuffer but it would be very + // slow due to uncachable video memory reads) + if (!qglIsEnabled(GL_VERTEX_ARRAY)) + Con_Print("R_Mesh_Draw: vertex array not enabled\n"); + CHECKGLERROR + if (gl_state.pointer_vertex_pointer) + for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++) + paranoidblah += *p; + if (gl_state.pointer_color_enabled) + { + if (!qglIsEnabled(GL_COLOR_ARRAY)) + Con_Print("R_Mesh_Draw: color array set but not enabled\n"); + CHECKGLERROR + if (gl_state.pointer_color && gl_state.pointer_color_enabled) + for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++) + paranoidblah += *p; + } + for (i = 0;i < vid.texarrayunits;i++) + { + if (gl_state.units[i].arrayenabled) + { + GL_ClientActiveTexture(i); + if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY)) + Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n"); + CHECKGLERROR + if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled) + for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++) + paranoidblah += *p; + } + } +#endif + if (element3i) + { + for (i = 0;i < (unsigned int) numtriangles * 3;i++) + { + if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices) + { + Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices); + return; + } + } + } + if (element3s) + { + for (i = 0;i < (unsigned int) numtriangles * 3;i++) + { + if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices) + { + Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices); + return; + } + } + } + } + if (r_render.integer || r_refdef.draw2dstage) + { + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + CHECKGLERROR + if (gl_mesh_testmanualfeeding.integer) + { +#ifndef USE_GLES2 + unsigned int i, j, element; + const GLfloat *p; + qglBegin(GL_TRIANGLES); + if(vid.renderpath == RENDERPATH_GL20) + { + for (i = 0;i < (unsigned int) numtriangles * 3;i++) + { + if (element3i) + element = element3i[i]; + else if (element3s) + element = element3s[i]; + else + element = firstvertex + i; + for (j = 0;j < vid.texarrayunits;j++) + { + if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled) + { + if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, p[0], p[1], p[2], p[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, p[0], p[1], p[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, p[0], p[1]); + else + qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, p[0]); + } + else if (gl_state.units[j].pointer_texcoord_gltype == (int)(GL_SHORT | 0x80000000)) + { + const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1], s[2], s[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1], s[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, s[0], s[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, s[0]); + } + else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE) + { + const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 127.0f), sb[1] * (1.0f / 127.0f), sb[2] * (1.0f / 127.0f), sb[3] * (1.0f / 127.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 127.0f), sb[1] * (1.0f / 127.0f), sb[2] * (1.0f / 127.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 127.0f), sb[1] * (1.0f / 127.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 127.0f)); + } + else if (gl_state.units[j].pointer_texcoord_gltype == GL_UNSIGNED_BYTE) + { + const GLubyte *sb = (const GLubyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 255.0f), sb[1] * (1.0f / 255.0f), sb[2] * (1.0f / 255.0f), sb[3] * (1.0f / 255.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 255.0f), sb[1] * (1.0f / 255.0f), sb[2] * (1.0f / 255.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 255.0f), sb[1] * (1.0f / 255.0f)); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, sb[0] * (1.0f / 255.0f)); + } + else if (gl_state.units[j].pointer_texcoord_gltype == (int)(GL_UNSIGNED_BYTE | 0x80000000)) + { + const GLubyte *sb = (const GLubyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglVertexAttrib4f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1], sb[2], sb[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglVertexAttrib3f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1], sb[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglVertexAttrib2f(GLSLATTRIB_TEXCOORD0 + j, sb[0], sb[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglVertexAttrib1f(GLSLATTRIB_TEXCOORD0 + j, sb[0]); + } + } + } + if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4) + { + if (gl_state.pointer_color_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglVertexAttrib4f(GLSLATTRIB_COLOR, p[0], p[1], p[2], p[3]); + } + else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE) + { + const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglVertexAttrib4Nub(GLSLATTRIB_COLOR, ub[0], ub[1], ub[2], ub[3]); + } + } + if (gl_state.pointer_vertex_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride); + if (gl_state.pointer_vertex_components == 4) + qglVertexAttrib4f(GLSLATTRIB_POSITION, p[0], p[1], p[2], p[3]); + else if (gl_state.pointer_vertex_components == 3) + qglVertexAttrib3f(GLSLATTRIB_POSITION, p[0], p[1], p[2]); + else + qglVertexAttrib2f(GLSLATTRIB_POSITION, p[0], p[1]); + } + } + } + else + { + for (i = 0;i < (unsigned int) numtriangles * 3;i++) + { + if (element3i) + element = element3i[i]; + else if (element3s) + element = element3s[i]; + else + element = firstvertex + i; + for (j = 0;j < vid.texarrayunits;j++) + { + if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled) + { + if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0 + j, p[0], p[1], p[2], p[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0 + j, p[0], p[1], p[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0 + j, p[0], p[1]); + else + qglMultiTexCoord1f(GL_TEXTURE0 + j, p[0]); + } + else + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(p[0], p[1], p[2], p[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(p[0], p[1], p[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(p[0], p[1]); + else + qglTexCoord1f(p[0]); + } + } + else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT) + { + const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0 + j, s[0], s[1], s[2], s[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0 + j, s[0], s[1], s[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0 + j, s[0], s[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglMultiTexCoord1f(GL_TEXTURE0 + j, s[0]); + } + else + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(s[0], s[1], s[2], s[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(s[0], s[1], s[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(s[0], s[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglTexCoord1f(s[0]); + } + } + else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE) + { + const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0 + j, sb[0], sb[1], sb[2], sb[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0 + j, sb[0], sb[1], sb[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0 + j, sb[0], sb[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglMultiTexCoord1f(GL_TEXTURE0 + j, sb[0]); + } + else + { + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(sb[0], sb[1], sb[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(sb[0], sb[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglTexCoord1f(sb[0]); + } + } + } + } + if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4) + { + if (gl_state.pointer_color_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglColor4f(p[0], p[1], p[2], p[3]); + } + else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE) + { + const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglColor4ub(ub[0], ub[1], ub[2], ub[3]); + } + } + if (gl_state.pointer_vertex_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride); + if (gl_state.pointer_vertex_components == 4) + qglVertex4f(p[0], p[1], p[2], p[3]); + else if (gl_state.pointer_vertex_components == 3) + qglVertex3f(p[0], p[1], p[2]); + else + qglVertex2f(p[0], p[1]); + } + } + } + qglEnd(); + CHECKGLERROR +#endif + } + else if (bufferobject3s) + { + GL_BindEBO(bufferobject3s); +#ifndef USE_GLES2 + if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) + { + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s); + CHECKGLERROR + } + else +#endif + { + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s); + CHECKGLERROR + } + } + else if (bufferobject3i) + { + GL_BindEBO(bufferobject3i); +#ifndef USE_GLES2 + if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) + { + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i); + CHECKGLERROR + } + else +#endif + { + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i); + CHECKGLERROR + } + } + else if (element3s) + { + GL_BindEBO(0); +#ifndef USE_GLES2 + if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) + { + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, element3s); + CHECKGLERROR + } + else +#endif + { + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s); + CHECKGLERROR + } + } + else if (element3i) + { + GL_BindEBO(0); +#ifndef USE_GLES2 + if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) + { + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, element3i); + CHECKGLERROR + } + else +#endif + { + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i); + CHECKGLERROR + } + } + else + { + qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices); + CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (gl_state.d3dvertexbuffer && ((element3s && element3s_indexbuffer) || (element3i && element3i_indexbuffer))) + { + if (element3s_indexbuffer) + { + IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3s_indexbuffer->devicebuffer); + IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3s_bufferoffset>>1, numtriangles); + } + else if (element3i_indexbuffer) + { + IDirect3DDevice9_SetIndices(vid_d3d9dev, (IDirect3DIndexBuffer9 *)element3i_indexbuffer->devicebuffer); + IDirect3DDevice9_DrawIndexedPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, 0, firstvertex, numvertices, element3i_bufferoffset>>2, numtriangles); + } + else + IDirect3DDevice9_DrawPrimitive(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices); + } + else + { + if (element3s) + IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3s, D3DFMT_INDEX16, gl_state.d3dvertexdata, gl_state.d3dvertexsize); + else if (element3i) + IDirect3DDevice9_DrawIndexedPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, firstvertex, numvertices, numtriangles, element3i, D3DFMT_INDEX32, gl_state.d3dvertexdata, gl_state.d3dvertexsize); + else + IDirect3DDevice9_DrawPrimitiveUP(vid_d3d9dev, D3DPT_TRIANGLELIST, numvertices, (void *)gl_state.d3dvertexdata, gl_state.d3dvertexsize); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_DrawTriangles(firstvertex, numvertices, numtriangles, element3i, element3s); + break; + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // GLES does not have glDrawRangeElements so this is a bit shorter than the GL20 path + if (bufferobject3s) + { + GL_BindEBO(bufferobject3s); + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s); + CHECKGLERROR + } + else if (bufferobject3i) + { + GL_BindEBO(bufferobject3i); + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i); + CHECKGLERROR + } + else if (element3s) + { + GL_BindEBO(0); + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s); + CHECKGLERROR + } + else if (element3i) + { + static int enableandroidhack=0;//Tegra 3 doesn't list uint extension: using the most precise & dirty way of detection + GL_BindEBO(0); + if (!enableandroidhack) + { + CHECKGLERROR + qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i); + if (glGetError()!=GL_NO_ERROR) + enableandroidhack=1; + } + if (enableandroidhack) + { + unsigned short tmpconv[numelements]; + int i; + for (i=0;ibufferobject = 0; + buffer->devicebuffer = NULL; + buffer->size = size; + buffer->isindexbuffer = isindexbuffer; + buffer->isuniformbuffer = isuniformbuffer; + buffer->isdynamic = isdynamic; + buffer->isindex16 = isindex16; + strlcpy(buffer->name, name, sizeof(buffer->name)); + R_Mesh_UpdateMeshBuffer(buffer, data, size, false, 0); + return buffer; +} + +void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size, qboolean subdata, size_t offset) +{ + if (!buffer) + return; + if (buffer->isindexbuffer) + { + r_refdef.stats[r_stat_indexbufferuploadcount]++; + r_refdef.stats[r_stat_indexbufferuploadsize] += size; + } + else + { + r_refdef.stats[r_stat_vertexbufferuploadcount]++; + r_refdef.stats[r_stat_vertexbufferuploadsize] += size; + } + if (!subdata) + buffer->size = size; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (!buffer->bufferobject) + qglGenBuffersARB(1, (GLuint *)&buffer->bufferobject); + if (buffer->isuniformbuffer) + GL_BindUBO(buffer->bufferobject); + else if (buffer->isindexbuffer) + GL_BindEBO(buffer->bufferobject); + else + GL_BindVBO(buffer->bufferobject); + if (subdata) + qglBufferSubDataARB(buffer->isuniformbuffer ? GL_UNIFORM_BUFFER : (buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER), offset, size, data); + else + qglBufferDataARB(buffer->isuniformbuffer ? GL_UNIFORM_BUFFER : (buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER), size, data, buffer->isdynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW); + if (buffer->isuniformbuffer) + GL_BindUBO(0); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + int result; + void *datapointer = NULL; + if (buffer->isindexbuffer) + { + IDirect3DIndexBuffer9 *d3d9indexbuffer = (IDirect3DIndexBuffer9 *)buffer->devicebuffer; + if (offset+size > buffer->size || !buffer->devicebuffer) + { + if (buffer->devicebuffer) + IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9*)buffer->devicebuffer); + buffer->devicebuffer = NULL; + if (FAILED(result = IDirect3DDevice9_CreateIndexBuffer(vid_d3d9dev, offset+size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, buffer->isindex16 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9indexbuffer, NULL))) + Sys_Error("IDirect3DDevice9_CreateIndexBuffer(%p, %d, %x, %x, %x, %p, NULL) returned %x\n", vid_d3d9dev, (int)size, buffer->isdynamic ? (int)D3DUSAGE_DYNAMIC : 0, buffer->isindex16 ? (int)D3DFMT_INDEX16 : (int)D3DFMT_INDEX32, buffer->isdynamic ? (int)D3DPOOL_DEFAULT : (int)D3DPOOL_MANAGED, &d3d9indexbuffer, (int)result); + buffer->devicebuffer = (void *)d3d9indexbuffer; + buffer->size = offset+size; + } + if (!FAILED(IDirect3DIndexBuffer9_Lock(d3d9indexbuffer, (unsigned int)offset, (unsigned int)size, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0))) + { + if (data) + memcpy(datapointer, data, size); + else + memset(datapointer, 0, size); + IDirect3DIndexBuffer9_Unlock(d3d9indexbuffer); + } + } + else + { + IDirect3DVertexBuffer9 *d3d9vertexbuffer = (IDirect3DVertexBuffer9 *)buffer->devicebuffer; + if (offset+size > buffer->size || !buffer->devicebuffer) + { + if (buffer->devicebuffer) + IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9*)buffer->devicebuffer); + buffer->devicebuffer = NULL; + if (FAILED(result = IDirect3DDevice9_CreateVertexBuffer(vid_d3d9dev, offset+size, buffer->isdynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED, &d3d9vertexbuffer, NULL))) + Sys_Error("IDirect3DDevice9_CreateVertexBuffer(%p, %d, %x, %x, %x, %p, NULL) returned %x\n", vid_d3d9dev, (int)size, buffer->isdynamic ? (int)D3DUSAGE_DYNAMIC : 0, 0, buffer->isdynamic ? (int)D3DPOOL_DEFAULT : (int)D3DPOOL_MANAGED, &d3d9vertexbuffer, (int)result); + buffer->devicebuffer = (void *)d3d9vertexbuffer; + buffer->size = offset+size; + } + if (!FAILED(IDirect3DVertexBuffer9_Lock(d3d9vertexbuffer, (unsigned int)offset, (unsigned int)size, &datapointer, buffer->isdynamic ? D3DLOCK_DISCARD : 0))) + { + if (data) + memcpy(datapointer, data, size); + else + memset(datapointer, 0, size); + IDirect3DVertexBuffer9_Unlock(d3d9vertexbuffer); + } + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } +} + +void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer) +{ + if (!buffer) + return; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // GL clears the binding if we delete something bound + if (gl_state.uniformbufferobject == buffer->bufferobject) + gl_state.uniformbufferobject = 0; + if (gl_state.vertexbufferobject == buffer->bufferobject) + gl_state.vertexbufferobject = 0; + if (gl_state.elementbufferobject == buffer->bufferobject) + gl_state.elementbufferobject = 0; + qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (gl_state.d3dvertexbuffer == (void *)buffer) + gl_state.d3dvertexbuffer = NULL; + if (buffer->devicebuffer) + { + if (buffer->isindexbuffer) + IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)buffer->devicebuffer); + else + IDirect3DVertexBuffer9_Release((IDirect3DVertexBuffer9 *)buffer->devicebuffer); + buffer->devicebuffer = NULL; + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } + Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer); +} + +static const char *buffertypename[R_BUFFERDATA_COUNT] = {"vertex", "index16", "index32", "uniform"}; +void GL_Mesh_ListVBOs(qboolean printeach) +{ + int i, endindex; + int type; + int isdynamic; + int index16count, index16mem; + int index32count, index32mem; + int vertexcount, vertexmem; + int uniformcount, uniformmem; + int totalcount, totalmem; + size_t bufferstat[R_BUFFERDATA_COUNT][2][2]; + r_meshbuffer_t *buffer; + memset(bufferstat, 0, sizeof(bufferstat)); + endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray); + for (i = 0;i < endindex;i++) + { + buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i); + if (!buffer) + continue; + if (buffer->isuniformbuffer) + type = R_BUFFERDATA_UNIFORM; + else if (buffer->isindexbuffer && buffer->isindex16) + type = R_BUFFERDATA_INDEX16; + else if (buffer->isindexbuffer) + type = R_BUFFERDATA_INDEX32; + else + type = R_BUFFERDATA_VERTEX; + isdynamic = buffer->isdynamic; + bufferstat[type][isdynamic][0]++; + bufferstat[type][isdynamic][1] += buffer->size; + if (printeach) + Con_Printf("buffer #%i %s = %i bytes (%s %s)\n", i, buffer->name, (int)buffer->size, isdynamic ? "dynamic" : "static", buffertypename[type]); + } + index16count = (int)(bufferstat[R_BUFFERDATA_INDEX16][0][0] + bufferstat[R_BUFFERDATA_INDEX16][1][0]); + index16mem = (int)(bufferstat[R_BUFFERDATA_INDEX16][0][1] + bufferstat[R_BUFFERDATA_INDEX16][1][1]); + index32count = (int)(bufferstat[R_BUFFERDATA_INDEX32][0][0] + bufferstat[R_BUFFERDATA_INDEX32][1][0]); + index32mem = (int)(bufferstat[R_BUFFERDATA_INDEX32][0][1] + bufferstat[R_BUFFERDATA_INDEX32][1][1]); + vertexcount = (int)(bufferstat[R_BUFFERDATA_VERTEX ][0][0] + bufferstat[R_BUFFERDATA_VERTEX ][1][0]); + vertexmem = (int)(bufferstat[R_BUFFERDATA_VERTEX ][0][1] + bufferstat[R_BUFFERDATA_VERTEX ][1][1]); + uniformcount = (int)(bufferstat[R_BUFFERDATA_UNIFORM][0][0] + bufferstat[R_BUFFERDATA_UNIFORM][1][0]); + uniformmem = (int)(bufferstat[R_BUFFERDATA_UNIFORM][0][1] + bufferstat[R_BUFFERDATA_UNIFORM][1][1]); + totalcount = index16count + index32count + vertexcount + uniformcount; + totalmem = index16mem + index32mem + vertexmem + uniformmem; + Con_Printf("%i 16bit indexbuffers totalling %i bytes (%.3f MB)\n%i 32bit indexbuffers totalling %i bytes (%.3f MB)\n%i vertexbuffers totalling %i bytes (%.3f MB)\n%i uniformbuffers totalling %i bytes (%.3f MB)\ncombined %i buffers totalling %i bytes (%.3fMB)\n", index16count, index16mem, index16mem / 10248576.0, index32count, index32mem, index32mem / 10248576.0, vertexcount, vertexmem, vertexmem / 10248576.0, uniformcount, uniformmem, uniformmem / 10248576.0, totalcount, totalmem, totalmem / 10248576.0); +} + + + +void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset) + { + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + gl_state.pointer_vertex_components = components; + gl_state.pointer_vertex_gltype = gltype; + gl_state.pointer_vertex_stride = stride; + gl_state.pointer_vertex_pointer = pointer; + gl_state.pointer_vertex_vertexbuffer = vertexbuffer; + gl_state.pointer_vertex_offset = bufferoffset; + CHECKGLERROR + GL_BindVBO(bufferobject); + qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset) + { + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + gl_state.pointer_vertex_components = components; + gl_state.pointer_vertex_gltype = gltype; + gl_state.pointer_vertex_stride = stride; + gl_state.pointer_vertex_pointer = pointer; + gl_state.pointer_vertex_vertexbuffer = vertexbuffer; + gl_state.pointer_vertex_offset = bufferoffset; + CHECKGLERROR + GL_BindVBO(bufferobject); + // LordHavoc: special flag added to gltype for unnormalized types + qglVertexAttribPointer(GLSLATTRIB_POSITION, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } +} + +void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) +{ + // note: vertexbuffer may be non-NULL even if pointer is NULL, so check + // the pointer only. + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: +#ifdef GL_MODELVIEW + CHECKGLERROR + if (pointer) + { + // caller wants color array enabled + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + if (!gl_state.pointer_color_enabled) + { + gl_state.pointer_color_enabled = true; + CHECKGLERROR + qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR + } + if (gl_state.pointer_color_components != components || gl_state.pointer_color_gltype != gltype || gl_state.pointer_color_stride != stride || gl_state.pointer_color_pointer != pointer || gl_state.pointer_color_vertexbuffer != vertexbuffer || gl_state.pointer_color_offset != bufferoffset) + { + gl_state.pointer_color_components = components; + gl_state.pointer_color_gltype = gltype; + gl_state.pointer_color_stride = stride; + gl_state.pointer_color_pointer = pointer; + gl_state.pointer_color_vertexbuffer = vertexbuffer; + gl_state.pointer_color_offset = bufferoffset; + CHECKGLERROR + GL_BindVBO(bufferobject); + qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + } + else + { + // caller wants color array disabled + if (gl_state.pointer_color_enabled) + { + gl_state.pointer_color_enabled = false; + CHECKGLERROR + qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR + // when color array is on the glColor gets trashed, set it again + qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR + } + } +#endif + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + CHECKGLERROR + if (pointer) + { + // caller wants color array enabled + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + if (!gl_state.pointer_color_enabled) + { + gl_state.pointer_color_enabled = true; + CHECKGLERROR + qglEnableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR + } + if (gl_state.pointer_color_components != components || gl_state.pointer_color_gltype != gltype || gl_state.pointer_color_stride != stride || gl_state.pointer_color_pointer != pointer || gl_state.pointer_color_vertexbuffer != vertexbuffer || gl_state.pointer_color_offset != bufferoffset) + { + gl_state.pointer_color_components = components; + gl_state.pointer_color_gltype = gltype; + gl_state.pointer_color_stride = stride; + gl_state.pointer_color_pointer = pointer; + gl_state.pointer_color_vertexbuffer = vertexbuffer; + gl_state.pointer_color_offset = bufferoffset; + CHECKGLERROR + GL_BindVBO(bufferobject); + // LordHavoc: special flag added to gltype for unnormalized types + qglVertexAttribPointer(GLSLATTRIB_COLOR, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + } + else + { + // caller wants color array disabled + if (gl_state.pointer_color_enabled) + { + gl_state.pointer_color_enabled = false; + CHECKGLERROR + qglDisableVertexAttribArray(GLSLATTRIB_COLOR);CHECKGLERROR + // when color array is on the glColor gets trashed, set it again + qglVertexAttrib4f(GLSLATTRIB_COLOR, gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR + } + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } +} + +void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) +{ + gltextureunit_t *unit = gl_state.units + unitnum; + // update array settings + // note: there is no need to check bufferobject here because all cases + // that involve a valid bufferobject also supply a texcoord array + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: +#ifdef GL_MODELVIEW + CHECKGLERROR + if (pointer) + { + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + // texture array unit is enabled, enable the array + if (!unit->arrayenabled) + { + unit->arrayenabled = true; + GL_ClientActiveTexture(unitnum); + qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR + } + // texcoord array + if (unit->pointer_texcoord_components != components || unit->pointer_texcoord_gltype != gltype || unit->pointer_texcoord_stride != stride || unit->pointer_texcoord_pointer != pointer || unit->pointer_texcoord_vertexbuffer != vertexbuffer || unit->pointer_texcoord_offset != bufferoffset) + { + unit->pointer_texcoord_components = components; + unit->pointer_texcoord_gltype = gltype; + unit->pointer_texcoord_stride = stride; + unit->pointer_texcoord_pointer = pointer; + unit->pointer_texcoord_vertexbuffer = vertexbuffer; + unit->pointer_texcoord_offset = bufferoffset; + GL_ClientActiveTexture(unitnum); + GL_BindVBO(bufferobject); + qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + } + else + { + // texture array unit is disabled, disable the array + if (unit->arrayenabled) + { + unit->arrayenabled = false; + GL_ClientActiveTexture(unitnum); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR + } + } +#endif + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + CHECKGLERROR + if (pointer) + { + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + // texture array unit is enabled, enable the array + if (!unit->arrayenabled) + { + unit->arrayenabled = true; + qglEnableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR + } + // texcoord array + if (unit->pointer_texcoord_components != components || unit->pointer_texcoord_gltype != gltype || unit->pointer_texcoord_stride != stride || unit->pointer_texcoord_pointer != pointer || unit->pointer_texcoord_vertexbuffer != vertexbuffer || unit->pointer_texcoord_offset != bufferoffset) + { + unit->pointer_texcoord_components = components; + unit->pointer_texcoord_gltype = gltype; + unit->pointer_texcoord_stride = stride; + unit->pointer_texcoord_pointer = pointer; + unit->pointer_texcoord_vertexbuffer = vertexbuffer; + unit->pointer_texcoord_offset = bufferoffset; + GL_BindVBO(bufferobject); + // LordHavoc: special flag added to gltype for unnormalized types + qglVertexAttribPointer(unitnum+GLSLATTRIB_TEXCOORD0, components, gltype & ~0x80000000, (gltype & 0x80000000) == 0, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR + } + } + else + { + // texture array unit is disabled, disable the array + if (unit->arrayenabled) + { + unit->arrayenabled = false; + qglDisableVertexAttribArray(unitnum+GLSLATTRIB_TEXCOORD0);CHECKGLERROR + } + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } +} + +int R_Mesh_TexBound(unsigned int unitnum, int id) +{ + gltextureunit_t *unit = gl_state.units + unitnum; + if (unitnum >= vid.teximageunits) + return 0; + if (id == GL_TEXTURE_2D) + return unit->t2d; + if (id == GL_TEXTURE_3D) + return unit->t3d; + if (id == GL_TEXTURE_CUBE_MAP) + return unit->tcubemap; + return 0; +} + +void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + R_Mesh_TexBind(0, tex); + GL_ActiveTexture(0);CHECKGLERROR + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, sx, sy, width, height);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + IDirect3DSurface9 *currentsurface = NULL; + IDirect3DSurface9 *texturesurface = NULL; + RECT sourcerect; + RECT destrect; + sourcerect.left = sx; + sourcerect.top = sy; + sourcerect.right = sx + width; + sourcerect.bottom = sy + height; + destrect.left = tx; + destrect.top = ty; + destrect.right = tx + width; + destrect.bottom = ty + height; + if (!FAILED(IDirect3DTexture9_GetSurfaceLevel(((IDirect3DTexture9 *)tex->d3dtexture), 0, &texturesurface))) + { + if (!FAILED(IDirect3DDevice9_GetRenderTarget(vid_d3d9dev, 0, ¤tsurface))) + { + IDirect3DDevice9_StretchRect(vid_d3d9dev, currentsurface, &sourcerect, texturesurface, &destrect, D3DTEXF_NONE); + IDirect3DSurface9_Release(currentsurface); + } + IDirect3DSurface9_Release(texturesurface); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_CopyRectangleToTexture(tex->texnum, 0, tx, ty, sx, sy, width, height); + break; + } +} + +#ifdef SUPPORTD3D +int d3drswrap[16] = {D3DRS_WRAP0, D3DRS_WRAP1, D3DRS_WRAP2, D3DRS_WRAP3, D3DRS_WRAP4, D3DRS_WRAP5, D3DRS_WRAP6, D3DRS_WRAP7, D3DRS_WRAP8, D3DRS_WRAP9, D3DRS_WRAP10, D3DRS_WRAP11, D3DRS_WRAP12, D3DRS_WRAP13, D3DRS_WRAP14, D3DRS_WRAP15}; +#endif + +void R_Mesh_ClearBindingsForTexture(int texnum) +{ + gltextureunit_t *unit; + unsigned int unitnum; + // this doesn't really unbind the texture, but it does prevent a mistaken "do nothing" behavior on the next time this same texnum is bound on the same unit as the same type (this mainly affects r_shadow_bouncegrid because 3D textures are so rarely used) + for (unitnum = 0;unitnum < vid.teximageunits;unitnum++) + { + unit = gl_state.units + unitnum; + if (unit->t2d == texnum) + unit->t2d = -1; + if (unit->t3d == texnum) + unit->t3d = -1; + if (unit->tcubemap == texnum) + unit->tcubemap = -1; + } +} + +void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex) +{ + gltextureunit_t *unit = gl_state.units + unitnum; + int tex2d, tex3d, texcubemap, texnum; + if (unitnum >= vid.teximageunits) + return; +// if (unit->texture == tex) +// return; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (!tex) + { + tex = r_texture_white; + // not initialized enough yet... + if (!tex) + return; + } + unit->texture = tex; + texnum = R_GetTexture(tex); + switch(tex->gltexturetypeenum) + { + case GL_TEXTURE_2D: if (unit->t2d != texnum) {GL_ActiveTexture(unitnum);unit->t2d = texnum;qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR}break; + case GL_TEXTURE_3D: if (unit->t3d != texnum) {GL_ActiveTexture(unitnum);unit->t3d = texnum;qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR}break; + case GL_TEXTURE_CUBE_MAP: if (unit->tcubemap != texnum) {GL_ActiveTexture(unitnum);unit->tcubemap = texnum;qglBindTexture(GL_TEXTURE_CUBE_MAP, unit->tcubemap);CHECKGLERROR}break; + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + unit->texture = tex; + tex2d = 0; + tex3d = 0; + texcubemap = 0; + if (tex) + { + texnum = R_GetTexture(tex); + switch(tex->gltexturetypeenum) + { + case GL_TEXTURE_2D: + tex2d = texnum; + break; + case GL_TEXTURE_3D: + tex3d = texnum; + break; + case GL_TEXTURE_CUBE_MAP: + texcubemap = texnum; + break; + } + } + // update 2d texture binding + if (unit->t2d != tex2d) + { + GL_ActiveTexture(unitnum); + if (tex2d) + { + if (unit->t2d == 0) + { + qglEnable(GL_TEXTURE_2D);CHECKGLERROR + } + } + else + { + if (unit->t2d) + { + qglDisable(GL_TEXTURE_2D);CHECKGLERROR + } + } + unit->t2d = tex2d; + qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR + } + // update 3d texture binding + if (unit->t3d != tex3d) + { + GL_ActiveTexture(unitnum); + if (tex3d) + { + if (unit->t3d == 0) + { + qglEnable(GL_TEXTURE_3D);CHECKGLERROR + } + } + else + { + if (unit->t3d) + { + qglDisable(GL_TEXTURE_3D);CHECKGLERROR + } + } + unit->t3d = tex3d; + qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR + } + // update cubemap texture binding + if (unit->tcubemap != texcubemap) + { + GL_ActiveTexture(unitnum); + if (texcubemap) + { + if (unit->tcubemap == 0) + { + qglEnable(GL_TEXTURE_CUBE_MAP);CHECKGLERROR + } + } + else + { + if (unit->tcubemap) + { + qglDisable(GL_TEXTURE_CUBE_MAP);CHECKGLERROR + } + } + unit->tcubemap = texcubemap; + qglBindTexture(GL_TEXTURE_CUBE_MAP, unit->tcubemap);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + extern cvar_t gl_texture_anisotropy; + if (!tex) + { + tex = r_texture_white; + // not initialized enough yet... + if (!tex) + return; + } + // upload texture if needed + R_GetTexture(tex); + if (unit->texture == tex) + return; + unit->texture = tex; + IDirect3DDevice9_SetTexture(vid_d3d9dev, unitnum, (IDirect3DBaseTexture9*)tex->d3dtexture); + //IDirect3DDevice9_SetRenderState(vid_d3d9dev, d3drswrap[unitnum], (tex->flags & TEXF_CLAMP) ? (D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2) : 0); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSU, tex->d3daddressu); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSV, tex->d3daddressv); + if (tex->d3daddressw) + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_ADDRESSW, tex->d3daddressw); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAGFILTER, tex->d3dmagfilter); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MINFILTER, tex->d3dminfilter); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPFILTER, tex->d3dmipfilter); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MIPMAPLODBIAS, tex->d3dmipmaplodbias); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXMIPLEVEL, tex->d3dmaxmiplevelfilter); + IDirect3DDevice9_SetSamplerState(vid_d3d9dev, unitnum, D3DSAMP_MAXANISOTROPY, gl_texture_anisotropy.integer); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (!tex) + { + tex = r_texture_white; + // not initialized enough yet... + if (!tex) + return; + } + texnum = R_GetTexture(tex); + if (unit->texture == tex) + return; + unit->texture = tex; + DPSOFTRAST_SetTexture(unitnum, texnum); + break; + } +} + +void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix) +{ + gltextureunit_t *unit = gl_state.units + unitnum; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef GL_MODELVIEW + if (matrix && matrix->m[3][3]) + { + // texmatrix specified, check if it is different + if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t))) + { + float glmatrix[16]; + unit->texmatrixenabled = true; + unit->matrix = *matrix; + CHECKGLERROR + Matrix4x4_ToArrayFloatGL(&unit->matrix, glmatrix); + GL_ActiveTexture(unitnum); + qglMatrixMode(GL_TEXTURE);CHECKGLERROR + qglLoadMatrixf(glmatrix);CHECKGLERROR + qglMatrixMode(GL_MODELVIEW);CHECKGLERROR + } + } + else + { + // no texmatrix specified, revert to identity + if (unit->texmatrixenabled) + { + unit->texmatrixenabled = false; + unit->matrix = identitymatrix; + CHECKGLERROR + GL_ActiveTexture(unitnum); + qglMatrixMode(GL_TEXTURE);CHECKGLERROR + qglLoadIdentity();CHECKGLERROR + qglMatrixMode(GL_MODELVIEW);CHECKGLERROR + } + } +#endif + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + } +} + +void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale) +{ + gltextureunit_t *unit = gl_state.units + unitnum; + CHECKGLERROR + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + // do nothing + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: +#ifdef GL_TEXTURE_ENV + // GL_ARB_texture_env_combine + if (!combinergb) + combinergb = GL_MODULATE; + if (!combinealpha) + combinealpha = GL_MODULATE; + if (!rgbscale) + rgbscale = 1; + if (!alphascale) + alphascale = 1; + if (combinergb != combinealpha || rgbscale != 1 || alphascale != 1) + { + if (combinergb == GL_DECAL) + combinergb = GL_INTERPOLATE; + if (unit->combine != GL_COMBINE) + { + unit->combine = GL_COMBINE; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);CHECKGLERROR + qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE mode + } + if (unit->combinergb != combinergb) + { + unit->combinergb = combinergb; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, unit->combinergb);CHECKGLERROR + } + if (unit->combinealpha != combinealpha) + { + unit->combinealpha = combinealpha; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, unit->combinealpha);CHECKGLERROR + } + if (unit->rgbscale != rgbscale) + { + unit->rgbscale = rgbscale; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, unit->rgbscale);CHECKGLERROR + } + if (unit->alphascale != alphascale) + { + unit->alphascale = alphascale; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, unit->alphascale);CHECKGLERROR + } + } + else + { + if (unit->combine != combinergb) + { + unit->combine = combinergb; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR + } + } +#endif + break; + case RENDERPATH_GL11: + // normal GL texenv +#ifdef GL_TEXTURE_ENV + if (!combinergb) + combinergb = GL_MODULATE; + if (unit->combine != combinergb) + { + unit->combine = combinergb; + GL_ActiveTexture(unitnum); + qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combine);CHECKGLERROR + } +#endif + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + break; + } +} + +void R_Mesh_ResetTextureState(void) +{ + unsigned int unitnum; + + BACKENDACTIVECHECK + + for (unitnum = 0;unitnum < vid.teximageunits;unitnum++) + R_Mesh_TexBind(unitnum, NULL); + for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++) + R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + for (unitnum = 0;unitnum < vid.texunits;unitnum++) + { + R_Mesh_TexCombine(unitnum, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(unitnum, NULL); + } + break; + } +} + + + +#ifdef SUPPORTD3D +//#define r_vertex3f_d3d9fvf (D3DFVF_XYZ) +//#define r_vertexgeneric_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) +//#define r_vertexmesh_d3d9fvf (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX5 | D3DFVF_TEXCOORDSIZE1(3) | D3DFVF_TEXCOORDSIZE2(3) | D3DFVF_TEXCOORDSIZE3(3)) + +D3DVERTEXELEMENT9 r_vertex3f_d3d9elements[] = +{ + {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + D3DDECL_END() +}; + +D3DVERTEXELEMENT9 r_vertexgeneric_d3d9elements[] = +{ + {0, (int)((size_t)&((r_vertexgeneric_t *)0)->vertex3f ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, (int)((size_t)&((r_vertexgeneric_t *)0)->color4f ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, + {0, (int)((size_t)&((r_vertexgeneric_t *)0)->texcoord2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + D3DDECL_END() +}; + +D3DVERTEXELEMENT9 r_vertexmesh_d3d9elements[] = +{ + {0, (int)((size_t)&((r_vertexmesh_t *)0)->vertex3f ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->color4f ), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordtexture2f ), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->svector3f ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->tvector3f ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->normal3f ), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->texcoordlightmap2f), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->skeletalindex4ub ), D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 6}, + {0, (int)((size_t)&((r_vertexmesh_t *)0)->skeletalweight4ub ), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 7}, + D3DDECL_END() +}; + +IDirect3DVertexDeclaration9 *r_vertex3f_d3d9decl; +IDirect3DVertexDeclaration9 *r_vertexgeneric_d3d9decl; +IDirect3DVertexDeclaration9 *r_vertexmesh_d3d9decl; +#endif + +static void R_Mesh_InitVertexDeclarations(void) +{ +#ifdef SUPPORTD3D + r_vertex3f_d3d9decl = NULL; + r_vertexgeneric_d3d9decl = NULL; + r_vertexmesh_d3d9decl = NULL; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: + IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9elements, &r_vertex3f_d3d9decl); + IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9elements, &r_vertexgeneric_d3d9decl); + IDirect3DDevice9_CreateVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9elements, &r_vertexmesh_d3d9decl); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } +#endif +} + +static void R_Mesh_DestroyVertexDeclarations(void) +{ +#ifdef SUPPORTD3D + if (r_vertex3f_d3d9decl) + IDirect3DVertexDeclaration9_Release(r_vertex3f_d3d9decl); + r_vertex3f_d3d9decl = NULL; + if (r_vertexgeneric_d3d9decl) + IDirect3DVertexDeclaration9_Release(r_vertexgeneric_d3d9decl); + r_vertexgeneric_d3d9decl = NULL; + if (r_vertexmesh_d3d9decl) + IDirect3DVertexDeclaration9_Release(r_vertexmesh_d3d9decl); + r_vertexmesh_d3d9decl = NULL; +#endif +} + +void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer, int bufferoffset) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + vertexbuffer = R_BufferData_Store(numvertices * sizeof(float[3]), (void *)vertex3f, R_BUFFERDATA_VERTEX, &bufferoffset); + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (vertexbuffer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, bufferoffset); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + } + else + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + } + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (vertexbuffer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, bufferoffset); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + else + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + break; + case RENDERPATH_GL11: + if (vertexbuffer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, bufferoffset); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + else + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertex3f_d3d9decl); + if (vertexbuffer) + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, bufferoffset, sizeof(float[3])); + else + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0); + gl_state.d3dvertexbuffer = (void *)vertexbuffer; + gl_state.d3dvertexdata = (void *)vertex3f; + gl_state.d3dvertexsize = sizeof(float[3]); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3])); + DPSOFTRAST_SetColorPointer(NULL, 0); + DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL); + break; + } +} + + + +r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices) +{ + size_t size; + size = sizeof(r_vertexgeneric_t) * numvertices; + if (gl_state.preparevertices_tempdatamaxsize < size) + { + gl_state.preparevertices_tempdatamaxsize = size; + gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize); + } + gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata; + gl_state.preparevertices_numvertices = numvertices; + return gl_state.preparevertices_vertexgeneric; +} + +qboolean R_Mesh_PrepareVertices_Generic_Unlock(void) +{ + R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL, 0); + gl_state.preparevertices_vertexgeneric = NULL; + gl_state.preparevertices_numvertices = 0; + return true; +} + +void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f) +{ + int i; + r_vertexgeneric_t *vertex; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (gl_state.usevbo_dynamicvertex) + { + r_meshbuffer_t *buffer_vertex3f = NULL; + r_meshbuffer_t *buffer_color4f = NULL; + r_meshbuffer_t *buffer_texcoord2f = NULL; + int bufferoffset_vertex3f = 0; + int bufferoffset_color4f = 0; + int bufferoffset_texcoord2f = 0; + buffer_color4f = R_BufferData_Store(numvertices * sizeof(float[4]), color4f , R_BUFFERDATA_VERTEX, &bufferoffset_color4f ); + buffer_vertex3f = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f ); + buffer_texcoord2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoord2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoord2f); + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(float[3]) , vertex3f , buffer_vertex3f , bufferoffset_vertex3f ); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(float[4]) , color4f , buffer_color4f , bufferoffset_color4f ); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(float[2]) , texcoord2f , buffer_texcoord2f , bufferoffset_texcoord2f ); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 ); + } + else if (!vid.useinterleavedarrays) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + return; + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (!vid.useinterleavedarrays) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0); + if (vid.texunits >= 2) + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + if (vid.texunits >= 3) + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + return; + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3])); + DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4])); + DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoord2f); + DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(float[2]), NULL); + DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), NULL); + return; + } + + // no quick path for this case, convert to vertex structs + vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices); + for (i = 0;i < numvertices;i++) + VectorCopy(vertex3f + 3*i, vertex[i].vertex3f); + if (color4f) + { + for (i = 0;i < numvertices;i++) + Vector4Copy(color4f + 4*i, vertex[i].color4f); + } + else + { + for (i = 0;i < numvertices;i++) + Vector4Copy(gl_state.color4f, vertex[i].color4f); + } + if (texcoord2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f); + R_Mesh_PrepareVertices_Generic_Unlock(); + R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL, 0); +} + +void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer, int bufferoffset) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + vertexbuffer = R_BufferData_Store(numvertices * sizeof(*vertex), (void *)vertex, R_BUFFERDATA_VERTEX, &bufferoffset); + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoord2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + } + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoord2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + } + break; + case RENDERPATH_GL11: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoord2f - (unsigned char *)vertex)); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , NULL, 0); + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexgeneric_d3d9decl); + if (vertexbuffer) + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, bufferoffset, sizeof(*vertex)); + else + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0); + gl_state.d3dvertexbuffer = (void *)vertexbuffer; + gl_state.d3dvertexdata = (void *)vertex; + gl_state.d3dvertexsize = sizeof(*vertex); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex)); + DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex)); + DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoord2f); + DPSOFTRAST_SetTexCoordPointer(1, 2, sizeof(*vertex), NULL); + DPSOFTRAST_SetTexCoordPointer(2, 2, sizeof(*vertex), NULL); + DPSOFTRAST_SetTexCoordPointer(3, 2, sizeof(*vertex), NULL); + DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), NULL); + break; + } +} + + + +r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices) +{ + size_t size; + size = sizeof(r_vertexmesh_t) * numvertices; + if (gl_state.preparevertices_tempdatamaxsize < size) + { + gl_state.preparevertices_tempdatamaxsize = size; + gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize); + } + gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata; + gl_state.preparevertices_numvertices = numvertices; + return gl_state.preparevertices_vertexmesh; +} + +qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void) +{ + R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL, 0); + gl_state.preparevertices_vertexmesh = NULL; + gl_state.preparevertices_numvertices = 0; + return true; +} + +void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f) +{ + int i; + r_vertexmesh_t *vertex; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (gl_state.usevbo_dynamicvertex) + { + r_meshbuffer_t *buffer_vertex3f = NULL; + r_meshbuffer_t *buffer_color4f = NULL; + r_meshbuffer_t *buffer_texcoordtexture2f = NULL; + r_meshbuffer_t *buffer_svector3f = NULL; + r_meshbuffer_t *buffer_tvector3f = NULL; + r_meshbuffer_t *buffer_normal3f = NULL; + r_meshbuffer_t *buffer_texcoordlightmap2f = NULL; + int bufferoffset_vertex3f = 0; + int bufferoffset_color4f = 0; + int bufferoffset_texcoordtexture2f = 0; + int bufferoffset_svector3f = 0; + int bufferoffset_tvector3f = 0; + int bufferoffset_normal3f = 0; + int bufferoffset_texcoordlightmap2f = 0; + buffer_color4f = R_BufferData_Store(numvertices * sizeof(float[4]), color4f , R_BUFFERDATA_VERTEX, &bufferoffset_color4f ); + buffer_vertex3f = R_BufferData_Store(numvertices * sizeof(float[3]), vertex3f , R_BUFFERDATA_VERTEX, &bufferoffset_vertex3f ); + buffer_svector3f = R_BufferData_Store(numvertices * sizeof(float[3]), svector3f , R_BUFFERDATA_VERTEX, &bufferoffset_svector3f ); + buffer_tvector3f = R_BufferData_Store(numvertices * sizeof(float[3]), tvector3f , R_BUFFERDATA_VERTEX, &bufferoffset_tvector3f ); + buffer_normal3f = R_BufferData_Store(numvertices * sizeof(float[3]), normal3f , R_BUFFERDATA_VERTEX, &bufferoffset_normal3f ); + buffer_texcoordtexture2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordtexture2f , R_BUFFERDATA_VERTEX, &bufferoffset_texcoordtexture2f ); + buffer_texcoordlightmap2f = R_BufferData_Store(numvertices * sizeof(float[2]), texcoordlightmap2f, R_BUFFERDATA_VERTEX, &bufferoffset_texcoordlightmap2f); + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(float[3]) , vertex3f , buffer_vertex3f , bufferoffset_vertex3f ); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(float[4]) , color4f , buffer_color4f , bufferoffset_color4f ); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(float[2]) , texcoordtexture2f , buffer_texcoordtexture2f , bufferoffset_texcoordtexture2f ); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(float[3]) , svector3f , buffer_svector3f , bufferoffset_svector3f ); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(float[3]) , tvector3f , buffer_tvector3f , bufferoffset_tvector3f ); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT , sizeof(float[3]) , normal3f , buffer_normal3f , bufferoffset_normal3f ); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(float[2]) , texcoordlightmap2f, buffer_texcoordlightmap2f, bufferoffset_texcoordlightmap2f); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 ); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 ); + } + else if (!vid.useinterleavedarrays) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0); + return; + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (!vid.useinterleavedarrays) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0); + if (vid.texunits >= 2) + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0); + if (vid.texunits >= 3) + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + return; + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + break; + case RENDERPATH_SOFT: + DPSOFTRAST_SetVertexPointer(vertex3f, sizeof(float[3])); + DPSOFTRAST_SetColorPointer(color4f, sizeof(float[4])); + DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(float[2]), texcoordtexture2f); + DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(float[3]), svector3f); + DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(float[3]), tvector3f); + DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(float[3]), normal3f); + DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(float[2]), texcoordlightmap2f); + return; + } + + vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices); + for (i = 0;i < numvertices;i++) + VectorCopy(vertex3f + 3*i, vertex[i].vertex3f); + if (svector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(svector3f + 3*i, vertex[i].svector3f); + if (tvector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(tvector3f + 3*i, vertex[i].tvector3f); + if (normal3f) + for (i = 0;i < numvertices;i++) + VectorCopy(normal3f + 3*i, vertex[i].normal3f); + if (color4f) + { + for (i = 0;i < numvertices;i++) + Vector4Copy(color4f + 4*i, vertex[i].color4f); + } + else + { + for (i = 0;i < numvertices;i++) + Vector4Copy(gl_state.color4f, vertex[i].color4f); + } + if (texcoordtexture2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f); + if (texcoordlightmap2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f); + R_Mesh_PrepareVertices_Mesh_Unlock(); + R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL, 0); +} + +void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer, int bufferoffset) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + vertexbuffer = R_BufferData_Store(numvertices * sizeof(*vertex), (void *)vertex, R_BUFFERDATA_VERTEX, &bufferoffset); + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordtexture2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(*vertex), vertex->svector3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->svector3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(*vertex), vertex->tvector3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->tvector3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT , sizeof(*vertex), vertex->normal3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->normal3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT , sizeof(*vertex), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(*vertex), vertex->skeletalindex4ub , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->skeletalindex4ub - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->skeletalweight4ub , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->skeletalweight4ub - (unsigned char *)vertex)); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(*vertex), vertex->svector3f , NULL, 0); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(*vertex), vertex->tvector3f , NULL, 0); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT , sizeof(*vertex), vertex->normal3f , NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT , sizeof(*vertex), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(*vertex), vertex->skeletalindex4ub , NULL, 0); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->skeletalweight4ub , NULL, 0); + } + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordtexture2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex)); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0); + } + break; + case RENDERPATH_GL11: + if (vertexbuffer) + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->color4f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, bufferoffset + (int)((unsigned char *)vertex->texcoordtexture2f - (unsigned char *)vertex)); + } + else + { + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(*vertex), vertex->color4f , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0); + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetVertexDeclaration(vid_d3d9dev, r_vertexmesh_d3d9decl); + if (vertexbuffer) + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, (IDirect3DVertexBuffer9*)vertexbuffer->devicebuffer, bufferoffset, sizeof(*vertex)); + else + IDirect3DDevice9_SetStreamSource(vid_d3d9dev, 0, NULL, 0, 0); + gl_state.d3dvertexbuffer = (void *)vertexbuffer; + gl_state.d3dvertexdata = (void *)vertex; + gl_state.d3dvertexsize = sizeof(*vertex); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_SetVertexPointer(vertex->vertex3f, sizeof(*vertex)); + DPSOFTRAST_SetColorPointer(vertex->color4f, sizeof(*vertex)); + DPSOFTRAST_SetTexCoordPointer(0, 2, sizeof(*vertex), vertex->texcoordtexture2f); + DPSOFTRAST_SetTexCoordPointer(1, 3, sizeof(*vertex), vertex->svector3f); + DPSOFTRAST_SetTexCoordPointer(2, 3, sizeof(*vertex), vertex->tvector3f); + DPSOFTRAST_SetTexCoordPointer(3, 3, sizeof(*vertex), vertex->normal3f); + DPSOFTRAST_SetTexCoordPointer(4, 2, sizeof(*vertex), vertex->texcoordlightmap2f); + break; + } +} + +void GL_BlendEquationSubtract(qboolean negated) +{ + if(negated) + { + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_BlendSubtract(true); + break; + } + } + else + { + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglBlendEquationEXT(GL_FUNC_ADD); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_BlendSubtract(false); + break; + } + } +} diff --git a/app/jni/gl_backend.h b/app/jni/gl_backend.h new file mode 100644 index 0000000..04d23db --- /dev/null +++ b/app/jni/gl_backend.h @@ -0,0 +1,127 @@ + +#ifndef GL_BACKEND_H +#define GL_BACKEND_H + +extern r_viewport_t gl_viewport; +extern matrix4x4_t gl_modelmatrix; +extern matrix4x4_t gl_viewmatrix; +extern matrix4x4_t gl_modelviewmatrix; +extern matrix4x4_t gl_projectionmatrix; +extern matrix4x4_t gl_modelviewprojectionmatrix; +extern float gl_modelview16f[16]; +extern float gl_modelviewprojection16f[16]; +extern qboolean gl_modelmatrixchanged; + +extern cvar_t gl_vbo_dynamicvertex; +extern cvar_t gl_vbo_dynamicindex; + +#define POLYGONELEMENTS_MAXPOINTS 258 +extern int polygonelement3i[(POLYGONELEMENTS_MAXPOINTS-2)*3]; +extern unsigned short polygonelement3s[(POLYGONELEMENTS_MAXPOINTS-2)*3]; +#define QUADELEMENTS_MAXQUADS 128 +extern int quadelement3i[QUADELEMENTS_MAXQUADS*6]; +extern unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6]; + +void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out); +qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor); +void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float zNear, float zFar, const float *nearplane); +void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, float zFar, const float *nearplane); +void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane); +void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane); +void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane); +void R_SetViewport(const r_viewport_t *v); +void R_GetViewport(r_viewport_t *v); +void GL_Finish(void); + +void GL_BlendFunc(int blendfunc1, int blendfunc2); +void GL_BlendEquationSubtract(qboolean negated); +void GL_DepthMask(int state); +void GL_DepthTest(int state); +void GL_DepthFunc(int state); +void GL_DepthRange(float nearfrac, float farfrac); +void R_SetStencilSeparate(qboolean enable, int writemask, int frontfail, int frontzfail, int frontzpass, int backfail, int backzfail, int backzpass, int frontcompare, int backcompare, int comparereference, int comparemask); +void R_SetStencil(qboolean enable, int writemask, int fail, int zfail, int zpass, int compare, int comparereference, int comparemask); +void GL_PolygonOffset(float planeoffset, float depthoffset); +void GL_CullFace(int state); +void GL_AlphaTest(int state); +void GL_AlphaToCoverage(qboolean state); +void GL_ColorMask(int r, int g, int b, int a); +void GL_Color(float cr, float cg, float cb, float ca); +void GL_ActiveTexture(unsigned int num); +void GL_ClientActiveTexture(unsigned int num); +void GL_Scissor(int x, int y, int width, int height); +void GL_ScissorTest(int state); +void GL_Clear(int mask, const float *colorvalue, float depthvalue, int stencilvalue); +void GL_ReadPixelsBGRA(int x, int y, int width, int height, unsigned char *outpixels); +int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4); +void R_Mesh_DestroyFramebufferObject(int fbo); +void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4); + +unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int geometrystrings_count, const char **geometrystrings_list, int fragmentstrings_count, const char **fragmentstrings_list); +void GL_Backend_FreeProgram(unsigned int prog); + +extern cvar_t gl_paranoid; +extern cvar_t gl_printcheckerror; + +// adds console variables and registers the render module (only call from GL_Init) +void gl_backend_init(void); + +// starts mesh rendering for the frame +void R_Mesh_Start(void); + +// ends mesh rendering for the frame +// (only valid after R_Mesh_Start) +void R_Mesh_Finish(void); + + +// vertex buffer and index buffer creation/updating/freeing +r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isuniformbuffer, qboolean isdynamic, qboolean isindex16); +void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size, qboolean subdata, size_t offset); +void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer); +void GL_Mesh_ListVBOs(qboolean printeach); + +void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *buffer, int bufferoffset); + +r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices); +qboolean R_Mesh_PrepareVertices_Generic_Unlock(void); +void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f); +void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer, int bufferoffset); + +r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices); +qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void); // if this returns false, you need to prepare the mesh again! +void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f); +void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *buffer, int bufferoffset); + +// sets up the requested vertex transform matrix +void R_EntityMatrix(const matrix4x4_t *matrix); +// sets the vertex array pointer +void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); +// sets the color array pointer (GL_Color only works when this is NULL) +void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); +// sets the texcoord array pointer for an array unit, if GL_UNSIGNED_BYTE | 0x80000000 is specified it will be an unnormalized type (integer values) +void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); +// returns current texture bound to this identifier +int R_Mesh_TexBound(unsigned int unitnum, int id); +// copies a section of the framebuffer to a 2D texture +void R_Mesh_CopyToTexture(rtexture_t *tex, int tx, int ty, int sx, int sy, int width, int height); +// bind a given texture to a given image unit +void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex); +// sets the texcoord matrix for a texenv unit, can be NULL or blank (will use identity) +void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix); +// sets the combine state for a texenv unit +void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale); +// set up a blank texture state (unbinds all textures, texcoord pointers, and resets combine settings) +void R_Mesh_ResetTextureState(void); +// before a texture is freed, make sure there are no references to it +void R_Mesh_ClearBindingsForTexture(int texnum); + +// renders a mesh +void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, int element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, int element3s_bufferoffset); + +// saves a section of the rendered frame to a .tga or .jpg file +qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *buffer2, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg, qboolean png, qboolean gammacorrect, qboolean keep_alpha); +// used by R_Envmap_f and internally in backend, clears the frame +void R_ClearScreen(qboolean fogcolor); + +#endif + diff --git a/app/jni/gl_draw.c b/app/jni/gl_draw.c new file mode 100644 index 0000000..88431d9 --- /dev/null +++ b/app/jni/gl_draw.c @@ -0,0 +1,2268 @@ +/* +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 "image.h" +#include "wad.h" + +#include "cl_video.h" +#include "cl_dyntexture.h" + +#include "ft2.h" +#include "ft2_fontdefs.h" + +dp_fonts_t dp_fonts; +static mempool_t *fonts_mempool = NULL; + +cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"}; +cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"}; +cvar_t r_textcontrast = {CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 0 makes them all black)"}; + +cvar_t r_font_postprocess_blur = {CVAR_SAVE, "r_font_postprocess_blur", "0", "font blur amount"}; +cvar_t r_font_postprocess_outline = {CVAR_SAVE, "r_font_postprocess_outline", "0", "font outline amount"}; +cvar_t r_font_postprocess_shadow_x = {CVAR_SAVE, "r_font_postprocess_shadow_x", "0", "font shadow X shift amount, applied during outlining"}; +cvar_t r_font_postprocess_shadow_y = {CVAR_SAVE, "r_font_postprocess_shadow_y", "0", "font shadow Y shift amount, applied during outlining"}; +cvar_t r_font_postprocess_shadow_z = {CVAR_SAVE, "r_font_postprocess_shadow_z", "0", "font shadow Z shift amount, applied during blurring"}; +cvar_t r_font_hinting = {CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"}; +cvar_t r_font_antialias = {CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */}; +cvar_t r_nearest_2d = {CVAR_SAVE, "r_nearest_2d", "0", "use nearest filtering on all 2d textures (including conchars)"}; +cvar_t r_nearest_conchars = {CVAR_SAVE, "r_nearest_conchars", "0", "use nearest filtering on conchars texture"}; + +extern cvar_t v_glslgamma; + +//============================================================================= +/* Support Routines */ + +#define FONT_FILESIZE 13468 +static cachepic_t *cachepichash[CACHEPICHASHSIZE]; +static cachepic_t cachepics[MAX_CACHED_PICS]; +static int numcachepics; + +rtexturepool_t *drawtexturepool; + +static const unsigned char concharimage[FONT_FILESIZE] = +{ +#include "lhfont.h" +}; + +static rtexture_t *draw_generateconchars(void) +{ + int i; + unsigned char *data; + double random; + rtexture_t *tex; + + data = LoadTGA_BGRA (concharimage, FONT_FILESIZE, NULL); +// Gold numbers + for (i = 0;i < 8192;i++) + { + random = lhrandom (0.0,1.0); + data[i*4+3] = data[i*4+0]; + data[i*4+2] = 83 + (unsigned char)(random * 64); + data[i*4+1] = 71 + (unsigned char)(random * 32); + data[i*4+0] = 23 + (unsigned char)(random * 16); + } +// White chars + for (i = 8192;i < 32768;i++) + { + random = lhrandom (0.0,1.0); + data[i*4+3] = data[i*4+0]; + data[i*4+2] = 95 + (unsigned char)(random * 64); + data[i*4+1] = 95 + (unsigned char)(random * 64); + data[i*4+0] = 95 + (unsigned char)(random * 64); + } +// Gold numbers + for (i = 32768;i < 40960;i++) + { + random = lhrandom (0.0,1.0); + data[i*4+3] = data[i*4+0]; + data[i*4+2] = 83 + (unsigned char)(random * 64); + data[i*4+1] = 71 + (unsigned char)(random * 32); + data[i*4+0] = 23 + (unsigned char)(random * 16); + } +// Red chars + for (i = 40960;i < 65536;i++) + { + random = lhrandom (0.0,1.0); + data[i*4+3] = data[i*4+0]; + data[i*4+2] = 96 + (unsigned char)(random * 64); + data[i*4+1] = 43 + (unsigned char)(random * 32); + data[i*4+0] = 27 + (unsigned char)(random * 32); + } + +#if 0 + Image_WriteTGABGRA ("gfx/generated_conchars.tga", 256, 256, data); +#endif + + tex = R_LoadTexture2D(drawtexturepool, "conchars", 256, 256, data, TEXTYPE_BGRA, TEXF_ALPHA | (r_nearest_conchars.integer ? TEXF_FORCENEAREST : 0), -1, NULL); + Mem_Free(data); + return tex; +} + +static rtexture_t *draw_generateditherpattern(void) +{ + int x, y; + unsigned char pixels[8][8]; + for (y = 0;y < 8;y++) + for (x = 0;x < 8;x++) + pixels[y][x] = ((x^y) & 4) ? 254 : 0; + return R_LoadTexture2D(drawtexturepool, "ditherpattern", 8, 8, pixels[0], TEXTYPE_PALETTE, TEXF_FORCENEAREST, -1, palette_bgra_transparent); +} + +typedef struct embeddedpic_s +{ + const char *name; + int width; + int height; + const char *pixels; +} +embeddedpic_t; + +static const embeddedpic_t embeddedpics[] = +{ + { + "gfx/prydoncursor001", 16, 16, + "477777774......." + "77.....6........" + "7.....6........." + "7....6.........." + "7.....6........." + "7..6...6........" + "7.6.6...6......." + "76...6...6......" + "4.....6.6......." + ".......6........" + "................" + "................" + "................" + "................" + "................" + "................" + }, + { + "ui/mousepointer", 16, 16, + "477777774......." + "77.....6........" + "7.....6........." + "7....6.........." + "7.....6........." + "7..6...6........" + "7.6.6...6......." + "76...6...6......" + "4.....6.6......." + ".......6........" + "................" + "................" + "................" + "................" + "................" + "................" + }, + { + "gfx/crosshair1", 16, 16, + "................" + "................" + "................" + "...33......33..." + "...355....553..." + "....577..775...." + ".....77..77....." + "................" + "................" + ".....77..77....." + "....577..775...." + "...355....553..." + "...33......33..." + "................" + "................" + "................" + }, + { + "gfx/crosshair2", 16, 16, + "................" + "................" + "................" + "...3........3..." + "....5......5...." + ".....7....7....." + "......7..7......" + "................" + "................" + "......7..7......" + ".....7....7....." + "....5......5...." + "...3........3..." + "................" + "................" + "................" + }, + { + "gfx/crosshair3", 16, 16, + "................" + ".......77......." + ".......77......." + "................" + "................" + ".......44......." + ".......44......." + ".77..44..44..77." + ".77..44..44..77." + ".......44......." + ".......44......." + "................" + "................" + ".......77......." + ".......77......." + "................" + }, + { + "gfx/crosshair4", 16, 16, + "................" + "................" + "................" + "................" + "................" + "................" + "................" + "................" + "........7777777." + "........752....." + "........72......" + "........7......." + "........7......." + "........7......." + "........7......." + "................" + }, + { + "gfx/crosshair5", 8, 8, + "........" + "........" + "....7..." + "........" + "..7.7.7." + "........" + "....7..." + "........" + }, + { + "gfx/crosshair6", 2, 2, + "77" + "77" + }, + { + "gfx/crosshair7", 16, 16, + "................" + ".3............3." + "..5...2332...5.." + "...7.3....3.7..." + "....7......7...." + "...3.7....7.3..." + "..2...7..7...2.." + "..3..........3.." + "..3..........3.." + "..2...7..7...2.." + "...3.7....7.3..." + "....7......7...." + "...7.3....3.7..." + "..5...2332...5.." + ".3............3." + "................" + }, + {NULL, 0, 0, NULL} +}; + +static rtexture_t *draw_generatepic(const char *name, qboolean quiet) +{ + const embeddedpic_t *p; + for (p = embeddedpics;p->name;p++) + if (!strcmp(name, p->name)) + return R_LoadTexture2D(drawtexturepool, p->name, p->width, p->height, (const unsigned char *)p->pixels, TEXTYPE_PALETTE, TEXF_ALPHA, -1, palette_bgra_embeddedpic); + if (!strcmp(name, "gfx/conchars")) + return draw_generateconchars(); + if (!strcmp(name, "gfx/colorcontrol/ditherpattern")) + return draw_generateditherpattern(); + if (!quiet) + Con_DPrintf("Draw_CachePic: failed to load %s\n", name); + return r_texture_notexture; +} + +int draw_frame = 1; + +/* +================ +Draw_CachePic +================ +*/ +// FIXME: move this to client somehow +cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) +{ + int crc, hashkey; + unsigned char *pixels = NULL; + cachepic_t *pic; + fs_offset_t lmpsize; + unsigned char *lmpdata; + char lmpname[MAX_QPATH]; + int texflags; + int j; + qboolean ddshasalpha; + float ddsavgcolor[4]; + qboolean loaded = false; + char vabuf[1024]; + + texflags = TEXF_ALPHA; + if (!(cachepicflags & CACHEPICFLAG_NOCLAMP)) + texflags |= TEXF_CLAMP; + if (cachepicflags & CACHEPICFLAG_MIPMAP) + texflags |= TEXF_MIPMAP; + if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer && gl_texturecompression.integer) + texflags |= TEXF_COMPRESS; + if ((cachepicflags & CACHEPICFLAG_NEAREST) || r_nearest_2d.integer) + texflags |= TEXF_FORCENEAREST; + + // check whether the picture has already been cached + crc = CRC_Block((unsigned char *)path, strlen(path)); + hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE; + for (pic = cachepichash[hashkey];pic;pic = pic->chain) + { + if (!strcmp (path, pic->name)) + { + // if it was created (or replaced) by Draw_NewPic, just return it + if(pic->flags & CACHEPICFLAG_NEWPIC) + return pic; + if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that + { + if(!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT)) + { + if(pic->tex) + pic->autoload = false; // persist it + else + goto reload; // load it below, and then persist + } + return pic; + } + } + } + + if (numcachepics == MAX_CACHED_PICS) + { + Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n"); + // FIXME: support NULL in callers? + return cachepics; // return the first one + } + pic = cachepics + (numcachepics++); + memset(pic, 0, sizeof(*pic)); + strlcpy (pic->name, path, sizeof(pic->name)); + // link into list + pic->chain = cachepichash[hashkey]; + cachepichash[hashkey] = pic; + +reload: + // TODO why does this crash? + if(pic->allow_free_tex && pic->tex) + R_PurgeTexture(pic->tex); + + // check whether it is an dynamic texture (if so, we can directly use its texture handler) + pic->flags = cachepicflags; + pic->tex = CL_GetDynTexture( path ); + // if so, set the width/height, too + if( pic->tex ) { + pic->allow_free_tex = false; + pic->width = R_TextureWidth(pic->tex); + pic->height = R_TextureHeight(pic->tex); + // we're done now (early-out) + return pic; + } + + pic->allow_free_tex = true; + + pic->hasalpha = true; // assume alpha unless we know it has none + pic->texflags = texflags; + pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT); + pic->lastusedframe = draw_frame; + + // load a high quality image from disk if possible + if (!loaded && r_texture_dds_load.integer != 0 && (pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false))) + { + // note this loads even if autoload is true, otherwise we can't get the width/height + loaded = true; + pic->hasalpha = ddshasalpha; + pic->width = R_TextureWidth(pic->tex); + pic->height = R_TextureHeight(pic->tex); + } + if (!loaded && ((pixels = loadimagepixelsbgra(pic->name, false, true, false, NULL)) || (!strncmp(pic->name, "gfx/", 4) && (pixels = loadimagepixelsbgra(pic->name+4, false, true, false, NULL))))) + { + loaded = true; + pic->hasalpha = false; + if (pic->texflags & TEXF_ALPHA) + { + for (j = 3;j < image_width * image_height * 4;j += 4) + { + if (pixels[j] < 255) + { + pic->hasalpha = true; + break; + } + } + } + + pic->width = image_width; + pic->height = image_height; + if (!pic->autoload) + { + pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, image_width, image_height, pixels, vid.sRGB2D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, pic->texflags & (pic->hasalpha ? ~0 : ~TEXF_ALPHA), -1, NULL); +#ifndef USE_GLES2 + if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) + R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); +#endif + } + } + if (!loaded) + { + pic->autoload = false; + // never compress the fallback images + pic->texflags &= ~TEXF_COMPRESS; + } + + // now read the low quality version (wad or lmp file), and take the pic + // size from that even if we don't upload the texture, this way the pics + // show up the right size in the menu even if they were replaced with + // higher or lower resolution versions + dpsnprintf(lmpname, sizeof(lmpname), "%s.lmp", pic->name); + if ((!strncmp(pic->name, "gfx/", 4) || (gamemode == GAME_BLOODOMNICIDE && !strncmp(pic->name, "locale/", 6))) && (lmpdata = FS_LoadFile(lmpname, tempmempool, false, &lmpsize))) + { + if (developer_loading.integer) + Con_Printf("loading lump \"%s\"\n", pic->name); + + if (lmpsize >= 9) + { + pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216; + pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216; + // if no high quality replacement image was found, upload the original low quality texture + if (!loaded) + { + loaded = true; + pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent); + } + } + Mem_Free(lmpdata); + } + else if ((lmpdata = W_GetLumpName (pic->name + 4))) + { + if (developer_loading.integer) + Con_Printf("loading gfx.wad lump \"%s\"\n", pic->name + 4); + + if (!strcmp(pic->name, "gfx/conchars")) + { + // conchars is a raw image and with color 0 as transparent instead of 255 + pic->width = 128; + pic->height = 128; + // if no high quality replacement image was found, upload the original low quality texture + if (!loaded) + { + loaded = true; + pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, 128, 128, lmpdata, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_font); + } + } + else + { + pic->width = lmpdata[0] + lmpdata[1] * 256 + lmpdata[2] * 65536 + lmpdata[3] * 16777216; + pic->height = lmpdata[4] + lmpdata[5] * 256 + lmpdata[6] * 65536 + lmpdata[7] * 16777216; + // if no high quality replacement image was found, upload the original low quality texture + if (!loaded) + { + loaded = true; + pic->tex = R_LoadTexture2D(drawtexturepool, pic->name, pic->width, pic->height, lmpdata + 8, vid.sRGB2D != 0 ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, pic->texflags, -1, palette_bgra_transparent); + } + } + } + + if (pixels) + { + Mem_Free(pixels); + pixels = NULL; + } + if (!loaded) + { + // if it's not found on disk, generate an image + pic->tex = draw_generatepic(pic->name, (cachepicflags & CACHEPICFLAG_QUIET) != 0); + pic->width = R_TextureWidth(pic->tex); + pic->height = R_TextureHeight(pic->tex); + pic->allow_free_tex = (pic->tex != r_texture_notexture); + } + + return pic; +} + +cachepic_t *Draw_CachePic (const char *path) +{ + return Draw_CachePic_Flags (path, 0); // default to persistent! +} + +rtexture_t *Draw_GetPicTexture(cachepic_t *pic) +{ + char vabuf[1024]; + if (pic->autoload && !pic->tex) + { + if (pic->tex == NULL && r_texture_dds_load.integer != 0) + { + qboolean ddshasalpha; + float ddsavgcolor[4]; + pic->tex = R_LoadTextureDDSFile(drawtexturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), vid.sRGB2D, pic->texflags, &ddshasalpha, ddsavgcolor, 0, false); + } + if (pic->tex == NULL) + { + pic->tex = loadtextureimage(drawtexturepool, pic->name, false, pic->texflags, true, vid.sRGB2D); +#ifndef USE_GLES2 + if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) + R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); +#endif + } + if (pic->tex == NULL && !strncmp(pic->name, "gfx/", 4)) + { + pic->tex = loadtextureimage(drawtexturepool, pic->name+4, false, pic->texflags, true, vid.sRGB2D); +#ifndef USE_GLES2 + if (r_texture_dds_save.integer && qglGetCompressedTexImageARB && pic->tex) + R_SaveTextureDDSFile(pic->tex, va(vabuf, sizeof(vabuf), "dds/%s.dds", pic->name), r_texture_dds_save.integer < 2, pic->hasalpha); +#endif + } + if (pic->tex == NULL) + pic->tex = draw_generatepic(pic->name, true); + } + pic->lastusedframe = draw_frame; + return pic->tex; +} + +void Draw_Frame(void) +{ + int i; + cachepic_t *pic; + static double nextpurgetime; + if (nextpurgetime > realtime) + return; + nextpurgetime = realtime + 0.05; + for (i = 0, pic = cachepics;i < numcachepics;i++, pic++) + { + if (pic->autoload && pic->tex && pic->lastusedframe < draw_frame) + { + R_FreeTexture(pic->tex); + pic->tex = NULL; + } + } + draw_frame++; +} + +cachepic_t *Draw_NewPic(const char *picname, int width, int height, int alpha, unsigned char *pixels_bgra) +{ + int crc, hashkey; + cachepic_t *pic; + + crc = CRC_Block((unsigned char *)picname, strlen(picname)); + hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE; + for (pic = cachepichash[hashkey];pic;pic = pic->chain) + if (!strcmp (picname, pic->name)) + break; + + if (pic) + { + if (pic->flags == CACHEPICFLAG_NEWPIC && pic->tex && pic->width == width && pic->height == height) + { + R_UpdateTexture(pic->tex, pixels_bgra, 0, 0, 0, width, height, 1); + return pic; + } + } + else + { + if (numcachepics == MAX_CACHED_PICS) + { + Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n"); + // FIXME: support NULL in callers? + return cachepics; // return the first one + } + pic = cachepics + (numcachepics++); + memset(pic, 0, sizeof(*pic)); + strlcpy (pic->name, picname, sizeof(pic->name)); + // link into list + pic->chain = cachepichash[hashkey]; + cachepichash[hashkey] = pic; + } + + pic->flags = CACHEPICFLAG_NEWPIC; // disable texflags checks in Draw_CachePic + pic->width = width; + pic->height = height; + if (pic->allow_free_tex && pic->tex) + R_FreeTexture(pic->tex); + pic->tex = R_LoadTexture2D(drawtexturepool, picname, width, height, pixels_bgra, TEXTYPE_BGRA, (alpha ? TEXF_ALPHA : 0), -1, NULL); + return pic; +} + +void Draw_FreePic(const char *picname) +{ + int crc; + int hashkey; + cachepic_t *pic; + // this doesn't really free the pic, but does free it's texture + crc = CRC_Block((unsigned char *)picname, strlen(picname)); + hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE; + for (pic = cachepichash[hashkey];pic;pic = pic->chain) + { + if (!strcmp (picname, pic->name) && pic->tex) + { + R_FreeTexture(pic->tex); + pic->tex = NULL; + pic->width = 0; + pic->height = 0; + return; + } + } +} + +static float snap_to_pixel_x(float x, float roundUpAt); +extern int con_linewidth; // to force rewrapping +void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, float voffset) +{ + int i, ch; + float maxwidth; + char widthfile[MAX_QPATH]; + char *widthbuf; + fs_offset_t widthbufsize; + + if(override || !fnt->texpath[0]) + { + strlcpy(fnt->texpath, name, sizeof(fnt->texpath)); + // load the cvars when the font is FIRST loader + fnt->settings.scale = scale; + fnt->settings.voffset = voffset; + fnt->settings.antialias = r_font_antialias.integer; + fnt->settings.hinting = r_font_hinting.integer; + fnt->settings.outline = r_font_postprocess_outline.value; + fnt->settings.blur = r_font_postprocess_blur.value; + fnt->settings.shadowx = r_font_postprocess_shadow_x.value; + fnt->settings.shadowy = r_font_postprocess_shadow_y.value; + fnt->settings.shadowz = r_font_postprocess_shadow_z.value; + } + // fix bad scale + if (fnt->settings.scale <= 0) + fnt->settings.scale = 1; + + if(drawtexturepool == NULL) + return; // before gl_draw_start, so will be loaded later + + if(fnt->ft2) + { + // clear freetype font + Font_UnloadFont(fnt->ft2); + Mem_Free(fnt->ft2); + fnt->ft2 = NULL; + } + + if(fnt->req_face != -1) + { + if(!Font_LoadFont(fnt->texpath, fnt)) + Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath); + } + + fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; + if(fnt->tex == r_texture_notexture) + { + for (i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + if (!fnt->fallbacks[i][0]) + break; + fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; + if(fnt->tex != r_texture_notexture) + break; + } + if(fnt->tex == r_texture_notexture) + { + fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION | (r_nearest_conchars.integer ? CACHEPICFLAG_NEAREST : 0))->tex; + strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile)); + } + else + dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]); + } + else + dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath); + + // unspecified width == 1 (base width) + for(ch = 0; ch < 256; ++ch) + fnt->width_of[ch] = 1; + + // FIXME load "name.width", if it fails, fill all with 1 + if((widthbuf = (char *) FS_LoadFile(widthfile, tempmempool, true, &widthbufsize))) + { + float extraspacing = 0; + const char *p = widthbuf; + + ch = 0; + while(ch < 256) + { + if(!COM_ParseToken_Simple(&p, false, false, true)) + return; + + switch(*com_token) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case '.': + fnt->width_of[ch] = atof(com_token) + extraspacing; + ch++; + break; + default: + if(!strcmp(com_token, "extraspacing")) + { + if(!COM_ParseToken_Simple(&p, false, false, true)) + return; + extraspacing = atof(com_token); + } + else if(!strcmp(com_token, "scale")) + { + if(!COM_ParseToken_Simple(&p, false, false, true)) + return; + fnt->settings.scale = atof(com_token); + } + else + { + Con_Printf("Warning: skipped unknown font property %s\n", com_token); + if(!COM_ParseToken_Simple(&p, false, false, true)) + return; + } + break; + } + } + + Mem_Free(widthbuf); + } + + if(fnt->ft2) + { + for (i = 0; i < MAX_FONT_SIZES; ++i) + { + ft2_font_map_t *map = Font_MapForIndex(fnt->ft2, i); + if (!map) + break; + for(ch = 0; ch < 256; ++ch) + map->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/map->size); + } + } + + maxwidth = fnt->width_of[0]; + for(i = 1; i < 256; ++i) + maxwidth = max(maxwidth, fnt->width_of[i]); + fnt->maxwidth = maxwidth; + + // fix up maxwidth for overlap + fnt->maxwidth *= fnt->settings.scale; + + if(fnt == FONT_CONSOLE) + con_linewidth = -1; // rewrap console in next frame +} + +extern cvar_t developer_font; +dp_font_t *FindFont(const char *title, qboolean allocate_new) +{ + int i, oldsize; + + // find font + for(i = 0; i < dp_fonts.maxsize; ++i) + if(!strcmp(dp_fonts.f[i].title, title)) + return &dp_fonts.f[i]; + // if not found - try allocate + if (allocate_new) + { + // find any font with empty title + for(i = 0; i < dp_fonts.maxsize; ++i) + { + if(!strcmp(dp_fonts.f[i].title, "")) + { + strlcpy(dp_fonts.f[i].title, title, sizeof(dp_fonts.f[i].title)); + return &dp_fonts.f[i]; + } + } + // if no any 'free' fonts - expand buffer + oldsize = dp_fonts.maxsize; + dp_fonts.maxsize = dp_fonts.maxsize + FONTS_EXPAND; + if (developer_font.integer) + Con_Printf("FindFont: enlarging fonts buffer (%i -> %i)\n", oldsize, dp_fonts.maxsize); + dp_fonts.f = (dp_font_t *)Mem_Realloc(fonts_mempool, dp_fonts.f, sizeof(dp_font_t) * dp_fonts.maxsize); + // relink ft2 structures + for(i = 0; i < oldsize; ++i) + if (dp_fonts.f[i].ft2) + dp_fonts.f[i].ft2->settings = &dp_fonts.f[i].settings; + // register a font in first expanded slot + strlcpy(dp_fonts.f[oldsize].title, title, sizeof(dp_fonts.f[oldsize].title)); + return &dp_fonts.f[oldsize]; + } + return NULL; +} + +static float snap_to_pixel_x(float x, float roundUpAt) +{ + float pixelpos = x * vid.width / vid_conwidth.value; + int snap = (int) pixelpos; + if (pixelpos - snap >= roundUpAt) ++snap; + return ((float)snap * vid_conwidth.value / vid.width); + /* + x = (int)(x * vid.width / vid_conwidth.value); + x = (x * vid_conwidth.value / vid.width); + return x; + */ +} + +static float snap_to_pixel_y(float y, float roundUpAt) +{ + float pixelpos = y * vid.height / vid_conheight.value; + int snap = (int) pixelpos; + if (pixelpos - snap > roundUpAt) ++snap; + return ((float)snap * vid_conheight.value / vid.height); + /* + y = (int)(y * vid.height / vid_conheight.value); + y = (y * vid_conheight.value / vid.height); + return y; + */ +} + +static void LoadFont_f(void) +{ + dp_font_t *f; + int i, sizes; + const char *filelist, *c, *cm; + float sz, scale, voffset; + char mainfont[MAX_QPATH]; + + if(Cmd_Argc() < 2) + { + Con_Printf("Available font commands:\n"); + for(i = 0; i < dp_fonts.maxsize; ++i) + if (dp_fonts.f[i].title[0]) + Con_Printf(" loadfont %s gfx/tgafile[...] [custom switches] [sizes...]\n", dp_fonts.f[i].title); + Con_Printf("A font can simply be gfx/tgafile, or alternatively you\n" + "can specify multiple fonts and faces\n" + "Like this: gfx/vera-sans:2,gfx/fallback:1\n" + "to load face 2 of the font gfx/vera-sans and use face 1\n" + "of gfx/fallback as fallback font.\n" + "You can also specify a list of font sizes to load, like this:\n" + "loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32\n" + "In many cases, 8 12 16 24 32 should be a good choice.\n" + "custom switches:\n" + " scale x : scale all characters by this amount when rendering (doesnt change line height)\n" + " voffset x : offset all chars vertical when rendering, this is multiplied to character height\n" + ); + return; + } + f = FindFont(Cmd_Argv(1), true); + if(f == NULL) + { + Con_Printf("font function not found\n"); + return; + } + + if(Cmd_Argc() < 3) + filelist = "gfx/conchars"; + else + filelist = Cmd_Argv(2); + + memset(f->fallbacks, 0, sizeof(f->fallbacks)); + memset(f->fallback_faces, 0, sizeof(f->fallback_faces)); + + // first font is handled "normally" + c = strchr(filelist, ':'); + cm = strchr(filelist, ','); + if(c && (!cm || c < cm)) + f->req_face = atoi(c+1); + else + { + f->req_face = 0; + c = cm; + } + + if(!c || (c - filelist) > MAX_QPATH) + strlcpy(mainfont, filelist, sizeof(mainfont)); + else + { + memcpy(mainfont, filelist, c - filelist); + mainfont[c - filelist] = 0; + } + + for(i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + c = strchr(filelist, ','); + if(!c) + break; + filelist = c + 1; + if(!*filelist) + break; + c = strchr(filelist, ':'); + cm = strchr(filelist, ','); + if(c && (!cm || c < cm)) + f->fallback_faces[i] = atoi(c+1); + else + { + f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index + c = cm; + } + if(!c || (c-filelist) > MAX_QPATH) + { + strlcpy(f->fallbacks[i], filelist, sizeof(mainfont)); + } + else + { + memcpy(f->fallbacks[i], filelist, c - filelist); + f->fallbacks[i][c - filelist] = 0; + } + } + + // for now: by default load only one size: the default size + f->req_sizes[0] = 0; + for(i = 1; i < MAX_FONT_SIZES; ++i) + f->req_sizes[i] = -1; + + scale = 1; + voffset = 0; + if(Cmd_Argc() >= 4) + { + for(sizes = 0, i = 3; i < Cmd_Argc(); ++i) + { + // special switches + if (!strcmp(Cmd_Argv(i), "scale")) + { + i++; + if (i < Cmd_Argc()) + scale = atof(Cmd_Argv(i)); + continue; + } + if (!strcmp(Cmd_Argv(i), "voffset")) + { + i++; + if (i < Cmd_Argc()) + voffset = atof(Cmd_Argv(i)); + continue; + } + + if (sizes == -1) + continue; // no slot for other sizes + + // parse one of sizes + sz = atof(Cmd_Argv(i)); + if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes + { + // search for duplicated sizes + int j; + for (j=0; jreq_sizes[j] == sz) + break; + if (j != sizes) + continue; // sz already in req_sizes, don't add it again + + if (sizes == MAX_FONT_SIZES) + { + Con_Printf("Warning: specified more than %i different font sizes, exceding ones are ignored\n", MAX_FONT_SIZES); + sizes = -1; + continue; + } + f->req_sizes[sizes] = sz; + sizes++; + } + } + } + + LoadFont(true, mainfont, f, scale, voffset); +} + +/* +=============== +Draw_Init +=============== +*/ +static void gl_draw_start(void) +{ + int i; + char vabuf[1024]; + drawtexturepool = R_AllocTexturePool(); + + numcachepics = 0; + memset(cachepichash, 0, sizeof(cachepichash)); + + font_start(); + + // load default font textures + for(i = 0; i < dp_fonts.maxsize; ++i) + if (dp_fonts.f[i].title[0]) + LoadFont(false, va(vabuf, sizeof(vabuf), "gfx/font_%s", dp_fonts.f[i].title), &dp_fonts.f[i], 1, 0); + + // draw the loading screen so people have something to see in the newly opened window + SCR_UpdateLoadingScreen(true, true); +} + +static void gl_draw_shutdown(void) +{ + font_shutdown(); + + R_FreeTexturePool(&drawtexturepool); + + numcachepics = 0; + memset(cachepichash, 0, sizeof(cachepichash)); +} + +static void gl_draw_newmap(void) +{ + font_newmap(); +} + +void GL_Draw_Init (void) +{ + int i, j; + + Cvar_RegisterVariable(&r_font_postprocess_blur); + Cvar_RegisterVariable(&r_font_postprocess_outline); + Cvar_RegisterVariable(&r_font_postprocess_shadow_x); + Cvar_RegisterVariable(&r_font_postprocess_shadow_y); + Cvar_RegisterVariable(&r_font_postprocess_shadow_z); + Cvar_RegisterVariable(&r_font_hinting); + Cvar_RegisterVariable(&r_font_antialias); + Cvar_RegisterVariable(&r_textshadow); + Cvar_RegisterVariable(&r_textbrightness); + Cvar_RegisterVariable(&r_textcontrast); + Cvar_RegisterVariable(&r_nearest_2d); + Cvar_RegisterVariable(&r_nearest_conchars); + + // allocate fonts storage + fonts_mempool = Mem_AllocPool("FONTS", 0, NULL); + dp_fonts.maxsize = MAX_FONTS; + dp_fonts.f = (dp_font_t *)Mem_Alloc(fonts_mempool, sizeof(dp_font_t) * dp_fonts.maxsize); + memset(dp_fonts.f, 0, sizeof(dp_font_t) * dp_fonts.maxsize); + + // assign starting font names + strlcpy(FONT_DEFAULT->title, "default", sizeof(FONT_DEFAULT->title)); + strlcpy(FONT_DEFAULT->texpath, "gfx/conchars", sizeof(FONT_DEFAULT->texpath)); + strlcpy(FONT_CONSOLE->title, "console", sizeof(FONT_CONSOLE->title)); + strlcpy(FONT_SBAR->title, "sbar", sizeof(FONT_SBAR->title)); + strlcpy(FONT_NOTIFY->title, "notify", sizeof(FONT_NOTIFY->title)); + strlcpy(FONT_CHAT->title, "chat", sizeof(FONT_CHAT->title)); + strlcpy(FONT_CENTERPRINT->title, "centerprint", sizeof(FONT_CENTERPRINT->title)); + strlcpy(FONT_INFOBAR->title, "infobar", sizeof(FONT_INFOBAR->title)); + strlcpy(FONT_MENU->title, "menu", sizeof(FONT_MENU->title)); + for(i = 0, j = 0; i < MAX_USERFONTS; ++i) + if(!FONT_USER(i)->title[0]) + dpsnprintf(FONT_USER(i)->title, sizeof(FONT_USER(i)->title), "user%d", j++); + + Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions"); + R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap, NULL, NULL); +} + +static void _DrawQ_Setup(void) // see R_ResetViewRendering2D +{ + if (r_refdef.draw2dstage == 1) + return; + r_refdef.draw2dstage = 1; + + R_ResetViewRendering2D_Common(0, NULL, NULL, vid_conwidth.integer, vid_conheight.integer); +} + +qboolean r_draw2d_force = false; +static void _DrawQ_SetupAndProcessDrawFlag(int flags, cachepic_t *pic, float alpha) +{ + _DrawQ_Setup(); + if(!r_draw2d.integer && !r_draw2d_force) + return; + DrawQ_ProcessDrawFlag(flags, (alpha < 1) || (pic && pic->hasalpha)); +} +void DrawQ_ProcessDrawFlag(int flags, qboolean alpha) +{ + if(flags == DRAWFLAG_ADDITIVE) + { + GL_DepthMask(false); + GL_BlendFunc(alpha ? GL_SRC_ALPHA : GL_ONE, GL_ONE); + } + else if(flags == DRAWFLAG_MODULATE) + { + GL_DepthMask(false); + GL_BlendFunc(GL_DST_COLOR, GL_ZERO); + } + else if(flags == DRAWFLAG_2XMODULATE) + { + GL_DepthMask(false); + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + } + else if(flags == DRAWFLAG_SCREEN) + { + GL_DepthMask(false); + GL_BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); + } + else if(alpha) + { + GL_DepthMask(false); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + } +} + +void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags) +{ + float floats[36]; + + _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha); + if(!r_draw2d.integer && !r_draw2d_force) + return; + +// R_Mesh_ResetTextureState(); + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; + if (pic) + { + if (width == 0) + width = pic->width; + if (height == 0) + height = pic->height; + R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + +#if 0 + // AK07: lets be texel correct on the corners + { + float horz_offset = 0.5f / pic->width; + float vert_offset = 0.5f / pic->height; + + floats[12] = 0.0f + horz_offset;floats[13] = 0.0f + vert_offset; + floats[14] = 1.0f - horz_offset;floats[15] = 0.0f + vert_offset; + floats[16] = 1.0f - horz_offset;floats[17] = 1.0f - vert_offset; + floats[18] = 0.0f + horz_offset;floats[19] = 1.0f - vert_offset; + } +#endif + } + else + R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + + floats[2] = floats[5] = floats[8] = floats[11] = 0; + floats[0] = floats[9] = x; + floats[1] = floats[4] = y; + floats[3] = floats[6] = x + width; + floats[7] = floats[10] = y + height; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); +} + +void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, float org_x, float org_y, float angle, float red, float green, float blue, float alpha, int flags) +{ + float floats[36]; + float af = DEG2RAD(-angle); // forward + float ar = DEG2RAD(-angle + 90); // right + float sinaf = sin(af); + float cosaf = cos(af); + float sinar = sin(ar); + float cosar = cos(ar); + + _DrawQ_SetupAndProcessDrawFlag(flags, pic, alpha); + if(!r_draw2d.integer && !r_draw2d_force) + return; + +// R_Mesh_ResetTextureState(); + if (pic) + { + if (width == 0) + width = pic->width; + if (height == 0) + height = pic->height; + R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + } + else + R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + + floats[2] = floats[5] = floats[8] = floats[11] = 0; + +// top left + floats[0] = x - cosaf*org_x - cosar*org_y; + floats[1] = y - sinaf*org_x - sinar*org_y; + +// top right + floats[3] = x + cosaf*(width-org_x) - cosar*org_y; + floats[4] = y + sinaf*(width-org_x) - sinar*org_y; + +// bottom right + floats[6] = x + cosaf*(width-org_x) + cosar*(height-org_y); + floats[7] = y + sinaf*(width-org_x) + sinar*(height-org_y); + +// bottom left + floats[9] = x - cosaf*org_x + cosar*(height-org_y); + floats[10] = y - sinaf*org_x + sinar*(height-org_y); + + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); +} + +void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags) +{ + float floats[36]; + + _DrawQ_SetupAndProcessDrawFlag(flags, NULL, alpha); + if(!r_draw2d.integer && !r_draw2d_force) + return; + +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + + floats[2] = floats[5] = floats[8] = floats[11] = 0; + floats[0] = floats[9] = x; + floats[1] = floats[4] = y; + floats[3] = floats[6] = x + width; + floats[7] = floats[10] = y + height; + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); +} + +/// color tag printing +static const vec4_t string_colors[] = +{ + // Quake3 colors + // LordHavoc: why on earth is cyan before magenta in Quake3? + // LordHavoc: note: Doom3 uses white for [0] and [7] + {0.0, 0.0, 0.0, 1.0}, // black + {1.0, 0.0, 0.0, 1.0}, // red + {0.0, 1.0, 0.0, 1.0}, // green + {1.0, 1.0, 0.0, 1.0}, // yellow + {0.0, 0.0, 1.0, 1.0}, // blue + {0.0, 1.0, 1.0, 1.0}, // cyan + {1.0, 0.0, 1.0, 1.0}, // magenta + {1.0, 1.0, 1.0, 1.0}, // white + // [515]'s BX_COLOREDTEXT extension + {1.0, 1.0, 1.0, 0.5}, // half transparent + {0.5, 0.5, 0.5, 1.0} // half brightness + // Black's color table + //{1.0, 1.0, 1.0, 1.0}, + //{1.0, 0.0, 0.0, 1.0}, + //{0.0, 1.0, 0.0, 1.0}, + //{0.0, 0.0, 1.0, 1.0}, + //{1.0, 1.0, 0.0, 1.0}, + //{0.0, 1.0, 1.0, 1.0}, + //{1.0, 0.0, 1.0, 1.0}, + //{0.1, 0.1, 0.1, 1.0} +}; + +#define STRING_COLORS_COUNT (sizeof(string_colors) / sizeof(vec4_t)) + +static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow) +{ + float C = r_textcontrast.value; + float B = r_textbrightness.value; + if (colorindex & 0x10000) // that bit means RGB color + { + color[0] = ((colorindex >> 12) & 0xf) / 15.0; + color[1] = ((colorindex >> 8) & 0xf) / 15.0; + color[2] = ((colorindex >> 4) & 0xf) / 15.0; + color[3] = (colorindex & 0xf) / 15.0; + } + else + Vector4Copy(string_colors[colorindex], color); + Vector4Set(color, color[0] * r * C + B, color[1] * g * C + B, color[2] * b * C + B, color[3] * a); + if (shadow) + { + float shadowalpha = (color[0]+color[1]+color[2]) * 0.8; + Vector4Set(color, 0, 0, 0, color[3] * bound(0, shadowalpha, 1)); + } +} + +// NOTE: this function always draws exactly one character if maxwidth <= 0 +float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) +{ + const char *text_start = text; + int colorindex = STRING_COLOR_DEFAULT; + size_t i; + float x = 0; + Uchar ch, mapch, nextch; + Uchar prevch = 0; // used for kerning + int tempcolorindex; + float kx; + int map_index = 0; + size_t bytes_left; + ft2_font_map_t *fontmap = NULL; + ft2_font_map_t *map = NULL; + //ft2_font_map_t *prevmap = NULL; + ft2_font_t *ft2 = fnt->ft2; + // float ftbase_x; + qboolean snap = true; + qboolean least_one = false; + float dw; // display w + //float dh; // display h + const float *width_of; + + if (!h) h = w; + if (!h) { + w = h = 1; + snap = false; + } + // do this in the end + w *= fnt->settings.scale; + h *= fnt->settings.scale; + + // find the most fitting size: + if (ft2 != NULL) + { + if (snap) + map_index = Font_IndexForSize(ft2, h, &w, &h); + else + map_index = Font_IndexForSize(ft2, h, NULL, NULL); + fontmap = Font_MapForIndex(ft2, map_index); + } + + dw = w * sw; + //dh = h * sh; + + if (*maxlen < 1) + *maxlen = 1<<30; + + if (!outcolor || *outcolor == -1) + colorindex = STRING_COLOR_DEFAULT; + else + colorindex = *outcolor; + + // maxwidth /= fnt->scale; // w and h are multiplied by it already + // ftbase_x = snap_to_pixel_x(0); + + if(maxwidth <= 0) + { + least_one = true; + maxwidth = -maxwidth; + } + + //if (snap) + // x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway + + if (fontmap) + width_of = fontmap->width_of; + else + width_of = fnt->width_of; + + i = 0; + while (((bytes_left = *maxlen - (text - text_start)) > 0) && *text) + { + size_t i0 = i; + nextch = ch = u8_getnchar(text, &text, bytes_left); + i = text - text_start; + if (!ch) + break; + if (ch == ' ' && !fontmap) + { + if(!least_one || i0) // never skip the first character + if(x + width_of[(int) ' '] * dw > maxwidth) + { + i = i0; + break; // oops, can't draw this + } + x += width_of[(int) ' '] * dw; + continue; + } + // i points to the char after ^ + if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen) + { + ch = *text; // colors are ascii, so no u8_ needed + if (ch <= '9' && ch >= '0') // ^[0-9] found + { + colorindex = ch - '0'; + ++text; + ++i; + continue; + } + // i points to the char after ^... + // i+3 points to 3 in ^x123 + // i+3 == *maxlen would mean that char is missing + else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found + { + // building colorindex... + ch = tolower(text[1]); + tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000 + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12; + else tempcolorindex = 0; + if (tempcolorindex) + { + ch = tolower(text[2]); + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8; + else tempcolorindex = 0; + if (tempcolorindex) + { + ch = tolower(text[3]); + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4; + else tempcolorindex = 0; + if (tempcolorindex) + { + colorindex = tempcolorindex | 0xf; + // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa) + i+=4; + text += 4; + continue; + } + } + } + } + else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second + { + i++; + text++; + } + i--; + } + ch = nextch; + + if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF)) + { + if (ch > 0xE000) + ch -= 0xE000; + if (ch > 0xFF) + continue; + if (fontmap) + map = ft2_oldstyle_map; + prevch = 0; + if(!least_one || i0) // never skip the first character + if(x + width_of[ch] * dw > maxwidth) + { + i = i0; + break; // oops, can't draw this + } + x += width_of[ch] * dw; + } else { + if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP) + { + map = FontMap_FindForChar(fontmap, ch); + if (!map) + { + if (!Font_LoadMapForIndex(ft2, map_index, ch, &map)) + break; + if (!map) + break; + } + } + mapch = ch - map->start; + if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL)) + x += kx * dw; + x += map->glyphs[mapch].advance_x * dw; + //prevmap = map; + prevch = ch; + } + } + + *maxlen = i; + + if (outcolor) + *outcolor = colorindex; + + return x; +} + +float DrawQ_Color[4]; +float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt) +{ + int shadow, colorindex = STRING_COLOR_DEFAULT; + size_t i; + float x = startx, y, s, t, u, v, thisw; + float *av, *at, *ac; + int batchcount; + static float vertex3f[QUADELEMENTS_MAXQUADS*4*3]; + static float texcoord2f[QUADELEMENTS_MAXQUADS*4*2]; + static float color4f[QUADELEMENTS_MAXQUADS*4*4]; + Uchar ch, mapch, nextch; + Uchar prevch = 0; // used for kerning + int tempcolorindex; + int map_index = 0; + //ft2_font_map_t *prevmap = NULL; // the previous map + ft2_font_map_t *map = NULL; // the currently used map + ft2_font_map_t *fontmap = NULL; // the font map for the size + float ftbase_y; + const char *text_start = text; + float kx, ky; + ft2_font_t *ft2 = fnt->ft2; + qboolean snap = true; + float pix_x, pix_y; + size_t bytes_left; + float dw, dh; + const float *width_of; + + int tw, th; + tw = R_TextureWidth(fnt->tex); + th = R_TextureHeight(fnt->tex); + + if (!h) h = w; + if (!h) { + h = w = 1; + snap = false; + } + + starty -= (fnt->settings.scale - 1) * h * 0.5 - fnt->settings.voffset*h; // center & offset + w *= fnt->settings.scale; + h *= fnt->settings.scale; + + if (ft2 != NULL) + { + if (snap) + map_index = Font_IndexForSize(ft2, h, &w, &h); + else + map_index = Font_IndexForSize(ft2, h, NULL, NULL); + fontmap = Font_MapForIndex(ft2, map_index); + } + + dw = w * sw; + dh = h * sh; + + // draw the font at its baseline when using freetype + //ftbase_x = 0; + ftbase_y = dh * (4.5/6.0); + + if (maxlen < 1) + maxlen = 1<<30; + + _DrawQ_SetupAndProcessDrawFlag(flags, NULL, 0); + if(!r_draw2d.integer && !r_draw2d_force) + return startx + DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, &maxlen, w, h, sw, sh, NULL, ignorecolorcodes, fnt, 1000000000); + +// R_Mesh_ResetTextureState(); + if (!fontmap) + R_Mesh_TexBind(0, fnt->tex); + R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + + ac = color4f; + at = texcoord2f; + av = vertex3f; + batchcount = 0; + + //ftbase_x = snap_to_pixel_x(ftbase_x); + if(snap) + { + startx = snap_to_pixel_x(startx, 0.4); + starty = snap_to_pixel_y(starty, 0.4); + ftbase_y = snap_to_pixel_y(ftbase_y, 0.3); + } + + pix_x = vid.width / vid_conwidth.value; + pix_y = vid.height / vid_conheight.value; + + if (fontmap) + width_of = fontmap->width_of; + else + width_of = fnt->width_of; + + for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--) + { + prevch = 0; + text = text_start; + + if (!outcolor || *outcolor == -1) + colorindex = STRING_COLOR_DEFAULT; + else + colorindex = *outcolor; + + DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0); + + x = startx; + y = starty; + /* + if (shadow) + { + x += r_textshadow.value * vid.width / vid_conwidth.value; + y += r_textshadow.value * vid.height / vid_conheight.value; + } + */ + while (((bytes_left = maxlen - (text - text_start)) > 0) && *text) + { + nextch = ch = u8_getnchar(text, &text, bytes_left); + i = text - text_start; + if (!ch) + break; + if (ch == ' ' && !fontmap) + { + x += width_of[(int) ' '] * dw; + continue; + } + if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen) + { + ch = *text; // colors are ascii, so no u8_ needed + if (ch <= '9' && ch >= '0') // ^[0-9] found + { + colorindex = ch - '0'; + DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0); + ++text; + ++i; + continue; + } + else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found + { + // building colorindex... + ch = tolower(text[1]); + tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000 + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12; + else tempcolorindex = 0; + if (tempcolorindex) + { + ch = tolower(text[2]); + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8; + else tempcolorindex = 0; + if (tempcolorindex) + { + ch = tolower(text[3]); + if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4; + else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4; + else tempcolorindex = 0; + if (tempcolorindex) + { + colorindex = tempcolorindex | 0xf; + // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa) + //Con_Printf("^1colorindex:^7 %x\n", colorindex); + DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0); + i+=4; + text+=4; + continue; + } + } + } + } + else if (ch == STRING_COLOR_TAG) + { + i++; + text++; + } + i--; + } + // get the backup + ch = nextch; + // using a value of -1 for the oldstyle map because NULL means uninitialized... + // this way we don't need to rebind fnt->tex for every old-style character + // E000..E0FF: emulate old-font characters (to still have smileys and such available) + if (shadow) + { + x += 1.0/pix_x * r_textshadow.value; + y += 1.0/pix_y * r_textshadow.value; + } + if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF)) + { + if (ch >= 0xE000) + ch -= 0xE000; + if (ch > 0xFF) + goto out; + if (fontmap) + { + if (map != ft2_oldstyle_map) + { + if (batchcount) + { + // switching from freetype to non-freetype rendering + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + batchcount = 0; + ac = color4f; + at = texcoord2f; + av = vertex3f; + } + R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + map = ft2_oldstyle_map; + } + } + prevch = 0; + //num = (unsigned char) text[i]; + //thisw = fnt->width_of[num]; + thisw = fnt->width_of[ch]; + // FIXME make these smaller to just include the occupied part of the character for slightly faster rendering + if (r_nearest_conchars.integer) + { + s = (ch & 15)*0.0625f; + t = (ch >> 4)*0.0625f; + u = 0.0625f * thisw; + v = 0.0625f; + } + else + { + s = (ch & 15)*0.0625f + (0.5f / tw); + t = (ch >> 4)*0.0625f + (0.5f / th); + u = 0.0625f * thisw - (1.0f / tw); + v = 0.0625f - (1.0f / th); + } + ac[ 0] = DrawQ_Color[0];ac[ 1] = DrawQ_Color[1];ac[ 2] = DrawQ_Color[2];ac[ 3] = DrawQ_Color[3]; + ac[ 4] = DrawQ_Color[0];ac[ 5] = DrawQ_Color[1];ac[ 6] = DrawQ_Color[2];ac[ 7] = DrawQ_Color[3]; + ac[ 8] = DrawQ_Color[0];ac[ 9] = DrawQ_Color[1];ac[10] = DrawQ_Color[2];ac[11] = DrawQ_Color[3]; + ac[12] = DrawQ_Color[0];ac[13] = DrawQ_Color[1];ac[14] = DrawQ_Color[2];ac[15] = DrawQ_Color[3]; + at[ 0] = s ; at[ 1] = t ; + at[ 2] = s+u ; at[ 3] = t ; + at[ 4] = s+u ; at[ 5] = t+v ; + at[ 6] = s ; at[ 7] = t+v ; + av[ 0] = x ; av[ 1] = y ; av[ 2] = 10; + av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10; + av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10; + av[ 9] = x ; av[10] = y+dh ; av[11] = 10; + ac += 16; + at += 8; + av += 12; + batchcount++; + if (batchcount >= QUADELEMENTS_MAXQUADS) + { + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + batchcount = 0; + ac = color4f; + at = texcoord2f; + av = vertex3f; + } + x += width_of[ch] * dw; + } else { + if (!map || map == ft2_oldstyle_map || ch < map->start || ch >= map->start + FONT_CHARS_PER_MAP) + { + // new charmap - need to render + if (batchcount) + { + // we need a different character map, render what we currently have: + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + batchcount = 0; + ac = color4f; + at = texcoord2f; + av = vertex3f; + } + // find the new map + map = FontMap_FindForChar(fontmap, ch); + if (!map) + { + if (!Font_LoadMapForIndex(ft2, map_index, ch, &map)) + { + shadow = -1; + break; + } + if (!map) + { + // this shouldn't happen + shadow = -1; + break; + } + } + R_SetupShader_Generic(map->pic->tex, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + } + + mapch = ch - map->start; + thisw = map->glyphs[mapch].advance_x; + + //x += ftbase_x; + y += ftbase_y; + if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky)) + { + x += kx * dw; + y += ky * dh; + } + else + kx = ky = 0; + ac[ 0] = DrawQ_Color[0]; ac[ 1] = DrawQ_Color[1]; ac[ 2] = DrawQ_Color[2]; ac[ 3] = DrawQ_Color[3]; + ac[ 4] = DrawQ_Color[0]; ac[ 5] = DrawQ_Color[1]; ac[ 6] = DrawQ_Color[2]; ac[ 7] = DrawQ_Color[3]; + ac[ 8] = DrawQ_Color[0]; ac[ 9] = DrawQ_Color[1]; ac[10] = DrawQ_Color[2]; ac[11] = DrawQ_Color[3]; + ac[12] = DrawQ_Color[0]; ac[13] = DrawQ_Color[1]; ac[14] = DrawQ_Color[2]; ac[15] = DrawQ_Color[3]; + at[0] = map->glyphs[mapch].txmin; at[1] = map->glyphs[mapch].tymin; + at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin; + at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax; + at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax; + av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10; + av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10; + av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10; + av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10; + //x -= ftbase_x; + y -= ftbase_y; + + x += thisw * dw; + ac += 16; + at += 8; + av += 12; + batchcount++; + if (batchcount >= QUADELEMENTS_MAXQUADS) + { + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + batchcount = 0; + ac = color4f; + at = texcoord2f; + av = vertex3f; + } + + //prevmap = map; + prevch = ch; + } +out: + if (shadow) + { + x -= 1.0/pix_x * r_textshadow.value; + y -= 1.0/pix_y * r_textshadow.value; + } + } + } + if (batchcount > 0) + { + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + } + + if (outcolor) + *outcolor = colorindex; + + // note: this relies on the proper text (not shadow) being drawn last + return x; +} + +float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt) +{ + return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt); +} + +float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) +{ + return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth); +} + +float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt) +{ + return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000); +} + +float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth) +{ + return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth); +} + +#if 0 +// not used +// no ^xrgb management +static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor) +{ + int color, numchars = 0; + char *outputend2c = output2c + maxoutchars - 2; + if (!outcolor || *outcolor == -1) + color = STRING_COLOR_DEFAULT; + else + color = *outcolor; + if (!maxreadchars) + maxreadchars = 1<<30; + textend = text + maxreadchars; + while (text != textend && *text) + { + if (*text == STRING_COLOR_TAG && !ignorecolorcodes && text + 1 != textend) + { + if (text[1] == STRING_COLOR_TAG) + text++; + else if (text[1] >= '0' && text[1] <= '9') + { + color = text[1] - '0'; + text += 2; + continue; + } + } + if (output2c >= outputend2c) + break; + *output2c++ = *text++; + *output2c++ = color; + numchars++; + } + output2c[0] = output2c[1] = 0; + if (outcolor) + *outcolor = color; + return numchars; +} +#endif + +void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags) +{ + float floats[36]; + + _DrawQ_SetupAndProcessDrawFlag(flags, pic, a1*a2*a3*a4); + if(!r_draw2d.integer && !r_draw2d_force) + return; + +// R_Mesh_ResetTextureState(); + if (pic) + { + if (width == 0) + width = pic->width; + if (height == 0) + height = pic->height; + R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1, (flags & (DRAWFLAGS_BLEND | DRAWFLAG_NOGAMMA)) ? false : true, true, false); + } + else + R_SetupShader_Generic_NoTexture((flags & (DRAWFLAGS_BLEND | DRAWFLAG_NOGAMMA)) ? false : true, true); + + floats[2] = floats[5] = floats[8] = floats[11] = 0; + floats[0] = floats[9] = x; + floats[1] = floats[4] = y; + floats[3] = floats[6] = x + width; + floats[7] = floats[10] = y + height; + floats[12] = s1;floats[13] = t1; + floats[14] = s2;floats[15] = t2; + floats[16] = s4;floats[17] = t4; + floats[18] = s3;floats[19] = t3; + floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1; + floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2; + floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4; + floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); +} + +void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags, qboolean hasalpha) +{ + _DrawQ_Setup(); + if(!r_draw2d.integer && !r_draw2d_force) + return; + DrawQ_ProcessDrawFlag(flags, hasalpha); + +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1, (flags & DRAWFLAGS_BLEND) ? false : true, true, false); + + R_Mesh_PrepareVertices_Generic_Arrays(mesh->num_vertices, mesh->data_vertex3f, mesh->data_color4f, mesh->data_texcoord2f); + R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, NULL, 0, mesh->data_element3s, NULL, 0); +} + +void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags) +{ + int num; + + _DrawQ_SetupAndProcessDrawFlag(flags, NULL, 1); + if(!r_draw2d.integer && !r_draw2d_force) + return; + + GL_Color(1,1,1,1); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: +#ifndef USE_GLES2 + CHECKGLERROR + qglBegin(GL_LINE_LOOP); + for (num = 0;num < mesh->num_vertices;num++) + { + if (mesh->data_color4f) + GL_Color(mesh->data_color4f[num*4+0], mesh->data_color4f[num*4+1], mesh->data_color4f[num*4+2], mesh->data_color4f[num*4+3]); + qglVertex2f(mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1]); + } + qglEnd(); + CHECKGLERROR +#endif + break; + case RENDERPATH_D3D9: + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + return; + } +} + +//[515]: this is old, delete +void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags) +{ + _DrawQ_SetupAndProcessDrawFlag(flags, NULL, alpha); + if(!r_draw2d.integer && !r_draw2d_force) + return; + + R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: +#ifndef USE_GLES2 + CHECKGLERROR + + //qglLineWidth(width);CHECKGLERROR + + GL_Color(r,g,b,alpha); + CHECKGLERROR + qglBegin(GL_LINES); + qglVertex2f(x1, y1); + qglVertex2f(x2, y2); + qglEnd(); + CHECKGLERROR +#endif + break; + case RENDERPATH_D3D9: + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + return; + } +} + +void DrawQ_Lines (float width, int numlines, int flags, qboolean hasalpha) +{ + _DrawQ_SetupAndProcessDrawFlag(flags, NULL, hasalpha ? 0.5f : 1.0f); + + if(!r_draw2d.integer && !r_draw2d_force) + return; + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + CHECKGLERROR + + R_SetupShader_Generic_NoTexture((flags & DRAWFLAGS_BLEND) ? false : true, true); + + //qglLineWidth(width);CHECKGLERROR + + CHECKGLERROR + qglDrawArrays(GL_LINES, 0, numlines*2); + CHECKGLERROR + break; + case RENDERPATH_D3D9: + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + return; + } +} + +void DrawQ_SetClipArea(float x, float y, float width, float height) +{ + int ix, iy, iw, ih; + _DrawQ_Setup(); + + // We have to convert the con coords into real coords + // OGL uses top to bottom + ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer)); + iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer)); + iw = (int)(0.5 + (x+width) * ((float)vid.width / vid_conwidth.integer)) - ix; + ih = (int)(0.5 + (y+height) * ((float) vid.height / vid_conheight.integer)) - iy; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_SOFT: + GL_Scissor(ix, vid.height - iy - ih, iw, ih); + break; + case RENDERPATH_D3D9: + GL_Scissor(ix, iy, iw, ih); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + + GL_ScissorTest(true); +} + +void DrawQ_ResetClipArea(void) +{ + _DrawQ_Setup(); + GL_ScissorTest(false); +} + +void DrawQ_Finish(void) +{ + r_refdef.draw2dstage = 0; +} + +void DrawQ_RecalcView(void) +{ + if(r_refdef.draw2dstage) + r_refdef.draw2dstage = -1; // next draw call will set viewport etc. again +} + +static float blendvertex3f[9] = {-5000, -5000, 10, 10000, -5000, 10, -5000, 10000, 10}; +void R_DrawGamma(void) +{ + float c[4]; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_GLES2: + if (vid_usinghwgamma || v_glslgamma.integer) + return; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + if (vid_usinghwgamma) + return; + break; + case RENDERPATH_GLES1: + case RENDERPATH_SOFT: + return; + } + // all the blends ignore depth +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(true, true); + GL_DepthMask(true); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(false); + + // interpretation of brightness and contrast: + // color range := brightness .. (brightness + contrast) + // i.e. "c *= contrast; c += brightness" + // plausible values for brightness thus range from -contrast to 1 + + // apply pre-brightness (subtractive brightness, for where contrast was >= 1) + if (vid.support.ext_blend_subtract) + { + if (v_color_enable.integer) + { + c[0] = -v_color_black_r.value / v_color_white_r.value; + c[1] = -v_color_black_g.value / v_color_white_g.value; + c[2] = -v_color_black_b.value / v_color_white_b.value; + } + else + c[0] = c[1] = c[2] = -v_brightness.value / v_contrast.value; + if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f) + { + // need SUBTRACTIVE blending to do this! + GL_BlendEquationSubtract(true); + GL_BlendFunc(GL_ONE, GL_ONE); + GL_Color(c[0], c[1], c[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + GL_BlendEquationSubtract(false); + } + } + + // apply contrast + if (v_color_enable.integer) + { + c[0] = v_color_white_r.value; + c[1] = v_color_white_g.value; + c[2] = v_color_white_b.value; + } + else + c[0] = c[1] = c[2] = v_contrast.value; + if (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f) + { + GL_BlendFunc(GL_DST_COLOR, GL_ONE); + while (c[0] >= 1.003f || c[1] >= 1.003f || c[2] >= 1.003f) + { + float cc[4]; + cc[0] = bound(0, c[0] - 1, 1); + cc[1] = bound(0, c[1] - 1, 1); + cc[2] = bound(0, c[2] - 1, 1); + GL_Color(cc[0], cc[1], cc[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + c[0] /= 1 + cc[0]; + c[1] /= 1 + cc[1]; + c[2] /= 1 + cc[2]; + } + } + if (c[0] <= 0.997f || c[1] <= 0.997f || c[2] <= 0.997f) + { + GL_BlendFunc(GL_DST_COLOR, GL_ZERO); + GL_Color(c[0], c[1], c[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + } + + // apply post-brightness (additive brightness, for where contrast was <= 1) + if (v_color_enable.integer) + { + c[0] = v_color_black_r.value; + c[1] = v_color_black_g.value; + c[2] = v_color_black_b.value; + } + else + c[0] = c[1] = c[2] = v_brightness.value; + if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f) + { + GL_BlendFunc(GL_ONE, GL_ONE); + GL_Color(c[0], c[1], c[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + } +} + diff --git a/app/jni/gl_rmain.c b/app/jni/gl_rmain.c new file mode 100644 index 0000000..5526949 --- /dev/null +++ b/app/jni/gl_rmain.c @@ -0,0 +1,12691 @@ +/* +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 "cl_dyntexture.h" +#include "r_shadow.h" +#include "polygon.h" +#include "image.h" +#include "ft2.h" +#include "csprogs.h" +#include "cl_video.h" +#include "dpsoftrast.h" + +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +#endif + +mempool_t *r_main_mempool; +rtexturepool_t *r_main_texturepool; + +static int r_textureframe = 0; ///< used only by R_GetCurrentTexture + +static qboolean r_loadnormalmap; +static qboolean r_loadgloss; +qboolean r_loadfog; +static qboolean r_loaddds; +static qboolean r_savedds; +static qboolean r_gpuskeletal; + +cvar_t r_worldscale = {CVAR_SAVE, "r_worldscale", "40.0", "World scale multiplier (default is 40)"}; + +float GetStereoSeparation() +{ + return r_worldscale.value * 0.065; +} + + +//Define the stereo side we are drawing +int r_stereo_side; + +// +// screen size info +// +r_refdef_t r_refdef; + +cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; +cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; +cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"}; +cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"}; +cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"}; +cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"}; +cvar_t r_motionblur_velocityfactor = {CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"}; +cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"}; +cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"}; +cvar_t r_motionblur_mousefactor = {CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"}; +cvar_t r_motionblur_mousefactor_minspeed = {CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"}; +cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"}; + +// TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat? +cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light"}; +cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio"}; +cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression)"}; +cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level"}; + +cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"}; +cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"}; +cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"}; +cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"}; +cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" }; +cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"}; +cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"}; +cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"}; +cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"}; +cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"}; +cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"}; +cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; +cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"}; +cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"}; +cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"}; +cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"}; +cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"}; +cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"}; +cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"}; +cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"}; +cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"}; +cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"}; +cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"}; +cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"}; +cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"}; +cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"}; +cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"}; +cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"}; +cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"}; +cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"}; +cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"}; +cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"}; +cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"}; +cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"}; +cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"}; + +cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps"}; +cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier"}; +#define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit)) + +cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"}; +cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"}; +cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"}; +cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."}; +cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"}; +cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"}; +cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"}; +cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."}; +cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"}; +cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"}; +cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "1", "increases shadowmap quality (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."}; +cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."}; +cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"}; +cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; +cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};//changed default 14 to 0 to fix Tegra Z-buffer depth +cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"}; +cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"}; +cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"}; +cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"}; +cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"}; +cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"}; +cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "1", "lower distance limit for transparent sorting"}; +cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"}; +cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"}; +cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9 +cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9 + +cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"}; +cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"}; +cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"}; +cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"}; +cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"}; +cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"}; +cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"}; +cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"}; + +cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"}; +cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"}; + +cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"}; +static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"}; +static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"}; + +cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"}; +cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"}; +cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"}; +cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"}; +cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"}; +cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"}; +cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"}; +cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"}; +cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"}; + +cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"}; +cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"}; +cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"}; +cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"}; +cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"}; +cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"}; +cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"}; +cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"}; +cvar_t r_glsl_offsetmapping_lod = {CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"}; +cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."}; +cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"}; +cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; +cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; + +cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"}; +cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"}; +cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"}; +cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"}; +cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"}; +cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"}; +cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"}; +cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"}; +cvar_t r_water_fbo = {CVAR_SAVE, "r_water_fbo", "1", "enables use of render to texture for water effects, otherwise copy to texture is used (slower)"}; + +cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"}; +cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"}; +cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"}; +cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"}; + +cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"}; +cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"}; + +cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"}; +cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"}; +cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"}; +cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"}; +cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"}; +cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"}; + +cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"}; +cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"}; +cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"}; +cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"}; +cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"}; +cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"}; +cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"}; +cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"}; +cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"}; +cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"}; + +cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"}; + +cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"}; + +cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"}; + +cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; + +cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"}; +cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"}; +cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"}; +cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"}; + +cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"}; +cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"}; + +cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."}; + +cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"}; +cvar_t r_buffermegs[R_BUFFERDATA_COUNT] = +{ + {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"}, + {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"}, + {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"}, + {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"}, +}; + +extern cvar_t v_glslgamma; +extern cvar_t v_glslgamma_2d; + +extern qboolean v_flipped_state; + +r_framebufferstate_t r_fb; + +/// shadow volume bsp struct with automatically growing nodes buffer +svbsp_t r_svbsp; + +int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT + +rtexture_t *r_texture_blanknormalmap; +rtexture_t *r_texture_white; +rtexture_t *r_texture_grey128; +rtexture_t *r_texture_black; +rtexture_t *r_texture_notexture; +rtexture_t *r_texture_whitecube; +rtexture_t *r_texture_normalizationcube; +rtexture_t *r_texture_fogattenuation; +rtexture_t *r_texture_fogheighttexture; +rtexture_t *r_texture_gammaramps; +unsigned int r_texture_gammaramps_serial; +//rtexture_t *r_texture_fogintensity; +rtexture_t *r_texture_reflectcube; + +// TODO: hash lookups? +typedef struct cubemapinfo_s +{ + char basename[64]; + rtexture_t *texture; +} +cubemapinfo_t; + +int r_texture_numcubemaps; +cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS]; + +unsigned int r_queries[MAX_OCCLUSION_QUERIES]; +unsigned int r_numqueries; +unsigned int r_maxqueries; + +typedef struct r_qwskincache_s +{ + char name[MAX_QPATH]; + skinframe_t *skinframe; +} +r_qwskincache_t; + +static r_qwskincache_t *r_qwskincache; +static int r_qwskincache_size; + +/// vertex coordinates for a quad that covers the screen exactly +extern const float r_screenvertex3f[12]; +extern const float r_d3dscreenvertex3f[12]; +const float r_screenvertex3f[12] = +{ + 0, 0, 0, + 1, 0, 0, + 1, 1, 0, + 0, 1, 0 +}; +const float r_d3dscreenvertex3f[12] = +{ + 0, 1, 0, + 1, 1, 0, + 1, 0, 0, + 0, 0, 0 +}; + +void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) +{ + int i; + for (i = 0;i < verts;i++) + { + out[0] = in[0] * r; + out[1] = in[1] * g; + out[2] = in[2] * b; + out[3] = in[3]; + in += 4; + out += 4; + } +} + +void R_FillColors(float *out, int verts, float r, float g, float b, float a) +{ + int i; + for (i = 0;i < verts;i++) + { + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = a; + out += 4; + } +} + +// FIXME: move this to client? +void FOG_clear(void) +{ + if (gamemode == GAME_NEHAHRA) + { + Cvar_Set("gl_fogenable", "0"); + Cvar_Set("gl_fogdensity", "0.2"); + Cvar_Set("gl_fogred", "0.3"); + Cvar_Set("gl_foggreen", "0.3"); + Cvar_Set("gl_fogblue", "0.3"); + } + r_refdef.fog_density = 0; + r_refdef.fog_red = 0; + r_refdef.fog_green = 0; + r_refdef.fog_blue = 0; + r_refdef.fog_alpha = 1; + r_refdef.fog_start = 0; + r_refdef.fog_end = 16384; + r_refdef.fog_height = 1<<30; + r_refdef.fog_fadedepth = 128; + memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename)); +} + +static void R_BuildBlankTextures(void) +{ + unsigned char data[4]; + data[2] = 128; // normal X + data[1] = 128; // normal Y + data[0] = 255; // normal Z + data[3] = 255; // height + r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL); + data[0] = 255; + data[1] = 255; + data[2] = 255; + data[3] = 255; + r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL); + data[0] = 128; + data[1] = 128; + data[2] = 128; + data[3] = 255; + r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL); + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 255; + r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL); +} + +static void R_BuildNoTexture(void) +{ + int x, y; + unsigned char pix[16][16][4]; + // this makes a light grey/dark grey checkerboard texture + for (y = 0;y < 16;y++) + { + for (x = 0;x < 16;x++) + { + if ((y < 8) ^ (x < 8)) + { + pix[y][x][0] = 128; + pix[y][x][1] = 128; + pix[y][x][2] = 128; + pix[y][x][3] = 255; + } + else + { + pix[y][x][0] = 64; + pix[y][x][1] = 64; + pix[y][x][2] = 64; + pix[y][x][3] = 255; + } + } + } + r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL); +} + +static void R_BuildWhiteCube(void) +{ + unsigned char data[6*1*1*4]; + memset(data, 255, sizeof(data)); + r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL); +} + +static void R_BuildNormalizationCube(void) +{ + int x, y, side; + vec3_t v; + vec_t s, t, intensity; +#define NORMSIZE 64 + unsigned char *data; + data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4); + for (side = 0;side < 6;side++) + { + for (y = 0;y < NORMSIZE;y++) + { + for (x = 0;x < NORMSIZE;x++) + { + s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f; + t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f; + switch(side) + { + default: + case 0: + v[0] = 1; + v[1] = -t; + v[2] = -s; + break; + case 1: + v[0] = -1; + v[1] = -t; + v[2] = s; + break; + case 2: + v[0] = s; + v[1] = 1; + v[2] = t; + break; + case 3: + v[0] = s; + v[1] = -1; + v[2] = -t; + break; + case 4: + v[0] = s; + v[1] = -t; + v[2] = 1; + break; + case 5: + v[0] = -s; + v[1] = -t; + v[2] = -1; + break; + } + intensity = 127.0f / sqrt(DotProduct(v, v)); + data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]); + data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]); + data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]); + data[((side*64+y)*64+x)*4+3] = 255; + } + } + } + r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL); + Mem_Free(data); +} + +static void R_BuildFogTexture(void) +{ + int x, b; +#define FOGWIDTH 256 + unsigned char data1[FOGWIDTH][4]; + //unsigned char data2[FOGWIDTH][4]; + double d, r, alpha; + + r_refdef.fogmasktable_start = r_refdef.fog_start; + r_refdef.fogmasktable_alpha = r_refdef.fog_alpha; + r_refdef.fogmasktable_range = r_refdef.fogrange; + r_refdef.fogmasktable_density = r_refdef.fog_density; + + r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH; + for (x = 0;x < FOGMASKTABLEWIDTH;x++) + { + d = (x * r - r_refdef.fogmasktable_start); + if(developer_extra.integer) + Con_DPrintf("%f ", d); + d = max(0, d); + if (r_fog_exp2.integer) + alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d); + else + alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d); + if(developer_extra.integer) + Con_DPrintf(" : %f ", alpha); + alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha; + if(developer_extra.integer) + Con_DPrintf(" = %f\n", alpha); + r_refdef.fogmasktable[x] = bound(0, alpha, 1); + } + + for (x = 0;x < FOGWIDTH;x++) + { + b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255); + data1[x][0] = b; + data1[x][1] = b; + data1[x][2] = b; + data1[x][3] = 255; + //data2[x][0] = 255 - b; + //data2[x][1] = 255 - b; + //data2[x][2] = 255 - b; + //data2[x][3] = 255; + } + if (r_texture_fogattenuation) + { + R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1); + //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1); + } + else + { + r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL); + //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL); + } +} + +static void R_BuildFogHeightTexture(void) +{ + unsigned char *inpixels; + int size; + int x; + int y; + int j; + float c[4]; + float f; + inpixels = NULL; + strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename)); + if (r_refdef.fogheighttexturename[0]) + inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL); + if (!inpixels) + { + r_refdef.fog_height_tablesize = 0; + if (r_texture_fogheighttexture) + R_FreeTexture(r_texture_fogheighttexture); + r_texture_fogheighttexture = NULL; + if (r_refdef.fog_height_table2d) + Mem_Free(r_refdef.fog_height_table2d); + r_refdef.fog_height_table2d = NULL; + if (r_refdef.fog_height_table1d) + Mem_Free(r_refdef.fog_height_table1d); + r_refdef.fog_height_table1d = NULL; + return; + } + size = image_width; + r_refdef.fog_height_tablesize = size; + r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4); + r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4); + memcpy(r_refdef.fog_height_table1d, inpixels, size * 4); + Mem_Free(inpixels); + // LordHavoc: now the magic - what is that table2d for? it is a cooked + // average fog color table accounting for every fog layer between a point + // and the camera. (Note: attenuation is handled separately!) + for (y = 0;y < size;y++) + { + for (x = 0;x < size;x++) + { + Vector4Clear(c); + f = 0; + if (x < y) + { + for (j = x;j <= y;j++) + { + Vector4Add(c, r_refdef.fog_height_table1d + j*4, c); + f++; + } + } + else + { + for (j = x;j >= y;j--) + { + Vector4Add(c, r_refdef.fog_height_table1d + j*4, c); + f++; + } + } + f = 1.0f / f; + r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f); + r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f); + r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f); + r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f); + } + } + r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL); +} + +//======================================================================================================================================================= + +static const char *builtinshaderstrings[] = +{ +#include "shader_glsl.h" +0 +}; + +const char *builtinhlslshaderstrings[] = +{ +#include "shader_hlsl.h" +0 +}; + +char *glslshaderstring = NULL; +char *hlslshaderstring = NULL; + +//======================================================================================================================================================= + +typedef struct shaderpermutationinfo_s +{ + const char *pretext; + const char *name; +} +shaderpermutationinfo_t; + +typedef struct shadermodeinfo_s +{ + const char *filename; + const char *pretext; + const char *name; +} +shadermodeinfo_t; + +// NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES! +shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = +{ + {"#define USEDIFFUSE\n", " diffuse"}, + {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"}, + {"#define USEVIEWTINT\n", " viewtint"}, + {"#define USECOLORMAPPING\n", " colormapping"}, + {"#define USESATURATION\n", " saturation"}, + {"#define USEFOGINSIDE\n", " foginside"}, + {"#define USEFOGOUTSIDE\n", " fogoutside"}, + {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"}, + {"#define USEFOGALPHAHACK\n", " fogalphahack"}, + {"#define USEGAMMARAMPS\n", " gammaramps"}, + {"#define USECUBEFILTER\n", " cubefilter"}, + {"#define USEGLOW\n", " glow"}, + {"#define USEBLOOM\n", " bloom"}, + {"#define USESPECULAR\n", " specular"}, + {"#define USEPOSTPROCESSING\n", " postprocessing"}, + {"#define USEREFLECTION\n", " reflection"}, + {"#define USEOFFSETMAPPING\n", " offsetmapping"}, + {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"}, + {"#define USESHADOWMAP2D\n", " shadowmap2d"}, + {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm + {"#define USESHADOWMAPORTHO\n", " shadowmaportho"}, + {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"}, + {"#define USEALPHAKILL\n", " alphakill"}, + {"#define USEREFLECTCUBE\n", " reflectcube"}, + {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"}, + {"#define USEBOUNCEGRID\n", " bouncegrid"}, + {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm + {"#define USETRIPPY\n", " trippy"}, + {"#define USEDEPTHRGB\n", " depthrgb"}, + {"#define USEALPHAGENVERTEX\n", " alphagenvertex"}, + {"#define USESKELETAL\n", " skeletal"} +}; + +// NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS! +shadermodeinfo_t glslshadermodeinfo[SHADERMODE_COUNT] = +{ + {"glsl/default.glsl", "#define MODE_GENERIC\n", " generic"}, + {"glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"}, + {"glsl/default.glsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, + {"glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, + {"glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, + {"glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"}, + {"glsl/default.glsl", "#define MODE_FAKELIGHT\n", " fakelight"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, + {"glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, + {"glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, + {"glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"}, + {"glsl/default.glsl", "#define MODE_WATER\n", " water"}, + {"glsl/default.glsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, + {"glsl/default.glsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, +}; + +shadermodeinfo_t hlslshadermodeinfo[SHADERMODE_COUNT] = +{ + {"hlsl/default.hlsl", "#define MODE_GENERIC\n", " generic"}, + {"hlsl/default.hlsl", "#define MODE_POSTPROCESS\n", " postprocess"}, + {"hlsl/default.hlsl", "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"}, + {"hlsl/default.hlsl", "#define MODE_FLATCOLOR\n", " flatcolor"}, + {"hlsl/default.hlsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTMAP\n", " lightmap"}, + {"hlsl/default.hlsl", "#define MODE_FAKELIGHT\n", " fakelight"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"}, + {"hlsl/default.hlsl", "#define MODE_LIGHTSOURCE\n", " lightsource"}, + {"hlsl/default.hlsl", "#define MODE_REFRACTION\n", " refraction"}, + {"hlsl/default.hlsl", "#define MODE_WATER\n", " water"}, + {"hlsl/default.hlsl", "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"}, + {"hlsl/default.hlsl", "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"}, +}; + +struct r_glsl_permutation_s; +typedef struct r_glsl_permutation_s +{ + /// hash lookup data + struct r_glsl_permutation_s *hashnext; + unsigned int mode; + unsigned int permutation; + + /// indicates if we have tried compiling this permutation already + qboolean compiled; + /// 0 if compilation failed + int program; + // texture units assigned to each detected uniform + int tex_Texture_First; + int tex_Texture_Second; + int tex_Texture_GammaRamps; + int tex_Texture_Normal; + int tex_Texture_Color; + int tex_Texture_Gloss; + int tex_Texture_Glow; + int tex_Texture_SecondaryNormal; + int tex_Texture_SecondaryColor; + int tex_Texture_SecondaryGloss; + int tex_Texture_SecondaryGlow; + int tex_Texture_Pants; + int tex_Texture_Shirt; + int tex_Texture_FogHeightTexture; + int tex_Texture_FogMask; + int tex_Texture_Lightmap; + int tex_Texture_Deluxemap; + int tex_Texture_Attenuation; + int tex_Texture_Cube; + int tex_Texture_Refraction; + int tex_Texture_Reflection; + int tex_Texture_ShadowMap2D; + int tex_Texture_CubeProjection; + int tex_Texture_ScreenNormalMap; + int tex_Texture_ScreenDiffuse; + int tex_Texture_ScreenSpecular; + int tex_Texture_ReflectMask; + int tex_Texture_ReflectCube; + int tex_Texture_BounceGrid; + /// locations of detected uniforms in program object, or -1 if not found + int loc_Texture_First; + int loc_Texture_Second; + int loc_Texture_GammaRamps; + int loc_Texture_Normal; + int loc_Texture_Color; + int loc_Texture_Gloss; + int loc_Texture_Glow; + int loc_Texture_SecondaryNormal; + int loc_Texture_SecondaryColor; + int loc_Texture_SecondaryGloss; + int loc_Texture_SecondaryGlow; + int loc_Texture_Pants; + int loc_Texture_Shirt; + int loc_Texture_FogHeightTexture; + int loc_Texture_FogMask; + int loc_Texture_Lightmap; + int loc_Texture_Deluxemap; + int loc_Texture_Attenuation; + int loc_Texture_Cube; + int loc_Texture_Refraction; + int loc_Texture_Reflection; + int loc_Texture_ShadowMap2D; + int loc_Texture_CubeProjection; + int loc_Texture_ScreenNormalMap; + int loc_Texture_ScreenDiffuse; + int loc_Texture_ScreenSpecular; + int loc_Texture_ReflectMask; + int loc_Texture_ReflectCube; + int loc_Texture_BounceGrid; + int loc_Alpha; + int loc_BloomBlur_Parameters; + int loc_ClientTime; + int loc_Color_Ambient; + int loc_Color_Diffuse; + int loc_Color_Specular; + int loc_Color_Glow; + int loc_Color_Pants; + int loc_Color_Shirt; + int loc_DeferredColor_Ambient; + int loc_DeferredColor_Diffuse; + int loc_DeferredColor_Specular; + int loc_DeferredMod_Diffuse; + int loc_DeferredMod_Specular; + int loc_DistortScaleRefractReflect; + int loc_EyePosition; + int loc_FogColor; + int loc_FogHeightFade; + int loc_FogPlane; + int loc_FogPlaneViewDist; + int loc_FogRangeRecip; + int loc_LightColor; + int loc_LightDir; + int loc_LightPosition; + int loc_OffsetMapping_ScaleSteps; + int loc_OffsetMapping_LodDistance; + int loc_OffsetMapping_Bias; + int loc_PixelSize; + int loc_ReflectColor; + int loc_ReflectFactor; + int loc_ReflectOffset; + int loc_RefractColor; + int loc_Saturation; + int loc_ScreenCenterRefractReflect; + int loc_ScreenScaleRefractReflect; + int loc_ScreenToDepth; + int loc_ShadowMap_Parameters; + int loc_ShadowMap_TextureScale; + int loc_SpecularPower; + int loc_Skeletal_Transform12; + int loc_UserVec1; + int loc_UserVec2; + int loc_UserVec3; + int loc_UserVec4; + int loc_ViewTintColor; + int loc_ViewToLight; + int loc_ModelToLight; + int loc_TexMatrix; + int loc_BackgroundTexMatrix; + int loc_ModelViewProjectionMatrix; + int loc_ModelViewMatrix; + int loc_PixelToScreenTexCoord; + int loc_ModelToReflectCube; + int loc_ShadowMapMatrix; + int loc_BloomColorSubtract; + int loc_NormalmapScrollBlend; + int loc_BounceGridMatrix; + int loc_BounceGridIntensity; + /// uniform block bindings + int ubibind_Skeletal_Transform12_UniformBlock; + /// uniform block indices + int ubiloc_Skeletal_Transform12_UniformBlock; +} +r_glsl_permutation_t; + +#define SHADERPERMUTATION_HASHSIZE 256 + + +// non-degradable "lightweight" shader parameters to keep the permutations simpler +// these can NOT degrade! only use for simple stuff +enum +{ + SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation + SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation + SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled + SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled + SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled + SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled + SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending + SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping + SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1 + SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2 + SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler + SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math) + SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines) +}; +#define SHADERSTATICPARMS_COUNT 13 + +static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT]; +static int shaderstaticparms_count = 0; + +static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0}; +#define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F)) + +extern qboolean r_shadow_shadowmapsampler; +extern int r_shadow_shadowmappcf; +qboolean R_CompileShader_CheckStaticParms(void) +{ + static int r_compileshader_staticparms_save[1]; + memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms)); + memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms)); + + // detect all + if (r_glsl_saturation_redcompensate.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE); + if (r_glsl_vertextextureblend_usebothalphas.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS); + if (r_shadow_glossexact.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH); + if (r_glsl_postprocess.integer) + { + if (r_glsl_postprocess_uservec1_enable.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1); + if (r_glsl_postprocess_uservec2_enable.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2); + if (r_glsl_postprocess_uservec3_enable.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3); + if (r_glsl_postprocess_uservec4_enable.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4); + } + if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD); + + if (r_shadow_shadowmapsampler) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER); + if (r_shadow_shadowmappcf > 1) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2); + else if (r_shadow_shadowmappcf) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1); + if (r_celshading.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING); + if (r_celoutlines.integer) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES); + + return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0; +} + +#define R_COMPILESHADER_STATICPARM_EMIT(p, n) \ + if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \ + shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \ + else \ + shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n" +static void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation) +{ + shaderstaticparms_count = 0; + + // emit all + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES"); +} + +/// information about each possible shader permutation +r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE]; +/// currently selected permutation +r_glsl_permutation_t *r_glsl_permutation; +/// storage for permutations linked in the hash table +memexpandablearray_t r_glsl_permutationarray; + +static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, unsigned int permutation) +{ + //unsigned int hashdepth = 0; + unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1); + r_glsl_permutation_t *p; + for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext) + { + if (p->mode == mode && p->permutation == permutation) + { + //if (hashdepth > 10) + // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth); + return p; + } + //hashdepth++; + } + p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray); + p->mode = mode; + p->permutation = permutation; + p->hashnext = r_glsl_permutationhash[mode][hashindex]; + r_glsl_permutationhash[mode][hashindex] = p; + //if (hashdepth > 10) + // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth); + return p; +} + +static char *R_ShaderStrCat(const char **strings) +{ + char *string, *s; + const char **p = strings; + const char *t; + size_t len = 0; + for (p = strings;(t = *p);p++) + len += strlen(t); + len++; + s = string = (char *)Mem_Alloc(r_main_mempool, len); + len = 0; + for (p = strings;(t = *p);p++) + { + len = strlen(t); + memcpy(s, t, len); + s += len; + } + *s = 0; + return string; +} + +static char *R_GetShaderText(const char *filename, qboolean printfromdisknotice, qboolean builtinonly) +{ + char *shaderstring; + if (!filename || !filename[0]) + return NULL; + // LordHavoc: note that FS_LoadFile appends a 0 byte to make it a valid string, so does R_ShaderStrCat + if (!strcmp(filename, "glsl/default.glsl")) + { + if (builtinonly) + return R_ShaderStrCat(builtinshaderstrings); + if (!glslshaderstring) + { + glslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); + if (glslshaderstring) + Con_DPrintf("Loading shaders from file %s...\n", filename); + else + glslshaderstring = R_ShaderStrCat(builtinshaderstrings); + } + shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(glslshaderstring) + 1); + memcpy(shaderstring, glslshaderstring, strlen(glslshaderstring) + 1); + return shaderstring; + } + if (!strcmp(filename, "hlsl/default.hlsl")) + { + if (builtinonly) + return R_ShaderStrCat(builtinhlslshaderstrings); + if (!hlslshaderstring) + { + hlslshaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); + if (hlslshaderstring) + Con_DPrintf("Loading shaders from file %s...\n", filename); + else + hlslshaderstring = R_ShaderStrCat(builtinhlslshaderstrings); + } + shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(hlslshaderstring) + 1); + memcpy(shaderstring, hlslshaderstring, strlen(hlslshaderstring) + 1); + return shaderstring; + } + // we don't have builtin strings for any other files + if (builtinonly) + return NULL; + shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL); + if (shaderstring) + { + if (printfromdisknotice) + Con_DPrintf("from disk %s... ", filename); + return shaderstring; + } + return shaderstring; +} + +static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation) +{ + int i; + int ubibind; + int sampler; + shadermodeinfo_t *modeinfo = glslshadermodeinfo + mode; + char *sourcestring; + char permutationname[256]; + int vertstrings_count = 0; + int geomstrings_count = 0; + int fragstrings_count = 0; + const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + + if (p->compiled) + return; + p->compiled = true; + p->program = 0; + + permutationname[0] = 0; + sourcestring = R_GetShaderText(modeinfo->filename, true, false); + + strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); + + // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object) + if(vid.support.glshaderversion >= 140) + { + vertstrings_list[vertstrings_count++] = "#version 140\n"; + geomstrings_list[geomstrings_count++] = "#version 140\n"; + fragstrings_list[fragstrings_count++] = "#version 140\n"; + vertstrings_list[vertstrings_count++] = "#define GLSL140\n"; + geomstrings_list[geomstrings_count++] = "#define GLSL140\n"; + fragstrings_list[fragstrings_count++] = "#define GLSL140\n"; + } + // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad) + else if(vid.support.glshaderversion >= 130) + { + vertstrings_list[vertstrings_count++] = "#version 130\n"; + geomstrings_list[geomstrings_count++] = "#version 130\n"; + fragstrings_list[fragstrings_count++] = "#version 130\n"; + vertstrings_list[vertstrings_count++] = "#define GLSL130\n"; + geomstrings_list[geomstrings_count++] = "#define GLSL130\n"; + fragstrings_list[fragstrings_count++] = "#define GLSL130\n"; + } + + // the first pretext is which type of shader to compile as + // (later these will all be bound together as a program object) + vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n"; + geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n"; + fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n"; + + // the second pretext is the mode (for example a light source) + vertstrings_list[vertstrings_count++] = modeinfo->pretext; + geomstrings_list[geomstrings_count++] = modeinfo->pretext; + fragstrings_list[fragstrings_count++] = modeinfo->pretext; + strlcat(permutationname, modeinfo->name, sizeof(permutationname)); + + // now add all the permutation pretexts + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + { + if (permutation & (1<program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list); + if (p->program) + { + CHECKGLERROR + qglUseProgram(p->program);CHECKGLERROR + // look up all the uniform variable names we care about, so we don't + // have to look them up every time we set them + + p->loc_Texture_First = qglGetUniformLocation(p->program, "Texture_First"); + p->loc_Texture_Second = qglGetUniformLocation(p->program, "Texture_Second"); + p->loc_Texture_GammaRamps = qglGetUniformLocation(p->program, "Texture_GammaRamps"); + p->loc_Texture_Normal = qglGetUniformLocation(p->program, "Texture_Normal"); + p->loc_Texture_Color = qglGetUniformLocation(p->program, "Texture_Color"); + p->loc_Texture_Gloss = qglGetUniformLocation(p->program, "Texture_Gloss"); + p->loc_Texture_Glow = qglGetUniformLocation(p->program, "Texture_Glow"); + p->loc_Texture_SecondaryNormal = qglGetUniformLocation(p->program, "Texture_SecondaryNormal"); + p->loc_Texture_SecondaryColor = qglGetUniformLocation(p->program, "Texture_SecondaryColor"); + p->loc_Texture_SecondaryGloss = qglGetUniformLocation(p->program, "Texture_SecondaryGloss"); + p->loc_Texture_SecondaryGlow = qglGetUniformLocation(p->program, "Texture_SecondaryGlow"); + p->loc_Texture_Pants = qglGetUniformLocation(p->program, "Texture_Pants"); + p->loc_Texture_Shirt = qglGetUniformLocation(p->program, "Texture_Shirt"); + p->loc_Texture_FogHeightTexture = qglGetUniformLocation(p->program, "Texture_FogHeightTexture"); + p->loc_Texture_FogMask = qglGetUniformLocation(p->program, "Texture_FogMask"); + p->loc_Texture_Lightmap = qglGetUniformLocation(p->program, "Texture_Lightmap"); + p->loc_Texture_Deluxemap = qglGetUniformLocation(p->program, "Texture_Deluxemap"); + p->loc_Texture_Attenuation = qglGetUniformLocation(p->program, "Texture_Attenuation"); + p->loc_Texture_Cube = qglGetUniformLocation(p->program, "Texture_Cube"); + p->loc_Texture_Refraction = qglGetUniformLocation(p->program, "Texture_Refraction"); + p->loc_Texture_Reflection = qglGetUniformLocation(p->program, "Texture_Reflection"); + p->loc_Texture_ShadowMap2D = qglGetUniformLocation(p->program, "Texture_ShadowMap2D"); + p->loc_Texture_CubeProjection = qglGetUniformLocation(p->program, "Texture_CubeProjection"); + p->loc_Texture_ScreenNormalMap = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap"); + p->loc_Texture_ScreenDiffuse = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse"); + p->loc_Texture_ScreenSpecular = qglGetUniformLocation(p->program, "Texture_ScreenSpecular"); + p->loc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask"); + p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube"); + p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid"); + p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha"); + p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters"); + p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime"); + p->loc_Color_Ambient = qglGetUniformLocation(p->program, "Color_Ambient"); + p->loc_Color_Diffuse = qglGetUniformLocation(p->program, "Color_Diffuse"); + p->loc_Color_Specular = qglGetUniformLocation(p->program, "Color_Specular"); + p->loc_Color_Glow = qglGetUniformLocation(p->program, "Color_Glow"); + p->loc_Color_Pants = qglGetUniformLocation(p->program, "Color_Pants"); + p->loc_Color_Shirt = qglGetUniformLocation(p->program, "Color_Shirt"); + p->loc_DeferredColor_Ambient = qglGetUniformLocation(p->program, "DeferredColor_Ambient"); + p->loc_DeferredColor_Diffuse = qglGetUniformLocation(p->program, "DeferredColor_Diffuse"); + p->loc_DeferredColor_Specular = qglGetUniformLocation(p->program, "DeferredColor_Specular"); + p->loc_DeferredMod_Diffuse = qglGetUniformLocation(p->program, "DeferredMod_Diffuse"); + p->loc_DeferredMod_Specular = qglGetUniformLocation(p->program, "DeferredMod_Specular"); + p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect"); + p->loc_EyePosition = qglGetUniformLocation(p->program, "EyePosition"); + p->loc_FogColor = qglGetUniformLocation(p->program, "FogColor"); + p->loc_FogHeightFade = qglGetUniformLocation(p->program, "FogHeightFade"); + p->loc_FogPlane = qglGetUniformLocation(p->program, "FogPlane"); + p->loc_FogPlaneViewDist = qglGetUniformLocation(p->program, "FogPlaneViewDist"); + p->loc_FogRangeRecip = qglGetUniformLocation(p->program, "FogRangeRecip"); + p->loc_LightColor = qglGetUniformLocation(p->program, "LightColor"); + p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir"); + p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition"); + p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps"); + p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance"); + p->loc_OffsetMapping_Bias = qglGetUniformLocation(p->program, "OffsetMapping_Bias"); + p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize"); + p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor"); + p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor"); + p->loc_ReflectOffset = qglGetUniformLocation(p->program, "ReflectOffset"); + p->loc_RefractColor = qglGetUniformLocation(p->program, "RefractColor"); + p->loc_Saturation = qglGetUniformLocation(p->program, "Saturation"); + p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect"); + p->loc_ScreenScaleRefractReflect = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect"); + p->loc_ScreenToDepth = qglGetUniformLocation(p->program, "ScreenToDepth"); + p->loc_ShadowMap_Parameters = qglGetUniformLocation(p->program, "ShadowMap_Parameters"); + p->loc_ShadowMap_TextureScale = qglGetUniformLocation(p->program, "ShadowMap_TextureScale"); + p->loc_SpecularPower = qglGetUniformLocation(p->program, "SpecularPower"); + p->loc_UserVec1 = qglGetUniformLocation(p->program, "UserVec1"); + p->loc_UserVec2 = qglGetUniformLocation(p->program, "UserVec2"); + p->loc_UserVec3 = qglGetUniformLocation(p->program, "UserVec3"); + p->loc_UserVec4 = qglGetUniformLocation(p->program, "UserVec4"); + p->loc_ViewTintColor = qglGetUniformLocation(p->program, "ViewTintColor"); + p->loc_ViewToLight = qglGetUniformLocation(p->program, "ViewToLight"); + p->loc_ModelToLight = qglGetUniformLocation(p->program, "ModelToLight"); + p->loc_TexMatrix = qglGetUniformLocation(p->program, "TexMatrix"); + p->loc_BackgroundTexMatrix = qglGetUniformLocation(p->program, "BackgroundTexMatrix"); + p->loc_ModelViewMatrix = qglGetUniformLocation(p->program, "ModelViewMatrix"); + p->loc_ModelViewProjectionMatrix = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix"); + p->loc_PixelToScreenTexCoord = qglGetUniformLocation(p->program, "PixelToScreenTexCoord"); + p->loc_ModelToReflectCube = qglGetUniformLocation(p->program, "ModelToReflectCube"); + p->loc_ShadowMapMatrix = qglGetUniformLocation(p->program, "ShadowMapMatrix"); + p->loc_BloomColorSubtract = qglGetUniformLocation(p->program, "BloomColorSubtract"); + p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend"); + p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix"); + p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity"); + // initialize the samplers to refer to the texture units we use + p->tex_Texture_First = -1; + p->tex_Texture_Second = -1; + p->tex_Texture_GammaRamps = -1; + p->tex_Texture_Normal = -1; + p->tex_Texture_Color = -1; + p->tex_Texture_Gloss = -1; + p->tex_Texture_Glow = -1; + p->tex_Texture_SecondaryNormal = -1; + p->tex_Texture_SecondaryColor = -1; + p->tex_Texture_SecondaryGloss = -1; + p->tex_Texture_SecondaryGlow = -1; + p->tex_Texture_Pants = -1; + p->tex_Texture_Shirt = -1; + p->tex_Texture_FogHeightTexture = -1; + p->tex_Texture_FogMask = -1; + p->tex_Texture_Lightmap = -1; + p->tex_Texture_Deluxemap = -1; + p->tex_Texture_Attenuation = -1; + p->tex_Texture_Cube = -1; + p->tex_Texture_Refraction = -1; + p->tex_Texture_Reflection = -1; + p->tex_Texture_ShadowMap2D = -1; + p->tex_Texture_CubeProjection = -1; + p->tex_Texture_ScreenNormalMap = -1; + p->tex_Texture_ScreenDiffuse = -1; + p->tex_Texture_ScreenSpecular = -1; + p->tex_Texture_ReflectMask = -1; + p->tex_Texture_ReflectCube = -1; + p->tex_Texture_BounceGrid = -1; + // bind the texture samplers in use + sampler = 0; + if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;} + if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;} + if (p->loc_Texture_GammaRamps >= 0) {p->tex_Texture_GammaRamps = sampler;qglUniform1i(p->loc_Texture_GammaRamps , sampler);sampler++;} + if (p->loc_Texture_Normal >= 0) {p->tex_Texture_Normal = sampler;qglUniform1i(p->loc_Texture_Normal , sampler);sampler++;} + if (p->loc_Texture_Color >= 0) {p->tex_Texture_Color = sampler;qglUniform1i(p->loc_Texture_Color , sampler);sampler++;} + if (p->loc_Texture_Gloss >= 0) {p->tex_Texture_Gloss = sampler;qglUniform1i(p->loc_Texture_Gloss , sampler);sampler++;} + if (p->loc_Texture_Glow >= 0) {p->tex_Texture_Glow = sampler;qglUniform1i(p->loc_Texture_Glow , sampler);sampler++;} + if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;} + if (p->loc_Texture_SecondaryColor >= 0) {p->tex_Texture_SecondaryColor = sampler;qglUniform1i(p->loc_Texture_SecondaryColor , sampler);sampler++;} + if (p->loc_Texture_SecondaryGloss >= 0) {p->tex_Texture_SecondaryGloss = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss , sampler);sampler++;} + if (p->loc_Texture_SecondaryGlow >= 0) {p->tex_Texture_SecondaryGlow = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow , sampler);sampler++;} + if (p->loc_Texture_Pants >= 0) {p->tex_Texture_Pants = sampler;qglUniform1i(p->loc_Texture_Pants , sampler);sampler++;} + if (p->loc_Texture_Shirt >= 0) {p->tex_Texture_Shirt = sampler;qglUniform1i(p->loc_Texture_Shirt , sampler);sampler++;} + if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;} + if (p->loc_Texture_FogMask >= 0) {p->tex_Texture_FogMask = sampler;qglUniform1i(p->loc_Texture_FogMask , sampler);sampler++;} + if (p->loc_Texture_Lightmap >= 0) {p->tex_Texture_Lightmap = sampler;qglUniform1i(p->loc_Texture_Lightmap , sampler);sampler++;} + if (p->loc_Texture_Deluxemap >= 0) {p->tex_Texture_Deluxemap = sampler;qglUniform1i(p->loc_Texture_Deluxemap , sampler);sampler++;} + if (p->loc_Texture_Attenuation >= 0) {p->tex_Texture_Attenuation = sampler;qglUniform1i(p->loc_Texture_Attenuation , sampler);sampler++;} + if (p->loc_Texture_Cube >= 0) {p->tex_Texture_Cube = sampler;qglUniform1i(p->loc_Texture_Cube , sampler);sampler++;} + if (p->loc_Texture_Refraction >= 0) {p->tex_Texture_Refraction = sampler;qglUniform1i(p->loc_Texture_Refraction , sampler);sampler++;} + if (p->loc_Texture_Reflection >= 0) {p->tex_Texture_Reflection = sampler;qglUniform1i(p->loc_Texture_Reflection , sampler);sampler++;} + if (p->loc_Texture_ShadowMap2D >= 0) {p->tex_Texture_ShadowMap2D = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D , sampler);sampler++;} + if (p->loc_Texture_CubeProjection >= 0) {p->tex_Texture_CubeProjection = sampler;qglUniform1i(p->loc_Texture_CubeProjection , sampler);sampler++;} + if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;} + if (p->loc_Texture_ScreenDiffuse >= 0) {p->tex_Texture_ScreenDiffuse = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse , sampler);sampler++;} + if (p->loc_Texture_ScreenSpecular >= 0) {p->tex_Texture_ScreenSpecular = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular , sampler);sampler++;} + if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;} + if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;} + if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;} + // get the uniform block indices so we can bind them + if (vid.support.arb_uniform_buffer_object) + p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock"); + else + p->ubiloc_Skeletal_Transform12_UniformBlock = -1; + // clear the uniform block bindings + p->ubibind_Skeletal_Transform12_UniformBlock = -1; + // bind the uniform blocks in use + ubibind = 0; + if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;} + // we're done compiling and setting up the shader, at least until it is used + CHECKGLERROR + Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler); + } + else + Con_Printf("^1GLSL shader %s failed! some features may not work properly.\n", permutationname); + + // free the strings + if (sourcestring) + Mem_Free(sourcestring); +} + +static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int permutation) +{ + r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation); + if (r_glsl_permutation != perm) + { + r_glsl_permutation = perm; + if (!r_glsl_permutation->program) + { + if (!r_glsl_permutation->compiled) + R_GLSL_CompilePermutation(perm, mode, permutation); + if (!r_glsl_permutation->program) + { + // remove features until we find a valid permutation + int i; + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + { + // reduce i more quickly whenever it would not remove any bits + int j = 1<<(SHADERPERMUTATION_COUNT-1-i); + if (!(permutation & j)) + continue; + permutation -= j; + r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation); + if (!r_glsl_permutation->compiled) + R_GLSL_CompilePermutation(perm, mode, permutation); + if (r_glsl_permutation->program) + break; + } + if (i >= SHADERPERMUTATION_COUNT) + { + //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext); + r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation); + qglUseProgram(0);CHECKGLERROR + return; // no bit left to clear, entire mode is broken + } + } + } + CHECKGLERROR + qglUseProgram(r_glsl_permutation->program);CHECKGLERROR + } + if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f); + if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f); + if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time); + CHECKGLERROR +} + +#ifdef SUPPORTD3D + +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +extern D3DCAPS9 vid_d3d9caps; +#endif + +struct r_hlsl_permutation_s; +typedef struct r_hlsl_permutation_s +{ + /// hash lookup data + struct r_hlsl_permutation_s *hashnext; + unsigned int mode; + unsigned int permutation; + + /// indicates if we have tried compiling this permutation already + qboolean compiled; + /// NULL if compilation failed + IDirect3DVertexShader9 *vertexshader; + IDirect3DPixelShader9 *pixelshader; +} +r_hlsl_permutation_t; + +typedef enum D3DVSREGISTER_e +{ + D3DVSREGISTER_TexMatrix = 0, // float4x4 + D3DVSREGISTER_BackgroundTexMatrix = 4, // float4x4 + D3DVSREGISTER_ModelViewProjectionMatrix = 8, // float4x4 + D3DVSREGISTER_ModelViewMatrix = 12, // float4x4 + D3DVSREGISTER_ShadowMapMatrix = 16, // float4x4 + D3DVSREGISTER_ModelToLight = 20, // float4x4 + D3DVSREGISTER_EyePosition = 24, + D3DVSREGISTER_FogPlane = 25, + D3DVSREGISTER_LightDir = 26, + D3DVSREGISTER_LightPosition = 27, +} +D3DVSREGISTER_t; + +typedef enum D3DPSREGISTER_e +{ + D3DPSREGISTER_Alpha = 0, + D3DPSREGISTER_BloomBlur_Parameters = 1, + D3DPSREGISTER_ClientTime = 2, + D3DPSREGISTER_Color_Ambient = 3, + D3DPSREGISTER_Color_Diffuse = 4, + D3DPSREGISTER_Color_Specular = 5, + D3DPSREGISTER_Color_Glow = 6, + D3DPSREGISTER_Color_Pants = 7, + D3DPSREGISTER_Color_Shirt = 8, + D3DPSREGISTER_DeferredColor_Ambient = 9, + D3DPSREGISTER_DeferredColor_Diffuse = 10, + D3DPSREGISTER_DeferredColor_Specular = 11, + D3DPSREGISTER_DeferredMod_Diffuse = 12, + D3DPSREGISTER_DeferredMod_Specular = 13, + D3DPSREGISTER_DistortScaleRefractReflect = 14, + D3DPSREGISTER_EyePosition = 15, // unused + D3DPSREGISTER_FogColor = 16, + D3DPSREGISTER_FogHeightFade = 17, + D3DPSREGISTER_FogPlane = 18, + D3DPSREGISTER_FogPlaneViewDist = 19, + D3DPSREGISTER_FogRangeRecip = 20, + D3DPSREGISTER_LightColor = 21, + D3DPSREGISTER_LightDir = 22, // unused + D3DPSREGISTER_LightPosition = 23, + D3DPSREGISTER_OffsetMapping_ScaleSteps = 24, + D3DPSREGISTER_PixelSize = 25, + D3DPSREGISTER_ReflectColor = 26, + D3DPSREGISTER_ReflectFactor = 27, + D3DPSREGISTER_ReflectOffset = 28, + D3DPSREGISTER_RefractColor = 29, + D3DPSREGISTER_Saturation = 30, + D3DPSREGISTER_ScreenCenterRefractReflect = 31, + D3DPSREGISTER_ScreenScaleRefractReflect = 32, + D3DPSREGISTER_ScreenToDepth = 33, + D3DPSREGISTER_ShadowMap_Parameters = 34, + D3DPSREGISTER_ShadowMap_TextureScale = 35, + D3DPSREGISTER_SpecularPower = 36, + D3DPSREGISTER_UserVec1 = 37, + D3DPSREGISTER_UserVec2 = 38, + D3DPSREGISTER_UserVec3 = 39, + D3DPSREGISTER_UserVec4 = 40, + D3DPSREGISTER_ViewTintColor = 41, + D3DPSREGISTER_PixelToScreenTexCoord = 42, + D3DPSREGISTER_BloomColorSubtract = 43, + D3DPSREGISTER_ViewToLight = 44, // float4x4 + D3DPSREGISTER_ModelToReflectCube = 48, // float4x4 + D3DPSREGISTER_NormalmapScrollBlend = 52, + D3DPSREGISTER_OffsetMapping_LodDistance = 53, + D3DPSREGISTER_OffsetMapping_Bias = 54, + // next at 54 +} +D3DPSREGISTER_t; + +/// information about each possible shader permutation +r_hlsl_permutation_t *r_hlsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE]; +/// currently selected permutation +r_hlsl_permutation_t *r_hlsl_permutation; +/// storage for permutations linked in the hash table +memexpandablearray_t r_hlsl_permutationarray; + +static r_hlsl_permutation_t *R_HLSL_FindPermutation(unsigned int mode, unsigned int permutation) +{ + //unsigned int hashdepth = 0; + unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1); + r_hlsl_permutation_t *p; + for (p = r_hlsl_permutationhash[mode][hashindex];p;p = p->hashnext) + { + if (p->mode == mode && p->permutation == permutation) + { + //if (hashdepth > 10) + // Con_Printf("R_HLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth); + return p; + } + //hashdepth++; + } + p = (r_hlsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_hlsl_permutationarray); + p->mode = mode; + p->permutation = permutation; + p->hashnext = r_hlsl_permutationhash[mode][hashindex]; + r_hlsl_permutationhash[mode][hashindex] = p; + //if (hashdepth > 10) + // Con_Printf("R_HLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth); + return p; +} + +#include +//#include +//#include + +static void R_HLSL_CacheShader(r_hlsl_permutation_t *p, const char *cachename, const char *vertstring, const char *fragstring) +{ + DWORD *vsbin = NULL; + DWORD *psbin = NULL; + fs_offset_t vsbinsize; + fs_offset_t psbinsize; +// IDirect3DVertexShader9 *vs = NULL; +// IDirect3DPixelShader9 *ps = NULL; + ID3DXBuffer *vslog = NULL; + ID3DXBuffer *vsbuffer = NULL; + ID3DXConstantTable *vsconstanttable = NULL; + ID3DXBuffer *pslog = NULL; + ID3DXBuffer *psbuffer = NULL; + ID3DXConstantTable *psconstanttable = NULL; + int vsresult = 0; + int psresult = 0; + char temp[MAX_INPUTLINE]; + const char *vsversion = "vs_3_0", *psversion = "ps_3_0"; + char vabuf[1024]; + qboolean debugshader = gl_paranoid.integer != 0; + if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";} + if (p->permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) {vsversion = "vs_3_0";psversion = "ps_3_0";} + if (!debugshader) + { + vsbin = (DWORD *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.vsbin", cachename), r_main_mempool, true, &vsbinsize); + psbin = (DWORD *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.psbin", cachename), r_main_mempool, true, &psbinsize); + } + if ((!vsbin && vertstring) || (!psbin && fragstring)) + { + const char* dllnames_d3dx9 [] = + { + "d3dx9_43.dll", + "d3dx9_42.dll", + "d3dx9_41.dll", + "d3dx9_40.dll", + "d3dx9_39.dll", + "d3dx9_38.dll", + "d3dx9_37.dll", + "d3dx9_36.dll", + "d3dx9_35.dll", + "d3dx9_34.dll", + "d3dx9_33.dll", + "d3dx9_32.dll", + "d3dx9_31.dll", + "d3dx9_30.dll", + "d3dx9_29.dll", + "d3dx9_28.dll", + "d3dx9_27.dll", + "d3dx9_26.dll", + "d3dx9_25.dll", + "d3dx9_24.dll", + NULL + }; + dllhandle_t d3dx9_dll = NULL; + HRESULT (WINAPI *qD3DXCompileShaderFromFileA)(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable); + HRESULT (WINAPI *qD3DXPreprocessShader)(LPCSTR pSrcData, UINT SrcDataSize, CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPD3DXBUFFER* ppShaderText, LPD3DXBUFFER* ppErrorMsgs); + HRESULT (WINAPI *qD3DXCompileShader)(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable); + dllfunction_t d3dx9_dllfuncs[] = + { + {"D3DXCompileShaderFromFileA", (void **) &qD3DXCompileShaderFromFileA}, + {"D3DXPreprocessShader", (void **) &qD3DXPreprocessShader}, + {"D3DXCompileShader", (void **) &qD3DXCompileShader}, + {NULL, NULL} + }; + // LordHavoc: the June 2010 SDK lacks these macros to make ID3DXBuffer usable in C, and to make it work in both C and C++ the macros are needed... +#ifndef ID3DXBuffer_GetBufferPointer +#if !defined(__cplusplus) || defined(CINTERFACE) +#define ID3DXBuffer_GetBufferPointer(p) (p)->lpVtbl->GetBufferPointer(p) +#define ID3DXBuffer_GetBufferSize(p) (p)->lpVtbl->GetBufferSize(p) +#define ID3DXBuffer_Release(p) (p)->lpVtbl->Release(p) +#else +#define ID3DXBuffer_GetBufferPointer(p) (p)->GetBufferPointer() +#define ID3DXBuffer_GetBufferSize(p) (p)->GetBufferSize() +#define ID3DXBuffer_Release(p) (p)->Release() +#endif +#endif + if (Sys_LoadLibrary(dllnames_d3dx9, &d3dx9_dll, d3dx9_dllfuncs)) + { + DWORD shaderflags = 0; + if (debugshader) + shaderflags = D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION; + vsbin = (DWORD *)Mem_Realloc(tempmempool, vsbin, 0); + psbin = (DWORD *)Mem_Realloc(tempmempool, psbin, 0); + if (vertstring && vertstring[0]) + { + if (debugshader) + { + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_vs.fx", cachename), vertstring, strlen(vertstring)); + vsresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_vs.fx", fs_gamedir, cachename), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable); + } + else + vsresult = qD3DXCompileShader(vertstring, strlen(vertstring), NULL, NULL, "main", vsversion, shaderflags, &vsbuffer, &vslog, &vsconstanttable); + if (vsbuffer) + { + vsbinsize = ID3DXBuffer_GetBufferSize(vsbuffer); + vsbin = (DWORD *)Mem_Alloc(tempmempool, vsbinsize); + memcpy(vsbin, ID3DXBuffer_GetBufferPointer(vsbuffer), vsbinsize); + ID3DXBuffer_Release(vsbuffer); + } + if (vslog) + { + strlcpy(temp, (const char *)ID3DXBuffer_GetBufferPointer(vslog), min(sizeof(temp), ID3DXBuffer_GetBufferSize(vslog))); + Con_DPrintf("HLSL vertex shader compile output for %s follows:\n%s\n", cachename, temp); + ID3DXBuffer_Release(vslog); + } + } + if (fragstring && fragstring[0]) + { + if (debugshader) + { + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_ps.fx", cachename), fragstring, strlen(fragstring)); + psresult = qD3DXCompileShaderFromFileA(va(vabuf, sizeof(vabuf), "%s/%s_ps.fx", fs_gamedir, cachename), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable); + } + else + psresult = qD3DXCompileShader(fragstring, strlen(fragstring), NULL, NULL, "main", psversion, shaderflags, &psbuffer, &pslog, &psconstanttable); + if (psbuffer) + { + psbinsize = ID3DXBuffer_GetBufferSize(psbuffer); + psbin = (DWORD *)Mem_Alloc(tempmempool, psbinsize); + memcpy(psbin, ID3DXBuffer_GetBufferPointer(psbuffer), psbinsize); + ID3DXBuffer_Release(psbuffer); + } + if (pslog) + { + strlcpy(temp, (const char *)ID3DXBuffer_GetBufferPointer(pslog), min(sizeof(temp), ID3DXBuffer_GetBufferSize(pslog))); + Con_DPrintf("HLSL pixel shader compile output for %s follows:\n%s\n", cachename, temp); + ID3DXBuffer_Release(pslog); + } + } + Sys_UnloadLibrary(&d3dx9_dll); + } + else + Con_DPrintf("Unable to compile shader - D3DXCompileShader function not found\n"); + } + if (vsbin && psbin) + { + vsresult = IDirect3DDevice9_CreateVertexShader(vid_d3d9dev, vsbin, &p->vertexshader); + if (FAILED(vsresult)) + Con_DPrintf("HLSL CreateVertexShader failed for %s (hresult = %8x)\n", cachename, vsresult); + psresult = IDirect3DDevice9_CreatePixelShader(vid_d3d9dev, psbin, &p->pixelshader); + if (FAILED(psresult)) + Con_DPrintf("HLSL CreatePixelShader failed for %s (hresult = %8x)\n", cachename, psresult); + } + // free the shader data + vsbin = (DWORD *)Mem_Realloc(tempmempool, vsbin, 0); + psbin = (DWORD *)Mem_Realloc(tempmempool, psbin, 0); +} + +static void R_HLSL_CompilePermutation(r_hlsl_permutation_t *p, unsigned int mode, unsigned int permutation) +{ + int i; + shadermodeinfo_t *modeinfo = hlslshadermodeinfo + mode; + int vertstring_length = 0; + int geomstring_length = 0; + int fragstring_length = 0; + char *t; + char *sourcestring; + char *vertstring, *geomstring, *fragstring; + char permutationname[256]; + char cachename[256]; + int vertstrings_count = 0; + int geomstrings_count = 0; + int fragstrings_count = 0; + const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1]; + + if (p->compiled) + return; + p->compiled = true; + p->vertexshader = NULL; + p->pixelshader = NULL; + + permutationname[0] = 0; + cachename[0] = 0; + sourcestring = R_GetShaderText(modeinfo->filename, true, false); + + strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); + strlcat(cachename, "hlsl/", sizeof(cachename)); + + // define HLSL so that the shader can tell apart the HLSL compiler and the Cg compiler + vertstrings_count = 0; + geomstrings_count = 0; + fragstrings_count = 0; + vertstrings_list[vertstrings_count++] = "#define HLSL\n"; + geomstrings_list[geomstrings_count++] = "#define HLSL\n"; + fragstrings_list[fragstrings_count++] = "#define HLSL\n"; + + // the first pretext is which type of shader to compile as + // (later these will all be bound together as a program object) + vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n"; + geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n"; + fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n"; + + // the second pretext is the mode (for example a light source) + vertstrings_list[vertstrings_count++] = modeinfo->pretext; + geomstrings_list[geomstrings_count++] = modeinfo->pretext; + fragstrings_list[fragstrings_count++] = modeinfo->pretext; + strlcat(permutationname, modeinfo->name, sizeof(permutationname)); + strlcat(cachename, modeinfo->name, sizeof(cachename)); + + // now add all the permutation pretexts + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + { + if (permutation & (1<vertexshader || !vertstring[0]) && (p->pixelshader || !fragstring[0])) + Con_DPrintf("^5HLSL shader %s compiled.\n", permutationname); + else + Con_Printf("^1HLSL shader %s failed! some features may not work properly.\n", permutationname); + + // free the strings + if (vertstring) + Mem_Free(vertstring); + if (geomstring) + Mem_Free(geomstring); + if (fragstring) + Mem_Free(fragstring); + if (sourcestring) + Mem_Free(sourcestring); +} + +static inline void hlslVSSetParameter16f(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 4);} +static inline void hlslVSSetParameter4fv(D3DVSREGISTER_t r, const float *a) {IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, a, 1);} +static inline void hlslVSSetParameter4f(D3DVSREGISTER_t r, float x, float y, float z, float w) {float temp[4];Vector4Set(temp, x, y, z, w);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslVSSetParameter3f(D3DVSREGISTER_t r, float x, float y, float z) {float temp[4];Vector4Set(temp, x, y, z, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslVSSetParameter2f(D3DVSREGISTER_t r, float x, float y) {float temp[4];Vector4Set(temp, x, y, 0, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslVSSetParameter1f(D3DVSREGISTER_t r, float x) {float temp[4];Vector4Set(temp, x, 0, 0, 0);IDirect3DDevice9_SetVertexShaderConstantF(vid_d3d9dev, r, temp, 1);} + +static inline void hlslPSSetParameter16f(D3DPSREGISTER_t r, const float *a) {IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, a, 4);} +static inline void hlslPSSetParameter4fv(D3DPSREGISTER_t r, const float *a) {IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, a, 1);} +static inline void hlslPSSetParameter4f(D3DPSREGISTER_t r, float x, float y, float z, float w) {float temp[4];Vector4Set(temp, x, y, z, w);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslPSSetParameter3f(D3DPSREGISTER_t r, float x, float y, float z) {float temp[4];Vector4Set(temp, x, y, z, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslPSSetParameter2f(D3DPSREGISTER_t r, float x, float y) {float temp[4];Vector4Set(temp, x, y, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);} +static inline void hlslPSSetParameter1f(D3DPSREGISTER_t r, float x) {float temp[4];Vector4Set(temp, x, 0, 0, 0);IDirect3DDevice9_SetPixelShaderConstantF(vid_d3d9dev, r, temp, 1);} + +void R_SetupShader_SetPermutationHLSL(unsigned int mode, unsigned int permutation) +{ + r_hlsl_permutation_t *perm = R_HLSL_FindPermutation(mode, permutation); + if (r_hlsl_permutation != perm) + { + r_hlsl_permutation = perm; + if (!r_hlsl_permutation->vertexshader && !r_hlsl_permutation->pixelshader) + { + if (!r_hlsl_permutation->compiled) + R_HLSL_CompilePermutation(perm, mode, permutation); + if (!r_hlsl_permutation->vertexshader && !r_hlsl_permutation->pixelshader) + { + // remove features until we find a valid permutation + int i; + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + { + // reduce i more quickly whenever it would not remove any bits + int j = 1<<(SHADERPERMUTATION_COUNT-1-i); + if (!(permutation & j)) + continue; + permutation -= j; + r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation); + if (!r_hlsl_permutation->compiled) + R_HLSL_CompilePermutation(perm, mode, permutation); + if (r_hlsl_permutation->vertexshader || r_hlsl_permutation->pixelshader) + break; + } + if (i >= SHADERPERMUTATION_COUNT) + { + //Con_Printf("Could not find a working HLSL shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext); + r_hlsl_permutation = R_HLSL_FindPermutation(mode, permutation); + return; // no bit left to clear, entire mode is broken + } + } + } + IDirect3DDevice9_SetVertexShader(vid_d3d9dev, r_hlsl_permutation->vertexshader); + IDirect3DDevice9_SetPixelShader(vid_d3d9dev, r_hlsl_permutation->pixelshader); + } + hlslVSSetParameter16f(D3DVSREGISTER_ModelViewProjectionMatrix, gl_modelviewprojection16f); + hlslVSSetParameter16f(D3DVSREGISTER_ModelViewMatrix, gl_modelview16f); + hlslPSSetParameter1f(D3DPSREGISTER_ClientTime, cl.time); +} +#endif + +static void R_SetupShader_SetPermutationSoft(unsigned int mode, unsigned int permutation) +{ + DPSOFTRAST_SetShader(mode, permutation, r_shadow_glossexact.integer); + DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f); + DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewMatrixM1, 1, false, gl_modelview16f); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ClientTime, cl.time); +} + +void R_GLSL_Restart_f(void) +{ + unsigned int i, limit; + if (glslshaderstring) + Mem_Free(glslshaderstring); + glslshaderstring = NULL; + if (hlslshaderstring) + Mem_Free(hlslshaderstring); + hlslshaderstring = NULL; + switch(vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + r_hlsl_permutation_t *p; + r_hlsl_permutation = NULL; + limit = Mem_ExpandableArray_IndexRange(&r_hlsl_permutationarray); + for (i = 0;i < limit;i++) + { + if ((p = (r_hlsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_hlsl_permutationarray, i))) + { + if (p->vertexshader) + IDirect3DVertexShader9_Release(p->vertexshader); + if (p->pixelshader) + IDirect3DPixelShader9_Release(p->pixelshader); + Mem_ExpandableArray_FreeRecord(&r_hlsl_permutationarray, (void*)p); + } + } + memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash)); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + { + r_glsl_permutation_t *p; + r_glsl_permutation = NULL; + limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray); + for (i = 0;i < limit;i++) + { + if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i))) + { + GL_Backend_FreeProgram(p->program); + Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p); + } + } + memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash)); + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + break; + case RENDERPATH_SOFT: + break; + } +} + +static void R_GLSL_DumpShader_f(void) +{ + int i, language, mode, dupe; + char *text; + shadermodeinfo_t *modeinfo; + qfile_t *file; + + for (language = 0;language < 2;language++) + { + modeinfo = (language == 0 ? glslshadermodeinfo : hlslshadermodeinfo); + for (mode = 0;mode < SHADERMODE_COUNT;mode++) + { + // don't dump the same file multiple times (most or all shaders come from the same file) + for (dupe = mode - 1;dupe >= 0;dupe--) + if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename)) + break; + if (dupe >= 0) + continue; + text = R_GetShaderText(modeinfo[mode].filename, false, true); + if (!text) + continue; + file = FS_OpenRealFile(modeinfo[mode].filename, "w", false); + if (file) + { + FS_Print(file, "/* The engine may define the following macros:\n"); + FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n"); + for (i = 0;i < SHADERMODE_COUNT;i++) + FS_Print(file, modeinfo[i].pretext); + for (i = 0;i < SHADERPERMUTATION_COUNT;i++) + FS_Print(file, shaderpermutationinfo[i].pretext); + FS_Print(file, "*/\n"); + FS_Print(file, text); + FS_Close(file); + Con_Printf("%s written\n", modeinfo[mode].filename); + } + else + Con_Printf("failed to write to %s\n", modeinfo[mode].filename); + Mem_Free(text); + } + } +} + +void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha) +{ + unsigned int permutation = 0; + if (r_trippy.integer && !notrippy) + permutation |= SHADERPERMUTATION_TRIPPY; + permutation |= SHADERPERMUTATION_VIEWTINT; + if (first) + permutation |= SHADERPERMUTATION_DIFFUSE; + if (second) + permutation |= SHADERPERMUTATION_SPECULAR; + if (texturemode == GL_MODULATE) + permutation |= SHADERPERMUTATION_COLORMAPPING; + else if (texturemode == GL_ADD) + permutation |= SHADERPERMUTATION_GLOW; + else if (texturemode == GL_DECAL) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (usegamma && v_glslgamma.integer && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial) + permutation |= SHADERPERMUTATION_GAMMARAMPS; + if (suppresstexalpha) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + if (!second) + texturemode = GL_MODULATE; + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + switch (vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, permutation); + R_Mesh_TexBind(GL20TU_FIRST , first ); + R_Mesh_TexBind(GL20TU_SECOND, second); + if (permutation & SHADERPERMUTATION_GAMMARAMPS) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation); + if (r_glsl_permutation->tex_Texture_First >= 0) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first ); + if (r_glsl_permutation->tex_Texture_Second >= 0) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second); + if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + R_Mesh_TexBind(0, first ); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); + R_Mesh_TexBind(1, second); + if (second) + { + R_Mesh_TexCombine(1, texturemode, texturemode, rgbscale, 1); + R_Mesh_TexMatrix(1, NULL); + } + break; + case RENDERPATH_GL11: + R_Mesh_TexBind(0, first ); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); + break; + case RENDERPATH_SOFT: + R_SetupShader_SetPermutationSoft(SHADERMODE_GENERIC, permutation); + R_Mesh_TexBind(GL20TU_FIRST , first ); + R_Mesh_TexBind(GL20TU_SECOND, second); + break; + } +} + +void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy) +{ + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false); +} + +void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal) +{ + unsigned int permutation = 0; + if (r_trippy.integer && !notrippy) + permutation |= SHADERPERMUTATION_TRIPPY; + if (depthrgb) + permutation |= SHADERPERMUTATION_DEPTHRGB; + if (skeletal) + permutation |= SHADERPERMUTATION_SKELETAL; + + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + switch (vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + R_SetupShader_SetPermutationHLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation); + if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + R_Mesh_TexBind(0, 0); + R_Mesh_TexBind(1, 0); + break; + case RENDERPATH_GL11: + R_Mesh_TexBind(0, 0); + break; + case RENDERPATH_SOFT: + R_SetupShader_SetPermutationSoft(SHADERMODE_DEPTH_OR_SHADOW, permutation); + break; + } +} + +extern qboolean r_shadow_usingdeferredprepass; +extern rtexture_t *r_shadow_attenuationgradienttexture; +extern rtexture_t *r_shadow_attenuation2dtexture; +extern rtexture_t *r_shadow_attenuation3dtexture; +extern qboolean r_shadow_usingshadowmap2d; +extern qboolean r_shadow_usingshadowmaportho; +extern float r_shadow_shadowmap_texturescale[2]; +extern float r_shadow_shadowmap_parameters[4]; +extern qboolean r_shadow_shadowmapvsdct; +extern rtexture_t *r_shadow_shadowmap2ddepthbuffer; +extern rtexture_t *r_shadow_shadowmap2ddepthtexture; +extern rtexture_t *r_shadow_shadowmapvsdcttexture; +extern matrix4x4_t r_shadow_shadowmapmatrix; +extern int r_shadow_shadowmaplod; // changes for each light based on distance +extern int r_shadow_prepass_width; +extern int r_shadow_prepass_height; +extern rtexture_t *r_shadow_prepassgeometrydepthbuffer; +extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture; +extern rtexture_t *r_shadow_prepasslightingdiffusetexture; +extern rtexture_t *r_shadow_prepasslightingspeculartexture; + +#define BLENDFUNC_ALLOWS_COLORMOD 1 +#define BLENDFUNC_ALLOWS_FOG 2 +#define BLENDFUNC_ALLOWS_FOG_HACK0 4 +#define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8 +#define BLENDFUNC_ALLOWS_ANYFOG (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA) +static int R_BlendFuncFlags(int src, int dst) +{ + int r = 0; + + // a blendfunc allows colormod if: + // a) it can never keep the destination pixel invariant, or + // b) it can keep the destination pixel invariant, and still can do so if colormodded + // this is to prevent unintended side effects from colormod + + // a blendfunc allows fog if: + // blend(fog(src), fog(dst)) == fog(blend(src, dst)) + // this is to prevent unintended side effects from fog + + // these checks are the output of fogeval.pl + + r |= BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0; + if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0; + if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA; + if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0; + if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0; + if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0; + if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG; + if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD; + + return r; +} + +void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy) +{ + // select a permutation of the lighting shader appropriate to this + // combination of texture, entity, light source, and fogging, only use the + // minimum features necessary to avoid wasting rendering time in the + // fragment shader on features that are not being used + unsigned int permutation = 0; + unsigned int mode = 0; + int blendfuncflags; + static float dummy_colormod[3] = {1, 1, 1}; + float *colormod = rsurface.colormod; + float m16f[16]; + matrix4x4_t tempmatrix; + r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane; + if (r_trippy.integer && !notrippy) + permutation |= SHADERPERMUTATION_TRIPPY; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + permutation |= SHADERPERMUTATION_ALPHAKILL; + if (rsurface.texture->r_water_waterscroll[0] && rsurface.texture->r_water_waterscroll[1]) + permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic + if (rsurfacepass == RSURFPASS_BACKGROUND) + { + // distorted background + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) + { + mode = SHADERMODE_WATER; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + if((r_wateralpha.value < 1) && (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)) + { + // this is the right thing to do for wateralpha + GL_BlendFunc(GL_ONE, GL_ZERO); + blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO); + } + else + { + // this is the right thing to do for entity alpha + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION) + { + mode = SHADERMODE_REFRACTION; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + mode = SHADERMODE_GENERIC; + permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + } + else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY) + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + // normalmap (deferred prepass), may use alpha test on diffuse + mode = SHADERMODE_DEFERREDGEOMETRY; + GL_BlendFunc(GL_ONE, GL_ZERO); + blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO); + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + } + else if (rsurfacepass == RSURFPASS_RTLIGHT) + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + // light source + mode = SHADERMODE_LIGHTSOURCE; + if (rsurface.rtlight->currentcubemap != r_texture_whitecube) + permutation |= SHADERPERMUTATION_CUBEFILTER; + if (diffusescale > 0) + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE; + if (r_refdef.fogenabled) + permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); + if (rsurface.texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_shadow_usingshadowmap2d) + { + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + if(r_shadow_shadowmapvsdct) + permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (rsurface.texture->reflectmasktexture) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE); + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + // unshaded geometry (fullbright or ambient model lighting) + mode = SHADERMODE_FLATCOLOR; + ambientscale = diffusescale = specularscale = 0; + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); + if (rsurface.texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)) + { + permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) + permutation |= SHADERPERMUTATION_REFLECTION; + if (rsurface.texture->reflectmasktexture) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + // when using alphatocoverage, we don't need alphakill + if (vid.allowalphatocoverage) + { + if (r_transparent_alphatocoverage.integer) + { + GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); + permutation &= ~SHADERPERMUTATION_ALPHAKILL; + } + else + GL_AlphaToCoverage(false); + } + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL) + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + // directional model lighting + mode = SHADERMODE_LIGHTDIRECTION; + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + permutation |= SHADERPERMUTATION_GLOW; + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + if (r_refdef.fogenabled) + permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); + if (rsurface.texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)) + { + permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) + permutation |= SHADERPERMUTATION_REFLECTION; + if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)) + permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP; + if (rsurface.texture->reflectmasktexture) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld) + { + permutation |= SHADERPERMUTATION_BOUNCEGRID; + if (r_shadow_bouncegriddirectional) + permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL; + } + GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + // when using alphatocoverage, we don't need alphakill + if (vid.allowalphatocoverage) + { + if (r_transparent_alphatocoverage.integer) + { + GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); + permutation &= ~SHADERPERMUTATION_ALPHAKILL; + } + else + GL_AlphaToCoverage(false); + } + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + // ambient model lighting + mode = SHADERMODE_LIGHTDIRECTION; + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); + if (rsurface.texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)) + { + permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) + permutation |= SHADERPERMUTATION_REFLECTION; + if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)) + permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP; + if (rsurface.texture->reflectmasktexture) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld) + { + permutation |= SHADERPERMUTATION_BOUNCEGRID; + if (r_shadow_bouncegriddirectional) + permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL; + } + GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + // when using alphatocoverage, we don't need alphakill + if (vid.allowalphatocoverage) + { + if (r_transparent_alphatocoverage.integer) + { + GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); + permutation &= ~SHADERPERMUTATION_ALPHAKILL; + } + else + GL_AlphaToCoverage(false); + } + } + else + { + if (r_glsl_offsetmapping.integer && ((R_TextureFlags(rsurface.texture->nmaptexture) & TEXF_ALPHA) || rsurface.texture->offsetbias != 0.0f)) + { + switch(rsurface.texture->offsetmapping) + { + case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break; + case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break; + case OFFSETMAPPING_OFF: break; + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) + permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX) + permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX; + // lightmapped wall + if ((rsurface.texture->glowtexture || rsurface.texture->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); + if (rsurface.texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)) + { + permutation |= SHADERPERMUTATION_SHADOWMAPORTHO; + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) + permutation |= SHADERPERMUTATION_REFLECTION; + if (r_shadow_usingdeferredprepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)) + permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP; + if (rsurface.texture->reflectmasktexture) + permutation |= SHADERPERMUTATION_REFLECTCUBE; + if (FAKELIGHT_ENABLED) + { + // fake lightmapping (q1bsp, q3bsp, fullbright map) + mode = SHADERMODE_FAKELIGHT; + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE; + } + else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping) + { + // deluxemapping (light direction texture) + if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace) + mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE; + else + mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE; + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE; + } + else if (r_glsl_deluxemapping.integer >= 2) + { + // fake deluxemapping (uniform light direction in tangentspace) + if (rsurface.uselightmaptexture) + mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP; + else + mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR; + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE; + } + else if (rsurface.uselightmaptexture) + { + // ordinary lightmapping (q1bsp, q3bsp) + mode = SHADERMODE_LIGHTMAP; + } + else + { + // ordinary vertex coloring (q3bsp) + mode = SHADERMODE_VERTEXCOLOR; + } + if (r_shadow_bouncegridtexture && cl.csqc_vidvars.drawworld) + { + permutation |= SHADERPERMUTATION_BOUNCEGRID; + if (r_shadow_bouncegriddirectional) + permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL; + } + GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + blendfuncflags = R_BlendFuncFlags(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); + // when using alphatocoverage, we don't need alphakill + if (vid.allowalphatocoverage) + { + if (r_transparent_alphatocoverage.integer) + { + GL_AlphaToCoverage((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); + permutation &= ~SHADERPERMUTATION_ALPHAKILL; + } + else + GL_AlphaToCoverage(false); + } + } + if(!(blendfuncflags & BLENDFUNC_ALLOWS_COLORMOD)) + colormod = dummy_colormod; + if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG)) + permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE); + if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA) + permutation |= SHADERPERMUTATION_FOGALPHAHACK; + switch(vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset); + R_SetupShader_SetPermutationHLSL(mode, permutation); + Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);hlslPSSetParameter16f(D3DPSREGISTER_ModelToReflectCube, m16f); + if (mode == SHADERMODE_LIGHTSOURCE) + { + Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);hlslVSSetParameter16f(D3DVSREGISTER_ModelToLight, m16f); + hlslVSSetParameter3f(D3DVSREGISTER_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]); + } + else + { + if (mode == SHADERMODE_LIGHTDIRECTION) + { + hlslVSSetParameter3f(D3DVSREGISTER_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); + } + } + Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_TexMatrix, m16f); + Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_BackgroundTexMatrix, m16f); + Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);hlslVSSetParameter16f(D3DVSREGISTER_ShadowMapMatrix, m16f); + hlslVSSetParameter3f(D3DVSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); + hlslVSSetParameter4f(D3DVSREGISTER_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]); + + if (mode == SHADERMODE_LIGHTSOURCE) + { + hlslPSSetParameter3f(D3DPSREGISTER_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]); + hlslPSSetParameter3f(D3DPSREGISTER_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale); + + // additive passes are only darkened by fog, not tinted + hlslPSSetParameter3f(D3DPSREGISTER_FogColor, 0, 0, 0); + hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + } + else + { + if (mode == SHADERMODE_FLATCOLOR) + { + hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, colormod[0], colormod[1], colormod[2]); + } + else if (mode == SHADERMODE_LIGHTDIRECTION) + { + hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity) * colormod[2]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale); + hlslPSSetParameter3f(D3DPSREGISTER_LightColor, rsurface.modellight_diffuse[0], rsurface.modellight_diffuse[1], rsurface.modellight_diffuse[2]); + hlslPSSetParameter3f(D3DPSREGISTER_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); + } + else + { + hlslPSSetParameter3f(D3DPSREGISTER_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredMod_Specular, specularscale, specularscale, specularscale); + } + // additive passes are only darkened by fog, not tinted + if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) + hlslPSSetParameter3f(D3DPSREGISTER_FogColor, 0, 0, 0); + else + hlslPSSetParameter3f(D3DPSREGISTER_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); + hlslPSSetParameter4f(D3DPSREGISTER_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); + hlslPSSetParameter4f(D3DPSREGISTER_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]); + hlslPSSetParameter4f(D3DPSREGISTER_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]); + hlslPSSetParameter4f(D3DPSREGISTER_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); + hlslPSSetParameter4f(D3DPSREGISTER_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); + hlslPSSetParameter1f(D3DPSREGISTER_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); + hlslPSSetParameter1f(D3DPSREGISTER_ReflectOffset, rsurface.texture->reflectmin); + hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (rsurface.texture->specularpower - 1.0f) * (r_shadow_glossexact.integer ? 0.25f : 1.0f)); + if (mode == SHADERMODE_WATER) + hlslPSSetParameter2f(D3DPSREGISTER_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]); + } + hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + hlslPSSetParameter3f(D3DPSREGISTER_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); + hlslPSSetParameter1f(D3DPSREGISTER_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + hlslPSSetParameter3f(D3DPSREGISTER_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); + if (rsurface.texture->pantstexture) + hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]); + else + hlslPSSetParameter3f(D3DPSREGISTER_Color_Pants, 0, 0, 0); + if (rsurface.texture->shirttexture) + hlslPSSetParameter3f(D3DPSREGISTER_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]); + else + hlslPSSetParameter3f(D3DPSREGISTER_Color_Shirt, 0, 0, 0); + hlslPSSetParameter4f(D3DPSREGISTER_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]); + hlslPSSetParameter1f(D3DPSREGISTER_FogPlaneViewDist, rsurface.fogplaneviewdist); + hlslPSSetParameter1f(D3DPSREGISTER_FogRangeRecip, rsurface.fograngerecip); + hlslPSSetParameter1f(D3DPSREGISTER_FogHeightFade, rsurface.fogheightfade); + hlslPSSetParameter4f(D3DPSREGISTER_OffsetMapping_ScaleSteps, + r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale, + max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) + ); + hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); + hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_Bias, rsurface.texture->offsetbias); + hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); + + R_Mesh_TexBind(GL20TU_NORMAL , rsurface.texture->nmaptexture ); + R_Mesh_TexBind(GL20TU_COLOR , rsurface.texture->basetexture ); + R_Mesh_TexBind(GL20TU_GLOSS , rsurface.texture->glosstexture ); + R_Mesh_TexBind(GL20TU_GLOW , rsurface.texture->glowtexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL , rsurface.texture->backgroundnmaptexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR , rsurface.texture->backgroundbasetexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS , rsurface.texture->backgroundglosstexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW , rsurface.texture->backgroundglowtexture ); + if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS , rsurface.texture->pantstexture ); + if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT , rsurface.texture->shirttexture ); + if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK , rsurface.texture->reflectmasktexture ); + if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube); + if (permutation & SHADERPERMUTATION_FOGHEIGHTTEXTURE) R_Mesh_TexBind(GL20TU_FOGHEIGHTTEXTURE , r_texture_fogheighttexture ); + if (permutation & (SHADERPERMUTATION_FOGINSIDE | SHADERPERMUTATION_FOGOUTSIDE)) R_Mesh_TexBind(GL20TU_FOGMASK , r_texture_fogattenuation ); + R_Mesh_TexBind(GL20TU_LIGHTMAP , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white); + R_Mesh_TexBind(GL20TU_DELUXEMAP , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap); + if (rsurface.rtlight ) R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); + if (rsurfacepass == RSURFPASS_BACKGROUND) + { + R_Mesh_TexBind(GL20TU_REFRACTION , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black); + if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black); + R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } + else + { + if (permutation & SHADERPERMUTATION_REFLECTION ) R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } +// if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); + if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE , r_shadow_prepasslightingdiffusetexture ); + if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENSPECULAR , r_shadow_prepasslightingspeculartexture ); + if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) + { + R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture); + if (rsurface.rtlight) + { + if (permutation & SHADERPERMUTATION_CUBEFILTER ) R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); + if (permutation & SHADERPERMUTATION_SHADOWMAPVSDCT ) R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (!vid.useinterleavedarrays) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset); + R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset); + } + else + { + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset); + } + // this has to be after RSurf_PrepareVerticesForBatch + if (rsurface.batchskeletaltransform3x4buffer) + permutation |= SHADERPERMUTATION_SKELETAL; + R_SetupShader_SetPermutationGLSL(mode, permutation); + if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size); + if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);} + if (mode == SHADERMODE_LIGHTSOURCE) + { + if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);} + if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]); + if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]); + if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale); + if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale); + + // additive passes are only darkened by fog, not tinted + if (r_glsl_permutation->loc_FogColor >= 0) + qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0); + if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + } + else + { + if (mode == SHADERMODE_FLATCOLOR) + { + if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, colormod[0], colormod[1], colormod[2]); + } + else if (mode == SHADERMODE_LIGHTDIRECTION) + { + if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]); + if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); + if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale); + if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]); + if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); + } + else + { + if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); + if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); + if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, specularscale, specularscale, specularscale); + } + // additive passes are only darkened by fog, not tinted + if (r_glsl_permutation->loc_FogColor >= 0) + { + if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) + qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0); + else + qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); + } + if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); + if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]); + if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]); + if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); + if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); + if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); + if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin); + if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]); + } + if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);} + if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);} + if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);} + if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + + if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); + if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); + if (r_glsl_permutation->loc_Color_Pants >= 0) + { + if (rsurface.texture->pantstexture) + qglUniform3f(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]); + else + qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0); + } + if (r_glsl_permutation->loc_Color_Shirt >= 0) + { + if (rsurface.texture->shirttexture) + qglUniform3f(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]); + else + qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0); + } + if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]); + if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist); + if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip); + if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade); + if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps, + r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale, + max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) + ); + if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); + if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, rsurface.texture->offsetbias); + if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); + if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);} + if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegridintensity*r_refdef.view.colorscale); + + if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_texture_white ); + if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_texture_white ); + if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps , r_texture_gammaramps ); + if (r_glsl_permutation->tex_Texture_Normal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal , rsurface.texture->nmaptexture ); + if (r_glsl_permutation->tex_Texture_Color >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color , rsurface.texture->basetexture ); + if (r_glsl_permutation->tex_Texture_Gloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss , rsurface.texture->glosstexture ); + if (r_glsl_permutation->tex_Texture_Glow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow , rsurface.texture->glowtexture ); + if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal , rsurface.texture->backgroundnmaptexture ); + if (r_glsl_permutation->tex_Texture_SecondaryColor >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor , rsurface.texture->backgroundbasetexture ); + if (r_glsl_permutation->tex_Texture_SecondaryGloss >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss , rsurface.texture->backgroundglosstexture ); + if (r_glsl_permutation->tex_Texture_SecondaryGlow >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow , rsurface.texture->backgroundglowtexture ); + if (r_glsl_permutation->tex_Texture_Pants >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants , rsurface.texture->pantstexture ); + if (r_glsl_permutation->tex_Texture_Shirt >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt , rsurface.texture->shirttexture ); + if (r_glsl_permutation->tex_Texture_ReflectMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask , rsurface.texture->reflectmasktexture ); + if (r_glsl_permutation->tex_Texture_ReflectCube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube); + if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture ); + if (r_glsl_permutation->tex_Texture_FogMask >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask , r_texture_fogattenuation ); + if (r_glsl_permutation->tex_Texture_Lightmap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white); + if (r_glsl_permutation->tex_Texture_Deluxemap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap); + if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture ); + if (rsurfacepass == RSURFPASS_BACKGROUND) + { + if (r_glsl_permutation->tex_Texture_Refraction >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black); + if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black); + if (r_glsl_permutation->tex_Texture_Reflection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } + else + { + if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } + if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture ); + if (r_glsl_permutation->tex_Texture_ScreenDiffuse >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse , r_shadow_prepasslightingdiffusetexture ); + if (r_glsl_permutation->tex_Texture_ScreenSpecular >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular , r_shadow_prepasslightingspeculartexture ); + if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) + { + if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture ); + if (rsurface.rtlight) + { + if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap ); + if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture ); + } + } + if (r_glsl_permutation->tex_Texture_BounceGrid >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegridtexture); + CHECKGLERROR + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + break; + case RENDERPATH_SOFT: + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchsvector3f, rsurface.batchtvector3f, rsurface.batchnormal3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f); + R_SetupShader_SetPermutationSoft(mode, permutation); + {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelToReflectCubeM1, 1, false, m16f);} + if (mode == SHADERMODE_LIGHTSOURCE) + { + {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelToLightM1, 1, false, m16f);} + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, colormod[0] * ambientscale, colormod[1] * ambientscale, colormod[2] * ambientscale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale, r_refdef.view.colorscale * specularscale); + + // additive passes are only darkened by fog, not tinted + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, 0, 0, 0); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + } + else + { + if (mode == SHADERMODE_FLATCOLOR) + { + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, colormod[0], colormod[1], colormod[2]); + } + else if (mode == SHADERMODE_LIGHTDIRECTION) + { + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, (r_refdef.scene.ambient + rsurface.modellight_ambient[0] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[0], (r_refdef.scene.ambient + rsurface.modellight_ambient[1] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[1], (r_refdef.scene.ambient + rsurface.modellight_ambient[2] * r_refdef.lightmapintensity * r_refdef.scene.rtlightstylevalue[0]) * colormod[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, r_refdef.lightmapintensity * colormod[0], r_refdef.lightmapintensity * colormod[1], r_refdef.lightmapintensity * colormod[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0], colormod[1], colormod[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightColor, rsurface.modellight_diffuse[0] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[1] * r_refdef.scene.rtlightstylevalue[0], rsurface.modellight_diffuse[2] * r_refdef.scene.rtlightstylevalue[0]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]); + } + else + { + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Ambient, r_refdef.scene.ambient * colormod[0], r_refdef.scene.ambient * colormod[1], r_refdef.scene.ambient * colormod[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Diffuse, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2]); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Specular, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale, r_refdef.lightmapintensity * r_refdef.view.colorscale * specularscale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Diffuse, colormod[0] * diffusescale, colormod[1] * diffusescale, colormod[2] * diffusescale); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_DeferredMod_Specular, specularscale, specularscale, specularscale); + } + // additive passes are only darkened by fog, not tinted + if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, 0, 0, 0); + else + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_RefractColor, rsurface.texture->refractcolor4f[0], rsurface.texture->refractcolor4f[1], rsurface.texture->refractcolor4f[2], rsurface.texture->refractcolor4f[3] * rsurface.texture->lightmapcolor[3]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ReflectColor, rsurface.texture->reflectcolor4f[0], rsurface.texture->reflectcolor4f[1], rsurface.texture->reflectcolor4f[2], rsurface.texture->reflectcolor4f[3] * rsurface.texture->lightmapcolor[3]); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_ReflectOffset, rsurface.texture->reflectmin); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_SpecularPower, rsurface.texture->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_NormalmapScrollBlend, rsurface.texture->r_water_waterscroll[0], rsurface.texture->r_water_waterscroll[1]); + } + {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currenttexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_TexMatrixM1, 1, false, m16f);} + {Matrix4x4_ToArrayFloatGL(&rsurface.texture->currentbackgroundtexmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_BackgroundTexMatrixM1, 1, false, m16f);} + {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ShadowMapMatrixM1, 1, false, m16f);} + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Glow, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2]); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Alpha, rsurface.texture->lightmapcolor[3] * ((rsurface.texture->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? rsurface.texture->r_water_wateralpha : 1)); + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]); + if (DPSOFTRAST_UNIFORM_Color_Pants >= 0) + { + if (rsurface.texture->pantstexture) + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]); + else + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Pants, 0, 0, 0); + } + if (DPSOFTRAST_UNIFORM_Color_Shirt >= 0) + { + if (rsurface.texture->shirttexture) + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]); + else + DPSOFTRAST_Uniform3f(DPSOFTRAST_UNIFORM_Color_Shirt, 0, 0, 0); + } + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogPlaneViewDist, rsurface.fogplaneviewdist); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogRangeRecip, rsurface.fograngerecip); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_FogHeightFade, rsurface.fogheightfade); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_OffsetMapping_ScaleSteps, + r_glsl_offsetmapping_scale.value*rsurface.texture->offsetscale, + max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), + max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) + ); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_OffsetMapping_Bias, rsurface.texture->offsetbias); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); + + R_Mesh_TexBind(GL20TU_NORMAL , rsurface.texture->nmaptexture ); + R_Mesh_TexBind(GL20TU_COLOR , rsurface.texture->basetexture ); + R_Mesh_TexBind(GL20TU_GLOSS , rsurface.texture->glosstexture ); + R_Mesh_TexBind(GL20TU_GLOW , rsurface.texture->glowtexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL , rsurface.texture->backgroundnmaptexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_COLOR , rsurface.texture->backgroundbasetexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS , rsurface.texture->backgroundglosstexture ); + if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) R_Mesh_TexBind(GL20TU_SECONDARY_GLOW , rsurface.texture->backgroundglowtexture ); + if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_PANTS , rsurface.texture->pantstexture ); + if (permutation & SHADERPERMUTATION_COLORMAPPING) R_Mesh_TexBind(GL20TU_SHIRT , rsurface.texture->shirttexture ); + if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTMASK , rsurface.texture->reflectmasktexture ); + if (permutation & SHADERPERMUTATION_REFLECTCUBE) R_Mesh_TexBind(GL20TU_REFLECTCUBE , rsurface.texture->reflectcubetexture ? rsurface.texture->reflectcubetexture : r_texture_whitecube); + if (permutation & SHADERPERMUTATION_FOGHEIGHTTEXTURE) R_Mesh_TexBind(GL20TU_FOGHEIGHTTEXTURE , r_texture_fogheighttexture ); + if (permutation & (SHADERPERMUTATION_FOGINSIDE | SHADERPERMUTATION_FOGOUTSIDE)) R_Mesh_TexBind(GL20TU_FOGMASK , r_texture_fogattenuation ); + R_Mesh_TexBind(GL20TU_LIGHTMAP , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white); + R_Mesh_TexBind(GL20TU_DELUXEMAP , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap); + if (rsurface.rtlight ) R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); + if (rsurfacepass == RSURFPASS_BACKGROUND) + { + R_Mesh_TexBind(GL20TU_REFRACTION , waterplane->texture_refraction ? waterplane->texture_refraction : r_texture_black); + if(mode == SHADERMODE_GENERIC) R_Mesh_TexBind(GL20TU_FIRST , waterplane->texture_camera ? waterplane->texture_camera : r_texture_black); + R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } + else + { + if (permutation & SHADERPERMUTATION_REFLECTION ) R_Mesh_TexBind(GL20TU_REFLECTION , waterplane->texture_reflection ? waterplane->texture_reflection : r_texture_black); + } +// if (rsurfacepass == RSURFPASS_DEFERREDLIGHT ) R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); + if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENDIFFUSE , r_shadow_prepasslightingdiffusetexture ); + if (permutation & SHADERPERMUTATION_DEFERREDLIGHTMAP ) R_Mesh_TexBind(GL20TU_SCREENSPECULAR , r_shadow_prepasslightingspeculartexture ); + if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))) + { + R_Mesh_TexBind(GL20TU_SHADOWMAP2D, r_shadow_shadowmap2ddepthtexture); + if (rsurface.rtlight) + { + if (permutation & SHADERPERMUTATION_CUBEFILTER ) R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); + if (permutation & SHADERPERMUTATION_SHADOWMAPVSDCT ) R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); + } + } + break; + } +} + +void R_SetupShader_DeferredLight(const rtlight_t *rtlight) +{ + // select a permutation of the lighting shader appropriate to this + // combination of texture, entity, light source, and fogging, only use the + // minimum features necessary to avoid wasting rendering time in the + // fragment shader on features that are not being used + unsigned int permutation = 0; + unsigned int mode = 0; + const float *lightcolorbase = rtlight->currentcolor; + float ambientscale = rtlight->ambientscale; + float diffusescale = rtlight->diffusescale; + float specularscale = rtlight->specularscale; + // this is the location of the light in view space + vec3_t viewlightorigin; + // this transforms from view space (camera) to light space (cubemap) + matrix4x4_t viewtolight; + matrix4x4_t lighttoview; + float viewtolight16f[16]; + // light source + mode = SHADERMODE_DEFERREDLIGHTSOURCE; + if (rtlight->currentcubemap != r_texture_whitecube) + permutation |= SHADERPERMUTATION_CUBEFILTER; + if (diffusescale > 0) + permutation |= SHADERPERMUTATION_DIFFUSE; + if (specularscale > 0 && r_shadow_gloss.integer > 0) + permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE; + if (r_shadow_usingshadowmap2d) + { + permutation |= SHADERPERMUTATION_SHADOWMAP2D; + if (r_shadow_shadowmapvsdct) + permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT; + + if (r_shadow_shadowmap2ddepthbuffer) + permutation |= SHADERPERMUTATION_DEPTHRGB; + } + if (vid.allowalphatocoverage) + GL_AlphaToCoverage(false); + Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin); + Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld); + Matrix4x4_Invert_Simple(&viewtolight, &lighttoview); + Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f); + switch(vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + R_SetupShader_SetPermutationHLSL(mode, permutation); + hlslPSSetParameter3f(D3DPSREGISTER_LightPosition, viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); + hlslPSSetParameter16f(D3DPSREGISTER_ViewToLight, viewtolight16f); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + hlslPSSetParameter3f(D3DPSREGISTER_DeferredColor_Specular, lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); + hlslPSSetParameter2f(D3DPSREGISTER_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + hlslPSSetParameter4f(D3DPSREGISTER_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + hlslPSSetParameter1f(D3DPSREGISTER_SpecularPower, (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); + + R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); + R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); + R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2ddepthtexture ); + R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + R_SetupShader_SetPermutationGLSL(mode, permutation); + if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f( r_glsl_permutation->loc_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); + if (r_glsl_permutation->loc_ViewToLight >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight , 1, false, viewtolight16f); + if (r_glsl_permutation->loc_DeferredColor_Ambient >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + if (r_glsl_permutation->loc_DeferredColor_Diffuse >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + if (r_glsl_permutation->loc_DeferredColor_Specular >= 0) qglUniform3f( r_glsl_permutation->loc_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); + if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2f( r_glsl_permutation->loc_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f( r_glsl_permutation->loc_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f( r_glsl_permutation->loc_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f( r_glsl_permutation->loc_ScreenToDepth , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f( r_glsl_permutation->loc_PixelToScreenTexCoord , 1.0f/vid.width, 1.0f/vid.height); + + if (r_glsl_permutation->tex_Texture_Attenuation >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation , r_shadow_attenuationgradienttexture ); + if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap , r_shadow_prepassgeometrynormalmaptexture ); + if (r_glsl_permutation->tex_Texture_Cube >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube , rsurface.rtlight->currentcubemap ); + if (r_glsl_permutation->tex_Texture_ShadowMap2D >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D , r_shadow_shadowmap2ddepthtexture ); + if (r_glsl_permutation->tex_Texture_CubeProjection >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection , r_shadow_shadowmapvsdcttexture ); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + break; + case RENDERPATH_SOFT: + R_SetupShader_SetPermutationGLSL(mode, permutation); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_LightPosition , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]); + DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ViewToLightM1 , 1, false, viewtolight16f); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Ambient , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale ); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Diffuse , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale ); + DPSOFTRAST_Uniform3f( DPSOFTRAST_UNIFORM_DeferredColor_Specular , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale); + DPSOFTRAST_Uniform2f( DPSOFTRAST_UNIFORM_ShadowMap_TextureScale , r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]); + DPSOFTRAST_Uniform4f( DPSOFTRAST_UNIFORM_ShadowMap_Parameters , r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]); + DPSOFTRAST_Uniform1f( DPSOFTRAST_UNIFORM_SpecularPower , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f); + DPSOFTRAST_Uniform2f( DPSOFTRAST_UNIFORM_ScreenToDepth , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); + + R_Mesh_TexBind(GL20TU_ATTENUATION , r_shadow_attenuationgradienttexture ); + R_Mesh_TexBind(GL20TU_SCREENNORMALMAP , r_shadow_prepassgeometrynormalmaptexture ); + R_Mesh_TexBind(GL20TU_CUBE , rsurface.rtlight->currentcubemap ); + R_Mesh_TexBind(GL20TU_SHADOWMAP2D , r_shadow_shadowmap2ddepthtexture ); + R_Mesh_TexBind(GL20TU_CUBEPROJECTION , r_shadow_shadowmapvsdcttexture ); + break; + } +} + +#define SKINFRAME_HASH 1024 + +typedef struct +{ + int loadsequence; // incremented each level change + memexpandablearray_t array; + skinframe_t *hash[SKINFRAME_HASH]; +} +r_skinframe_t; +r_skinframe_t r_skinframe; + +void R_SkinFrame_PrepareForPurge(void) +{ + r_skinframe.loadsequence++; + // wrap it without hitting zero + if (r_skinframe.loadsequence >= 200) + r_skinframe.loadsequence = 1; +} + +void R_SkinFrame_MarkUsed(skinframe_t *skinframe) +{ + if (!skinframe) + return; + // mark the skinframe as used for the purging code + skinframe->loadsequence = r_skinframe.loadsequence; +} + +void R_SkinFrame_Purge(void) +{ + int i; + skinframe_t *s; + for (i = 0;i < SKINFRAME_HASH;i++) + { + for (s = r_skinframe.hash[i];s;s = s->next) + { + if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence) + { + if (s->merged == s->base) + s->merged = NULL; + // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black] + R_PurgeTexture(s->stain );s->stain = NULL; + R_PurgeTexture(s->merged);s->merged = NULL; + R_PurgeTexture(s->base );s->base = NULL; + R_PurgeTexture(s->pants );s->pants = NULL; + R_PurgeTexture(s->shirt );s->shirt = NULL; + R_PurgeTexture(s->nmap );s->nmap = NULL; + R_PurgeTexture(s->gloss );s->gloss = NULL; + R_PurgeTexture(s->glow );s->glow = NULL; + R_PurgeTexture(s->fog );s->fog = NULL; + R_PurgeTexture(s->reflect);s->reflect = NULL; + s->loadsequence = 0; + } + } + } +} + +skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) { + skinframe_t *item; + char basename[MAX_QPATH]; + + Image_StripImageExtension(name, basename, sizeof(basename)); + + if( last == NULL ) { + int hashindex; + hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1); + item = r_skinframe.hash[hashindex]; + } else { + item = last->next; + } + + // linearly search through the hash bucket + for( ; item ; item = item->next ) { + if( !strcmp( item->basename, basename ) ) { + return item; + } + } + return NULL; +} + +skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add) +{ + skinframe_t *item; + int hashindex; + char basename[MAX_QPATH]; + + Image_StripImageExtension(name, basename, sizeof(basename)); + + hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1); + for (item = r_skinframe.hash[hashindex];item;item = item->next) + if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc))) + break; + + if (!item) { + rtexture_t *dyntexture; + // check whether its a dynamic texture + dyntexture = CL_GetDynTexture( basename ); + if (!add && !dyntexture) + return NULL; + item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array); + memset(item, 0, sizeof(*item)); + strlcpy(item->basename, basename, sizeof(item->basename)); + item->base = dyntexture; // either NULL or dyntexture handle + item->textureflags = textureflags & ~TEXF_FORCE_RELOAD; + item->comparewidth = comparewidth; + item->compareheight = compareheight; + item->comparecrc = comparecrc; + item->next = r_skinframe.hash[hashindex]; + r_skinframe.hash[hashindex] = item; + } + else if (textureflags & TEXF_FORCE_RELOAD) + { + rtexture_t *dyntexture; + // check whether its a dynamic texture + dyntexture = CL_GetDynTexture( basename ); + if (!add && !dyntexture) + return NULL; + if (item->merged == item->base) + item->merged = NULL; + // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black] + R_PurgeTexture(item->stain );item->stain = NULL; + R_PurgeTexture(item->merged);item->merged = NULL; + R_PurgeTexture(item->base );item->base = NULL; + R_PurgeTexture(item->pants );item->pants = NULL; + R_PurgeTexture(item->shirt );item->shirt = NULL; + R_PurgeTexture(item->nmap );item->nmap = NULL; + R_PurgeTexture(item->gloss );item->gloss = NULL; + R_PurgeTexture(item->glow );item->glow = NULL; + R_PurgeTexture(item->fog );item->fog = NULL; + R_PurgeTexture(item->reflect);item->reflect = NULL; + item->loadsequence = 0; + } + else if( item->base == NULL ) + { + rtexture_t *dyntexture; + // check whether its a dynamic texture + // this only needs to be done because Purge doesnt delete skinframes - only sets the texture pointers to NULL and we need to restore it before returing.. [11/29/2007 Black] + dyntexture = CL_GetDynTexture( basename ); + item->base = dyntexture; // either NULL or dyntexture handle + } + + R_SkinFrame_MarkUsed(item); + return item; +} + +#define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \ + { \ + unsigned long long avgcolor[5], wsum; \ + int pix, comp, w; \ + avgcolor[0] = 0; \ + avgcolor[1] = 0; \ + avgcolor[2] = 0; \ + avgcolor[3] = 0; \ + avgcolor[4] = 0; \ + wsum = 0; \ + for(pix = 0; pix < cnt; ++pix) \ + { \ + w = 0; \ + for(comp = 0; comp < 3; ++comp) \ + w += getpixel; \ + if(w) /* ignore perfectly black pixels because that is better for model skins */ \ + { \ + ++wsum; \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + w = getpixel; \ + for(comp = 0; comp < 3; ++comp) \ + avgcolor[comp] += getpixel * w; \ + avgcolor[3] += w; \ + } \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + avgcolor[4] += getpixel; \ + } \ + if(avgcolor[3] == 0) /* no pixels seen? even worse */ \ + avgcolor[3] = 1; \ + skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \ + } + +extern cvar_t gl_picmip; +skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) +{ + int j; + unsigned char *pixels; + unsigned char *bumppixels; + unsigned char *basepixels = NULL; + int basepixels_width = 0; + int basepixels_height = 0; + skinframe_t *skinframe; + rtexture_t *ddsbase = NULL; + qboolean ddshasalpha = false; + float ddsavgcolor[4]; + char basename[MAX_QPATH]; + int miplevel = R_PicmipForFlags(textureflags); + int savemiplevel = miplevel; + int mymiplevel; + char vabuf[1024]; + + if (cls.state == ca_dedicated) + return NULL; + + // return an existing skinframe if already loaded + // if loading of the first image fails, don't make a new skinframe as it + // would cause all future lookups of this to be missing + skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false); + if (skinframe && skinframe->base) + return skinframe; + + Image_StripImageExtension(name, basename, sizeof(basename)); + + // check for DDS texture file first + if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false))) + { + basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel); + if (basepixels == NULL) + return NULL; + } + + // FIXME handle miplevel + + if (developer_loading.integer) + Con_Printf("loading skin \"%s\"\n", name); + + // we've got some pixels to store, so really allocate this new texture now + if (!skinframe) + skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true); + textureflags &= ~TEXF_FORCE_RELOAD; + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = false; + + if (ddsbase) + { + skinframe->base = ddsbase; + skinframe->hasalpha = ddshasalpha; + VectorCopy(ddsavgcolor, skinframe->avgcolor); + if (r_loadfog && skinframe->hasalpha) + skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + } + else + { + basepixels_width = image_width; + basepixels_height = image_height; + skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL); + if (textureflags & TEXF_ALPHA) + { + for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) + { + if (basepixels[j] < 255) + { + skinframe->hasalpha = true; + break; + } + } + if (r_loadfog && skinframe->hasalpha) + { + // has transparent pixels + pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + for (j = 0;j < image_width * image_height * 4;j += 4) + { + pixels[j+0] = 255; + pixels[j+1] = 255; + pixels[j+2] = 255; + pixels[j+3] = basepixels[j+3]; + } + skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL); + Mem_Free(pixels); + } + } + R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]); +#ifndef USE_GLES2 + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + if (r_savedds && qglGetCompressedTexImageARB && skinframe->base) + R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha); + if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog) + R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); +#endif + } + + if (r_loaddds) + { + mymiplevel = savemiplevel; + if (r_loadnormalmap) + skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true); + skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + if (r_loadgloss) + skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true); + } + + // _norm is the name used by tenebrae and has been adopted as standard + if (r_loadnormalmap && skinframe->nmap == NULL) + { + mymiplevel = savemiplevel; + if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL) + { + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + Mem_Free(pixels); + pixels = NULL; + } + else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL) + { + pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value); + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + Mem_Free(pixels); + Mem_Free(bumppixels); + } + else if (r_shadow_bumpscale_basetexture.value > 0) + { + pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4); + Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value); + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); + Mem_Free(pixels); + } +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap) + R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); +#endif + } + + // _luma is supported only for tenebrae compatibility + // _glow is the preferred name + mymiplevel = savemiplevel; + if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel)))) + { + skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow) + R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); +#endif + Mem_Free(pixels);pixels = NULL; + } + + mymiplevel = savemiplevel; + if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel))) + { + skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss) + R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); +#endif + Mem_Free(pixels); + pixels = NULL; + } + + mymiplevel = savemiplevel; + if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel))) + { + skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants) + R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); +#endif + Mem_Free(pixels); + pixels = NULL; + } + + mymiplevel = savemiplevel; + if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel))) + { + skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt) + R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false); +#endif + Mem_Free(pixels); + pixels = NULL; + } + + mymiplevel = savemiplevel; + if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel))) + { + skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL); +#ifndef USE_GLES2 + if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect) + R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true); +#endif + Mem_Free(pixels); + pixels = NULL; + } + + if (basepixels) + Mem_Free(basepixels); + + return skinframe; +} + +// this is only used by .spr32 sprites, HL .spr files, HL .bsp files +skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB) +{ + int i; + unsigned char *temp1, *temp2; + skinframe_t *skinframe; + char vabuf[1024]; + + if (cls.state == ca_dedicated) + return NULL; + + // if already loaded just return it, otherwise make a new skinframe + skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true); + if (skinframe->base) + return skinframe; + textureflags &= ~TEXF_FORCE_RELOAD; + + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = false; + + // if no data was provided, then clearly the caller wanted to get a blank skinframe + if (!skindata) + return NULL; + + if (developer_loading.integer) + Con_Printf("loading 32bit skin \"%s\"\n", name); + + if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0) + { + temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8); + temp2 = temp1 + width * height * 4; + Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value); + skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); + Mem_Free(temp1); + } + skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL); + if (textureflags & TEXF_ALPHA) + { + for (i = 3;i < width * height * 4;i += 4) + { + if (skindata[i] < 255) + { + skinframe->hasalpha = true; + break; + } + } + if (r_loadfog && skinframe->hasalpha) + { + unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4); + memcpy(fogpixels, skindata, width * height * 4); + for (i = 0;i < width * height * 4;i += 4) + fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255; + skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL); + Mem_Free(fogpixels); + } + } + + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + + return skinframe; +} + +skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height) +{ + int i; + int featuresmask; + skinframe_t *skinframe; + + if (cls.state == ca_dedicated) + return NULL; + + // if already loaded just return it, otherwise make a new skinframe + skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true); + if (skinframe->base) + return skinframe; + //textureflags &= ~TEXF_FORCE_RELOAD; + + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = false; + + // if no data was provided, then clearly the caller wanted to get a blank skinframe + if (!skindata) + return NULL; + + if (developer_loading.integer) + Con_Printf("loading quake skin \"%s\"\n", name); + + // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped) + skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK + memcpy(skinframe->qpixels, skindata, width*height); + skinframe->qwidth = width; + skinframe->qheight = height; + + featuresmask = 0; + for (i = 0;i < width * height;i++) + featuresmask |= palette_featureflags[skindata[i]]; + + skinframe->hasalpha = false; + skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT)); + skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0; + skinframe->qgeneratemerged = true; + skinframe->qgeneratebase = skinframe->qhascolormapping; + skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW); + + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + + return skinframe; +} + +static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped) +{ + int width; + int height; + unsigned char *skindata; + char vabuf[1024]; + + if (!skinframe->qpixels) + return; + + if (!skinframe->qhascolormapping) + colormapped = false; + + if (colormapped) + { + if (!skinframe->qgeneratebase) + return; + } + else + { + if (!skinframe->qgeneratemerged) + return; + } + + width = skinframe->qwidth; + height = skinframe->qheight; + skindata = skinframe->qpixels; + + if (skinframe->qgeneratenmap) + { + unsigned char *temp1, *temp2; + skinframe->qgeneratenmap = false; + temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8); + temp2 = temp1 + width * height * 4; + // use either a custom palette or the quake palette + Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete); + Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value); + skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL); + Mem_Free(temp1); + } + + if (skinframe->qgenerateglow) + { + skinframe->qgenerateglow = false; + skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow + } + + if (colormapped) + { + skinframe->qgeneratebase = false; + skinframe->base = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap); + skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite); + skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite); + } + else + { + skinframe->qgeneratemerged = false; + skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete); + } + + if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase) + { + Mem_Free(skinframe->qpixels); + skinframe->qpixels = NULL; + } +} + +skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette) +{ + int i; + skinframe_t *skinframe; + char vabuf[1024]; + + if (cls.state == ca_dedicated) + return NULL; + + // if already loaded just return it, otherwise make a new skinframe + skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true); + if (skinframe->base) + return skinframe; + textureflags &= ~TEXF_FORCE_RELOAD; + + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = false; + + // if no data was provided, then clearly the caller wanted to get a blank skinframe + if (!skindata) + return NULL; + + if (developer_loading.integer) + Con_Printf("loading embedded 8bit image \"%s\"\n", name); + + skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette); + if (textureflags & TEXF_ALPHA) + { + for (i = 0;i < width * height;i++) + { + if (((unsigned char *)palette)[skindata[i]*4+3] < 255) + { + skinframe->hasalpha = true; + break; + } + } + if (r_loadfog && skinframe->hasalpha) + skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette); + } + + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + + return skinframe; +} + +skinframe_t *R_SkinFrame_LoadMissing(void) +{ + skinframe_t *skinframe; + + if (cls.state == ca_dedicated) + return NULL; + + skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true); + skinframe->stain = NULL; + skinframe->merged = NULL; + skinframe->base = NULL; + skinframe->pants = NULL; + skinframe->shirt = NULL; + skinframe->nmap = NULL; + skinframe->gloss = NULL; + skinframe->glow = NULL; + skinframe->fog = NULL; + skinframe->reflect = NULL; + skinframe->hasalpha = false; + + skinframe->avgcolor[0] = rand() / RAND_MAX; + skinframe->avgcolor[1] = rand() / RAND_MAX; + skinframe->avgcolor[2] = rand() / RAND_MAX; + skinframe->avgcolor[3] = 1; + + return skinframe; +} + +//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"}; +typedef struct suffixinfo_s +{ + const char *suffix; + qboolean flipx, flipy, flipdiagonal; +} +suffixinfo_t; +static suffixinfo_t suffix[3][6] = +{ + { + {"px", false, false, false}, + {"nx", false, false, false}, + {"py", false, false, false}, + {"ny", false, false, false}, + {"pz", false, false, false}, + {"nz", false, false, false} + }, + { + {"posx", false, false, false}, + {"negx", false, false, false}, + {"posy", false, false, false}, + {"negy", false, false, false}, + {"posz", false, false, false}, + {"negz", false, false, false} + }, + { + {"rt", true, false, true}, + {"lf", false, true, true}, + {"ft", true, true, false}, + {"bk", false, false, false}, + {"up", true, false, true}, + {"dn", true, false, true} + } +}; + +static int componentorder[4] = {0, 1, 2, 3}; + +static rtexture_t *R_LoadCubemap(const char *basename) +{ + int i, j, cubemapsize; + unsigned char *cubemappixels, *image_buffer; + rtexture_t *cubemaptexture; + char name[256]; + // must start 0 so the first loadimagepixels has no requested width/height + cubemapsize = 0; + cubemappixels = NULL; + cubemaptexture = NULL; + // keep trying different suffix groups (posx, px, rt) until one loads + for (j = 0;j < 3 && !cubemappixels;j++) + { + // load the 6 images in the suffix group + for (i = 0;i < 6;i++) + { + // generate an image name based on the base and and suffix + dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix); + // load it + if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) + { + // an image loaded, make sure width and height are equal + if (image_width == image_height && (!cubemappixels || image_width == cubemapsize)) + { + // if this is the first image to load successfully, allocate the cubemap memory + if (!cubemappixels && image_width >= 1) + { + cubemapsize = image_width; + // note this clears to black, so unavailable sides are black + cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4); + } + // copy the image with any flipping needed by the suffix (px and posx types don't need flipping) + if (cubemappixels) + Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder); + } + else + Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height); + // free the image + Mem_Free(image_buffer); + } + } + } + // if a cubemap loaded, upload it + if (cubemappixels) + { + if (developer_loading.integer) + Con_Printf("loading cubemap \"%s\"\n", basename); + + cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + Mem_Free(cubemappixels); + } + else + { + Con_DPrintf("failed to load cubemap \"%s\"\n", basename); + if (developer_loading.integer) + { + Con_Printf("(tried tried images "); + for (j = 0;j < 3;j++) + for (i = 0;i < 6;i++) + Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix); + Con_Print(" and was unable to find any of them).\n"); + } + } + return cubemaptexture; +} + +rtexture_t *R_GetCubemap(const char *basename) +{ + int i; + for (i = 0;i < r_texture_numcubemaps;i++) + if (r_texture_cubemaps[i] != NULL) + if (!strcasecmp(r_texture_cubemaps[i]->basename, basename)) + return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube; + if (i >= MAX_CUBEMAPS || !r_main_mempool) + return r_texture_whitecube; + r_texture_numcubemaps++; + r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t)); + strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename)); + r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename); + return r_texture_cubemaps[i]->texture; +} + +static void R_Main_FreeViewCache(void) +{ + if (r_refdef.viewcache.entityvisible) + Mem_Free(r_refdef.viewcache.entityvisible); + if (r_refdef.viewcache.world_pvsbits) + Mem_Free(r_refdef.viewcache.world_pvsbits); + if (r_refdef.viewcache.world_leafvisible) + Mem_Free(r_refdef.viewcache.world_leafvisible); + if (r_refdef.viewcache.world_surfacevisible) + Mem_Free(r_refdef.viewcache.world_surfacevisible); + memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache)); +} + +static void R_Main_ResizeViewCache(void) +{ + int numentities = r_refdef.scene.numentities; + int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1; + int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1; + int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1; + int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1; + if (r_refdef.viewcache.maxentities < numentities) + { + r_refdef.viewcache.maxentities = numentities; + if (r_refdef.viewcache.entityvisible) + Mem_Free(r_refdef.viewcache.entityvisible); + r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities); + } + if (r_refdef.viewcache.world_numclusters != numclusters) + { + r_refdef.viewcache.world_numclusters = numclusters; + r_refdef.viewcache.world_numclusterbytes = numclusterbytes; + if (r_refdef.viewcache.world_pvsbits) + Mem_Free(r_refdef.viewcache.world_pvsbits); + r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes); + } + if (r_refdef.viewcache.world_numleafs != numleafs) + { + r_refdef.viewcache.world_numleafs = numleafs; + if (r_refdef.viewcache.world_leafvisible) + Mem_Free(r_refdef.viewcache.world_leafvisible); + r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs); + } + if (r_refdef.viewcache.world_numsurfaces != numsurfaces) + { + r_refdef.viewcache.world_numsurfaces = numsurfaces; + if (r_refdef.viewcache.world_surfacevisible) + Mem_Free(r_refdef.viewcache.world_surfacevisible); + r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces); + } +} + +extern rtexture_t *loadingscreentexture; +static void gl_main_start(void) +{ + loadingscreentexture = NULL; + r_texture_blanknormalmap = NULL; + r_texture_white = NULL; + r_texture_grey128 = NULL; + r_texture_black = NULL; + r_texture_whitecube = NULL; + r_texture_normalizationcube = NULL; + r_texture_fogattenuation = NULL; + r_texture_fogheighttexture = NULL; + r_texture_gammaramps = NULL; + r_texture_numcubemaps = 0; + r_uniformbufferalignment = 32; + + r_loaddds = r_texture_dds_load.integer != 0; + r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer; + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + Cvar_SetValueQuick(&r_textureunits, vid.texunits); + Cvar_SetValueQuick(&gl_combine, 1); + Cvar_SetValueQuick(&r_glsl, 1); + r_loadnormalmap = true; + r_loadgloss = true; + r_loadfog = false; + if (vid.support.arb_uniform_buffer_object) + qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + Cvar_SetValueQuick(&r_textureunits, vid.texunits); + Cvar_SetValueQuick(&gl_combine, 1); + Cvar_SetValueQuick(&r_glsl, 0); + r_loadnormalmap = false; + r_loadgloss = false; + r_loadfog = true; + break; + case RENDERPATH_GL11: + Cvar_SetValueQuick(&r_textureunits, vid.texunits); + Cvar_SetValueQuick(&gl_combine, 0); + Cvar_SetValueQuick(&r_glsl, 0); + r_loadnormalmap = false; + r_loadgloss = false; + r_loadfog = true; + break; + } + + R_AnimCache_Free(); + R_FrameData_Reset(); + R_BufferData_Reset(); + + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + + r_qwskincache = NULL; + r_qwskincache_size = 0; + + // due to caching of texture_t references, the collision cache must be reset + Collision_Cache_Reset(true); + + // set up r_skinframe loading system for textures + memset(&r_skinframe, 0, sizeof(r_skinframe)); + r_skinframe.loadsequence = 1; + Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256); + + r_main_texturepool = R_AllocTexturePool(); + R_BuildBlankTextures(); + R_BuildNoTexture(); + if (vid.support.arb_texture_cube_map) + { + R_BuildWhiteCube(); + R_BuildNormalizationCube(); + } + r_texture_fogattenuation = NULL; + r_texture_fogheighttexture = NULL; + r_texture_gammaramps = NULL; + //r_texture_fogintensity = NULL; + memset(&r_fb, 0, sizeof(r_fb)); + r_glsl_permutation = NULL; + memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash)); + Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256); + glslshaderstring = NULL; +#ifdef SUPPORTD3D + r_hlsl_permutation = NULL; + memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash)); + Mem_ExpandableArray_NewArray(&r_hlsl_permutationarray, r_main_mempool, sizeof(r_hlsl_permutation_t), 256); +#endif + hlslshaderstring = NULL; + memset(&r_svbsp, 0, sizeof (r_svbsp)); + + memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps)); + r_texture_numcubemaps = 0; + + r_refdef.fogmasktable_density = 0; +} + +static void gl_main_shutdown(void) +{ + R_AnimCache_Free(); + R_FrameData_Reset(); + R_BufferData_Reset(); + + R_Main_FreeViewCache(); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef GL_SAMPLES_PASSED_ARB + if (r_maxqueries) + qglDeleteQueriesARB(r_maxqueries, r_queries); +#endif + break; + case RENDERPATH_D3D9: + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } + + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + + r_qwskincache = NULL; + r_qwskincache_size = 0; + + // clear out the r_skinframe state + Mem_ExpandableArray_FreeArray(&r_skinframe.array); + memset(&r_skinframe, 0, sizeof(r_skinframe)); + + if (r_svbsp.nodes) + Mem_Free(r_svbsp.nodes); + memset(&r_svbsp, 0, sizeof (r_svbsp)); + R_FreeTexturePool(&r_main_texturepool); + loadingscreentexture = NULL; + r_texture_blanknormalmap = NULL; + r_texture_white = NULL; + r_texture_grey128 = NULL; + r_texture_black = NULL; + r_texture_whitecube = NULL; + r_texture_normalizationcube = NULL; + r_texture_fogattenuation = NULL; + r_texture_fogheighttexture = NULL; + r_texture_gammaramps = NULL; + r_texture_numcubemaps = 0; + //r_texture_fogintensity = NULL; + memset(&r_fb, 0, sizeof(r_fb)); + R_GLSL_Restart_f(); + + r_glsl_permutation = NULL; + memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash)); + Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray); + glslshaderstring = NULL; +#ifdef SUPPORTD3D + r_hlsl_permutation = NULL; + memset(r_hlsl_permutationhash, 0, sizeof(r_hlsl_permutationhash)); + Mem_ExpandableArray_FreeArray(&r_hlsl_permutationarray); +#endif + hlslshaderstring = NULL; +} + +static void gl_main_newmap(void) +{ + // FIXME: move this code to client + char *entities, entname[MAX_QPATH]; + if (r_qwskincache) + Mem_Free(r_qwskincache); + r_qwskincache = NULL; + r_qwskincache_size = 0; + if (cl.worldmodel) + { + dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension); + if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL))) + { + CL_ParseEntityLump(entities); + Mem_Free(entities); + return; + } + if (cl.worldmodel->brush.entities) + CL_ParseEntityLump(cl.worldmodel->brush.entities); + } + R_Main_FreeViewCache(); + + R_FrameData_Reset(); + R_BufferData_Reset(); +} + +void GL_Main_Init(void) +{ + int i; + r_main_mempool = Mem_AllocPool("Renderer", 0, NULL); + + Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed"); + Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl"); + // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable + if (gamemode == GAME_NEHAHRA) + { + Cvar_RegisterVariable (&gl_fogenable); + Cvar_RegisterVariable (&gl_fogdensity); + Cvar_RegisterVariable (&gl_fogred); + Cvar_RegisterVariable (&gl_foggreen); + Cvar_RegisterVariable (&gl_fogblue); + Cvar_RegisterVariable (&gl_fogstart); + Cvar_RegisterVariable (&gl_fogend); + Cvar_RegisterVariable (&gl_skyclip); + } + Cvar_RegisterVariable(&r_worldscale); + Cvar_RegisterVariable(&r_motionblur); + Cvar_RegisterVariable(&r_damageblur); + Cvar_RegisterVariable(&r_motionblur_averaging); + Cvar_RegisterVariable(&r_motionblur_randomize); + Cvar_RegisterVariable(&r_motionblur_minblur); + Cvar_RegisterVariable(&r_motionblur_maxblur); + Cvar_RegisterVariable(&r_motionblur_velocityfactor); + Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed); + Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed); + Cvar_RegisterVariable(&r_motionblur_mousefactor); + Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed); + Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed); + Cvar_RegisterVariable(&r_equalize_entities_fullbright); + Cvar_RegisterVariable(&r_equalize_entities_minambient); + Cvar_RegisterVariable(&r_equalize_entities_by); + Cvar_RegisterVariable(&r_equalize_entities_to); + Cvar_RegisterVariable(&r_depthfirst); + Cvar_RegisterVariable(&r_useinfinitefarclip); + Cvar_RegisterVariable(&r_farclip_base); + Cvar_RegisterVariable(&r_farclip_world); + Cvar_RegisterVariable(&r_nearclip); + Cvar_RegisterVariable(&r_deformvertexes); + Cvar_RegisterVariable(&r_transparent); + Cvar_RegisterVariable(&r_transparent_alphatocoverage); + Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest); + Cvar_RegisterVariable(&r_transparent_useplanardistance); + Cvar_RegisterVariable(&r_showoverdraw); + Cvar_RegisterVariable(&r_showbboxes); + Cvar_RegisterVariable(&r_showsurfaces); + Cvar_RegisterVariable(&r_showtris); + Cvar_RegisterVariable(&r_shownormals); + Cvar_RegisterVariable(&r_showlighting); + Cvar_RegisterVariable(&r_showshadowvolumes); + Cvar_RegisterVariable(&r_showcollisionbrushes); + Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor); + Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset); + Cvar_RegisterVariable(&r_showdisabledepthtest); + Cvar_RegisterVariable(&r_drawportals); + Cvar_RegisterVariable(&r_drawentities); + Cvar_RegisterVariable(&r_draw2d); + Cvar_RegisterVariable(&r_drawworld); + Cvar_RegisterVariable(&r_cullentities_trace); + Cvar_RegisterVariable(&r_cullentities_trace_samples); + Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples); + Cvar_RegisterVariable(&r_cullentities_trace_enlarge); + Cvar_RegisterVariable(&r_cullentities_trace_delay); + Cvar_RegisterVariable(&r_sortentities); + Cvar_RegisterVariable(&r_drawviewmodel); + Cvar_RegisterVariable(&r_drawexteriormodel); + Cvar_RegisterVariable(&r_speeds); + Cvar_RegisterVariable(&r_fullbrights); + Cvar_RegisterVariable(&r_wateralpha); + Cvar_RegisterVariable(&r_dynamic); + Cvar_RegisterVariable(&r_fakelight); + Cvar_RegisterVariable(&r_fakelight_intensity); + Cvar_RegisterVariable(&r_fullbright); + Cvar_RegisterVariable(&r_shadows); + Cvar_RegisterVariable(&r_shadows_darken); + Cvar_RegisterVariable(&r_shadows_drawafterrtlighting); + Cvar_RegisterVariable(&r_shadows_castfrombmodels); + Cvar_RegisterVariable(&r_shadows_throwdistance); + Cvar_RegisterVariable(&r_shadows_throwdirection); + Cvar_RegisterVariable(&r_shadows_focus); + Cvar_RegisterVariable(&r_shadows_shadowmapscale); + Cvar_RegisterVariable(&r_shadows_shadowmapbias); + Cvar_RegisterVariable(&r_q1bsp_skymasking); + Cvar_RegisterVariable(&r_polygonoffset_submodel_factor); + Cvar_RegisterVariable(&r_polygonoffset_submodel_offset); + Cvar_RegisterVariable(&r_polygonoffset_decals_factor); + Cvar_RegisterVariable(&r_polygonoffset_decals_offset); + Cvar_RegisterVariable(&r_fog_exp2); + Cvar_RegisterVariable(&r_fog_clear); + Cvar_RegisterVariable(&r_drawfog); + Cvar_RegisterVariable(&r_transparentdepthmasking); + Cvar_RegisterVariable(&r_transparent_sortmindist); + Cvar_RegisterVariable(&r_transparent_sortmaxdist); + Cvar_RegisterVariable(&r_transparent_sortarraysize); + Cvar_RegisterVariable(&r_texture_dds_load); + Cvar_RegisterVariable(&r_texture_dds_save); + Cvar_RegisterVariable(&r_textureunits); + Cvar_RegisterVariable(&gl_combine); + Cvar_RegisterVariable(&r_usedepthtextures); + Cvar_RegisterVariable(&r_viewfbo); + Cvar_RegisterVariable(&r_viewscale); + Cvar_RegisterVariable(&r_viewscale_fpsscaling); + Cvar_RegisterVariable(&r_viewscale_fpsscaling_min); + Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply); + Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize); + Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax); + Cvar_RegisterVariable(&r_viewscale_fpsscaling_target); + Cvar_RegisterVariable(&r_glsl); + Cvar_RegisterVariable(&r_glsl_deluxemapping); + Cvar_RegisterVariable(&r_glsl_offsetmapping); + Cvar_RegisterVariable(&r_glsl_offsetmapping_steps); + Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping); + Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps); + Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps); + Cvar_RegisterVariable(&r_glsl_offsetmapping_scale); + Cvar_RegisterVariable(&r_glsl_offsetmapping_lod); + Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance); + Cvar_RegisterVariable(&r_glsl_postprocess); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec1); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec2); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec3); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec4); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable); + Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable); + Cvar_RegisterVariable(&r_celshading); + Cvar_RegisterVariable(&r_celoutlines); + + Cvar_RegisterVariable(&r_water); + Cvar_RegisterVariable(&r_water_resolutionmultiplier); + Cvar_RegisterVariable(&r_water_clippingplanebias); + Cvar_RegisterVariable(&r_water_refractdistort); + Cvar_RegisterVariable(&r_water_reflectdistort); + Cvar_RegisterVariable(&r_water_scissormode); + Cvar_RegisterVariable(&r_water_lowquality); + Cvar_RegisterVariable(&r_water_hideplayer); + Cvar_RegisterVariable(&r_water_fbo); + + Cvar_RegisterVariable(&r_lerpsprites); + Cvar_RegisterVariable(&r_lerpmodels); + Cvar_RegisterVariable(&r_lerplightstyles); + Cvar_RegisterVariable(&r_waterscroll); + Cvar_RegisterVariable(&r_bloom); + Cvar_RegisterVariable(&r_bloom_colorscale); + Cvar_RegisterVariable(&r_bloom_brighten); + Cvar_RegisterVariable(&r_bloom_blur); + Cvar_RegisterVariable(&r_bloom_resolution); + Cvar_RegisterVariable(&r_bloom_colorexponent); + Cvar_RegisterVariable(&r_bloom_colorsubtract); + Cvar_RegisterVariable(&r_bloom_scenebrightness); + Cvar_RegisterVariable(&r_hdr_scenebrightness); + Cvar_RegisterVariable(&r_hdr_glowintensity); + Cvar_RegisterVariable(&r_hdr_irisadaptation); + Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier); + Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue); + Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue); + Cvar_RegisterVariable(&r_hdr_irisadaptation_value); + Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up); + Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down); + Cvar_RegisterVariable(&r_hdr_irisadaptation_radius); + Cvar_RegisterVariable(&r_smoothnormals_areaweighting); + Cvar_RegisterVariable(&developer_texturelogging); + Cvar_RegisterVariable(&gl_lightmaps); + Cvar_RegisterVariable(&r_test); + Cvar_RegisterVariable(&r_batch_multidraw); + Cvar_RegisterVariable(&r_batch_multidraw_mintriangles); + Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath); + Cvar_RegisterVariable(&r_glsl_skeletal); + Cvar_RegisterVariable(&r_glsl_saturation); + Cvar_RegisterVariable(&r_glsl_saturation_redcompensate); + Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas); + Cvar_RegisterVariable(&r_framedatasize); + for (i = 0;i < R_BUFFERDATA_COUNT;i++) + Cvar_RegisterVariable(&r_buffermegs[i]); + Cvar_RegisterVariable(&r_batch_dynamicbuffer); + if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE) + Cvar_SetValue("r_fullbrights", 0); + R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL); +} + +void Render_Init(void) +{ + gl_backend_init(); + R_Textures_Init(); + GL_Main_Init(); + Font_Init(); + GL_Draw_Init(); + R_Shadow_Init(); + R_Sky_Init(); + GL_Surf_Init(); + Sbar_Init(); + R_Particles_Init(); + R_Explosion_Init(); + R_LightningBeams_Init(); + Mod_RenderInit(); +} + +/* +=============== +GL_Init +=============== +*/ +#ifndef USE_GLES2 +extern char *ENGINE_EXTENSIONS; +void GL_Init (void) +{ + gl_renderer = (const char *)qglGetString(GL_RENDERER); + gl_vendor = (const char *)qglGetString(GL_VENDOR); + gl_version = (const char *)qglGetString(GL_VERSION); + gl_extensions = (const char *)qglGetString(GL_EXTENSIONS); + + if (!gl_extensions) + gl_extensions = ""; + if (!gl_platformextensions) + gl_platformextensions = ""; + + Con_Printf("GL_VENDOR: %s\n", gl_vendor); + Con_Printf("GL_RENDERER: %s\n", gl_renderer); + Con_Printf("GL_VERSION: %s\n", gl_version); + Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions); + Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); + + VID_CheckExtensions(); + + // LordHavoc: report supported extensions + Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); + + // clear to black (loading plaque will be seen over this) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); +} +#endif + +int R_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int i; + mplane_t *p; + if (r_trippy.integer) + return false; + for (i = 0;i < r_refdef.view.numfrustumplanes;i++) + { + // skip nearclip plane, it often culls portals when you are very close, and is almost never useful + if (i == 4) + continue; + p = r_refdef.view.frustum + i; + switch(p->signbits) + { + default: + case 0: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 1: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 2: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 3: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 4: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 5: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 6: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 7: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + } + } + return false; +} + +int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes) +{ + int i; + const mplane_t *p; + if (r_trippy.integer) + return false; + for (i = 0;i < numplanes;i++) + { + p = planes + i; + switch(p->signbits) + { + default: + case 0: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 1: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 2: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 3: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 4: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 5: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 6: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 7: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + } + } + return false; +} + +//================================================================================== + +// LordHavoc: this stores temporary data used within the same frame + +typedef struct r_framedata_mem_s +{ + struct r_framedata_mem_s *purge; // older mem block to free on next frame + size_t size; // how much usable space + size_t current; // how much space in use + size_t mark; // last "mark" location, temporary memory can be freed by returning to this + size_t wantedsize; // how much space was allocated + unsigned char *data; // start of real data (16byte aligned) +} +r_framedata_mem_t; + +static r_framedata_mem_t *r_framedata_mem; + +void R_FrameData_Reset(void) +{ + while (r_framedata_mem) + { + r_framedata_mem_t *next = r_framedata_mem->purge; + Mem_Free(r_framedata_mem); + r_framedata_mem = next; + } +} + +static void R_FrameData_Resize(qboolean mustgrow) +{ + size_t wantedsize; + wantedsize = (size_t)(r_framedatasize.value * 1024*1024); + wantedsize = bound(65536, wantedsize, 1000*1024*1024); + if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow) + { + r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize); + newmem->wantedsize = wantedsize; + newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15); + newmem->size = (unsigned char *)newmem + wantedsize - newmem->data; + newmem->current = 0; + newmem->mark = 0; + newmem->purge = r_framedata_mem; + r_framedata_mem = newmem; + } +} + +void R_FrameData_NewFrame(void) +{ + R_FrameData_Resize(false); + if (!r_framedata_mem) + return; + // if we ran out of space on the last frame, free the old memory now + while (r_framedata_mem->purge) + { + // repeatedly remove the second item in the list, leaving only head + r_framedata_mem_t *next = r_framedata_mem->purge->purge; + Mem_Free(r_framedata_mem->purge); + r_framedata_mem->purge = next; + } + // reset the current mem pointer + r_framedata_mem->current = 0; + r_framedata_mem->mark = 0; +} + +void *R_FrameData_Alloc(size_t size) +{ + void *data; + float newvalue; + + // align to 16 byte boundary - the data pointer is already aligned, so we + // only need to ensure the size of every allocation is also aligned + size = (size + 15) & ~15; + + while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size) + { + // emergency - we ran out of space, allocate more memory + newvalue = bound(0.25f, r_framedatasize.value * 2.0f, 256.0f); + // this might not be a growing it, but we'll allocate another buffer every time + Cvar_SetValueQuick(&r_framedatasize, newvalue); + R_FrameData_Resize(true); + } + + data = r_framedata_mem->data + r_framedata_mem->current; + r_framedata_mem->current += size; + + // count the usage for stats + r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current); + r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size); + + return (void *)data; +} + +void *R_FrameData_Store(size_t size, void *data) +{ + void *d = R_FrameData_Alloc(size); + if (d && data) + memcpy(d, data, size); + return d; +} + +void R_FrameData_SetMark(void) +{ + if (!r_framedata_mem) + return; + r_framedata_mem->mark = r_framedata_mem->current; +} + +void R_FrameData_ReturnToMark(void) +{ + if (!r_framedata_mem) + return; + r_framedata_mem->current = r_framedata_mem->mark; +} + +//================================================================================== + +// avoid reusing the same buffer objects on consecutive frames +#define R_BUFFERDATA_CYCLE 3 + +typedef struct r_bufferdata_buffer_s +{ + struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame + size_t size; // how much usable space + size_t current; // how much space in use + r_meshbuffer_t *buffer; // the buffer itself +} +r_bufferdata_buffer_t; + +static int r_bufferdata_cycle = 0; // incremented and wrapped each frame +static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT]; + +/// frees all dynamic buffers +void R_BufferData_Reset(void) +{ + int cycle, type; + r_bufferdata_buffer_t **p, *mem; + for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++) + { + for (type = 0;type < R_BUFFERDATA_COUNT;type++) + { + // free all buffers + p = &r_bufferdata_buffer[cycle][type]; + while (*p) + { + mem = *p; + *p = (*p)->purge; + if (mem->buffer) + R_Mesh_DestroyMeshBuffer(mem->buffer); + Mem_Free(mem); + } + } + } +} + +// resize buffer as needed (this actually makes a new one, the old one will be recycled next frame) +static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize) +{ + r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type]; + size_t size; + float newvalue = r_buffermegs[type].value; + + // increase the cvar if we have to (but only if we already have a mem) + if (mustgrow && mem) + newvalue *= 2.0f; + newvalue = bound(0.25f, newvalue, 256.0f); + while (newvalue * 1024*1024 < minsize) + newvalue *= 2.0f; + + // clamp the cvar to valid range + newvalue = bound(0.25f, newvalue, 256.0f); + if (r_buffermegs[type].value != newvalue) + Cvar_SetValueQuick(&r_buffermegs[type], newvalue); + + // calculate size in bytes + size = (size_t)(newvalue * 1024*1024); + size = bound(131072, size, 256*1024*1024); + + // allocate a new buffer if the size is different (purge old one later) + // or if we were told we must grow the buffer + if (!mem || mem->size != size || mustgrow) + { + mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem)); + mem->size = size; + mem->current = 0; + if (type == R_BUFFERDATA_VERTEX) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false); + else if (type == R_BUFFERDATA_INDEX16) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true); + else if (type == R_BUFFERDATA_INDEX32) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false); + else if (type == R_BUFFERDATA_UNIFORM) + mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false); + mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type]; + r_bufferdata_buffer[r_bufferdata_cycle][type] = mem; + } +} + +void R_BufferData_NewFrame(void) +{ + int type; + r_bufferdata_buffer_t **p, *mem; + // cycle to the next frame's buffers + r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE; + // if we ran out of space on the last time we used these buffers, free the old memory now + for (type = 0;type < R_BUFFERDATA_COUNT;type++) + { + if (r_bufferdata_buffer[r_bufferdata_cycle][type]) + { + R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072); + // free all but the head buffer, this is how we recycle obsolete + // buffers after they are no longer in use + p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge; + while (*p) + { + mem = *p; + *p = (*p)->purge; + if (mem->buffer) + R_Mesh_DestroyMeshBuffer(mem->buffer); + Mem_Free(mem); + } + // reset the current offset + r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0; + } + } +} + +r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset) +{ + r_bufferdata_buffer_t *mem; + int offset = 0; + int padsize; + + *returnbufferoffset = 0; + + // align size to a byte boundary appropriate for the buffer type, this + // makes all allocations have aligned start offsets + if (type == R_BUFFERDATA_UNIFORM) + padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1); + else + padsize = (datasize + 15) & ~15; + + // if we ran out of space in this buffer we must allocate a new one + if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size) + R_BufferData_Resize(type, true, padsize); + + // if the resize did not give us enough memory, fail + if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size) + Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n"); + + mem = r_bufferdata_buffer[r_bufferdata_cycle][type]; + offset = mem->current; + mem->current += padsize; + + // upload the data to the buffer at the chosen offset + if (offset == 0) + R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0); + R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset); + + // count the usage for stats + r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current); + r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size); + + // return the buffer offset + *returnbufferoffset = offset; + + return mem->buffer; +} + +//================================================================================== + +// LordHavoc: animcache originally written by Echon, rewritten since then + +/** + * Animation cache prevents re-generating mesh data for an animated model + * multiple times in one frame for lighting, shadowing, reflections, etc. + */ + +void R_AnimCache_Free(void) +{ +} + +void R_AnimCache_ClearCache(void) +{ + int i; + entity_render_t *ent; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + ent->animcache_vertex3f = NULL; + ent->animcache_vertex3f_vertexbuffer = NULL; + ent->animcache_vertex3f_bufferoffset = 0; + ent->animcache_normal3f = NULL; + ent->animcache_normal3f_vertexbuffer = NULL; + ent->animcache_normal3f_bufferoffset = 0; + ent->animcache_svector3f = NULL; + ent->animcache_svector3f_vertexbuffer = NULL; + ent->animcache_svector3f_bufferoffset = 0; + ent->animcache_tvector3f = NULL; + ent->animcache_tvector3f_vertexbuffer = NULL; + ent->animcache_tvector3f_bufferoffset = 0; + ent->animcache_vertexmesh = NULL; + ent->animcache_vertexmesh_vertexbuffer = NULL; + ent->animcache_vertexmesh_bufferoffset = 0; + ent->animcache_skeletaltransform3x4 = NULL; + ent->animcache_skeletaltransform3x4buffer = NULL; + ent->animcache_skeletaltransform3x4offset = 0; + ent->animcache_skeletaltransform3x4size = 0; + } +} + +static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) +{ + int i; + + // check if we need the meshbuffers + if (!vid.useinterleavedarrays) + return; + + if (!ent->animcache_vertexmesh && ent->animcache_normal3f) + ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices); + // TODO: upload vertexbuffer? + if (ent->animcache_vertexmesh) + { + r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1; + r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices); + memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices); + for (i = 0;i < numvertices;i++) + memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3])); + if (ent->animcache_svector3f) + for (i = 0;i < numvertices;i++) + memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3])); + if (ent->animcache_tvector3f) + for (i = 0;i < numvertices;i++) + memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3])); + if (ent->animcache_normal3f) + for (i = 0;i < numvertices;i++) + memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3])); + } +} + +qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) +{ + dp_model_t *model = ent->model; + int numvertices; + + // see if this ent is worth caching + if (!model || !model->Draw || !model->AnimateVertices) + return false; + // nothing to cache if it contains no animations and has no skeleton + if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms)) + return false; + // see if it is already cached for gpuskeletal + if (ent->animcache_skeletaltransform3x4) + return false; + // see if it is already cached as a mesh + if (ent->animcache_vertex3f) + { + // check if we need to add normals or tangents + if (ent->animcache_normal3f) + wantnormals = false; + if (ent->animcache_svector3f) + wanttangents = false; + if (!wantnormals && !wanttangents) + return false; + } + + // check which kind of cache we need to generate + if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub) + { + // cache the skeleton so the vertex shader can use it + r_refdef.stats[r_stat_animcache_skeletal_count] += 1; + r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones; + r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones); + ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones); + Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); + // note: this can fail if the buffer is at the grow limit + ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones; + ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset); + } + else if (ent->animcache_vertex3f) + { + // mesh was already cached but we may need to add normals/tangents + // (this only happens with multiple views, reflections, cameras, etc) + if (wantnormals || wanttangents) + { + numvertices = model->surfmesh.num_vertices; + if (wantnormals) + ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + if (wanttangents) + { + ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + } + model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL); + R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + r_refdef.stats[r_stat_animcache_shade_count] += 1; + r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices); + } + } + else + { + // generate mesh cache + numvertices = model->surfmesh.num_vertices; + ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + if (wantnormals) + ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + if (wanttangents) + { + ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices); + } + model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f); + R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + if (wantnormals || wanttangents) + { + r_refdef.stats[r_stat_animcache_shade_count] += 1; + r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices); + } + r_refdef.stats[r_stat_animcache_shape_count] += 1; + r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices; + r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices); + } + return true; +} + +void R_AnimCache_CacheVisibleEntities(void) +{ + int i; + qboolean wantnormals = true; + qboolean wanttangents = !r_showsurfaces.integer; + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_GLES2: + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + wanttangents = false; + break; + case RENDERPATH_SOFT: + break; + } + + if (r_shownormals.integer) + wanttangents = wantnormals = true; + + // TODO: thread this + // NOTE: R_PrepareRTLights() also caches entities + + for (i = 0;i < r_refdef.scene.numentities;i++) + if (r_refdef.viewcache.entityvisible[i]) + R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents); +} + +//================================================================================== + +extern cvar_t r_overheadsprites_pushback; + +static void R_View_UpdateEntityLighting (void) +{ + int i; + entity_render_t *ent; + vec3_t tempdiffusenormal, avg; + vec_t f, fa, fd, fdd; + qboolean skipunseen = r_shadows.integer != 1; //|| R_Shadow_ShadowMappingEnabled(); + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + + // skip unseen models + if ((!r_refdef.viewcache.entityvisible[i] && skipunseen)) + continue; + + // skip bsp models + if (ent->model && ent->model == cl.worldmodel) + { + // TODO: use modellight for r_ambient settings on world? + VectorSet(ent->modellight_ambient, 0, 0, 0); + VectorSet(ent->modellight_diffuse, 0, 0, 0); + VectorSet(ent->modellight_lightdir, 0, 0, 1); + continue; + } + + if (ent->flags & RENDER_CUSTOMIZEDMODELLIGHT) + { + // aleady updated by CSQC + // TODO: force modellight on BSP models in this case? + VectorCopy(ent->modellight_lightdir, tempdiffusenormal); + } + else + { + // fetch the lighting from the worldmodel data + VectorClear(ent->modellight_ambient); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if (ent->flags & RENDER_LIGHT) + { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + + // complete lightning for lit sprites + // todo: make a EF_ field so small ents could be lit purely by modellight and skipping real rtlight pass (like EF_NORTLIGHT)? + if (ent->model->type == mod_sprite && !(ent->model->data_textures[0].basematerialflags & MATERIALFLAG_FULLBRIGHT)) + { + if (ent->model->sprite.sprnum_type == SPR_OVERHEAD) // apply offset for overhead sprites + org[2] = org[2] + r_overheadsprites_pushback.value; + R_LightPoint(ent->modellight_ambient, org, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + } + else + R_CompleteLightPoint(ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal, org, LP_LIGHTMAP); + + if(ent->flags & RENDER_EQUALIZE) + { + // first fix up ambient lighting... + if(r_equalize_entities_minambient.value > 0) + { + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + if(fd > 0) + { + fa = (0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]); + if(fa < r_equalize_entities_minambient.value * fd) + { + // solve: + // fa'/fd' = minambient + // fa'+0.25*fd' = fa+0.25*fd + // ... + // fa' = fd' * minambient + // fd'*(0.25+minambient) = fa+0.25*fd + // ... + // fd' = (fa+0.25*fd) * 1 / (0.25+minambient) + // fa' = (fa+0.25*fd) * minambient / (0.25+minambient) + // ... + fdd = (fa + 0.25f * fd) / (0.25f + r_equalize_entities_minambient.value); + f = fdd / fd; // f>0 because all this is additive; f<1 because fddmodellight_ambient, (1-f)*0.25f, ent->modellight_diffuse, ent->modellight_ambient); + VectorScale(ent->modellight_diffuse, f, ent->modellight_diffuse); + } + } + } + + if(r_equalize_entities_to.value > 0 && r_equalize_entities_by.value != 0) + { + fa = 0.299f * ent->modellight_ambient[0] + 0.587f * ent->modellight_ambient[1] + 0.114f * ent->modellight_ambient[2]; + fd = 0.299f * ent->modellight_diffuse[0] + 0.587f * ent->modellight_diffuse[1] + 0.114f * ent->modellight_diffuse[2]; + f = fa + 0.25 * fd; + if(f > 0) + { + // adjust brightness and saturation to target + avg[0] = avg[1] = avg[2] = fa / f; + VectorLerp(ent->modellight_ambient, r_equalize_entities_by.value, avg, ent->modellight_ambient); + avg[0] = avg[1] = avg[2] = fd / f; + VectorLerp(ent->modellight_diffuse, r_equalize_entities_by.value, avg, ent->modellight_diffuse); + } + } + } + } + else // highly rare + VectorSet(ent->modellight_ambient, 1, 1, 1); + } + + // move the light direction into modelspace coordinates for lighting code + Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir); + if(VectorLength2(ent->modellight_lightdir) == 0) + VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here + VectorNormalize(ent->modellight_lightdir); + } +} + +#define MAX_LINEOFSIGHTTRACES 64 + +static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs) +{ + int i; + vec3_t boxmins, boxmaxs; + vec3_t start; + vec3_t end; + dp_model_t *model = r_refdef.scene.worldmodel; + + if (!model || !model->brush.TraceLineOfSight) + return true; + + // expand the box a little + boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0]; + boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0]; + boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1]; + boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1]; + boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2]; + boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2]; + + // return true if eye is inside enlarged box + if (BoxesOverlap(boxmins, boxmaxs, eye, eye)) + return true; + + // try center + VectorCopy(eye, start); + VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end); + if (model->brush.TraceLineOfSight(model, start, end)) + return true; + + // try various random positions + for (i = 0;i < numsamples;i++) + { + VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2])); + if (model->brush.TraceLineOfSight(model, start, end)) + return true; + } + + return false; +} + + +static void R_View_UpdateEntityVisible (void) +{ + int i; + int renderimask; + int samples; + entity_render_t *ent; + + renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) + : r_fb.water.hideplayer ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) + : (chase_active.integer || r_fb.water.renderingscene) ? RENDER_VIEWMODEL + : RENDER_EXTERIORMODEL; + if (!r_drawviewmodel.integer) + renderimask |= RENDER_VIEWMODEL; + if (!r_drawexteriormodel.integer) + renderimask |= RENDER_EXTERIORMODEL; + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs) + { + // worldmodel can check visibility + memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities); + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + if (!(ent->flags & renderimask)) + if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) + if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs)) + r_refdef.viewcache.entityvisible[i] = true; + } + } + else + { + // no worldmodel or it can't check visibility + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs)); + } + } + if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer) + // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling + { + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if(!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*'))) + { + samples = ent->entitynumber ? r_cullentities_trace_samples.integer : r_cullentities_trace_tempentitysamples.integer; + if (samples < 0) + continue; // temp entities do pvs only + if(R_CanSeeBox(samples, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs)) + ent->last_trace_visibility = realtime; + if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value) + r_refdef.viewcache.entityvisible[i] = 0; + } + } + } +} + +/// only used if skyrendermasked, and normally returns false +static int R_DrawBrushModelsSky (void) +{ + int i, sky; + entity_render_t *ent; + + sky = false; + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if (!ent->model || !ent->model->DrawSky) + continue; + ent->model->DrawSky(ent); + sky = true; + } + return sky; +} + +static void R_DrawNoModel(entity_render_t *ent); +static void R_DrawModels(void) +{ + int i; + entity_render_t *ent; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + r_refdef.stats[r_stat_entities]++; + /* + if (ent->model && !strncmp(ent->model->name, "models/proto_", 13)) + { + vec3_t f, l, u, o; + Matrix4x4_ToVectors(&ent->matrix, f, l, u, o); + Con_Printf("R_DrawModels\n"); + Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]); + Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp); + Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp); + } + */ + if (ent->model && ent->model->Draw != NULL) + ent->model->Draw(ent); + else + R_DrawNoModel(ent); + } +} + +static void R_DrawModelsDepth(void) +{ + int i; + entity_render_t *ent; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if (ent->model && ent->model->DrawDepth != NULL) + ent->model->DrawDepth(ent); + } +} + +static void R_DrawModelsDebug(void) +{ + int i; + entity_render_t *ent; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if (ent->model && ent->model->DrawDebug != NULL) + ent->model->DrawDebug(ent); + } +} + +static void R_DrawModelsAddWaterPlanes(void) +{ + int i; + entity_render_t *ent; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if (ent->model && ent->model->DrawAddWaterPlanes != NULL) + ent->model->DrawAddWaterPlanes(ent); + } +} + +static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}}; + +void R_HDR_UpdateIrisAdaptation(const vec3_t point) +{ + if (r_hdr_irisadaptation.integer) + { + vec3_t p; + vec3_t ambient; + vec3_t diffuse; + vec3_t diffusenormal; + vec3_t forward; + vec_t brightness = 0.0f; + vec_t goal; + vec_t current; + vec_t d; + int c; + VectorCopy(r_refdef.view.forward, forward); + for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++) + { + p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value; + p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value; + p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value; + R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT); + d = DotProduct(forward, diffusenormal); + brightness += VectorLength(ambient); + if (d > 0) + brightness += d * VectorLength(diffuse); + } + brightness *= 1.0f / c; + brightness += 0.00001f; // make sure it's never zero + goal = r_hdr_irisadaptation_multiplier.value / brightness; + goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value); + current = r_hdr_irisadaptation_value.value; + if (current < goal) + current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal); + else if (current > goal) + current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal); + if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f) + Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current); + } + else if (r_hdr_irisadaptation_value.value != 1.0f) + Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f); +} + +static void R_View_SetFrustum(const int *scissor) +{ + int i; + double fpx = +1, fnx = -1, fpy = +1, fny = -1; + vec3_t forward, left, up, origin, v; + + if(scissor) + { + // flipped x coordinates (because x points left here) + fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width); + fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width); + + // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one + switch(vid.renderpath) + { + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + // non-flipped y coordinates + fny = -1.0 + 2.0 * (vid.height - scissor[1] - scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + fpy = -1.0 + 2.0 * (vid.height - scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + break; + case RENDERPATH_SOFT: + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // non-flipped y coordinates + fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + break; + } + } + + // we can't trust r_refdef.view.forward and friends in reflected scenes + Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin); + +#if 0 + r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x; + r_refdef.view.frustum[0].normal[1] = 0 - 0; + r_refdef.view.frustum[0].normal[2] = -1 - 0; + r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x; + r_refdef.view.frustum[1].normal[1] = 0 + 0; + r_refdef.view.frustum[1].normal[2] = -1 + 0; + r_refdef.view.frustum[2].normal[0] = 0 - 0; + r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y; + r_refdef.view.frustum[2].normal[2] = -1 - 0; + r_refdef.view.frustum[3].normal[0] = 0 + 0; + r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y; + r_refdef.view.frustum[3].normal[2] = -1 + 0; +#endif + +#if 0 + zNear = r_refdef.nearclip; + nudge = 1.0 - 1.0 / (1<<23); + r_refdef.view.frustum[4].normal[0] = 0 - 0; + r_refdef.view.frustum[4].normal[1] = 0 - 0; + r_refdef.view.frustum[4].normal[2] = -1 - -nudge; + r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge; + r_refdef.view.frustum[5].normal[0] = 0 + 0; + r_refdef.view.frustum[5].normal[1] = 0 + 0; + r_refdef.view.frustum[5].normal[2] = -1 + -nudge; + r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge; +#endif + + + +#if 0 + r_refdef.view.frustum[0].normal[0] = m[3] - m[0]; + r_refdef.view.frustum[0].normal[1] = m[7] - m[4]; + r_refdef.view.frustum[0].normal[2] = m[11] - m[8]; + r_refdef.view.frustum[0].dist = m[15] - m[12]; + + r_refdef.view.frustum[1].normal[0] = m[3] + m[0]; + r_refdef.view.frustum[1].normal[1] = m[7] + m[4]; + r_refdef.view.frustum[1].normal[2] = m[11] + m[8]; + r_refdef.view.frustum[1].dist = m[15] + m[12]; + + r_refdef.view.frustum[2].normal[0] = m[3] - m[1]; + r_refdef.view.frustum[2].normal[1] = m[7] - m[5]; + r_refdef.view.frustum[2].normal[2] = m[11] - m[9]; + r_refdef.view.frustum[2].dist = m[15] - m[13]; + + r_refdef.view.frustum[3].normal[0] = m[3] + m[1]; + r_refdef.view.frustum[3].normal[1] = m[7] + m[5]; + r_refdef.view.frustum[3].normal[2] = m[11] + m[9]; + r_refdef.view.frustum[3].dist = m[15] + m[13]; + + r_refdef.view.frustum[4].normal[0] = m[3] - m[2]; + r_refdef.view.frustum[4].normal[1] = m[7] - m[6]; + r_refdef.view.frustum[4].normal[2] = m[11] - m[10]; + r_refdef.view.frustum[4].dist = m[15] - m[14]; + + r_refdef.view.frustum[5].normal[0] = m[3] + m[2]; + r_refdef.view.frustum[5].normal[1] = m[7] + m[6]; + r_refdef.view.frustum[5].normal[2] = m[11] + m[10]; + r_refdef.view.frustum[5].dist = m[15] + m[14]; +#endif + + if (r_refdef.view.useperspective) + { + // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling + VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]); + VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]); + VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]); + VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]); + + // then the normals from the corners relative to origin + CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal); + CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal); + CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal); + CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal); + + // in a NORMAL view, forward cross left == up + // in a REFLECTED view, forward cross left == down + // so our cross products above need to be adjusted for a left handed coordinate system + CrossProduct(forward, left, v); + if(DotProduct(v, up) < 0) + { + VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal); + VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal); + VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal); + VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal); + } + + // Leaving those out was a mistake, those were in the old code, and they + // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix + // I couldn't reproduce it after adding those normalizations. --blub + VectorNormalize(r_refdef.view.frustum[0].normal); + VectorNormalize(r_refdef.view.frustum[1].normal); + VectorNormalize(r_refdef.view.frustum[2].normal); + VectorNormalize(r_refdef.view.frustum[3].normal); + + // make the corners absolute + VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]); + VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]); + VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]); + VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]); + + // one more normal + VectorCopy(forward, r_refdef.view.frustum[4].normal); + + r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal); + r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal); + r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal); + r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal); + r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip; + } + else + { + VectorScale(left, -r_refdef.view.ortho_x, r_refdef.view.frustum[0].normal); + VectorScale(left, r_refdef.view.ortho_x, r_refdef.view.frustum[1].normal); + VectorScale(up, -r_refdef.view.ortho_y, r_refdef.view.frustum[2].normal); + VectorScale(up, r_refdef.view.ortho_y, r_refdef.view.frustum[3].normal); + VectorCopy(forward, r_refdef.view.frustum[4].normal); + r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) + r_refdef.view.ortho_x; + r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) + r_refdef.view.ortho_x; + r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) + r_refdef.view.ortho_y; + r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) + r_refdef.view.ortho_y; + r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip; + } + r_refdef.view.numfrustumplanes = 5; + + if (r_refdef.view.useclipplane) + { + r_refdef.view.numfrustumplanes = 6; + r_refdef.view.frustum[5] = r_refdef.view.clipplane; + } + + for (i = 0;i < r_refdef.view.numfrustumplanes;i++) + PlaneClassify(r_refdef.view.frustum + i); + + // LordHavoc: note to all quake engine coders, Quake had a special case + // for 90 degrees which assumed a square view (wrong), so I removed it, + // Quake2 has it disabled as well. + + // rotate R_VIEWFORWARD right by FOV_X/2 degrees + //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2)); + //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal); + //PlaneClassify(&frustum[0]); + + // rotate R_VIEWFORWARD left by FOV_X/2 degrees + //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2)); + //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal); + //PlaneClassify(&frustum[1]); + + // rotate R_VIEWFORWARD up by FOV_X/2 degrees + //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2)); + //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal); + //PlaneClassify(&frustum[2]); + + // rotate R_VIEWFORWARD down by FOV_X/2 degrees + //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2)); + //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal); + //PlaneClassify(&frustum[3]); + + // nearclip plane + //VectorCopy(forward, r_refdef.view.frustum[4].normal); + //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value; + //PlaneClassify(&frustum[4]); +} + +static void R_View_UpdateWithScissor(const int *myscissor) +{ + R_Main_ResizeViewCache(); + R_View_SetFrustum(myscissor); + R_View_WorldVisibility(r_refdef.view.useclipplane); + R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); +} + +static void R_View_Update(void) +{ + R_Main_ResizeViewCache(); + R_View_SetFrustum(NULL); + R_View_WorldVisibility(r_refdef.view.useclipplane); + R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); +} + +float viewscalefpsadjusted = 1.0f; + +static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight) +{ + float scale = r_viewscale.value * sqrt(viewscalefpsadjusted); + scale = bound(0.03125f, scale, 1.0f); + *outwidth = (int)ceil(width * scale); + *outheight = (int)ceil(height * scale); +} + +void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + const float *customclipplane = NULL; + float plane[4]; + int /*rtwidth,*/ rtheight, scaledwidth, scaledheight; + if (r_refdef.view.useclipplane && allowwaterclippingplane) + { + // LordHavoc: couldn't figure out how to make this approach the + vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value; + vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal); + if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value) + dist = r_refdef.view.clipplane.dist; + plane[0] = r_refdef.view.clipplane.normal[0]; + plane[1] = r_refdef.view.clipplane.normal[1]; + plane[2] = r_refdef.view.clipplane.normal[2]; + plane[3] = -dist; + if(vid.renderpath != RENDERPATH_SOFT) customclipplane = plane; + } + + //rtwidth = fbo ? R_TextureWidth(depthtexture ? depthtexture : colortexture) : vid.width; + rtheight = fbo ? R_TextureHeight(depthtexture ? depthtexture : colortexture) : vid.height; + + R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &scaledwidth, &scaledheight); + if (!r_refdef.view.useperspective) + R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); + else if (vid.stencil && r_useinfinitefarclip.integer) + R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); + else + R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, rtheight - scaledheight - r_refdef.view.y, scaledwidth, scaledheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane); + R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL); + R_SetViewport(&r_refdef.view.viewport); + if (r_refdef.view.useclipplane && allowwaterclippingplane && vid.renderpath == RENDERPATH_SOFT) + { + matrix4x4_t mvpmatrix, invmvpmatrix, invtransmvpmatrix; + float screenplane[4]; + Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix); + Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix); + Matrix4x4_Transpose(&invtransmvpmatrix, &invmvpmatrix); + Matrix4x4_Transform4(&invtransmvpmatrix, plane, screenplane); + DPSOFTRAST_ClipPlane(screenplane[0], screenplane[1], screenplane[2], screenplane[3]); + } +} + +void R_EntityMatrix(const matrix4x4_t *matrix) +{ + if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t))) + { + gl_modelmatrixchanged = false; + gl_modelmatrix = *matrix; + Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix); + Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix); + Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f); + Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f); + CHECKGLERROR + switch(vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + hlslVSSetParameter16f(D3DVSREGISTER_ModelViewProjectionMatrix, gl_modelviewprojection16f); + hlslVSSetParameter16f(D3DVSREGISTER_ModelViewMatrix, gl_modelview16f); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 shader %s:%i\n", __FILE__, __LINE__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 shader %s:%i\n", __FILE__, __LINE__); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + qglLoadMatrixf(gl_modelview16f);CHECKGLERROR + break; + case RENDERPATH_SOFT: + DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewProjectionMatrixM1, 1, false, gl_modelviewprojection16f); + DPSOFTRAST_UniformMatrix4fv(DPSOFTRAST_UNIFORM_ModelViewMatrixM1, 1, false, gl_modelview16f); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f); + if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f); + break; + } + } +} + +void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, float x2, float y2) +{ + r_viewport_t viewport; + + CHECKGLERROR + + // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom + R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, x2, y2, -10, 100, NULL); + R_Mesh_SetRenderTargets(fbo, depthtexture, colortexture, NULL, NULL, NULL); + R_SetViewport(&viewport); + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_ScissorTest(false); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_DepthTest(false); + GL_DepthFunc(GL_LEQUAL); + R_EntityMatrix(&identitymatrix); + R_Mesh_ResetTextureState(); + GL_PolygonOffset(0, 0); + R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } + GL_CullFace(GL_NONE); + + CHECKGLERROR +} + +void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + DrawQ_Finish(); + + R_ResetViewRendering2D_Common(fbo, depthtexture, colortexture, 1, 1); +} + +void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + DrawQ_Finish(); + + R_SetupView(true, fbo, depthtexture, colortexture); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_ScissorTest(true); + GL_DepthMask(true); + GL_DepthRange(0, 1); + GL_DepthTest(true); + GL_DepthFunc(GL_LEQUAL); + R_EntityMatrix(&identitymatrix); + R_Mesh_ResetTextureState(); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } + GL_CullFace(r_refdef.view.cullface_back); +} + +/* +================ +R_RenderView_UpdateViewVectors +================ +*/ +void R_RenderView_UpdateViewVectors(void) +{ + // break apart the view matrix into vectors for various purposes + // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong + // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc + Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin); + VectorNegate(r_refdef.view.left, r_refdef.view.right); + // make an inverted copy of the view matrix for tracking sprites + Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix); +} + +void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); + +static void R_Water_StartFrame(void) +{ + int i; + int waterwidth, waterheight, texturewidth, textureheight, camerawidth, cameraheight; + r_waterstate_waterplane_t *p; + qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; + + if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d) + return; + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + return; + } + + // set waterwidth and waterheight to the water resolution that will be + // used (often less than the screen resolution for faster rendering) + R_GetScaledViewSize(bound(1, vid.width * r_water_resolutionmultiplier.value, vid.width), bound(1, vid.height * r_water_resolutionmultiplier.value, vid.height), &waterwidth, &waterheight); + + // calculate desired texture sizes + // can't use water if the card does not support the texture size + if (!r_water.integer || r_showsurfaces.integer) + texturewidth = textureheight = waterwidth = waterheight = camerawidth = cameraheight = 0; + else if (vid.support.arb_texture_non_power_of_two) + { + texturewidth = waterwidth; + textureheight = waterheight; + camerawidth = waterwidth; + cameraheight = waterheight; + } + else + { + for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2); + for (textureheight = 1;textureheight < waterheight;textureheight *= 2); + for (camerawidth = 1;camerawidth * 2 <= waterwidth ;camerawidth *= 2); + for (cameraheight = 1;cameraheight * 2 <= waterheight;cameraheight *= 2); + } + + // allocate textures as needed + if (r_fb.water.texturewidth != texturewidth || r_fb.water.textureheight != textureheight || r_fb.water.camerawidth != camerawidth || r_fb.water.cameraheight != cameraheight || (r_fb.depthtexture && !usewaterfbo)) + { + r_fb.water.maxwaterplanes = MAX_WATERPLANES; + for (i = 0, p = r_fb.water.waterplanes;i < r_fb.water.maxwaterplanes;i++, p++) + { + if (p->texture_refraction) + R_FreeTexture(p->texture_refraction); + p->texture_refraction = NULL; + if (p->fbo_refraction) + R_Mesh_DestroyFramebufferObject(p->fbo_refraction); + p->fbo_refraction = 0; + if (p->texture_reflection) + R_FreeTexture(p->texture_reflection); + p->texture_reflection = NULL; + if (p->fbo_reflection) + R_Mesh_DestroyFramebufferObject(p->fbo_reflection); + p->fbo_reflection = 0; + if (p->texture_camera) + R_FreeTexture(p->texture_camera); + p->texture_camera = NULL; + if (p->fbo_camera) + R_Mesh_DestroyFramebufferObject(p->fbo_camera); + p->fbo_camera = 0; + } + memset(&r_fb.water, 0, sizeof(r_fb.water)); + r_fb.water.texturewidth = texturewidth; + r_fb.water.textureheight = textureheight; + r_fb.water.camerawidth = camerawidth; + r_fb.water.cameraheight = cameraheight; + } + + if (r_fb.water.texturewidth) + { + int scaledwidth, scaledheight; + + r_fb.water.enabled = true; + + // water resolution is usually reduced + r_fb.water.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width); + r_fb.water.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height); + R_GetScaledViewSize(r_fb.water.waterwidth, r_fb.water.waterheight, &scaledwidth, &scaledheight); + + // set up variables that will be used in shader setup + r_fb.water.screenscale[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth; + r_fb.water.screenscale[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight; + r_fb.water.screencenter[0] = 0.5f * (float)scaledwidth / (float)r_fb.water.texturewidth; + r_fb.water.screencenter[1] = 0.5f * (float)scaledheight / (float)r_fb.water.textureheight; + } + + r_fb.water.maxwaterplanes = MAX_WATERPLANES; + r_fb.water.numwaterplanes = 0; +} + +void R_Water_AddWaterPlane(msurface_t *surface, int entno) +{ + int planeindex, bestplaneindex, vertexindex; + vec3_t mins, maxs, normal, center, v, n; + vec_t planescore, bestplanescore; + mplane_t plane; + r_waterstate_waterplane_t *p; + texture_t *t = R_GetCurrentTexture(surface->texture); + + rsurface.texture = t; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface)); + // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway + if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1) + return; + // average the vertex normals, find the surface bounds (after deformvertexes) + Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v); + Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n); + VectorCopy(n, normal); + VectorCopy(v, mins); + VectorCopy(v, maxs); + for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++) + { + Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v); + Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n); + VectorAdd(normal, n, normal); + mins[0] = min(mins[0], v[0]); + mins[1] = min(mins[1], v[1]); + mins[2] = min(mins[2], v[2]); + maxs[0] = max(maxs[0], v[0]); + maxs[1] = max(maxs[1], v[1]); + maxs[2] = max(maxs[2], v[2]); + } + VectorNormalize(normal); + VectorMAM(0.5f, mins, 0.5f, maxs, center); + + VectorCopy(normal, plane.normal); + VectorNormalize(plane.normal); + plane.dist = DotProduct(center, plane.normal); + PlaneClassify(&plane); + if (PlaneDiff(r_refdef.view.origin, &plane) < 0) + { + // skip backfaces (except if nocullface is set) +// if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) +// return; + VectorNegate(plane.normal, plane.normal); + plane.dist *= -1; + PlaneClassify(&plane); + } + + + // find a matching plane if there is one + bestplaneindex = -1; + bestplanescore = 1048576.0f; + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) + { + if(p->camera_entity == t->camera_entity) + { + planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f; + if (bestplaneindex < 0 || bestplanescore > planescore) + { + bestplaneindex = planeindex; + bestplanescore = planescore; + } + } + } + planeindex = bestplaneindex; + p = r_fb.water.waterplanes + planeindex; + + // if this surface does not fit any known plane rendered this frame, add one + if ((planeindex < 0 || bestplanescore > 0.001f) && r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes) + { + // store the new plane + planeindex = r_fb.water.numwaterplanes++; + p = r_fb.water.waterplanes + planeindex; + p->plane = plane; + // clear materialflags and pvs + p->materialflags = 0; + p->pvsvalid = false; + p->camera_entity = t->camera_entity; + VectorCopy(mins, p->mins); + VectorCopy(maxs, p->maxs); + } + else + { + // merge mins/maxs when we're adding this surface to the plane + p->mins[0] = min(p->mins[0], mins[0]); + p->mins[1] = min(p->mins[1], mins[1]); + p->mins[2] = min(p->mins[2], mins[2]); + p->maxs[0] = max(p->maxs[0], maxs[0]); + p->maxs[1] = max(p->maxs[1], maxs[1]); + p->maxs[2] = max(p->maxs[2], maxs[2]); + } + // merge this surface's materialflags into the waterplane + p->materialflags |= t->currentmaterialflags; + if(!(p->materialflags & MATERIALFLAG_CAMERA)) + { + // merge this surface's PVS into the waterplane + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS + && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0) + { + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid); + p->pvsvalid = true; + } + } +} + +extern cvar_t r_drawparticles; +extern cvar_t r_drawdecals; + +static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + int myscissor[4]; + r_refdef_view_t originalview; + r_refdef_view_t myview; + int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0; + r_waterstate_waterplane_t *p; + vec3_t visorigin; + qboolean usewaterfbo = (r_viewfbo.integer >= 1 || r_water_fbo.integer >= 1) && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; + char vabuf[1024]; + + originalview = r_refdef.view; + + // lowquality hack, temporarily shut down some cvars and restore afterwards + qualityreduction = r_water_lowquality.integer; + if (qualityreduction > 0) + { + if (qualityreduction >= 1) + { + old_r_shadows = r_shadows.integer; + old_r_worldrtlight = r_shadow_realtime_world.integer; + old_r_dlight = r_shadow_realtime_dlight.integer; + Cvar_SetValueQuick(&r_shadows, 0); + Cvar_SetValueQuick(&r_shadow_realtime_world, 0); + Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0); + } + if (qualityreduction >= 2) + { + old_r_dynamic = r_dynamic.integer; + old_r_particles = r_drawparticles.integer; + old_r_decals = r_drawdecals.integer; + Cvar_SetValueQuick(&r_dynamic, 0); + Cvar_SetValueQuick(&r_drawparticles, 0); + Cvar_SetValueQuick(&r_drawdecals, 0); + } + } + + // make sure enough textures are allocated + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) + { + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) + { + if (!p->texture_refraction) + p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_refraction", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (!p->texture_refraction) + goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_refraction == 0) + p->fbo_refraction = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_refraction, NULL, NULL, NULL); + } + } + else if (p->materialflags & MATERIALFLAG_CAMERA) + { + if (!p->texture_camera) + p->texture_camera = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_camera", planeindex), r_fb.water.camerawidth, r_fb.water.cameraheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR, -1, NULL); + if (!p->texture_camera) + goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_camera == 0) + p->fbo_camera = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_camera, NULL, NULL, NULL); + } + } + + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) + { + if (!p->texture_reflection) + p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "waterplane%i_reflection", planeindex), r_fb.water.texturewidth, r_fb.water.textureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (!p->texture_reflection) + goto error; + if (usewaterfbo) + { + if (r_fb.water.depthtexture == NULL) + r_fb.water.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "waterviewdepth", r_fb.water.texturewidth, r_fb.water.textureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + if (p->fbo_reflection == 0) + p->fbo_reflection = R_Mesh_CreateFramebufferObject(r_fb.water.depthtexture, p->texture_reflection, NULL, NULL, NULL); + } + } + } + + // render views + r_refdef.view = originalview; + r_refdef.view.showdebug = false; + r_refdef.view.width = r_fb.water.waterwidth; + r_refdef.view.height = r_fb.water.waterheight; + r_refdef.view.useclipplane = true; + myview = r_refdef.view; + r_fb.water.renderingscene = true; + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) + { + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) + { + r_refdef.view = myview; + if(r_water_scissormode.integer) + { + R_SetupView(true, p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); + if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) + continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible + } + + // render reflected scene and copy into texture + Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2); + // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems) + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin); + r_refdef.view.clipplane = p->plane; + // reverse the cullface settings for this render + r_refdef.view.cullface_front = GL_FRONT; + r_refdef.view.cullface_back = GL_BACK; + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes) + { + r_refdef.view.usecustompvs = true; + if (p->pvsvalid) + memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes); + else + memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes); + } + + r_fb.water.hideplayer = r_water_hideplayer.integer >= 2; + R_ResetViewRendering3D(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); + R_ClearScreen(r_refdef.fogenabled); + if(r_water_scissormode.integer & 2) + R_View_UpdateWithScissor(myscissor); + else + R_View_Update(); + R_AnimCache_CacheVisibleEntities(); + if(r_water_scissormode.integer & 1) + GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); + R_RenderScene(p->fbo_reflection, r_fb.water.depthtexture, p->texture_reflection); + + if (!p->fbo_reflection) + R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; + } + + // render the normal view scene and copy into texture + // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) + { + r_refdef.view = myview; + if(r_water_scissormode.integer) + { + R_SetupView(true, p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); + if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) + continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible + } + + r_fb.water.hideplayer = r_water_hideplayer.integer >= 1; + + r_refdef.view.clipplane = p->plane; + VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); + r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; + + if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity) + { + // we need to perform a matrix transform to render the view... so let's get the transformation matrix + r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones + CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); + R_RenderView_UpdateViewVectors(); + if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS) + { + r_refdef.view.usecustompvs = true; + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + } + } + + PlaneClassify(&r_refdef.view.clipplane); + + R_ResetViewRendering3D(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); + R_ClearScreen(r_refdef.fogenabled); + if(r_water_scissormode.integer & 2) + R_View_UpdateWithScissor(myscissor); + else + R_View_Update(); + R_AnimCache_CacheVisibleEntities(); + if(r_water_scissormode.integer & 1) + GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); + R_RenderScene(p->fbo_refraction, r_fb.water.depthtexture, p->texture_refraction); + + if (!p->fbo_refraction) + R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; + } + else if (p->materialflags & MATERIALFLAG_CAMERA) + { + r_refdef.view = myview; + + r_refdef.view.clipplane = p->plane; + VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); + r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; + + r_refdef.view.width = r_fb.water.camerawidth; + r_refdef.view.height = r_fb.water.cameraheight; + r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0); + r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView + r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView + + if(p->camera_entity) + { + // we need to perform a matrix transform to render the view... so let's get the transformation matrix + CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); + } + + // note: all of the view is used for displaying... so + // there is no use in scissoring + + // reverse the cullface settings for this render + r_refdef.view.cullface_front = GL_FRONT; + r_refdef.view.cullface_back = GL_BACK; + // also reverse the view matrix + Matrix4x4_ConcatScale3(&r_refdef.view.matrix, 1, 1, -1); // this serves to invert texcoords in the result, as the copied texture is mapped the wrong way round + R_RenderView_UpdateViewVectors(); + if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS) + { + r_refdef.view.usecustompvs = true; + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + } + + // camera needs no clipplane + r_refdef.view.useclipplane = false; + + PlaneClassify(&r_refdef.view.clipplane); + + r_fb.water.hideplayer = false; + + R_ResetViewRendering3D(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_AnimCache_CacheVisibleEntities(); + R_RenderScene(p->fbo_camera, r_fb.water.depthtexture, p->texture_camera); + + if (!p->fbo_camera) + R_Mesh_CopyToTexture(p->texture_camera, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.water.hideplayer = false; + } + + } + if(vid.renderpath==RENDERPATH_SOFT) DPSOFTRAST_ClipPlane(0, 0, 0, 1); + r_fb.water.renderingscene = false; + r_refdef.view = originalview; + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + if (!r_fb.water.depthtexture) + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_AnimCache_CacheVisibleEntities(); + goto finish; +error: + r_refdef.view = originalview; + r_fb.water.renderingscene = false; + Cvar_SetValueQuick(&r_water, 0); + Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n"); +finish: + // lowquality hack, restore cvars + if (qualityreduction > 0) + { + if (qualityreduction >= 1) + { + Cvar_SetValueQuick(&r_shadows, old_r_shadows); + Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight); + Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight); + } + if (qualityreduction >= 2) + { + Cvar_SetValueQuick(&r_dynamic, old_r_dynamic); + Cvar_SetValueQuick(&r_drawparticles, old_r_particles); + Cvar_SetValueQuick(&r_drawdecals, old_r_decals); + } + } +} + +qboolean R_Stereo_Active() +{ + return true; +} + +static void R_Bloom_StartFrame(void) +{ + int i; + int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight; + int viewwidth, viewheight; + qboolean useviewfbo = r_viewfbo.integer >= 1 && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2; + textype_t textype = TEXTYPE_COLORBUFFER; + + switch (vid.renderpath) + { + case RENDERPATH_GL20: + r_fb.usedepthtextures = r_usedepthtextures.integer != 0; + if (vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two) + { + if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F; + if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F; + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + r_fb.usedepthtextures = false; + break; + case RENDERPATH_SOFT: + r_fb.usedepthtextures = true; + break; + } + + if (r_viewscale_fpsscaling.integer) + { + double actualframetime; + double targetframetime; + double adjust; + actualframetime = r_refdef.lastdrawscreentime; + targetframetime = (1.0 / r_viewscale_fpsscaling_target.value); + adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value; + adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value); + if (r_viewscale_fpsscaling_stepsize.value > 0) + adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value; + viewscalefpsadjusted += adjust; + viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f); + } + else + viewscalefpsadjusted = 1.0f; + + R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight); + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + return; + } + + // set bloomwidth and bloomheight to the bloom resolution that will be + // used (often less than the screen resolution for faster rendering) + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width); + r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width; + r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height); + r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d); + r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d); + + // calculate desired texture sizes + if (vid.support.arb_texture_non_power_of_two) + { + screentexturewidth = vid.width; + screentextureheight = vid.height; + bloomtexturewidth = r_fb.bloomwidth; + bloomtextureheight = r_fb.bloomheight; + } + else + { + for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2); + for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2); + for (bloomtexturewidth = 1;bloomtexturewidth < r_fb.bloomwidth ;bloomtexturewidth *= 2); + for (bloomtextureheight = 1;bloomtextureheight < r_fb.bloomheight;bloomtextureheight *= 2); + } + + if ((r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > (int)vid.maxtexturesize_2d || r_refdef.view.height > (int)vid.maxtexturesize_2d)) + { + Cvar_SetValueQuick(&r_bloom, 0); + Cvar_SetValueQuick(&r_motionblur, 0); + Cvar_SetValueQuick(&r_damageblur, 0); + } + + if (!(r_glsl_postprocess.integer || (r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial)) + && !r_bloom.integer + && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)) + && !useviewfbo + && r_viewscale.value == 1.0f + && !r_viewscale_fpsscaling.integer) + screentexturewidth = screentextureheight = 0; + if (!r_bloom.integer) + bloomtexturewidth = bloomtextureheight = 0; + + // allocate textures as needed + if (r_fb.screentexturewidth != screentexturewidth + || r_fb.screentextureheight != screentextureheight + || r_fb.bloomtexturewidth != bloomtexturewidth + || r_fb.bloomtextureheight != bloomtextureheight + || r_fb.textype != textype + || useviewfbo != (r_fb.fbo != 0)) + { + for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++) + { + if (r_fb.bloomtexture[i]) + R_FreeTexture(r_fb.bloomtexture[i]); + r_fb.bloomtexture[i] = NULL; + + if (r_fb.bloomfbo[i]) + R_Mesh_DestroyFramebufferObject(r_fb.bloomfbo[i]); + r_fb.bloomfbo[i] = 0; + } + + if (r_fb.fbo) + R_Mesh_DestroyFramebufferObject(r_fb.fbo); + r_fb.fbo = 0; + + if (r_fb.colortexture) + R_FreeTexture(r_fb.colortexture); + r_fb.colortexture = NULL; + + if (r_fb.depthtexture) + R_FreeTexture(r_fb.depthtexture); + r_fb.depthtexture = NULL; + + if (r_fb.ghosttexture) + R_FreeTexture(r_fb.ghosttexture); + r_fb.ghosttexture = NULL; + + r_fb.screentexturewidth = screentexturewidth; + r_fb.screentextureheight = screentextureheight; + r_fb.bloomtexturewidth = bloomtexturewidth; + r_fb.bloomtextureheight = bloomtextureheight; + r_fb.textype = textype; + + if (r_fb.screentexturewidth && r_fb.screentextureheight) + { + if (r_motionblur.value > 0 || r_damageblur.value > 0) + r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + r_fb.ghosttexture_valid = false; + r_fb.colortexture = R_LoadTexture2D(r_main_texturepool, "framebuffercolor", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (useviewfbo) + { + r_fb.depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, "framebufferdepth", r_fb.screentexturewidth, r_fb.screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8); + r_fb.fbo = R_Mesh_CreateFramebufferObject(r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL); + R_Mesh_SetRenderTargets(r_fb.fbo, r_fb.depthtexture, r_fb.colortexture, NULL, NULL, NULL); + } + } + + if (r_fb.bloomtexturewidth && r_fb.bloomtextureheight) + { + for (i = 0;i < (int)(sizeof(r_fb.bloomtexture)/sizeof(r_fb.bloomtexture[i]));i++) + { + r_fb.bloomtexture[i] = R_LoadTexture2D(r_main_texturepool, "framebufferbloom", r_fb.bloomtexturewidth, r_fb.bloomtextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL); + if (useviewfbo) + r_fb.bloomfbo[i] = R_Mesh_CreateFramebufferObject(NULL, r_fb.bloomtexture[i], NULL, NULL, NULL); + } + } + } + + // bloom texture is a different resolution + r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width); + r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width; + r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height); + r_fb.bloomwidth = bound(1, r_fb.bloomwidth, r_fb.bloomtexturewidth); + r_fb.bloomheight = bound(1, r_fb.bloomheight, r_fb.bloomtextureheight); + + // set up a texcoord array for the full resolution screen image + // (we have to keep this around to copy back during final render) + r_fb.screentexcoord2f[0] = 0; + r_fb.screentexcoord2f[1] = (float)viewheight / (float)r_fb.screentextureheight; + r_fb.screentexcoord2f[2] = (float)viewwidth / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[3] = (float)viewheight / (float)r_fb.screentextureheight; + r_fb.screentexcoord2f[4] = (float)viewwidth / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[5] = 0; + r_fb.screentexcoord2f[6] = 0; + r_fb.screentexcoord2f[7] = 0; + + if(r_fb.fbo) + { + for (i = 1;i < 8;i += 2) + { + r_fb.screentexcoord2f[i] += 1 - (float)(viewheight + r_refdef.view.y) / (float)r_fb.screentextureheight; + } + } + + // set up a texcoord array for the reduced resolution bloom image + // (which will be additive blended over the screen image) + r_fb.bloomtexcoord2f[0] = 0; + r_fb.bloomtexcoord2f[1] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; + r_fb.bloomtexcoord2f[2] = (float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[3] = (float)r_fb.bloomheight / (float)r_fb.bloomtextureheight; + r_fb.bloomtexcoord2f[4] = (float)r_fb.bloomwidth / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[5] = 0; + r_fb.bloomtexcoord2f[6] = 0; + r_fb.bloomtexcoord2f[7] = 0; + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + for (i = 0;i < 4;i++) + { + r_fb.screentexcoord2f[i*2+0] += 0.5f / (float)r_fb.screentexturewidth; + r_fb.screentexcoord2f[i*2+1] += 0.5f / (float)r_fb.screentextureheight; + r_fb.bloomtexcoord2f[i*2+0] += 0.5f / (float)r_fb.bloomtexturewidth; + r_fb.bloomtexcoord2f[i*2+1] += 0.5f / (float)r_fb.bloomtextureheight; + } + break; + } + + R_Viewport_InitOrtho(&r_fb.bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL); + + if (r_fb.fbo) + r_refdef.view.clear = true; +} + +static void R_Bloom_MakeTexture(void) +{ + int x, range, dir; + float xoffset, yoffset, r, brighten; + rtexture_t *intex; + float colorscale = r_bloom_colorscale.value; + + r_refdef.stats[r_stat_bloom]++; + +#if 0 + // this copy is unnecessary since it happens in R_BlendView already + if (!r_fb.fbo) + { + R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + } +#endif + + // scale down screen texture to the bloom texture size + CHECKGLERROR + r_fb.bloomindex = 0; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); + R_SetViewport(&r_fb.bloomviewport); + GL_DepthTest(false); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(colorscale, colorscale, colorscale, 1); + // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that... + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_SOFT: + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f); + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f); + break; + } + // TODO: do boxfilter scale-down in shader? + R_SetupShader_Generic(r_fb.colortexture, NULL, GL_MODULATE, 1, false, true, true); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; + + // we now have a properly scaled bloom image + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy it into the bloom texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } + + // multiply bloom image by itself as many times as desired + for (x = 1;x < min(r_bloom_colorexponent.value, 32);) + { + intex = r_fb.bloomtexture[r_fb.bloomindex]; + r_fb.bloomindex ^= 1; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); + x *= 2; + r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1 + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); // square it and multiply by two + GL_Color(r,r,r,1); // apply fix factor + } + else + { + if(x <= 2) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); + GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it + GL_Color(1,1,1,1); // no fix factor supported here + } + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.bloomtexcoord2f); + R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; + + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy the darkened image to a texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } + } + + range = r_bloom_blur.integer * r_fb.bloomwidth / 320; + brighten = r_bloom_brighten.value; + brighten = sqrt(brighten); + if(range >= 1) + brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle" + + for (dir = 0;dir < 2;dir++) + { + intex = r_fb.bloomtexture[r_fb.bloomindex]; + r_fb.bloomindex ^= 1; + R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); + // blend on at multiple vertical offsets to achieve a vertical blur + // TODO: do offset blends using GLSL + // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges + GL_BlendFunc(GL_ONE, GL_ZERO); + R_SetupShader_Generic(intex, NULL, GL_MODULATE, 1, false, true, false); + for (x = -range;x <= range;x++) + { + if (!dir){xoffset = 0;yoffset = x;} + else {xoffset = x;yoffset = 0;} + xoffset /= (float)r_fb.bloomtexturewidth; + yoffset /= (float)r_fb.bloomtextureheight; + // compute a texcoord array with the specified x and y offset + r_fb.offsettexcoord2f[0] = xoffset+r_fb.bloomtexcoord2f[0]; + r_fb.offsettexcoord2f[1] = yoffset+r_fb.bloomtexcoord2f[1]; + r_fb.offsettexcoord2f[2] = xoffset+r_fb.bloomtexcoord2f[2]; + r_fb.offsettexcoord2f[3] = yoffset+r_fb.bloomtexcoord2f[3]; + r_fb.offsettexcoord2f[4] = xoffset+r_fb.bloomtexcoord2f[4]; + r_fb.offsettexcoord2f[5] = yoffset+r_fb.bloomtexcoord2f[5]; + r_fb.offsettexcoord2f[6] = xoffset+r_fb.bloomtexcoord2f[6]; + r_fb.offsettexcoord2f[7] = yoffset+r_fb.bloomtexcoord2f[7]; + // this r value looks like a 'dot' particle, fading sharply to + // black at the edges + // (probably not realistic but looks good enough) + //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1); + //r = brighten/(range*2+1); + r = brighten / (range * 2 + 1); + if(range >= 1) + r *= (1 - x*x/(float)(range*range)); + GL_Color(r, r, r, 1); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight; + GL_BlendFunc(GL_ONE, GL_ONE); + } + + if (!r_fb.bloomfbo[r_fb.bloomindex]) + { + // copy the vertically or horizontally blurred bloom view to a texture + R_Mesh_CopyToTexture(r_fb.bloomtexture[r_fb.bloomindex], 0, 0, r_fb.bloomviewport.x, r_fb.bloomviewport.y, r_fb.bloomviewport.width, r_fb.bloomviewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_fb.bloomviewport.width * r_fb.bloomviewport.height; + } + } +} + +static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + unsigned int permutation; + float uservecs[4][4]; + + R_EntityMatrix(&identitymatrix); + + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + permutation = + (r_fb.bloomtexture[r_fb.bloomindex] ? SHADERPERMUTATION_BLOOM : 0) + | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0) + | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0) + | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0) + | ((r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0); + + if (r_fb.colortexture) + { + if (!r_fb.fbo) + { + R_Mesh_CopyToTexture(r_fb.colortexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + } + + if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture) + { + // declare variables + float blur_factor, blur_mouseaccel, blur_velocity; + static float blur_average; + static vec3_t blur_oldangles; // used to see how quickly the mouse is moving + + // set a goal for the factoring + blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) + / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1); + blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) + / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1); + blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) + + (blur_mouseaccel * r_motionblur_mousefactor.value)); + + // from the goal, pick an averaged value between goal and last value + cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1); + blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha; + + // enforce minimum amount of blur + blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value; + + //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel); + + // calculate values into a standard alpha + cl.motionbluralpha = 1 - exp(- + ( + (r_motionblur.value * blur_factor / 80) + + + (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600)) + ) + / + max(0.0001, cl.time - cl.oldtime) // fps independent + ); + + // randomization for the blur value to combat persistent ghosting + cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value); + cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value); + + // apply the blur + R_ResetViewRendering2D(fbo, depthtexture, colortexture); + if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_Color(1, 1, 1, cl.motionbluralpha); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + case RENDERPATH_SOFT: + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.screentexcoord2f); + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f); + break; + } + R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + } + + // updates old view angles for next pass + VectorCopy(cl.viewangles, blur_oldangles); + + // copy view into the ghost texture + R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_refdef.stats[r_stat_bloom_copypixels] += r_refdef.view.viewport.width * r_refdef.view.viewport.height; + r_fb.ghosttexture_valid = true; + } + } + else + { + // no r_fb.colortexture means we're rendering to the real fb + // we may still have to do view tint... + if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) + { + // apply a color tint to the whole view + R_ResetViewRendering2D(0, NULL, NULL); + GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); + R_SetupShader_Generic_NoTexture(false, true); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + } + break; // no screen processing, no bloom, skip it + } + + if (r_fb.bloomtexture[0]) + { + // make the bloom texture + R_Bloom_MakeTexture(); + } + +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + memset(uservecs, 0, sizeof(uservecs)); + if (r_glsl_postprocess_uservec1_enable.integer) + sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]); + if (r_glsl_postprocess_uservec2_enable.integer) + sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]); + if (r_glsl_postprocess_uservec3_enable.integer) + sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]); + if (r_glsl_postprocess_uservec4_enable.integer) + sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]); + + R_ResetViewRendering2D(0, NULL, NULL); // here we render to the real framebuffer! + GL_Color(1, 1, 1, 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); + R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation); + if (r_glsl_permutation->tex_Texture_First >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , r_fb.colortexture); + if (r_glsl_permutation->tex_Texture_Second >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second , r_fb.bloomtexture[r_fb.bloomindex]); + if (r_glsl_permutation->tex_Texture_GammaRamps >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps ); + if (r_glsl_permutation->loc_ViewTintColor >= 0) qglUniform4f(r_glsl_permutation->loc_ViewTintColor , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + if (r_glsl_permutation->loc_PixelSize >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); + if (r_glsl_permutation->loc_UserVec1 >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec1 , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]); + if (r_glsl_permutation->loc_UserVec2 >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec2 , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]); + if (r_glsl_permutation->loc_UserVec3 >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec3 , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]); + if (r_glsl_permutation->loc_UserVec4 >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec4 , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]); + if (r_glsl_permutation->loc_Saturation >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation , r_glsl_saturation.value); + if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); + if (r_glsl_permutation->loc_BloomColorSubtract >= 0) qglUniform4f(r_glsl_permutation->loc_BloomColorSubtract , r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 0.0f); + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + // D3D has upside down Y coords, the easiest way to flip this is to flip the screen vertices rather than the texcoords, so we just use a different array for that... + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_d3dscreenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); + R_SetupShader_SetPermutationHLSL(SHADERMODE_POSTPROCESS, permutation); + R_Mesh_TexBind(GL20TU_FIRST , r_fb.colortexture); + R_Mesh_TexBind(GL20TU_SECOND , r_fb.bloomtexture[r_fb.bloomindex]); + R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps ); + hlslPSSetParameter4f(D3DPSREGISTER_ViewTintColor , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + hlslPSSetParameter2f(D3DPSREGISTER_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); + hlslPSSetParameter4f(D3DPSREGISTER_UserVec1 , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]); + hlslPSSetParameter4f(D3DPSREGISTER_UserVec2 , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]); + hlslPSSetParameter4f(D3DPSREGISTER_UserVec3 , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]); + hlslPSSetParameter4f(D3DPSREGISTER_UserVec4 , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]); + hlslPSSetParameter1f(D3DPSREGISTER_Saturation , r_glsl_saturation.value); + hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); + hlslPSSetParameter4f(D3DPSREGISTER_BloomColorSubtract , r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 0.0f); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.screentexcoord2f, r_fb.bloomtexcoord2f); + R_SetupShader_SetPermutationSoft(SHADERMODE_POSTPROCESS, permutation); + R_Mesh_TexBind(GL20TU_FIRST , r_fb.colortexture); + R_Mesh_TexBind(GL20TU_SECOND , r_fb.bloomtexture[r_fb.bloomindex]); + R_Mesh_TexBind(GL20TU_GAMMARAMPS, r_texture_gammaramps ); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_ViewTintColor , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelSize , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec1 , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec2 , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec3 , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_UserVec4 , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]); + DPSOFTRAST_Uniform1f(DPSOFTRAST_UNIFORM_Saturation , r_glsl_saturation.value); + DPSOFTRAST_Uniform2f(DPSOFTRAST_UNIFORM_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); + DPSOFTRAST_Uniform4f(DPSOFTRAST_UNIFORM_BloomColorSubtract , r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 0.0f); + break; + default: + break; + } + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) + { + // apply a color tint to the whole view + R_ResetViewRendering2D(0, NULL, NULL); + GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); + R_SetupShader_Generic_NoTexture(false, true); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + } + break; + } +} + +matrix4x4_t r_waterscrollmatrix; + +void R_UpdateFog(void) +{ + // Nehahra fog + if (gamemode == GAME_NEHAHRA) + { + if (gl_fogenable.integer) + { + r_refdef.oldgl_fogenable = true; + r_refdef.fog_density = gl_fogdensity.value; + r_refdef.fog_red = gl_fogred.value; + r_refdef.fog_green = gl_foggreen.value; + r_refdef.fog_blue = gl_fogblue.value; + r_refdef.fog_alpha = 1; + r_refdef.fog_start = 0; + r_refdef.fog_end = gl_skyclip.value; + r_refdef.fog_height = 1<<30; + r_refdef.fog_fadedepth = 128; + } + else if (r_refdef.oldgl_fogenable) + { + r_refdef.oldgl_fogenable = false; + r_refdef.fog_density = 0; + r_refdef.fog_red = 0; + r_refdef.fog_green = 0; + r_refdef.fog_blue = 0; + r_refdef.fog_alpha = 0; + r_refdef.fog_start = 0; + r_refdef.fog_end = 0; + r_refdef.fog_height = 1<<30; + r_refdef.fog_fadedepth = 128; + } + } + + // fog parms + r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1); + r_refdef.fog_start = max(0, r_refdef.fog_start); + r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end); + + if (r_refdef.fog_density && r_drawfog.integer) + { + r_refdef.fogenabled = true; + // this is the point where the fog reaches 0.9986 alpha, which we + // consider a good enough cutoff point for the texture + // (0.9986 * 256 == 255.6) + if (r_fog_exp2.integer) + r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start; + else + r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start; + r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end); + r_refdef.fograngerecip = 1.0f / r_refdef.fogrange; + r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip; + if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename)) + R_BuildFogHeightTexture(); + // fog color was already set + // update the fog texture + if (r_refdef.fogmasktable_start != r_refdef.fog_start || r_refdef.fogmasktable_alpha != r_refdef.fog_alpha || r_refdef.fogmasktable_density != r_refdef.fog_density || r_refdef.fogmasktable_range != r_refdef.fogrange) + R_BuildFogTexture(); + r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth); + r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale; + } + else + r_refdef.fogenabled = false; + + // fog color + if (r_refdef.fog_density) + { + r_refdef.fogcolor[0] = r_refdef.fog_red; + r_refdef.fogcolor[1] = r_refdef.fog_green; + r_refdef.fogcolor[2] = r_refdef.fog_blue; + + Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height); + r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3]; + r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0; + r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth); + + { + vec3_t fogvec; + VectorCopy(r_refdef.fogcolor, fogvec); + // color.rgb *= ContrastBoost * SceneBrightness; + VectorScale(fogvec, r_refdef.view.colorscale, fogvec); + r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f); + r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f); + r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f); + } + } +} + +void R_UpdateVariables(void) +{ + R_Textures_Frame(); + + r_refdef.scene.ambient = r_ambient.value * (1.0f / 64.0f); + + r_refdef.farclip = r_farclip_base.value; + if (r_refdef.scene.worldmodel) + r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2; + r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f); + + if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1) + Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1); + r_refdef.polygonfactor = 0; + r_refdef.polygonoffset = 0; + r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1); + r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1); + + r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0; + r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil; + r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer; + r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil; + r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1; + if (FAKELIGHT_ENABLED) + { + r_refdef.lightmapintensity *= r_fakelight_intensity.value; + } + else if (r_refdef.scene.worldmodel) + { + r_refdef.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale; + } + if (r_showsurfaces.integer) + { + r_refdef.scene.rtworld = false; + r_refdef.scene.rtworldshadows = false; + r_refdef.scene.rtdlight = false; + r_refdef.scene.rtdlightshadows = false; + r_refdef.lightmapintensity = 0; + } + + r_gpuskeletal = false; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal! + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + if(v_glslgamma.integer && !vid_gammatables_trivial) + { + if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial) + { + // build GLSL gamma texture +#define RAMPWIDTH 256 + unsigned short ramp[RAMPWIDTH * 3]; + unsigned char rampbgr[RAMPWIDTH][4]; + int i; + + r_texture_gammaramps_serial = vid_gammatables_serial; + + VID_BuildGammaTables(&ramp[0], RAMPWIDTH); + for(i = 0; i < RAMPWIDTH; ++i) + { + rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5); + rampbgr[i][3] = 0; + } + if (r_texture_gammaramps) + { + R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1); + } + else + { + r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL); + } + } + } + else + { + // remove GLSL gamma texture + } + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + break; + } +} + +static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT; +static r_refdef_scene_t r_scenes_store[ RST_COUNT ]; +/* +================ +R_SelectScene +================ +*/ +void R_SelectScene( r_refdef_scene_type_t scenetype ) { + if( scenetype != r_currentscenetype ) { + // store the old scenetype + r_scenes_store[ r_currentscenetype ] = r_refdef.scene; + r_currentscenetype = scenetype; + // move in the new scene + r_refdef.scene = r_scenes_store[ r_currentscenetype ]; + } +} + +/* +================ +R_GetScenePointer +================ +*/ +r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype ) +{ + // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function.. + if( scenetype == r_currentscenetype ) { + return &r_refdef.scene; + } else { + return &r_scenes_store[ scenetype ]; + } +} + +static int R_SortEntities_Compare(const void *ap, const void *bp) +{ + const entity_render_t *a = *(const entity_render_t **)ap; + const entity_render_t *b = *(const entity_render_t **)bp; + + // 1. compare model + if(a->model < b->model) + return -1; + if(a->model > b->model) + return +1; + + // 2. compare skin + // TODO possibly calculate the REAL skinnum here first using + // skinscenes? + if(a->skinnum < b->skinnum) + return -1; + if(a->skinnum > b->skinnum) + return +1; + + // everything we compared is equal + return 0; +} +static void R_SortEntities(void) +{ + // below or equal 2 ents, sorting never gains anything + if(r_refdef.scene.numentities <= 2) + return; + // sort + qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare); +} + +/* +================ +R_RenderView +================ +*/ +int dpsoftrast_test; +extern cvar_t r_shadow_bouncegrid; +void R_RenderView() +{ + matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix; + int fbo; + rtexture_t *depthtexture; + rtexture_t *colortexture; + + dpsoftrast_test = r_test.integer; + + if (r_timereport_active) + R_TimeReport("start"); + r_textureframe++; // used only by R_GetCurrentTexture + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + + if(R_CompileShader_CheckStaticParms()) + R_GLSL_Restart_f(); + + if (!r_drawentities.integer) + r_refdef.scene.numentities = 0; + else if (r_sortentities.integer) + R_SortEntities(); + + R_AnimCache_ClearCache(); + + /* adjust for stereo display */ + Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, GetStereoSeparation() * (0.5f - r_stereo_side), 0, 0, r_stereo_angle.value * (0.5f - r_stereo_side), 0, 1); + Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix); + + if (r_refdef.view.isoverlay) + { + // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas] + R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL); + GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0); + R_TimeReport("depthclear"); + + r_refdef.view.showdebug = false; + + r_fb.water.enabled = false; + r_fb.water.numwaterplanes = 0; + + R_RenderScene(0, NULL, NULL); + + r_refdef.view.matrix = originalmatrix; + + CHECKGLERROR + return; + } + + if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/) + { + r_refdef.view.matrix = originalmatrix; + return; + } + + r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value; + + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + // in sRGB fallback, behave similar to true sRGB: convert this + // value from linear to sRGB + r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale); + + R_RenderView_UpdateViewVectors(); + + R_Shadow_UpdateWorldLightSelection(); + + R_Bloom_StartFrame(); + + // apply bloom brightness offset + if(r_fb.bloomtexture[0]) + r_refdef.view.colorscale *= r_bloom_scenebrightness.value; + + R_Water_StartFrame(); + + // now we probably have an fbo to render into + fbo = r_fb.fbo; + depthtexture = r_fb.depthtexture; + colortexture = r_fb.colortexture; + + CHECKGLERROR + if (r_timereport_active) + R_TimeReport("viewsetup"); + + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + + if (r_refdef.view.clear || r_refdef.fogenabled || fbo) + { + R_ClearScreen(r_refdef.fogenabled); + if (r_timereport_active) + R_TimeReport("viewclear"); + } + r_refdef.view.clear = true; + + r_refdef.view.showdebug = true; + + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + + R_AnimCache_CacheVisibleEntities(); + if (r_timereport_active) + R_TimeReport("animcache"); + + R_Shadow_UpdateBounceGridTexture(); + if (r_timereport_active && r_shadow_bouncegrid.integer) + R_TimeReport("bouncegrid"); + + r_fb.water.numwaterplanes = 0; + if (r_fb.water.enabled) + R_RenderWaterPlanes(fbo, depthtexture, colortexture); + + R_RenderScene(fbo, depthtexture, colortexture); + r_fb.water.numwaterplanes = 0; + + R_BlendView(fbo, depthtexture, colortexture); + if (r_timereport_active) + R_TimeReport("blendview"); + + GL_Scissor(0, 0, vid.width, vid.height); + GL_ScissorTest(false); + + r_refdef.view.matrix = originalmatrix; + + CHECKGLERROR +} + +void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) + { + r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("waterworld"); + } + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + R_DrawModelsAddWaterPlanes(); + if (r_timereport_active) + R_TimeReport("watermodels"); + + if (r_fb.water.numwaterplanes) + { + R_Water_ProcessPlanes(fbo, depthtexture, colortexture); + if (r_timereport_active) + R_TimeReport("waterscenes"); + } +} + +extern cvar_t cl_locs_show; +static void R_DrawLocs(void); +static void R_DrawEntityBBoxes(void); +static void R_DrawModelDecals(void); +extern cvar_t cl_decals_newsystem; +extern qboolean r_shadow_usingdeferredprepass; +void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + qboolean shadowmapping = false; + + if (r_timereport_active) + R_TimeReport("beginscene"); + + r_refdef.stats[r_stat_renders]++; + + R_UpdateFog(); + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + R_MeshQueue_BeginScene(); + + R_SkyStartFrame(); + + Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0); + + if (r_timereport_active) + R_TimeReport("skystartframe"); + + if (cl.csqc_vidvars.drawworld) + { + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky) + { + r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("worldsky"); + } + + if (R_DrawBrushModelsSky() && r_timereport_active) + R_TimeReport("bmodelsky"); + + if (skyrendermasked && skyrenderlater) + { + // we have to force off the water clipping plane while rendering sky + R_SetupView(false, fbo, depthtexture, colortexture); + R_Sky(); + R_SetupView(true, fbo, depthtexture, colortexture); + if (r_timereport_active) + R_TimeReport("sky"); + } + } + + R_Shadow_PrepareLights(fbo, depthtexture, colortexture); + if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0) + R_Shadow_PrepareModelShadows(); + if (r_timereport_active) + R_TimeReport("preparelights"); + + if (R_Shadow_ShadowMappingEnabled()) + shadowmapping = true; + + if (r_shadow_usingdeferredprepass) + R_Shadow_DrawPrepass(); + + if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth) + { + r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("worlddepth"); + } + if (r_depthfirst.integer >= 2) + { + R_DrawModelsDepth(); + if (r_timereport_active) + R_TimeReport("modeldepth"); + } + + if (r_shadows.integer >= 2 && shadowmapping && r_refdef.lightmapintensity > 0) + { + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadowMaps(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + } + + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw) + { + r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("world"); + } + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + R_DrawModels(); + if (r_timereport_active) + R_TimeReport("models"); + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0) + { + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadows(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + } + + if (!r_shadow_usingdeferredprepass) + { + R_Shadow_DrawLights(); + if (r_timereport_active) + R_TimeReport("rtlights"); + } + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.lightmapintensity > 0) + { + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_DrawModelShadows(fbo, depthtexture, colortexture); + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + } + + if (cl.csqc_vidvars.drawworld) + { + if (cl_decals_newsystem.integer) + { + R_DrawModelDecals(); + if (r_timereport_active) + R_TimeReport("modeldecals"); + } + else + { + R_DrawDecals(); + if (r_timereport_active) + R_TimeReport("decals"); + } + + R_DrawParticles(); + if (r_timereport_active) + R_TimeReport("particles"); + + R_DrawExplosions(); + if (r_timereport_active) + R_TimeReport("explosions"); + + R_DrawLightningBeams(); + if (r_timereport_active) + R_TimeReport("lightning"); + } + + if (cl.csqc_loaded) + VM_CL_AddPolygonsToMeshQueue(CLVM_prog); + + if (r_refdef.view.showdebug) + { + if (cl_locs_show.integer) + { + R_DrawLocs(); + if (r_timereport_active) + R_TimeReport("showlocs"); + } + + if (r_drawportals.integer) + { + R_DrawPortals(); + if (r_timereport_active) + R_TimeReport("portals"); + } + + if (r_showbboxes.value > 0) + { + R_DrawEntityBBoxes(); + if (r_timereport_active) + R_TimeReport("bboxes"); + } + } + + if (r_transparent.integer) + { + R_MeshQueue_RenderTransparent(); + if (r_timereport_active) + R_TimeReport("drawtrans"); + } + + if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0 || r_showoverdraw.value > 0)) + { + r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("worlddebug"); + R_DrawModelsDebug(); + if (r_timereport_active) + R_TimeReport("modeldebug"); + } + + if (cl.csqc_vidvars.drawworld) + { + R_Shadow_DrawCoronas(); + if (r_timereport_active) + R_TimeReport("coronas"); + } + +#if 0 + { + GL_DepthTest(false); + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + GL_Color(1, 1, 1, 1); + qglBegin(GL_POLYGON); + qglVertex3f(r_refdef.view.frustumcorner[0][0], r_refdef.view.frustumcorner[0][1], r_refdef.view.frustumcorner[0][2]); + qglVertex3f(r_refdef.view.frustumcorner[1][0], r_refdef.view.frustumcorner[1][1], r_refdef.view.frustumcorner[1][2]); + qglVertex3f(r_refdef.view.frustumcorner[3][0], r_refdef.view.frustumcorner[3][1], r_refdef.view.frustumcorner[3][2]); + qglVertex3f(r_refdef.view.frustumcorner[2][0], r_refdef.view.frustumcorner[2][1], r_refdef.view.frustumcorner[2][2]); + qglEnd(); + qglBegin(GL_POLYGON); + qglVertex3f(r_refdef.view.frustumcorner[0][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[0][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[0][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[1][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[1][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[1][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[3][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[3][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[3][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[2][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[2][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[2][2] + 1000 * r_refdef.view.forward[2]); + qglEnd(); + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); +} + +static const unsigned short bboxelements[36] = +{ + 5, 1, 3, 5, 3, 7, + 6, 2, 0, 6, 0, 4, + 7, 3, 2, 7, 2, 6, + 4, 0, 1, 4, 1, 5, + 4, 5, 7, 4, 7, 6, + 1, 0, 2, 1, 2, 3, +}; + +static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca) +{ + int i; + float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4]; + + RSurf_ActiveWorldEntity(); + + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); +// R_Mesh_ResetTextureState(); + + vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; // + vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2]; + vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2]; + vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2]; + vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2]; + vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2]; + vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2]; + vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2]; + R_FillColors(color4f, 8, cr, cg, cb, ca); + if (r_refdef.fogenabled) + { + for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4) + { + f1 = RSurf_FogVertex(v); + f2 = 1 - f1; + c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2; + c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2; + c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2; + } + } + R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL); + R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(false, false); + R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); +} + +static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + float color[4]; + prvm_edict_t *edict; + + // this function draws bounding boxes of server entities + if (!sv.active) + return; + + GL_CullFace(GL_NONE); + R_SetupShader_Generic_NoTexture(false, false); + + for (i = 0;i < numsurfaces;i++) + { + edict = PRVM_EDICT_NUM(surfacelist[i]); + switch ((int)PRVM_serveredictfloat(edict, solid)) + { + case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break; + case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break; + case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break; + case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break; + case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break; + case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break; + default: Vector4Set(color, 0, 0, 0, 0.50);break; + } + color[3] *= r_showbboxes.value; + color[3] = bound(0, color[3], 1); + GL_DepthTest(!r_showdisabledepthtest.integer); + GL_CullFace(r_refdef.view.cullface_front); + R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]); + } +} + +static void R_DrawEntityBBoxes(void) +{ + int i; + prvm_edict_t *edict; + vec3_t center; + prvm_prog_t *prog = SVVM_prog; + + // this function draws bounding boxes of server entities + if (!sv.active) + return; + + for (i = 0;i < prog->num_edicts;i++) + { + edict = PRVM_EDICT_NUM(i); + if (edict->priv.server->free) + continue; + // exclude the following for now, as they don't live in world coordinate space and can't be solid: + if(PRVM_serveredictedict(edict, tag_entity) != 0) + continue; + if(PRVM_serveredictedict(edict, viewmodelforclient) != 0) + continue; + VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL); + } +} + +static const int nomodelelement3i[24] = +{ + 5, 2, 0, + 5, 1, 2, + 5, 0, 3, + 5, 3, 1, + 0, 2, 4, + 2, 1, 4, + 3, 0, 4, + 1, 3, 4 +}; + +static const unsigned short nomodelelement3s[24] = +{ + 5, 2, 0, + 5, 1, 2, + 5, 0, 3, + 5, 3, 1, + 0, 2, 4, + 2, 1, 4, + 3, 0, 4, + 1, 3, 4 +}; + +static const float nomodelvertex3f[6*3] = +{ + -16, 0, 0, + 16, 0, 0, + 0, -16, 0, + 0, 16, 0, + 0, 0, -16, + 0, 0, 16 +}; + +static const float nomodelcolor4f[6*4] = +{ + 0.0f, 0.0f, 0.5f, 1.0f, + 0.0f, 0.0f, 0.5f, 1.0f, + 0.0f, 0.5f, 0.0f, 1.0f, + 0.0f, 0.5f, 0.0f, 1.0f, + 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.0f, 0.0f, 1.0f +}; + +static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int i; + float f1, f2, *c; + float color4f[6*4]; + + RSurf_ActiveCustomEntity(&ent->matrix, &ent->inversematrix, ent->flags, ent->shadertime, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha, 6, nomodelvertex3f, NULL, NULL, NULL, NULL, nomodelcolor4f, 8, nomodelelement3i, nomodelelement3s, false, false); + + // this is only called once per entity so numsurfaces is always 1, and + // surfacelist is always {0}, so this code does not handle batches + + if (rsurface.ent_flags & RENDER_ADDITIVE) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + } + else if (rsurface.colormod[3] < 1) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + } + else + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + } + GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1); + GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset); + GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST)); + GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back); + memcpy(color4f, nomodelcolor4f, sizeof(float[6*4])); + for (i = 0, c = color4f;i < 6;i++, c += 4) + { + c[0] *= rsurface.colormod[0]; + c[1] *= rsurface.colormod[1]; + c[2] *= rsurface.colormod[2]; + c[3] *= rsurface.colormod[3]; + } + if (r_refdef.fogenabled) + { + for (i = 0, c = color4f;i < 6;i++, c += 4) + { + f1 = RSurf_FogVertex(nomodelvertex3f + 3*i); + f2 = 1 - f1; + c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2); + c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2); + c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2); + } + } +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(false, false); + R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL); + R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0); +} + +void R_DrawNoModel(entity_render_t *ent) +{ + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1)) + R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight); + else + R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL); +} + +void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width) +{ + vec3_t right1, right2, diff, normal; + + VectorSubtract (org2, org1, normal); + + // calculate 'right' vector for start + VectorSubtract (r_refdef.view.origin, org1, diff); + CrossProduct (normal, diff, right1); + VectorNormalize (right1); + + // calculate 'right' vector for end + VectorSubtract (r_refdef.view.origin, org2, diff); + CrossProduct (normal, diff, right2); + VectorNormalize (right2); + + vert[ 0] = org1[0] + width * right1[0]; + vert[ 1] = org1[1] + width * right1[1]; + vert[ 2] = org1[2] + width * right1[2]; + vert[ 3] = org1[0] - width * right1[0]; + vert[ 4] = org1[1] - width * right1[1]; + vert[ 5] = org1[2] - width * right1[2]; + vert[ 6] = org2[0] - width * right2[0]; + vert[ 7] = org2[1] - width * right2[1]; + vert[ 8] = org2[2] - width * right2[2]; + vert[ 9] = org2[0] + width * right2[0]; + vert[10] = org2[1] + width * right2[1]; + vert[11] = org2[2] + width * right2[2]; +} + +void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2) +{ + vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1; + vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1; + vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1; + vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2; + vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2; + vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2; + vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2; + vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2; + vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2; + vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1; + vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1; + vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1; +} + +static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z) +{ + int i; + float *vertex3f; + float v[3]; + VectorSet(v, x, y, z); + for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3) + if (VectorDistance2(v, vertex3f) < mesh->epsilon2) + break; + if (i == mesh->numvertices) + { + if (mesh->numvertices < mesh->maxvertices) + { + VectorCopy(v, vertex3f); + mesh->numvertices++; + } + return mesh->numvertices; + } + else + return i; +} + +void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f) +{ + int i; + int *e, element[3]; + element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3; + element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3; + e = mesh->element3i + mesh->numtriangles * 3; + for (i = 0;i < numvertices - 2;i++, vertex3f += 3) + { + element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]); + if (mesh->numtriangles < mesh->maxtriangles) + { + *e++ = element[0]; + *e++ = element[1]; + *e++ = element[2]; + mesh->numtriangles++; + } + element[1] = element[2]; + } +} + +static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d) +{ + int i; + int *e, element[3]; + element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3; + element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3; + e = mesh->element3i + mesh->numtriangles * 3; + for (i = 0;i < numvertices - 2;i++, vertex3d += 3) + { + element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]); + if (mesh->numtriangles < mesh->maxtriangles) + { + *e++ = element[0]; + *e++ = element[1]; + *e++ = element[2]; + mesh->numtriangles++; + } + element[1] = element[2]; + } +} + +#define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0) +void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes) +{ + int planenum, planenum2; + int w; + int tempnumpoints; + mplane_t *plane, *plane2; + double maxdist; + double temppoints[2][256*3]; + // figure out how large a bounding box we need to properly compute this brush + maxdist = 0; + for (w = 0;w < numplanes;w++) + maxdist = max(maxdist, fabs(planes[w].dist)); + // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024 + maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0; + for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++) + { + w = 0; + tempnumpoints = 4; + PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist); + for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++) + { + if (planenum2 == planenum) + continue; + PolygonD_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, R_MESH_PLANE_DIST_EPSILON, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL); + w = !w; + } + if (tempnumpoints < 3) + continue; + // generate elements forming a triangle fan for this polygon + R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]); + } +} + +static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a) +{ + texturelayer_t *layer; + layer = t->currentlayers + t->currentnumlayers++; + layer->type = type; + layer->depthmask = depthmask; + layer->blendfunc1 = blendfunc1; + layer->blendfunc2 = blendfunc2; + layer->texture = texture; + layer->texmatrix = *matrix; + layer->color[0] = r; + layer->color[1] = g; + layer->color[2] = b; + layer->color[3] = a; +} + +static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms) +{ + if(parms[0] == 0 && parms[1] == 0) + return false; + if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set! + if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0) + return false; + return true; +} + +static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) +{ + double index, f; + index = parms[2] + rsurface.shadertime * parms[3]; + index -= floor(index); + switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1)) + { + default: + case Q3WAVEFUNC_NONE: + case Q3WAVEFUNC_NOISE: + case Q3WAVEFUNC_COUNT: + f = 0; + break; + case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break; + case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break; + case Q3WAVEFUNC_SAWTOOTH: f = index;break; + case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break; + case Q3WAVEFUNC_TRIANGLE: + index *= 4; + f = index - floor(index); + if (index < 1) + { + // f = f; + } + else if (index < 2) + f = 1 - f; + else if (index < 3) + f = -f; + else + f = -(1 - f); + break; + } + f = parms[0] + parms[1] * f; + if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set! + f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)]; + return (float) f; +} + +static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags) +{ + int w, h, idx; + double f; + double offsetd[2]; + float tcmat[12]; + matrix4x4_t matrix, temp; + switch(tcmod->tcmod) + { + case Q3TCMOD_COUNT: + case Q3TCMOD_NONE: + if (currentmaterialflags & MATERIALFLAG_WATERSCROLL) + matrix = r_waterscrollmatrix; + else + matrix = identitymatrix; + break; + case Q3TCMOD_ENTITYTRANSLATE: + // this is used in Q3 to allow the gamecode to control texcoord + // scrolling on the entity, which is not supported in darkplaces yet. + Matrix4x4_CreateTranslate(&matrix, 0, 0, 0); + break; + case Q3TCMOD_ROTATE: + f = tcmod->parms[0] * rsurface.shadertime; + Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0); + Matrix4x4_ConcatRotate(&matrix, (f / 360 - floor(f / 360)) * 360, 0, 0, 1); + Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0); + break; + case Q3TCMOD_SCALE: + Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1); + break; + case Q3TCMOD_SCROLL: + // extra care is needed because of precision breakdown with large values of time + offsetd[0] = tcmod->parms[0] * rsurface.shadertime; + offsetd[1] = tcmod->parms[1] * rsurface.shadertime; + Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0); + break; + case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures) + w = (int) tcmod->parms[0]; + h = (int) tcmod->parms[1]; + f = rsurface.shadertime / (tcmod->parms[2] * w * h); + f = f - floor(f); + idx = (int) floor(f * w * h); + Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0); + break; + case Q3TCMOD_STRETCH: + f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms); + Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f); + break; + case Q3TCMOD_TRANSFORM: + VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0); + VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0); + VectorSet(tcmat + 6, 0 , 0 , 1); + VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0); + Matrix4x4_FromArray12FloatGL(&matrix, tcmat); + break; + case Q3TCMOD_TURBULENT: + // this is handled in the RSurf_PrepareVertices function + matrix = identitymatrix; + break; + } + temp = *texmatrix; + Matrix4x4_Concat(texmatrix, &matrix, &temp); +} + +static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname) +{ + int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP; + char name[MAX_QPATH]; + skinframe_t *skinframe; + unsigned char pixels[296*194]; + strlcpy(cache->name, skinname, sizeof(cache->name)); + dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name); + if (developer_loading.integer) + Con_Printf("loading %s\n", name); + skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false); + if (!skinframe || !skinframe->base) + { + unsigned char *f; + fs_offset_t filesize; + skinframe = NULL; + f = FS_LoadFile(name, tempmempool, true, &filesize); + if (f) + { + if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194)) + skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height); + Mem_Free(f); + } + } + cache->skinframe = skinframe; +} + +texture_t *R_GetCurrentTexture(texture_t *t) +{ + int i; + const entity_render_t *ent = rsurface.entity; + dp_model_t *model = ent->model; // when calling this, ent must not be NULL + q3shaderinfo_layer_tcmod_t *tcmod; + + if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate) + return t->currentframe; + t->update_lastrenderframe = r_textureframe; + t->update_lastrenderentity = (void *)ent; + + if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS) + t->camera_entity = ent->entitynumber; + else + t->camera_entity = 0; + + // switch to an alternate material if this is a q1bsp animated material + { + texture_t *texture = t; + int s = rsurface.ent_skinnum; + if ((unsigned int)s >= (unsigned int)model->numskins) + s = 0; + if (model->skinscenes) + { + if (model->skinscenes[s].framecount > 1) + s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount; + else + s = model->skinscenes[s].firstframe; + } + if (s > 0) + t = t + s * model->num_surfaces; + if (t->animated) + { + // use an alternate animation if the entity's frame is not 0, + // and only if the texture has an alternate animation + if (rsurface.ent_alttextures && t->anim_total[1]) + t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0]; + else + t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0]; + } + texture->currentframe = t; + } + + // update currentskinframe to be a qw skin or animation frame + if (rsurface.ent_qwskin >= 0) + { + i = rsurface.ent_qwskin; + if (!r_qwskincache || r_qwskincache_size != cl.maxclients) + { + r_qwskincache_size = cl.maxclients; + if (r_qwskincache) + Mem_Free(r_qwskincache); + r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size); + } + if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin)) + R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin); + t->currentskinframe = r_qwskincache[i].skinframe; + if (t->currentskinframe == NULL) + t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)]; + } + else if (t->numskinframes >= 2) + t->currentskinframe = t->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->skinframerate, t->numskinframes)]; + if (t->backgroundnumskinframes >= 2) + t->backgroundcurrentskinframe = t->backgroundskinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundskinframerate, t->backgroundnumskinframes)]; + + t->currentmaterialflags = t->basematerialflags; + t->currentalpha = rsurface.colormod[3]; + if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer)) + t->currentalpha *= r_wateralpha.value; + if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) + t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later + if(!r_fb.water.enabled || r_refdef.view.isoverlay) + t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA); + if (!(rsurface.ent_flags & RENDER_LIGHT)) + t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; + else if (FAKELIGHT_ENABLED) + { + // no modellight if using fakelight for the map + } + else if ((rsurface.modeltexcoordlightmap2f == NULL || (rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT))) && !(t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + { + // pick a model lighting mode + if (VectorLength2(rsurface.modellight_diffuse) >= (1.0f / 256.0f)) + t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL; + else + t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT; + } + if (rsurface.ent_flags & RENDER_ADDITIVE) + t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + else if (t->currentalpha < 1) + t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags + if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND) + t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA); + if (rsurface.ent_flags & RENDER_DOUBLESIDED) + t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE; + if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL)) + t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE; + if (t->backgroundnumskinframes) + t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND; + if (t->currentmaterialflags & MATERIALFLAG_BLENDED) + { + if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA)) + t->currentmaterialflags &= ~MATERIALFLAG_BLENDED; + } + else + t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA); + if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA))) + { + // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on + t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST; + } + if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED)) + t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH; + + // there is no tcmod + if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL) + { + t->currenttexmatrix = r_waterscrollmatrix; + t->currentbackgroundtexmatrix = r_waterscrollmatrix; + } + else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE)) + { + Matrix4x4_CreateIdentity(&t->currenttexmatrix); + Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix); + } + + for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++) + R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags); + for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++) + R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags); + + t->colormapping = VectorLength2(rsurface.colormap_pantscolor) + VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f); + if (t->currentskinframe->qpixels) + R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping); + t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; + if (!t->basetexture) + t->basetexture = r_texture_notexture; + t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL; + t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL; + t->nmaptexture = t->currentskinframe->nmap; + if (!t->nmaptexture) + t->nmaptexture = r_texture_blanknormalmap; + t->glosstexture = r_texture_black; + t->glowtexture = t->currentskinframe->glow; + t->fogtexture = t->currentskinframe->fog; + t->reflectmasktexture = t->currentskinframe->reflect; + if (t->backgroundnumskinframes) + { + t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base; + t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap; + t->backgroundglosstexture = r_texture_black; + t->backgroundglowtexture = t->backgroundcurrentskinframe->glow; + if (!t->backgroundnmaptexture) + t->backgroundnmaptexture = r_texture_blanknormalmap; + // make sure that if glow is going to be used, both textures are not NULL + if (!t->backgroundglowtexture && t->glowtexture) + t->backgroundglowtexture = r_texture_black; + if (!t->glowtexture && t->backgroundglowtexture) + t->glowtexture = r_texture_black; + } + else + { + t->backgroundbasetexture = r_texture_white; + t->backgroundnmaptexture = r_texture_blanknormalmap; + t->backgroundglosstexture = r_texture_black; + t->backgroundglowtexture = NULL; + } + t->specularpower = r_shadow_glossexponent.value; + // TODO: store reference values for these in the texture? + t->specularscale = 0; + if (r_shadow_gloss.integer > 0) + { + if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss)) + { + if (r_shadow_glossintensity.value > 0) + { + t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white; + t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white; + t->specularscale = r_shadow_glossintensity.value; + } + } + else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0) + { + t->glosstexture = r_texture_white; + t->backgroundglosstexture = r_texture_white; + t->specularscale = r_shadow_gloss2intensity.value; + t->specularpower = r_shadow_gloss2exponent.value; + } + } + t->specularscale *= t->specularscalemod; + t->specularpower *= t->specularpowermod; + t->rtlightambient = 0; + + // lightmaps mode looks bad with dlights using actual texturing, so turn + // off the colormap and glossmap, but leave the normalmap on as it still + // accurately represents the shading involved + if (gl_lightmaps.integer) + { + t->basetexture = r_texture_grey128; + t->pantstexture = r_texture_black; + t->shirttexture = r_texture_black; + if (gl_lightmaps.integer < 2) + t->nmaptexture = r_texture_blanknormalmap; + t->glosstexture = r_texture_black; + t->glowtexture = NULL; + t->fogtexture = NULL; + t->reflectmasktexture = NULL; + t->backgroundbasetexture = NULL; + if (gl_lightmaps.integer < 2) + t->backgroundnmaptexture = r_texture_blanknormalmap; + t->backgroundglosstexture = r_texture_black; + t->backgroundglowtexture = NULL; + t->specularscale = 0; + t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE)); + } + + Vector4Set(t->lightmapcolor, rsurface.colormod[0], rsurface.colormod[1], rsurface.colormod[2], t->currentalpha); + VectorClear(t->dlightcolor); + t->currentnumlayers = 0; + if (t->currentmaterialflags & MATERIALFLAG_WALL) + { + int blendfunc1, blendfunc2; + qboolean depthmask; + if (t->currentmaterialflags & MATERIALFLAG_ADD) + { + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE; + } + else if (t->currentmaterialflags & MATERIALFLAG_ALPHA) + { + blendfunc1 = GL_SRC_ALPHA; + blendfunc2 = GL_ONE_MINUS_SRC_ALPHA; + } + else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND) + { + blendfunc1 = t->customblendfunc[0]; + blendfunc2 = t->customblendfunc[1]; + } + else + { + blendfunc1 = GL_ONE; + blendfunc2 = GL_ZERO; + } + // don't colormod evilblend textures + if(!(R_BlendFuncFlags(blendfunc1, blendfunc2) & BLENDFUNC_ALLOWS_COLORMOD)) + VectorSet(t->lightmapcolor, 1, 1, 1); + depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED); + if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + // fullbright is not affected by r_refdef.lightmapintensity + R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]); + if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]); + if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]); + } + else + { + vec3_t ambientcolor; + float colorscale; + // set the color tint used for lights affecting this surface + VectorSet(t->dlightcolor, t->lightmapcolor[0] * t->lightmapcolor[3], t->lightmapcolor[1] * t->lightmapcolor[3], t->lightmapcolor[2] * t->lightmapcolor[3]); + colorscale = 2; + // q3bsp has no lightmap updates, so the lightstylevalue that + // would normally be baked into the lightmap must be + // applied to the color + // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright) + if (model->type == mod_brushq3) + colorscale *= r_refdef.scene.rtlightstylevalue[0]; + colorscale *= r_refdef.lightmapintensity; + VectorScale(t->lightmapcolor, r_refdef.scene.ambient, ambientcolor); + VectorScale(t->lightmapcolor, colorscale, t->lightmapcolor); + // basic lit geometry + R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]); + // add pants/shirt if needed + if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * t->lightmapcolor[0], rsurface.colormap_pantscolor[1] * t->lightmapcolor[1], rsurface.colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]); + if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * t->lightmapcolor[0], rsurface.colormap_shirtcolor[1] * t->lightmapcolor[1], rsurface.colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]); + // now add ambient passes if needed + if (VectorLength2(ambientcolor) >= (1.0f/1048576.0f)) + { + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, ambientcolor[0], ambientcolor[1], ambientcolor[2], t->lightmapcolor[3]); + if (VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f) && t->pantstexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, rsurface.colormap_pantscolor[0] * ambientcolor[0], rsurface.colormap_pantscolor[1] * ambientcolor[1], rsurface.colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]); + if (VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->shirttexture) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, rsurface.colormap_shirtcolor[0] * ambientcolor[0], rsurface.colormap_shirtcolor[1] * ambientcolor[1], rsurface.colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]); + } + } + if (t->glowtexture != NULL && !gl_lightmaps.integer) + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, rsurface.glowmod[0], rsurface.glowmod[1], rsurface.glowmod[2], t->lightmapcolor[3]); + if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD)) + { + // if this is opaque use alpha blend which will darken the earlier + // passes cheaply. + // + // if this is an alpha blended material, all the earlier passes + // were darkened by fog already, so we only need to add the fog + // color ontop through the fog mask texture + // + // if this is an additive blended material, all the earlier passes + // were darkened by fog already, and we should not add fog color + // (because the background was not darkened, there is no fog color + // that was lost behind it). + R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->lightmapcolor[3]); + } + } + + return t->currentframe; +} + +rsurfacestate_t rsurface; + +void RSurf_ActiveWorldEntity(void) +{ + dp_model_t *model = r_refdef.scene.worldmodel; + //if (rsurface.entity == r_refdef.scene.worldentity) + // return; + rsurface.entity = r_refdef.scene.worldentity; + rsurface.skeleton = NULL; + memset(rsurface.userwavefunc_param, 0, sizeof(rsurface.userwavefunc_param)); + rsurface.ent_skinnum = 0; + rsurface.ent_qwskin = -1; + rsurface.ent_flags = r_refdef.scene.worldentity->flags; + rsurface.shadertime = r_refdef.scene.time; + rsurface.matrix = identitymatrix; + rsurface.inversematrix = identitymatrix; + rsurface.matrixscale = 1; + rsurface.inversematrixscale = 1; + R_EntityMatrix(&identitymatrix); + VectorCopy(r_refdef.view.origin, rsurface.localvieworigin); + Vector4Copy(r_refdef.fogplane, rsurface.fogplane); + rsurface.fograngerecip = r_refdef.fograngerecip; + rsurface.fogheightfade = r_refdef.fogheightfade; + rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist; + rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip; + VectorSet(rsurface.modellight_ambient, 0, 0, 0); + VectorSet(rsurface.modellight_diffuse, 0, 0, 0); + VectorSet(rsurface.modellight_lightdir, 0, 0, 1); + VectorSet(rsurface.colormap_pantscolor, 0, 0, 0); + VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0); + VectorSet(rsurface.colormod, r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale); + rsurface.colormod[3] = 1; + VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value); + memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend)); + rsurface.frameblend[0].lerp = 1; + rsurface.ent_alttextures = false; + rsurface.basepolygonfactor = r_refdef.polygonfactor; + rsurface.basepolygonoffset = r_refdef.polygonoffset; + rsurface.entityskeletaltransform3x4 = NULL; + rsurface.entityskeletaltransform3x4buffer = NULL; + rsurface.entityskeletaltransform3x4offset = 0; + rsurface.entityskeletaltransform3x4size = 0;; + rsurface.entityskeletalnumtransforms = 0; + rsurface.modelvertex3f = model->surfmesh.data_vertex3f; + rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; + rsurface.modelsvector3f = model->surfmesh.data_svector3f; + rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f; + rsurface.modeltvector3f = model->surfmesh.data_tvector3f; + rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f; + rsurface.modelnormal3f = model->surfmesh.data_normal3f; + rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f; + rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f; + rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f; + rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f; + rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f; + rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; + rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; + rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub; + rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub; + rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub; + rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub; + rsurface.modelelement3i = model->surfmesh.data_element3i; + rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; + rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; + rsurface.modelelement3s = model->surfmesh.data_element3s; + rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer; + rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset; + rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets; + rsurface.modelnumvertices = model->surfmesh.num_vertices; + rsurface.modelnumtriangles = model->surfmesh.num_triangles; + rsurface.modelsurfaces = model->data_surfaces; + rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh; + rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f; + rsurface.modelgeneratedvertex = false; + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; +} + +void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass) +{ + dp_model_t *model = ent->model; + //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents))) + // return; + rsurface.entity = (entity_render_t *)ent; + rsurface.skeleton = ent->skeleton; + memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param)); + rsurface.ent_skinnum = ent->skinnum; + rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1; + rsurface.ent_flags = ent->flags; + rsurface.shadertime = r_refdef.scene.time - ent->shadertime; + rsurface.matrix = ent->matrix; + rsurface.inversematrix = ent->inversematrix; + rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix); + rsurface.inversematrixscale = 1.0f / rsurface.matrixscale; + R_EntityMatrix(&rsurface.matrix); + Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin); + Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane); + rsurface.fogplaneviewdist *= rsurface.inversematrixscale; + rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale; + rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale; + rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip; + VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient); + VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse); + VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir); + VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor); + VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor); + VectorScale(ent->colormod, r_refdef.view.colorscale, rsurface.colormod); + rsurface.colormod[3] = ent->alpha; + VectorScale(ent->glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, rsurface.glowmod); + memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend)); + rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0; + rsurface.basepolygonfactor = r_refdef.polygonfactor; + rsurface.basepolygonoffset = r_refdef.polygonoffset; + if (ent->model->brush.submodel && !prepass) + { + rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value; + rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value; + } + // if the animcache code decided it should use the shader path, skip the deform step + rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4; + rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer; + rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset; + rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size; + rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0; + if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4) + { + if (ent->animcache_vertex3f) + { + r_refdef.stats[r_stat_batch_entitycache_count]++; + r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles; + rsurface.modelvertex3f = ent->animcache_vertex3f; + rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer; + rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset; + rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL; + rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL; + rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0; + rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL; + rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL; + rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0; + rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL; + rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL; + rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0; + rsurface.modelvertexmesh = ent->animcache_vertexmesh; + rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset; + } + else if (wanttangents) + { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; + rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; + } + else if (wantnormals) + { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; + rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + rsurface.modelsvector3f = NULL; + rsurface.modeltvector3f = NULL; + rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; + } + else + { + r_refdef.stats[r_stat_batch_entityanimate_count]++; + r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles; + rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3])); + rsurface.modelsvector3f = NULL; + rsurface.modeltvector3f = NULL; + rsurface.modelnormal3f = NULL; + model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = NULL; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; + } + rsurface.modelgeneratedvertex = true; + } + else + { + if (rsurface.entityskeletaltransform3x4) + { + r_refdef.stats[r_stat_batch_entityskeletal_count]++; + r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles; + } + else + { + r_refdef.stats[r_stat_batch_entitystatic_count]++; + r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces; + r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices; + r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles; + } + rsurface.modelvertex3f = model->surfmesh.data_vertex3f; + rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; + rsurface.modelsvector3f = model->surfmesh.data_svector3f; + rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f; + rsurface.modeltvector3f = model->surfmesh.data_tvector3f; + rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f; + rsurface.modelnormal3f = model->surfmesh.data_normal3f; + rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f; + rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh; + rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f; + rsurface.modelgeneratedvertex = false; + } + rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f; + rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f; + rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f; + rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f; + rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; + rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; + rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub; + rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub; + rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub; + rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer; + rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub; + rsurface.modelelement3i = model->surfmesh.data_element3i; + rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; + rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; + rsurface.modelelement3s = model->surfmesh.data_element3s; + rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer; + rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset; + rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets; + rsurface.modelnumvertices = model->surfmesh.num_vertices; + rsurface.modelnumtriangles = model->surfmesh.num_triangles; + rsurface.modelsurfaces = model->data_surfaces; + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = false; +} + +void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents) +{ + rsurface.entity = r_refdef.scene.worldentity; + rsurface.skeleton = NULL; + rsurface.ent_skinnum = 0; + rsurface.ent_qwskin = -1; + rsurface.ent_flags = entflags; + rsurface.shadertime = r_refdef.scene.time - shadertime; + rsurface.modelnumvertices = numvertices; + rsurface.modelnumtriangles = numtriangles; + rsurface.matrix = *matrix; + rsurface.inversematrix = *inversematrix; + rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix); + rsurface.inversematrixscale = 1.0f / rsurface.matrixscale; + R_EntityMatrix(&rsurface.matrix); + Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin); + Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane); + rsurface.fogplaneviewdist *= rsurface.inversematrixscale; + rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale; + rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale; + rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip; + VectorSet(rsurface.modellight_ambient, 0, 0, 0); + VectorSet(rsurface.modellight_diffuse, 0, 0, 0); + VectorSet(rsurface.modellight_lightdir, 0, 0, 1); + VectorSet(rsurface.colormap_pantscolor, 0, 0, 0); + VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0); + Vector4Set(rsurface.colormod, r * r_refdef.view.colorscale, g * r_refdef.view.colorscale, b * r_refdef.view.colorscale, a); + VectorSet(rsurface.glowmod, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value, r_refdef.view.colorscale * r_hdr_glowintensity.value); + memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend)); + rsurface.frameblend[0].lerp = 1; + rsurface.ent_alttextures = false; + rsurface.basepolygonfactor = r_refdef.polygonfactor; + rsurface.basepolygonoffset = r_refdef.polygonoffset; + rsurface.entityskeletaltransform3x4 = NULL; + rsurface.entityskeletaltransform3x4buffer = NULL; + rsurface.entityskeletaltransform3x4offset = 0; + rsurface.entityskeletaltransform3x4size = 0; + rsurface.entityskeletalnumtransforms = 0; + r_refdef.stats[r_stat_batch_entitycustom_count]++; + r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1; + r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices; + r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles; + if (wanttangents) + { + rsurface.modelvertex3f = (float *)vertex3f; + rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + } + else if (wantnormals) + { + rsurface.modelvertex3f = (float *)vertex3f; + rsurface.modelsvector3f = NULL; + rsurface.modeltvector3f = NULL; + rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + } + else + { + rsurface.modelvertex3f = (float *)vertex3f; + rsurface.modelsvector3f = NULL; + rsurface.modeltvector3f = NULL; + rsurface.modelnormal3f = NULL; + } + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmesh_vertexbuffer = NULL; + rsurface.modelvertexmesh_bufferoffset = 0; + rsurface.modelvertex3f_vertexbuffer = 0; + rsurface.modelvertex3f_bufferoffset = 0; + rsurface.modelsvector3f_vertexbuffer = 0; + rsurface.modelsvector3f_bufferoffset = 0; + rsurface.modeltvector3f_vertexbuffer = 0; + rsurface.modeltvector3f_bufferoffset = 0; + rsurface.modelnormal3f_vertexbuffer = 0; + rsurface.modelnormal3f_bufferoffset = 0; + rsurface.modelgeneratedvertex = true; + rsurface.modellightmapcolor4f = (float *)color4f; + rsurface.modellightmapcolor4f_vertexbuffer = 0; + rsurface.modellightmapcolor4f_bufferoffset = 0; + rsurface.modeltexcoordtexture2f = (float *)texcoord2f; + rsurface.modeltexcoordtexture2f_vertexbuffer = 0; + rsurface.modeltexcoordtexture2f_bufferoffset = 0; + rsurface.modeltexcoordlightmap2f = NULL; + rsurface.modeltexcoordlightmap2f_vertexbuffer = 0; + rsurface.modeltexcoordlightmap2f_bufferoffset = 0; + rsurface.modelskeletalindex4ub = NULL; + rsurface.modelskeletalindex4ub_vertexbuffer = NULL; + rsurface.modelskeletalindex4ub_bufferoffset = 0; + rsurface.modelskeletalweight4ub = NULL; + rsurface.modelskeletalweight4ub_vertexbuffer = NULL; + rsurface.modelskeletalweight4ub_bufferoffset = 0; + rsurface.modelelement3i = (int *)element3i; + rsurface.modelelement3i_indexbuffer = NULL; + rsurface.modelelement3i_bufferoffset = 0; + rsurface.modelelement3s = (unsigned short *)element3s; + rsurface.modelelement3s_indexbuffer = NULL; + rsurface.modelelement3s_bufferoffset = 0; + rsurface.modellightmapoffsets = NULL; + rsurface.modelsurfaces = NULL; + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; + rsurface.forcecurrenttextureupdate = true; + + if (rsurface.modelnumvertices && rsurface.modelelement3i) + { + if ((wantnormals || wanttangents) && !normal3f) + { + rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0); + } + if (wanttangents && !svector3f) + { + rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3])); + Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0); + } + } +} + +float RSurf_FogPoint(const float *v) +{ + // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader + float FogPlaneViewDist = r_refdef.fogplaneviewdist; + float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3]; + float FogHeightFade = r_refdef.fogheightfade; + float fogfrac; + unsigned int fogmasktableindex; + if (r_refdef.fogplaneviewabove) + fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade); + else + fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade); + fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier); + return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)]; +} + +float RSurf_FogVertex(const float *v) +{ + // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader + float FogPlaneViewDist = rsurface.fogplaneviewdist; + float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3]; + float FogHeightFade = rsurface.fogheightfade; + float fogfrac; + unsigned int fogmasktableindex; + if (r_refdef.fogplaneviewabove) + fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade); + else + fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade); + fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier); + return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)]; +} + +static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust) +{ + int i; + for (i = 0;i < numelements;i++) + outelement3i[i] = inelement3i[i] + adjust; +} + +static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}}; +extern cvar_t gl_vbo; +void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + int deformindex; + int firsttriangle; + int numtriangles; + int firstvertex; + int endvertex; + int numvertices; + int surfacefirsttriangle; + int surfacenumtriangles; + int surfacefirstvertex; + int surfaceendvertex; + int surfacenumvertices; + int batchnumsurfaces = texturenumsurfaces; + int batchnumvertices; + int batchnumtriangles; + int needsupdate; + int i, j; + qboolean gaps; + qboolean dynamicvertex; + float amplitude; + float animpos; + float scale; + float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3]; + float waveparms[4]; + unsigned char *ub; + q3shaderinfo_deform_t *deform; + const msurface_t *surface, *firstsurface; + r_vertexmesh_t *vertexmesh; + if (!texturenumsurfaces) + return; + // find vertex range of this surface batch + gaps = false; + firstsurface = texturesurfacelist[0]; + firsttriangle = firstsurface->num_firsttriangle; + batchnumvertices = 0; + batchnumtriangles = 0; + firstvertex = endvertex = firstsurface->num_firstvertex; + for (i = 0;i < texturenumsurfaces;i++) + { + surface = texturesurfacelist[i]; + if (surface != firstsurface + i) + gaps = true; + surfacefirstvertex = surface->num_firstvertex; + surfaceendvertex = surfacefirstvertex + surface->num_vertices; + surfacenumvertices = surface->num_vertices; + surfacenumtriangles = surface->num_triangles; + if (firstvertex > surfacefirstvertex) + firstvertex = surfacefirstvertex; + if (endvertex < surfaceendvertex) + endvertex = surfaceendvertex; + batchnumvertices += surfacenumvertices; + batchnumtriangles += surfacenumtriangles; + } + + r_refdef.stats[r_stat_batch_batches]++; + if (gaps) + r_refdef.stats[r_stat_batch_withgaps]++; + r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles; + + // we now know the vertex range used, and if there are any gaps in it + rsurface.batchfirstvertex = firstvertex; + rsurface.batchnumvertices = endvertex - firstvertex; + rsurface.batchfirsttriangle = firsttriangle; + rsurface.batchnumtriangles = batchnumtriangles; + + // this variable holds flags for which properties have been updated that + // may require regenerating vertexmesh array... + needsupdate = 0; + + // check if any dynamic vertex processing must occur + dynamicvertex = false; + + // a cvar to force the dynamic vertex path to be taken, for debugging + if (r_batch_debugdynamicvertexpath.integer) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles; + } + dynamicvertex = true; + } + + // if there is a chance of animated vertex colors, it's a dynamic batch + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles; + } + dynamicvertex = true; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR; + } + + for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++) + { + switch (deform->deform) + { + default: + case Q3DEFORM_PROJECTIONSHADOW: + case Q3DEFORM_TEXT0: + case Q3DEFORM_TEXT1: + case Q3DEFORM_TEXT2: + case Q3DEFORM_TEXT3: + case Q3DEFORM_TEXT4: + case Q3DEFORM_TEXT5: + case Q3DEFORM_TEXT6: + case Q3DEFORM_TEXT7: + case Q3DEFORM_NONE: + break; + case Q3DEFORM_AUTOSPRITE: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_AUTOSPRITE2: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_NORMAL: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_WAVE: + if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms)) + break; // if wavefunc is a nop, ignore this transform + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_BULGE: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_MOVE: + if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms)) + break; // if wavefunc is a nop, ignore this transform + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX; + needsupdate |= BATCHNEED_VERTEXMESH_VERTEX; + break; + } + } + switch(rsurface.texture->tcgen.tcgen) + { + default: + case Q3TCGEN_TEXTURE: + break; + case Q3TCGEN_LIGHTMAP: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_LIGHTMAP; + needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP; + break; + case Q3TCGEN_VECTOR: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + break; + case Q3TCGEN_ENVIRONMENT: + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + break; + } + if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles; + } + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + } + + if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles; + } + dynamicvertex = true; + needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)); + } + + // when the model data has no vertex buffer (dynamic mesh), we need to + // eliminate gaps + if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer) + batchneed |= BATCHNEED_NOGAPS; + + // the caller can specify BATCHNEED_NOGAPS to force a batch with + // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex), + // we ensure this by treating the vertex batch as dynamic... + if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles; + } + dynamicvertex = true; + } + + if (dynamicvertex) + { + // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set... + if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX; + if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL; + if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR; + if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR; + if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD; + if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP; + if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL) batchneed |= BATCHNEED_ARRAY_SKELETAL; + } + + // if needsupdate, we have to do a dynamic vertex batch for sure + if (needsupdate & batchneed) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles; + } + dynamicvertex = true; + } + + // see if we need to build vertexmesh from arrays + if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) + { + if (!dynamicvertex) + { + r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles; + } + dynamicvertex = true; + } + + // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data + if (dynamicvertex && rsurface.entityskeletaltransform3x4) + batchneed |= BATCHNEED_ARRAY_SKELETAL; + + rsurface.batchvertex3f = rsurface.modelvertex3f; + rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer; + rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; + rsurface.batchsvector3f = rsurface.modelsvector3f; + rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer; + rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; + rsurface.batchtvector3f = rsurface.modeltvector3f; + rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer; + rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; + rsurface.batchnormal3f = rsurface.modelnormal3f; + rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer; + rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; + rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f; + rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer; + rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer; + rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset; + rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f; + rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer; + rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset; + rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub; + rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer; + rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset; + rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub; + rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer; + rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset; + rsurface.batchvertexmesh = rsurface.modelvertexmesh; + rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer; + rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset; + rsurface.batchelement3i = rsurface.modelelement3i; + rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer; + rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset; + rsurface.batchelement3s = rsurface.modelelement3s; + rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer; + rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset; + rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4; + rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer; + rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset; + rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size; + rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms; + + // if any dynamic vertex processing has to occur in software, we copy the + // entire surface list together before processing to rebase the vertices + // to start at 0 (otherwise we waste a lot of room in a vertex buffer). + // + // if any gaps exist and we do not have a static vertex buffer, we have to + // copy the surface list together to avoid wasting upload bandwidth on the + // vertices in the gaps. + // + // if gaps exist and we have a static vertex buffer, we can choose whether + // to combine the index buffer ranges into one dynamic index buffer or + // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW). + // + // in many cases the batch is reduced to one draw call. + + rsurface.batchmultidraw = false; + rsurface.batchmultidrawnumsurfaces = 0; + rsurface.batchmultidrawsurfacelist = NULL; + + if (!dynamicvertex) + { + // static vertex data, just set pointers... + rsurface.batchgeneratedvertex = false; + // if there are gaps, we want to build a combined index buffer, + // otherwise use the original static buffer with an appropriate offset + if (gaps) + { + r_refdef.stats[r_stat_batch_copytriangles_batches] += 1; + r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles; + if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer) + { + rsurface.batchmultidraw = true; + rsurface.batchmultidrawnumsurfaces = texturenumsurfaces; + rsurface.batchmultidrawsurfacelist = texturesurfacelist; + return; + } + // build a new triangle elements array for this batch + rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3])); + rsurface.batchfirsttriangle = 0; + numtriangles = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle; + surfacenumtriangles = texturesurfacelist[i]->num_triangles; + memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3])); + numtriangles += surfacenumtriangles; + } + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + if (endvertex <= 65536) + { + // make a 16bit (unsigned short) index array if possible + rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3])); + for (i = 0;i < numtriangles*3;i++) + rsurface.batchelement3s[i] = rsurface.batchelement3i[i]; + } + // upload buffer data for the copytriangles batch + if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo) + { + if (rsurface.batchelement3s) + rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset); + else if (rsurface.batchelement3i) + rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset); + } + } + else + { + r_refdef.stats[r_stat_batch_fast_batches] += 1; + r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles; + } + return; + } + + // something needs software processing, do it for real... + // we only directly handle separate array data in this case and then + // generate interleaved data if needed... + rsurface.batchgeneratedvertex = true; + r_refdef.stats[r_stat_batch_dynamic_batches] += 1; + r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles; + + // now copy the vertex data into a combined array and make an index array + // (this is what Quake3 does all the time) + // we also apply any skeletal animation here that would have been done in + // the vertex shader, because most of the dynamic vertex animation cases + // need actual vertex positions and normals + //if (dynamicvertex) + { + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmesh_vertexbuffer = NULL; + rsurface.batchvertexmesh_bufferoffset = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchskeletalindex4ub = NULL; + rsurface.batchskeletalindex4ub_vertexbuffer = NULL; + rsurface.batchskeletalindex4ub_bufferoffset = 0; + rsurface.batchskeletalweight4ub = NULL; + rsurface.batchskeletalweight4ub_vertexbuffer = NULL; + rsurface.batchskeletalweight4ub_bufferoffset = 0; + rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3])); + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.batchskeletaltransform3x4buffer = NULL; + rsurface.batchskeletaltransform3x4offset = 0; + rsurface.batchskeletaltransform3x4size = 0; + // we'll only be setting up certain arrays as needed + if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) + rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t)); + if (batchneed & BATCHNEED_ARRAY_VERTEX) + rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); + if (batchneed & BATCHNEED_ARRAY_NORMAL) + rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); + if (batchneed & BATCHNEED_ARRAY_VECTOR) + { + rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); + rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); + } + if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) + rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4])); + if (batchneed & BATCHNEED_ARRAY_TEXCOORD) + rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); + if (batchneed & BATCHNEED_ARRAY_LIGHTMAP) + rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); + if (batchneed & BATCHNEED_ARRAY_SKELETAL) + { + rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4])); + rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4])); + } + numvertices = 0; + numtriangles = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surfacefirstvertex = texturesurfacelist[i]->num_firstvertex; + surfacenumvertices = texturesurfacelist[i]->num_vertices; + surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle; + surfacenumtriangles = texturesurfacelist[i]->num_triangles; + // copy only the data requested + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh) + memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0])); + if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP)) + { + if (batchneed & BATCHNEED_ARRAY_VERTEX) + { + if (rsurface.batchvertex3f) + memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + else + memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3])); + } + if (batchneed & BATCHNEED_ARRAY_NORMAL) + { + if (rsurface.modelnormal3f) + memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + else + memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3])); + } + if (batchneed & BATCHNEED_ARRAY_VECTOR) + { + if (rsurface.modelsvector3f) + { + memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + } + else + { + memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3])); + memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3])); + } + } + if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) + { + if (rsurface.modellightmapcolor4f) + memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4])); + else + memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4])); + } + if (batchneed & BATCHNEED_ARRAY_TEXCOORD) + { + if (rsurface.modeltexcoordtexture2f) + memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2])); + else + memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2])); + } + if (batchneed & BATCHNEED_ARRAY_LIGHTMAP) + { + if (rsurface.modeltexcoordlightmap2f) + memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2])); + else + memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2])); + } + if (batchneed & BATCHNEED_ARRAY_SKELETAL) + { + if (rsurface.modelskeletalindex4ub) + { + memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4])); + memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4])); + } + else + { + memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4])); + memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4])); + ub = rsurface.batchskeletalweight4ub + 4*numvertices; + for (j = 0;j < surfacenumvertices;j++) + ub[j*4] = 255; + } + } + } + RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex); + numvertices += surfacenumvertices; + numtriangles += surfacenumtriangles; + } + + // generate a 16bit index array as well if possible + // (in general, dynamic batches fit) + if (numvertices <= 65536) + { + rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3])); + for (i = 0;i < numtriangles*3;i++) + rsurface.batchelement3s[i] = rsurface.batchelement3i[i]; + } + + // since we've copied everything, the batch now starts at 0 + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = batchnumvertices; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = batchnumtriangles; + } + + // apply skeletal animation that would have been done in the vertex shader + if (rsurface.batchskeletaltransform3x4) + { + const unsigned char *si; + const unsigned char *sw; + const float *t[4]; + const float *b = rsurface.batchskeletaltransform3x4; + float *vp, *vs, *vt, *vn; + float w[4]; + float m[3][4], n[3][4]; + float tp[3], ts[3], tt[3], tn[3]; + r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1; + r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces; + r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices; + r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles; + si = rsurface.batchskeletalindex4ub; + sw = rsurface.batchskeletalweight4ub; + vp = rsurface.batchvertex3f; + vs = rsurface.batchsvector3f; + vt = rsurface.batchtvector3f; + vn = rsurface.batchnormal3f; + memset(m[0], 0, sizeof(m)); + memset(n[0], 0, sizeof(n)); + for (i = 0;i < batchnumvertices;i++) + { + t[0] = b + si[0]*12; + if (sw[0] == 255) + { + // common case - only one matrix + m[0][0] = t[0][ 0]; + m[0][1] = t[0][ 1]; + m[0][2] = t[0][ 2]; + m[0][3] = t[0][ 3]; + m[1][0] = t[0][ 4]; + m[1][1] = t[0][ 5]; + m[1][2] = t[0][ 6]; + m[1][3] = t[0][ 7]; + m[2][0] = t[0][ 8]; + m[2][1] = t[0][ 9]; + m[2][2] = t[0][10]; + m[2][3] = t[0][11]; + } + else if (sw[2] + sw[3]) + { + // blend 4 matrices + t[1] = b + si[1]*12; + t[2] = b + si[2]*12; + t[3] = b + si[3]*12; + w[0] = sw[0] * (1.0f / 255.0f); + w[1] = sw[1] * (1.0f / 255.0f); + w[2] = sw[2] * (1.0f / 255.0f); + w[3] = sw[3] * (1.0f / 255.0f); + // blend the matrices + m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3]; + m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3]; + m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3]; + m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3]; + m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3]; + m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3]; + m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3]; + m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3]; + m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3]; + m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3]; + m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3]; + m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3]; + } + else + { + // blend 2 matrices + t[1] = b + si[1]*12; + w[0] = sw[0] * (1.0f / 255.0f); + w[1] = sw[1] * (1.0f / 255.0f); + // blend the matrices + m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1]; + m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1]; + m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1]; + m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1]; + m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1]; + m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1]; + m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1]; + m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1]; + m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1]; + m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1]; + m[2][2] = t[0][10] * w[0] + t[1][10] * w[1]; + m[2][3] = t[0][11] * w[0] + t[1][11] * w[1]; + } + si += 4; + sw += 4; + // modify the vertex + VectorCopy(vp, tp); + vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3]; + vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3]; + vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3]; + vp += 3; + if (vn) + { + // the normal transformation matrix is a set of cross products... + CrossProduct(m[1], m[2], n[0]); + CrossProduct(m[2], m[0], n[1]); + CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m) + VectorCopy(vn, tn); + vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2]; + vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2]; + vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2]; + VectorNormalize(vn); + vn += 3; + if (vs) + { + VectorCopy(vs, ts); + vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2]; + vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2]; + vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2]; + VectorNormalize(vs); + vs += 3; + VectorCopy(vt, tt); + vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2]; + vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2]; + vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2]; + VectorNormalize(vt); + vt += 3; + } + } + } + rsurface.batchskeletaltransform3x4 = NULL; + rsurface.batchskeletalnumtransforms = 0; + } + + // q1bsp surfaces rendered in vertex color mode have to have colors + // calculated based on lightstyles + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) + { + // generate color arrays for the surfaces in this list + int c[4]; + int scale; + int size3; + const int *offsets; + const unsigned char *lm; + rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4])); + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + numvertices = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surface = texturesurfacelist[i]; + offsets = rsurface.modellightmapoffsets + surface->num_firstvertex; + surfacenumvertices = surface->num_vertices; + if (surface->lightmapinfo->samples) + { + for (j = 0;j < surfacenumvertices;j++) + { + lm = surface->lightmapinfo->samples + offsets[j]; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]]; + VectorScale(lm, scale, c); + if (surface->lightmapinfo->styles[1] != 255) + { + size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3; + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]]; + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[2] != 255) + { + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]]; + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[3] != 255) + { + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]]; + VectorMA(c, scale, lm, c); + } + } + } + c[0] >>= 7; + c[1] >>= 7; + c[2] >>= 7; + Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, min(c[0], 255) * (1.0f / 255.0f), min(c[1], 255) * (1.0f / 255.0f), min(c[2], 255) * (1.0f / 255.0f), 1); + numvertices++; + } + } + else + { + for (j = 0;j < surfacenumvertices;j++) + { + Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1); + numvertices++; + } + } + } + } + + // if vertices are deformed (sprite flares and things in maps, possibly + // water waves, bulges and other deformations), modify the copied vertices + // in place + for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++) + { + switch (deform->deform) + { + default: + case Q3DEFORM_PROJECTIONSHADOW: + case Q3DEFORM_TEXT0: + case Q3DEFORM_TEXT1: + case Q3DEFORM_TEXT2: + case Q3DEFORM_TEXT3: + case Q3DEFORM_TEXT4: + case Q3DEFORM_TEXT5: + case Q3DEFORM_TEXT6: + case Q3DEFORM_TEXT7: + case Q3DEFORM_NONE: + break; + case Q3DEFORM_AUTOSPRITE: + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward); + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright); + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup); + VectorNormalize(newforward); + VectorNormalize(newright); + VectorNormalize(newup); +// rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f); +// rsurface.batchvertex3f_vertexbuffer = NULL; +// rsurface.batchvertex3f_bufferoffset = 0; +// rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f); +// rsurface.batchsvector3f_vertexbuffer = NULL; +// rsurface.batchsvector3f_bufferoffset = 0; +// rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f); +// rsurface.batchtvector3f_vertexbuffer = NULL; +// rsurface.batchtvector3f_bufferoffset = 0; +// rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f); +// rsurface.batchnormal3f_vertexbuffer = NULL; +// rsurface.batchnormal3f_bufferoffset = 0; + // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1) + if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex)) + Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0); + if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex)) + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + // a single autosprite surface can contain multiple sprites... + for (j = 0;j < batchnumvertices - 3;j += 4) + { + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center); + VectorScale(center, 0.25f, center); + VectorCopy(rsurface.batchnormal3f + 3*j, forward); + VectorCopy(rsurface.batchsvector3f + 3*j, right); + VectorCopy(rsurface.batchtvector3f + 3*j, up); + for (i = 0;i < 4;i++) + { + VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v); + VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i)); + } + } + // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check + Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + break; + case Q3DEFORM_AUTOSPRITE2: + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward); + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright); + Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup); + VectorNormalize(newforward); + VectorNormalize(newright); + VectorNormalize(newup); +// rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f); +// rsurface.batchvertex3f_vertexbuffer = NULL; +// rsurface.batchvertex3f_bufferoffset = 0; + { + const float *v1, *v2; + vec3_t start, end; + float f, l; + struct + { + float length2; + const float *v1; + const float *v2; + } + shortest[2]; + memset(shortest, 0, sizeof(shortest)); + // a single autosprite surface can contain multiple sprites... + for (j = 0;j < batchnumvertices - 3;j += 4) + { + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center); + VectorScale(center, 0.25f, center); + // find the two shortest edges, then use them to define the + // axis vectors for rotating around the central axis + for (i = 0;i < 6;i++) + { + v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]); + v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]); + l = VectorDistance2(v1, v2); + // this length bias tries to make sense of square polygons, assuming they are meant to be upright + if (v1[2] != v2[2]) + l += (1.0f / 1024.0f); + if (shortest[0].length2 > l || i == 0) + { + shortest[1] = shortest[0]; + shortest[0].length2 = l; + shortest[0].v1 = v1; + shortest[0].v2 = v2; + } + else if (shortest[1].length2 > l || i == 1) + { + shortest[1].length2 = l; + shortest[1].v1 = v1; + shortest[1].v2 = v2; + } + } + VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start); + VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end); + // this calculates the right vector from the shortest edge + // and the up vector from the edge midpoints + VectorSubtract(shortest[0].v1, shortest[0].v2, right); + VectorNormalize(right); + VectorSubtract(end, start, up); + VectorNormalize(up); + // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector) + VectorSubtract(rsurface.localvieworigin, center, forward); + //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward); + VectorNegate(forward, forward); + VectorReflect(forward, 0, up, forward); + VectorNormalize(forward); + CrossProduct(up, forward, newright); + VectorNormalize(newright); + // rotate the quad around the up axis vector, this is made + // especially easy by the fact we know the quad is flat, + // so we only have to subtract the center position and + // measure distance along the right vector, and then + // multiply that by the newright vector and add back the + // center position + // we also need to subtract the old position to undo the + // displacement from the center, which we do with a + // DotProduct, the subtraction/addition of center is also + // optimized into DotProducts here + l = DotProduct(right, center); + for (i = 0;i < 4;i++) + { + v1 = rsurface.batchvertex3f + 3*(j+i); + f = DotProduct(right, v1) - l; + VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i)); + } + } + } + if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL + { +// rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchnormal3f_vertexbuffer = NULL; +// rsurface.batchnormal3f_bufferoffset = 0; + Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0); + } + if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL + { +// rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchsvector3f_vertexbuffer = NULL; +// rsurface.batchsvector3f_bufferoffset = 0; +// rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchtvector3f_vertexbuffer = NULL; +// rsurface.batchtvector3f_bufferoffset = 0; + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + } + break; + case Q3DEFORM_NORMAL: + // deform the normals to make reflections wavey + rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f); + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + float vertex[3]; + float *normal = rsurface.batchnormal3f + 3*j; + VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex); + normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]); + normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]); + normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]); + VectorNormalize(normal); + } + if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL + { +// rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchsvector3f_vertexbuffer = NULL; +// rsurface.batchsvector3f_bufferoffset = 0; +// rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchtvector3f_vertexbuffer = NULL; +// rsurface.batchtvector3f_bufferoffset = 0; + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + } + break; + case Q3DEFORM_WAVE: + // deform vertex array to make wavey water and flags and such + waveparms[0] = deform->waveparms[0]; + waveparms[1] = deform->waveparms[1]; + waveparms[2] = deform->waveparms[2]; + waveparms[3] = deform->waveparms[3]; + if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms)) + break; // if wavefunc is a nop, don't make a dynamic vertex array + // this is how a divisor of vertex influence on deformation + animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f; + scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms); +// rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f); +// rsurface.batchvertex3f_vertexbuffer = NULL; +// rsurface.batchvertex3f_bufferoffset = 0; +// rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f); +// rsurface.batchnormal3f_vertexbuffer = NULL; +// rsurface.batchnormal3f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + // if the wavefunc depends on time, evaluate it per-vertex + if (waveparms[3]) + { + waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos; + scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms); + } + VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j); + } + // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check + Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0); + if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL + { +// rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchsvector3f_vertexbuffer = NULL; +// rsurface.batchsvector3f_bufferoffset = 0; +// rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchtvector3f_vertexbuffer = NULL; +// rsurface.batchtvector3f_bufferoffset = 0; + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + } + break; + case Q3DEFORM_BULGE: + // deform vertex array to make the surface have moving bulges +// rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f); +// rsurface.batchvertex3f_vertexbuffer = NULL; +// rsurface.batchvertex3f_bufferoffset = 0; +// rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f); +// rsurface.batchnormal3f_vertexbuffer = NULL; +// rsurface.batchnormal3f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1]; + VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j); + } + // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check + Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0); + if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL + { +// rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchsvector3f_vertexbuffer = NULL; +// rsurface.batchsvector3f_bufferoffset = 0; +// rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3])); +// rsurface.batchtvector3f_vertexbuffer = NULL; +// rsurface.batchtvector3f_bufferoffset = 0; + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0); + } + break; + case Q3DEFORM_MOVE: + // deform vertex array + if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms)) + break; // if wavefunc is a nop, don't make a dynamic vertex array + scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms); + VectorScale(deform->parms, scale, waveparms); +// rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f); +// rsurface.batchvertex3f_vertexbuffer = NULL; +// rsurface.batchvertex3f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j); + break; + } + } + + // generate texcoords based on the chosen texcoord source + switch(rsurface.texture->tcgen.tcgen) + { + default: + case Q3TCGEN_TEXTURE: + break; + case Q3TCGEN_LIGHTMAP: +// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); +// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; +// rsurface.batchtexcoordtexture2f_bufferoffset = 0; + if (rsurface.batchtexcoordlightmap2f) + memcpy(rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, batchnumvertices * sizeof(float[2])); + break; + case Q3TCGEN_VECTOR: +// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); +// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; +// rsurface.batchtexcoordtexture2f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms); + rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3); + } + break; + case Q3TCGEN_ENVIRONMENT: + // make environment reflections using a spheremap + rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + // identical to Q3A's method, but executed in worldspace so + // carried models can be shiny too + + float viewer[3], d, reflected[3], worldreflected[3]; + + VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer); + // VectorNormalize(viewer); + + d = DotProduct(rsurface.batchnormal3f + 3*j, viewer); + + reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0]; + reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1]; + reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2]; + // note: this is proportinal to viewer, so we can normalize later + + Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected); + VectorNormalize(worldreflected); + + // note: this sphere map only uses world x and z! + // so positive and negative y will LOOK THE SAME. + rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1]; + rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2]; + } + break; + } + // the only tcmod that needs software vertex processing is turbulent, so + // check for it here and apply the changes if needed + // and we only support that as the first one + // (handling a mixture of turbulent and other tcmods would be problematic + // without punting it entirely to a software path) + if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT) + { + amplitude = rsurface.texture->tcmods[0].parms[1]; + animpos = rsurface.texture->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->tcmods[0].parms[3]; +// rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2])); +// rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; +// rsurface.batchtexcoordtexture2f_bufferoffset = 0; + for (j = 0;j < batchnumvertices;j++) + { + rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2); + rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2); + } + } + + if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) + { + // convert the modified arrays to vertex structs +// rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t)); +// rsurface.batchvertexmesh_vertexbuffer = NULL; +// rsurface.batchvertexmesh_bufferoffset = 0; + if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f); + if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f); + if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) + { + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + { + VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f); + VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f); + } + } + if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f) + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f); + if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f); + if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f) + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f); + if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub) + { + for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++) + { + Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub); + Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub); + } + } + } + + // upload buffer data for the dynamic batch + if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo) + { + if (rsurface.batchvertexmesh) + rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset); + else + { + if (rsurface.batchvertex3f) + rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset); + if (rsurface.batchsvector3f) + rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset); + if (rsurface.batchtvector3f) + rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset); + if (rsurface.batchnormal3f) + rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset); + if (rsurface.batchlightmapcolor4f) + rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset); + if (rsurface.batchtexcoordtexture2f) + rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset); + if (rsurface.batchtexcoordlightmap2f) + rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset); + if (rsurface.batchskeletalindex4ub) + rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset); + if (rsurface.batchskeletalweight4ub) + rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset); + } + if (rsurface.batchelement3s) + rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset); + else if (rsurface.batchelement3i) + rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset); + } +} + +void RSurf_DrawBatch(void) +{ + // sometimes a zero triangle surface (usually a degenerate patch) makes it + // through the pipeline, killing it earlier in the pipeline would have + // per-surface overhead rather than per-batch overhead, so it's best to + // reject it here, before it hits glDraw. + if (rsurface.batchnumtriangles == 0) + return; +#if 0 + // batch debugging code + if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f) + { + int i; + int j; + int c; + const int *e; + e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3; + for (i = 0;i < rsurface.batchnumtriangles*3;i++) + { + c = e[i]; + for (j = 0;j < rsurface.entity->model->num_surfaces;j++) + { + if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices)) + { + if (rsurface.modelsurfaces[j].texture != rsurface.texture) + Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name); + break; + } + } + } + } +#endif + if (rsurface.batchmultidraw) + { + // issue multiple draws rather than copying index data + int numsurfaces = rsurface.batchmultidrawnumsurfaces; + const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist; + int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle; + for (i = 0;i < numsurfaces;) + { + // combine consecutive surfaces as one draw + for (k = i, j = i + 1;j < numsurfaces;k = j, j++) + if (surfacelist[j] != surfacelist[k] + 1) + break; + firstvertex = surfacelist[i]->num_firstvertex; + endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices; + firsttriangle = surfacelist[i]->num_firsttriangle; + endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles; + R_Mesh_Draw(firstvertex, endvertex - firstvertex, firsttriangle, endtriangle - firsttriangle, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset); + i = j; + } + } + else + { + // there is only one consecutive run of index data (may have been combined) + R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset); + } +} + +static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface) +{ + // pick the closest matching water plane + int planeindex, vertexindex, bestplaneindex = -1; + float d, bestd; + vec3_t vert; + const float *v; + r_waterstate_waterplane_t *p; + qboolean prepared = false; + bestd = 0; + for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++) + { + if(p->camera_entity != rsurface.texture->camera_entity) + continue; + d = 0; + if(!prepared) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface); + prepared = true; + if(rsurface.batchnumvertices == 0) + break; + } + for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3) + { + Matrix4x4_Transform(&rsurface.matrix, v, vert); + d += fabs(PlaneDiff(vert, &p->plane)); + } + if (bestd > d || bestplaneindex < 0) + { + bestd = d; + bestplaneindex = planeindex; + } + } + return bestplaneindex; + // NOTE: this MAY return a totally unrelated water plane; we can ignore + // this situation though, as it might be better to render single larger + // batches with useless stuff (backface culled for example) than to + // render multiple smaller batches +} + +static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(void) +{ + int i; + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0;i < rsurface.batchnumvertices;i++) + Vector4Set(rsurface.passcolor4f + 4*i, 0.5f, 0.5f, 0.5f, 1.0f); +} + +static void RSurf_DrawBatch_GL11_ApplyFog(void) +{ + int i; + float f; + const float *v; + const float *c; + float *c2; + if (rsurface.passcolor4f) + { + // generate color arrays + c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4; + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) + { + f = RSurf_FogVertex(v); + c2[0] = c[0] * f; + c2[1] = c[1] * f; + c2[2] = c[2] * f; + c2[3] = c[3]; + } + } + else + { + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c2 += 4) + { + f = RSurf_FogVertex(v); + c2[0] = f; + c2[1] = f; + c2[2] = f; + c2[3] = 1; + } + } +} + +static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(void) +{ + int i; + float f; + const float *v; + const float *c; + float *c2; + if (!rsurface.passcolor4f) + return; + c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4; + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) + { + f = RSurf_FogVertex(v); + c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f); + c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f); + c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f); + c2[3] = c[3]; + } +} + +static void RSurf_DrawBatch_GL11_ApplyColor(float r, float g, float b, float a) +{ + int i; + const float *c; + float *c2; + if (!rsurface.passcolor4f) + return; + c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4; + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4) + { + c2[0] = c[0] * r; + c2[1] = c[1] * g; + c2[2] = c[2] * b; + c2[3] = c[3] * a; + } +} + +static void RSurf_DrawBatch_GL11_ApplyAmbient(void) +{ + int i; + const float *c; + float *c2; + if (!rsurface.passcolor4f) + return; + c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4; + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, c2 = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4) + { + c2[0] = c[0] + r_refdef.scene.ambient; + c2[1] = c[1] + r_refdef.scene.ambient; + c2[2] = c[2] + r_refdef.scene.ambient; + c2[3] = c[3]; + } +} + +static void RSurf_DrawBatch_GL11_Lightmap(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + // TODO: optimize + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + R_Mesh_TexBind(0, rsurface.lightmaptexture); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexMatrix(0, NULL); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_Unlit(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + // TODO: optimize applyfog && applycolor case + // just apply fog if necessary, and tint the fog color array if necessary + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_VertexColor(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + // TODO: optimize + rsurface.passcolor4f = rsurface.batchlightmapcolor4f; + rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer; + rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_ClampColor(void) +{ + int i; + const float *c1; + float *c2; + if (!rsurface.passcolor4f) + return; + for (i = 0, c1 = rsurface.passcolor4f + 4*rsurface.batchfirstvertex, c2 = rsurface.passcolor4f + 4*rsurface.batchfirstvertex;i < rsurface.batchnumvertices;i++, c1 += 4, c2 += 4) + { + c2[0] = bound(0.0f, c1[0], 1.0f); + c2[1] = bound(0.0f, c1[1], 1.0f); + c2[2] = bound(0.0f, c1[2], 1.0f); + c2[3] = bound(0.0f, c1[3], 1.0f); + } +} + +static void RSurf_DrawBatch_GL11_ApplyFakeLight(void) +{ + int i; + float f; + const float *v; + const float *n; + float *c; + //vec3_t eyedir; + + // fake shading + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, n = rsurface.batchnormal3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, n += 3, c += 4) + { + f = -DotProduct(r_refdef.view.forward, n); + f = max(0, f); + f = f * 0.85 + 0.15; // work around so stuff won't get black + f *= r_refdef.lightmapintensity; + Vector4Set(c, f, f, f, 1); + } +} + +static void RSurf_DrawBatch_GL11_FakeLight(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + RSurf_DrawBatch_GL11_ApplyFakeLight(); + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b, float *a, qboolean *applycolor) +{ + int i; + float f; + float alpha; + const float *v; + const float *n; + float *c; + vec3_t ambientcolor; + vec3_t diffusecolor; + vec3_t lightdir; + // TODO: optimize + // model lighting + VectorCopy(rsurface.modellight_lightdir, lightdir); + f = 0.5f * r_refdef.lightmapintensity; + ambientcolor[0] = rsurface.modellight_ambient[0] * *r * f; + ambientcolor[1] = rsurface.modellight_ambient[1] * *g * f; + ambientcolor[2] = rsurface.modellight_ambient[2] * *b * f; + diffusecolor[0] = rsurface.modellight_diffuse[0] * *r * f; + diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f; + diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f; + alpha = *a; + if (VectorLength2(diffusecolor) > 0) + { + // q3-style directional shading + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, n = rsurface.batchnormal3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, n += 3, c += 4) + { + if ((f = DotProduct(n, lightdir)) > 0) + VectorMA(ambientcolor, f, diffusecolor, c); + else + VectorCopy(ambientcolor, c); + c[3] = alpha; + } + *r = 1; + *g = 1; + *b = 1; + *a = 1; + *applycolor = false; + } + else + { + *r = ambientcolor[0]; + *g = ambientcolor[1]; + *b = ambientcolor[2]; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + } +} + +static void RSurf_DrawBatch_GL11_VertexShade(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + RSurf_DrawBatch_GL11_ApplyVertexShade(&r, &g, &b, &a, &applycolor); + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_MakeFogColor(float r, float g, float b, float a) +{ + int i; + float f; + const float *v; + float *c; + + // fake shading + rsurface.passcolor4f = (float *)R_FrameData_Alloc(rsurface.batchnumvertices * sizeof(float[4])); + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4) + { + f = 1 - RSurf_FogVertex(v); + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = f * a; + } +} + +void RSurf_SetupDepthAndCulling(void) +{ + // submodels are biased to avoid z-fighting with world surfaces that they + // may be exactly overlapping (avoids z-fighting artifacts on certain + // doors and things in Quake maps) + GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1); + GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset); + GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back); +} + +static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + // transparent sky would be ridiculous + if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) + return; + R_SetupShader_Generic_NoTexture(false, false); + skyrenderlater = true; + RSurf_SetupDepthAndCulling(); + GL_DepthMask(true); + // LordHavoc: HalfLife maps have freaky skypolys so don't use + // skymasking on them, and Quake3 never did sky masking (unlike + // software Quake and software Quake2), so disable the sky masking + // in Quake3 maps as it causes problems with q3map2 sky tricks, + // and skymasking also looks very bad when noclipping outside the + // level, so don't use it then either. + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis && !r_trippy.integer) + { + R_Mesh_ResetTextureState(); + if (skyrendermasked) + { + R_SetupShader_DepthOrShadow(false, false, false); + // depth-only (masking) + GL_ColorMask(0,0,0,0); + // just to make sure that braindead drivers don't draw + // anything despite that colormask... + GL_BlendFunc(GL_ZERO, GL_ONE); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + } + else + { + R_SetupShader_Generic_NoTexture(false, false); + // fog sky + GL_BlendFunc(GL_ONE, GL_ZERO); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); + } + RSurf_DrawBatch(); + if (skyrendermasked) + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + } + R_Mesh_ResetTextureState(); + GL_Color(1, 1, 1, 1); +} + +extern rtexture_t *r_shadow_prepasslightingdiffusetexture; +extern rtexture_t *r_shadow_prepasslightingspeculartexture; +static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) +{ + if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) + return; + if (prepass) + { + // render screenspace normalmap to texture + GL_DepthMask(true); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false); + RSurf_DrawBatch(); + return; + } + + // bind lightmap texture + + // water/refraction/reflection/camera surfaces have to be handled specially + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION))) + { + int start, end, startplaneindex; + for (start = 0;start < texturenumsurfaces;start = end) + { + startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]); + if(startplaneindex < 0) + { + // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this. + // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags); + end = start + 1; + continue; + } + for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++) + ; + // now that we have a batch using the same planeindex, render it + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA))) + { + // render water or distortion background + GL_DepthMask(true); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); + RSurf_DrawBatch(); + // blend surface on top + GL_DepthMask(false); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false); + RSurf_DrawBatch(); + } + else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)) + { + // render surface with reflection texture as input + GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); + RSurf_DrawBatch(); + } + } + return; + } + + // render surface batch normally + GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0); + RSurf_DrawBatch(); +} + +static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) +{ + // OpenGL 1.3 path - anything not completely ancient + qboolean applycolor; + qboolean applyfog; + int layerindex; + const texturelayer_t *layer; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + + for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++) + { + vec4_t layercolor; + int layertexrgbscale; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + if (layerindex == 0) + GL_AlphaTest(true); + else + { + GL_AlphaTest(false); + GL_DepthFunc(GL_EQUAL); + } + } + GL_DepthMask(layer->depthmask && writedepth); + GL_BlendFunc(layer->blendfunc1, layer->blendfunc2); + if (layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) + { + layertexrgbscale = 4; + VectorScale(layer->color, 0.25f, layercolor); + } + else if (layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) + { + layertexrgbscale = 2; + VectorScale(layer->color, 0.5f, layercolor); + } + else + { + layertexrgbscale = 1; + VectorScale(layer->color, 1.0f, layercolor); + } + layercolor[3] = layer->color[3]; + applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1; + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0); + applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED); + switch (layer->type) + { + case TEXTURELAYERTYPE_LITTEXTURE: + // single-pass lightmapped texture with 2x rgbscale + R_Mesh_TexBind(0, r_texture_white); + R_Mesh_TexMatrix(0, NULL); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + R_Mesh_TexBind(1, layer->texture); + R_Mesh_TexMatrix(1, &layer->texmatrix); + R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + RSurf_DrawBatch_GL11_VertexShade(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + else if (FAKELIGHT_ENABLED) + RSurf_DrawBatch_GL11_FakeLight(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + else if (rsurface.uselightmaptexture) + RSurf_DrawBatch_GL11_Lightmap(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + else + RSurf_DrawBatch_GL11_VertexColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + break; + case TEXTURELAYERTYPE_TEXTURE: + // singletexture unlit texture with transparency support + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + R_Mesh_TexBind(1, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); + RSurf_DrawBatch_GL11_Unlit(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + break; + case TEXTURELAYERTYPE_FOG: + // singletexture fogging + if (layer->texture) + { + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + } + else + { + R_Mesh_TexBind(0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); + } + R_Mesh_TexBind(1, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); + // generate a color array for the fog pass + RSurf_DrawBatch_GL11_MakeFogColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3]); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); + RSurf_DrawBatch(); + break; + default: + Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type); + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + GL_DepthFunc(GL_LEQUAL); + GL_AlphaTest(false); + } +} + +static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) +{ + // OpenGL 1.1 - crusty old voodoo path + qboolean applyfog; + int layerindex; + const texturelayer_t *layer; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + + for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++) + { + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + if (layerindex == 0) + GL_AlphaTest(true); + else + { + GL_AlphaTest(false); + GL_DepthFunc(GL_EQUAL); + } + } + GL_DepthMask(layer->depthmask && writedepth); + GL_BlendFunc(layer->blendfunc1, layer->blendfunc2); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0); + applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED); + switch (layer->type) + { + case TEXTURELAYERTYPE_LITTEXTURE: + if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)) + { + // two-pass lit texture with 2x rgbscale + // first the lightmap pass + R_Mesh_TexBind(0, r_texture_white); + R_Mesh_TexMatrix(0, NULL); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + RSurf_DrawBatch_GL11_VertexShade(1, 1, 1, 1, false, false); + else if (FAKELIGHT_ENABLED) + RSurf_DrawBatch_GL11_FakeLight(1, 1, 1, 1, false, false); + else if (rsurface.uselightmaptexture) + RSurf_DrawBatch_GL11_Lightmap(1, 1, 1, 1, false, false); + else + RSurf_DrawBatch_GL11_VertexColor(1, 1, 1, 1, false, false); + // then apply the texture to it + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + RSurf_DrawBatch_GL11_Unlit(layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false); + } + else + { + // single pass vertex-lighting-only texture with 1x rgbscale and transparency support + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + RSurf_DrawBatch_GL11_VertexShade(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + else if (FAKELIGHT_ENABLED) + RSurf_DrawBatch_GL11_FakeLight(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + else + RSurf_DrawBatch_GL11_VertexColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + } + break; + case TEXTURELAYERTYPE_TEXTURE: + // singletexture unlit texture with transparency support + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + RSurf_DrawBatch_GL11_Unlit(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + break; + case TEXTURELAYERTYPE_FOG: + // singletexture fogging + if (layer->texture) + { + R_Mesh_TexBind(0, layer->texture); + R_Mesh_TexMatrix(0, &layer->texmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + } + else + { + R_Mesh_TexBind(0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); + } + // generate a color array for the fog pass + RSurf_DrawBatch_GL11_MakeFogColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3]); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); + RSurf_DrawBatch(); + break; + default: + Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type); + } + } + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + GL_DepthFunc(GL_LEQUAL); + GL_AlphaTest(false); + } +} + +static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) +{ + int vi; + int j; + r_vertexgeneric_t *batchvertex; + float c[4]; + +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(false, false); + + if(rsurface.texture && rsurface.texture->currentskinframe) + { + memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c)); + c[3] *= rsurface.texture->currentalpha; + } + else + { + c[0] = 1; + c[1] = 0; + c[2] = 1; + c[3] = 1; + } + + if (rsurface.texture->pantstexture || rsurface.texture->shirttexture) + { + c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7); + c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7); + c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7); + } + + // brighten it up (as texture value 127 means "unlit") + c[0] *= 2 * r_refdef.view.colorscale; + c[1] *= 2 * r_refdef.view.colorscale; + c[2] *= 2 * r_refdef.view.colorscale; + + if(rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA) + c[3] *= r_wateralpha.value; + + if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD) + { + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND) + { + GL_BlendFunc(rsurface.texture->customblendfunc[0], rsurface.texture->customblendfunc[1]); + GL_DepthMask(false); + } + else + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(writedepth); + } + + if (r_showsurfaces.integer == 3) + { + rsurface.passcolor4f = NULL; + + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + { + qboolean applycolor = true; + float one = 1.0; + + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + + r_refdef.lightmapintensity = 1; + RSurf_DrawBatch_GL11_ApplyVertexShade(&one, &one, &one, &one, &applycolor); + r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all + } + else if (FAKELIGHT_ENABLED) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + + r_refdef.lightmapintensity = r_fakelight_intensity.value; + RSurf_DrawBatch_GL11_ApplyFakeLight(); + r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all + } + else + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + + rsurface.passcolor4f = rsurface.batchlightmapcolor4f; + rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer; + rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset; + } + + if(!rsurface.passcolor4f) + RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(); + + RSurf_DrawBatch_GL11_ApplyAmbient(); + RSurf_DrawBatch_GL11_ApplyColor(c[0], c[1], c[2], c[3]); + if(r_refdef.fogenabled) + RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(); + RSurf_DrawBatch_GL11_ClampColor(); + + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL); + R_SetupShader_Generic_NoTexture(false, false); + RSurf_DrawBatch(); + } + else if (!r_refdef.view.showdebug) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); + for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++) + { + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } + else if (r_showsurfaces.integer == 4) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); + for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++) + { + unsigned char c = (vi << 3) * (1.0f / 256.0f); + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Set(batchvertex[vi].color4f, c, c, c, 1); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } + else if (r_showsurfaces.integer == 2) + { + const int *e; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles); + for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3) + { + unsigned char c = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f); + VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f); + VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f); + VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f); + Vector4Set(batchvertex[j*3+0].color4f, c, c, c, 1); + Vector4Set(batchvertex[j*3+1].color4f, c, c, c, 1); + Vector4Set(batchvertex[j*3+2].color4f, c, c, c, 1); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0); + } + else + { + int texturesurfaceindex; + int k; + const msurface_t *surface; + float surfacecolor4f[4]; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices); + vi = 0; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + k = (int)(((size_t)surface) / sizeof(msurface_t)); + Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1); + for (j = 0;j < surface->num_vertices;j++) + { + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Copy(surfacecolor4f, batchvertex[vi].color4f); + vi++; + } + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } +} + +static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) +{ + CHECKGLERROR + RSurf_SetupDepthAndCulling(); + if (r_showsurfaces.integer) + { + R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth); + return; + } + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); + break; + case RENDERPATH_GL11: + R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth); + break; + } + CHECKGLERROR +} + +static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) +{ + CHECKGLERROR + RSurf_SetupDepthAndCulling(); + if (r_showsurfaces.integer) + { + R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth); + return; + } + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); + break; + case RENDERPATH_GL11: + R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth); + break; + } + CHECKGLERROR +} + +static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int i, j; + int texturenumsurfaces, endsurface; + texture_t *texture; + const msurface_t *surface; + const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE]; + + // if the model is static it doesn't matter what value we give for + // wantnormals and wanttangents, so this logic uses only rules applicable + // to a model, knowing that they are meaningless otherwise + if (ent == r_refdef.scene.worldentity) + RSurf_ActiveWorldEntity(); + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) + RSurf_ActiveModelEntity(ent, false, false, false); + else + { + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + RSurf_ActiveModelEntity(ent, true, true, false); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + RSurf_ActiveModelEntity(ent, true, false, false); + break; + } + } + + if (r_transparentdepthmasking.integer) + { + qboolean setup = false; + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + surface = rsurface.modelsurfaces + surfacelist[i]; + texture = surface->texture; + rsurface.texture = R_GetCurrentTexture(texture); + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + // scan ahead until we find a different texture + endsurface = min(i + 1024, numsurfaces); + texturenumsurfaces = 0; + texturesurfacelist[texturenumsurfaces++] = surface; + for (;j < endsurface;j++) + { + surface = rsurface.modelsurfaces + surfacelist[j]; + if (texture != surface->texture) + break; + texturesurfacelist[texturenumsurfaces++] = surface; + } + if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH)) + continue; + // render the range of surfaces as depth + if (!setup) + { + setup = true; + GL_ColorMask(0,0,0,0); + GL_Color(1,1,1,1); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); +// R_Mesh_ResetTextureState(); + } + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + RSurf_DrawBatch(); + } + if (setup) + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + } + + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + surface = rsurface.modelsurfaces + surfacelist[i]; + texture = surface->texture; + rsurface.texture = R_GetCurrentTexture(texture); + // scan ahead until we find a different texture + endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces); + texturenumsurfaces = 0; + texturesurfacelist[texturenumsurfaces++] = surface; + if(FAKELIGHT_ENABLED) + { + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + for (;j < endsurface;j++) + { + surface = rsurface.modelsurfaces + surfacelist[j]; + if (texture != surface->texture) + break; + texturesurfacelist[texturenumsurfaces++] = surface; + } + } + else + { + rsurface.lightmaptexture = surface->lightmaptexture; + rsurface.deluxemaptexture = surface->deluxemaptexture; + rsurface.uselightmaptexture = surface->lightmaptexture != NULL; + for (;j < endsurface;j++) + { + surface = rsurface.modelsurfaces + surfacelist[j]; + if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture) + break; + texturesurfacelist[texturenumsurfaces++] = surface; + } + } + // render the range of surfaces + if (ent == r_refdef.scene.worldentity) + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false); + else + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false); + } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + // transparent surfaces get pushed off into the transparent queue + int surfacelistindex; + const msurface_t *surface; + vec3_t tempcenter, center; + for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++) + { + surface = texturesurfacelist[surfacelistindex]; + if (r_transparent_sortsurfacesbynearest.integer) + { + tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]); + tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]); + tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]); + } + else + { + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + } + Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); + if (rsurface.entity->transparent_offset) // transparent offset + { + center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset; + center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset; + center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset; + } + R_MeshQueue_AddTransparent((rsurface.entity->flags & RENDER_WORLDOBJECT) ? TRANSPARENTSORT_SKY : (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? TRANSPARENTSORT_HUD : rsurface.texture->transparentsort, center, R_DrawSurface_TransparentCallback, rsurface.entity, surface - rsurface.modelsurfaces, rsurface.rtlight); + } +} + +static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) + return; + if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + return; + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); + RSurf_DrawBatch(); +} + +static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass) +{ + CHECKGLERROR + if (depthonly) + R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist); + else if (prepass) + { + if (!rsurface.texture->currentnumlayers) + return; + if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); + else + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); + } + else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3)) + R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); + else if (!rsurface.texture->currentnumlayers) + return; + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)))) + { + // in the deferred case, transparent surfaces were queued during prepass + if (!r_shadow_usingdeferredprepass) + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); + } + else + { + // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass); + } + CHECKGLERROR +} + +static void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) +{ + int i, j; + texture_t *texture; + R_FrameData_SetMark(); + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + // texture is the base texture pointer, rsurface.texture is the + // current frame/skin the texture is directing us to use (for example + // if a model has 2 skins and it is on skin 1, then skin 0 tells us to + // use skin 1 instead) + texture = surfacelist[i]->texture; + rsurface.texture = R_GetCurrentTexture(texture); + if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + // if this texture is not the kind we want, skip ahead to the next one + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + continue; + } + if(FAKELIGHT_ENABLED || depthonly || prepass) + { + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + } + else + { + rsurface.lightmaptexture = surfacelist[i]->lightmaptexture; + rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture; + rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++) + ; + } + // render the range of surfaces + R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass); + } + R_FrameData_ReturnToMark(); +} + +static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass) +{ + CHECKGLERROR + if (depthonly) + R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist); + else if (prepass) + { + if (!rsurface.texture->currentnumlayers) + return; + if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); + else + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); + } + else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3)) + R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); + else if (!rsurface.texture->currentnumlayers) + return; + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)))) + { + // in the deferred case, transparent surfaces were queued during prepass + if (!r_shadow_usingdeferredprepass) + R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist); + } + else + { + // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass); + } + CHECKGLERROR +} + +static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass) +{ + int i, j; + texture_t *texture; + R_FrameData_SetMark(); + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + // texture is the base texture pointer, rsurface.texture is the + // current frame/skin the texture is directing us to use (for example + // if a model has 2 skins and it is on skin 1, then skin 0 tells us to + // use skin 1 instead) + texture = surfacelist[i]->texture; + rsurface.texture = R_GetCurrentTexture(texture); + if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + // if this texture is not the kind we want, skip ahead to the next one + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + continue; + } + if(FAKELIGHT_ENABLED || depthonly || prepass) + { + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + } + else + { + rsurface.lightmaptexture = surfacelist[i]->lightmaptexture; + rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture; + rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + // simply scan ahead until we find a different texture or lightmap state + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++) + ; + } + // render the range of surfaces + R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass); + } + R_FrameData_ReturnToMark(); +} + +float locboxvertex3f[6*4*3] = +{ + 1,0,1, 1,0,0, 1,1,0, 1,1,1, + 0,1,1, 0,1,0, 0,0,0, 0,0,1, + 1,1,1, 1,1,0, 0,1,0, 0,1,1, + 0,0,1, 0,0,0, 1,0,0, 1,0,1, + 0,0,1, 1,0,1, 1,1,1, 0,1,1, + 1,0,0, 0,0,0, 0,1,0, 1,1,0 +}; + +unsigned short locboxelements[6*2*3] = +{ + 0, 1, 2, 0, 2, 3, + 4, 5, 6, 4, 6, 7, + 8, 9,10, 8,10,11, + 12,13,14, 12,14,15, + 16,17,18, 16,18,19, + 20,21,22, 20,22,23 +}; + +static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int i, j; + cl_locnode_t *loc = (cl_locnode_t *)ent; + vec3_t mins, size; + float vertex3f[6*4*3]; + CHECKGLERROR + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + GL_DepthTest(true); + GL_CullFace(GL_NONE); + R_EntityMatrix(&identitymatrix); + +// R_Mesh_ResetTextureState(); + + i = surfacelist[0]; + GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale, + ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale, + ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale, + surfacelist[0] < 0 ? 0.5f : 0.125f); + + if (VectorCompare(loc->mins, loc->maxs)) + { + VectorSet(size, 2, 2, 2); + VectorMA(loc->mins, -0.5f, size, mins); + } + else + { + VectorCopy(loc->mins, mins); + VectorSubtract(loc->maxs, loc->mins, size); + } + + for (i = 0;i < 6*4*3;) + for (j = 0;j < 3;j++, i++) + vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i]; + + R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL); + R_SetupShader_Generic_NoTexture(false, false); + R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0); +} + +void R_DrawLocs(void) +{ + int index; + cl_locnode_t *loc, *nearestloc; + vec3_t center; + nearestloc = CL_Locs_FindNearest(cl.movement_origin); + for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++) + { + VectorLerp(loc->mins, 0.5f, loc->maxs, center); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL); + } +} + +void R_DecalSystem_Reset(decalsystem_t *decalsystem) +{ + if (decalsystem->decals) + Mem_Free(decalsystem->decals); + memset(decalsystem, 0, sizeof(*decalsystem)); +} + +static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence) +{ + tridecal_t *decal; + tridecal_t *decals; + int i; + + // expand or initialize the system + if (decalsystem->maxdecals <= decalsystem->numdecals) + { + decalsystem_t old = *decalsystem; + qboolean useshortelements; + decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2); + useshortelements = decalsystem->maxdecals * 3 <= 65536; + decalsystem->decals = (tridecal_t *)Mem_Alloc(cls.levelmempool, decalsystem->maxdecals * (sizeof(tridecal_t) + sizeof(float[3][3]) + sizeof(float[3][2]) + sizeof(float[3][4]) + sizeof(int[3]) + (useshortelements ? sizeof(unsigned short[3]) : 0))); + decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals); + decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12); + decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6); + decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9); + decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL); + if (decalsystem->numdecals) + memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t)); + if (old.decals) + Mem_Free(old.decals); + for (i = 0;i < decalsystem->maxdecals*3;i++) + decalsystem->element3i[i] = i; + if (useshortelements) + for (i = 0;i < decalsystem->maxdecals*3;i++) + decalsystem->element3s[i] = i; + } + + // grab a decal and search for another free slot for the next one + decals = decalsystem->decals; + decal = decalsystem->decals + (i = decalsystem->freedecal++); + for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++) + ; + decalsystem->freedecal = i; + if (decalsystem->numdecals <= i) + decalsystem->numdecals = i + 1; + + // initialize the decal + decal->lived = 0; + decal->triangleindex = triangleindex; + decal->surfaceindex = surfaceindex; + decal->decalsequence = decalsequence; + decal->color4f[0][0] = c0[0]; + decal->color4f[0][1] = c0[1]; + decal->color4f[0][2] = c0[2]; + decal->color4f[0][3] = 1; + decal->color4f[1][0] = c1[0]; + decal->color4f[1][1] = c1[1]; + decal->color4f[1][2] = c1[2]; + decal->color4f[1][3] = 1; + decal->color4f[2][0] = c2[0]; + decal->color4f[2][1] = c2[1]; + decal->color4f[2][2] = c2[2]; + decal->color4f[2][3] = 1; + decal->vertex3f[0][0] = v0[0]; + decal->vertex3f[0][1] = v0[1]; + decal->vertex3f[0][2] = v0[2]; + decal->vertex3f[1][0] = v1[0]; + decal->vertex3f[1][1] = v1[1]; + decal->vertex3f[1][2] = v1[2]; + decal->vertex3f[2][0] = v2[0]; + decal->vertex3f[2][1] = v2[1]; + decal->vertex3f[2][2] = v2[2]; + decal->texcoord2f[0][0] = t0[0]; + decal->texcoord2f[0][1] = t0[1]; + decal->texcoord2f[1][0] = t1[0]; + decal->texcoord2f[1][1] = t1[1]; + decal->texcoord2f[2][0] = t2[0]; + decal->texcoord2f[2][1] = t2[1]; + TriangleNormal(v0, v1, v2, decal->plane); + VectorNormalize(decal->plane); + decal->plane[3] = DotProduct(v0, decal->plane); +} + +extern cvar_t cl_decals_bias; +extern cvar_t cl_decals_models; +extern cvar_t cl_decals_newsystem_intensitymultiplier; +// baseparms, parms, temps +static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex) +{ + int cornerindex; + int index; + float v[9][3]; + const float *vertex3f; + const float *normal3f; + int numpoints; + float points[2][9][3]; + float temp[3]; + float tc[9][2]; + float f; + float c[9][4]; + const int *e; + + e = rsurface.modelelement3i + 3*triangleindex; + + vertex3f = rsurface.modelvertex3f; + normal3f = rsurface.modelnormal3f; + + if (normal3f) + { + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + index = 3*e[cornerindex]; + VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]); + } + } + else + { + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + index = 3*e[cornerindex]; + VectorCopy(vertex3f + index, v[cornerindex]); + } + } + + // cull backfaces + //TriangleNormal(v[0], v[1], v[2], normal); + //if (DotProduct(normal, localnormal) < 0.0f) + // continue; + // clip by each of the box planes formed from the projection matrix + // if anything survives, we emit the decal + numpoints = PolygonF_Clip(3 , v[0] , planes[0][0], planes[0][1], planes[0][2], planes[0][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + if (numpoints < 3) + return; + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[1][0], planes[1][1], planes[1][2], planes[1][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); + if (numpoints < 3) + return; + numpoints = PolygonF_Clip(numpoints, points[0][0], planes[2][0], planes[2][1], planes[2][2], planes[2][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + if (numpoints < 3) + return; + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[3][0], planes[3][1], planes[3][2], planes[3][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); + if (numpoints < 3) + return; + numpoints = PolygonF_Clip(numpoints, points[0][0], planes[4][0], planes[4][1], planes[4][2], planes[4][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + if (numpoints < 3) + return; + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[5][0], planes[5][1], planes[5][2], planes[5][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), v[0]); + if (numpoints < 3) + return; + // some part of the triangle survived, so we have to accept it... + if (dynamic) + { + // dynamic always uses the original triangle + numpoints = 3; + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + index = 3*e[cornerindex]; + VectorCopy(vertex3f + index, v[cornerindex]); + } + } + for (cornerindex = 0;cornerindex < numpoints;cornerindex++) + { + // convert vertex positions to texcoords + Matrix4x4_Transform(projection, v[cornerindex], temp); + tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1; + tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1; + // calculate distance fade from the projection origin + f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value; + f = bound(0.0f, f, 1.0f); + c[cornerindex][0] = r * f; + c[cornerindex][1] = g * f; + c[cornerindex][2] = b * f; + c[cornerindex][3] = 1.0f; + //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]); + } + if (dynamic) + R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex, surfaceindex, decalsequence); + else + for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++) + R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence); +} +static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence) +{ + matrix4x4_t projection; + decalsystem_t *decalsystem; + qboolean dynamic; + dp_model_t *model; + const msurface_t *surface; + const msurface_t *surfaces; + const int *surfacelist; + const texture_t *texture; + int numtriangles; + int numsurfacelist; + int surfacelistindex; + int surfaceindex; + int triangleindex; + float localorigin[3]; + float localnormal[3]; + float localmins[3]; + float localmaxs[3]; + float localsize; + //float normal[3]; + float planes[6][4]; + float angles[3]; + bih_t *bih; + int bih_triangles_count; + int bih_triangles[256]; + int bih_surfaces[256]; + + decalsystem = &ent->decalsystem; + model = ent->model; + if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST))) + { + R_DecalSystem_Reset(&ent->decalsystem); + return; + } + + if (!model->brush.data_leafs && !cl_decals_models.integer) + { + if (decalsystem->model) + R_DecalSystem_Reset(decalsystem); + return; + } + + if (decalsystem->model != model) + R_DecalSystem_Reset(decalsystem); + decalsystem->model = model; + + RSurf_ActiveModelEntity(ent, true, false, false); + + Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin); + Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal); + VectorNormalize(localnormal); + localsize = worldsize*rsurface.inversematrixscale; + localmins[0] = localorigin[0] - localsize; + localmins[1] = localorigin[1] - localsize; + localmins[2] = localorigin[2] - localsize; + localmaxs[0] = localorigin[0] + localsize; + localmaxs[1] = localorigin[1] + localsize; + localmaxs[2] = localorigin[2] + localsize; + + //VectorCopy(localnormal, planes[4]); + //VectorVectors(planes[4], planes[2], planes[0]); + AnglesFromVectors(angles, localnormal, NULL, false); + AngleVectors(angles, planes[0], planes[2], planes[4]); + VectorNegate(planes[0], planes[1]); + VectorNegate(planes[2], planes[3]); + VectorNegate(planes[4], planes[5]); + planes[0][3] = DotProduct(planes[0], localorigin) - localsize; + planes[1][3] = DotProduct(planes[1], localorigin) - localsize; + planes[2][3] = DotProduct(planes[2], localorigin) - localsize; + planes[3][3] = DotProduct(planes[3], localorigin) - localsize; + planes[4][3] = DotProduct(planes[4], localorigin) - localsize; + planes[5][3] = DotProduct(planes[5], localorigin) - localsize; + +#if 1 +// works +{ + matrix4x4_t forwardprojection; + Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize); + Matrix4x4_Invert_Simple(&projection, &forwardprojection); +} +#else +// broken +{ + float projectionvector[4][3]; + VectorScale(planes[0], ilocalsize, projectionvector[0]); + VectorScale(planes[2], ilocalsize, projectionvector[1]); + VectorScale(planes[4], ilocalsize, projectionvector[2]); + projectionvector[0][0] = planes[0][0] * ilocalsize; + projectionvector[0][1] = planes[1][0] * ilocalsize; + projectionvector[0][2] = planes[2][0] * ilocalsize; + projectionvector[1][0] = planes[0][1] * ilocalsize; + projectionvector[1][1] = planes[1][1] * ilocalsize; + projectionvector[1][2] = planes[2][1] * ilocalsize; + projectionvector[2][0] = planes[0][2] * ilocalsize; + projectionvector[2][1] = planes[1][2] * ilocalsize; + projectionvector[2][2] = planes[2][2] * ilocalsize; + projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]); + projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]); + projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]); + Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]); +} +#endif + + dynamic = model->surfmesh.isanimated; + numsurfacelist = model->nummodelsurfaces; + surfacelist = model->sortedmodelsurfaces; + surfaces = model->data_surfaces; + + bih = NULL; + bih_triangles_count = -1; + if(!dynamic) + { + if(model->render_bih.numleafs) + bih = &model->render_bih; + else if(model->collision_bih.numleafs) + bih = &model->collision_bih; + } + if(bih) + bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs); + if(bih_triangles_count == 0) + return; + if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway + return; + if(bih_triangles_count > 0) + { + for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex) + { + surfaceindex = bih_surfaces[triangleindex]; + surface = surfaces + surfaceindex; + texture = surface->texture; + if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) + continue; + if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS) + continue; + R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex); + } + } + else + { + for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++) + { + surfaceindex = surfacelist[surfacelistindex]; + surface = surfaces + surfaceindex; + // check cull box first because it rejects more than any other check + if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs)) + continue; + // skip transparent surfaces + texture = surface->texture; + if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) + continue; + if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS) + continue; + numtriangles = surface->num_triangles; + for (triangleindex = 0; triangleindex < numtriangles; triangleindex++) + R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex); + } + } +} + +// do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead +static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, int decalsequence) +{ + int renderentityindex; + float worldmins[3]; + float worldmaxs[3]; + entity_render_t *ent; + + if (!cl_decals_newsystem.integer) + return; + + worldmins[0] = worldorigin[0] - worldsize; + worldmins[1] = worldorigin[1] - worldsize; + worldmins[2] = worldorigin[2] - worldsize; + worldmaxs[0] = worldorigin[0] + worldsize; + worldmaxs[1] = worldorigin[1] + worldsize; + worldmaxs[2] = worldorigin[2] + worldsize; + + R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence); + + for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++) + { + ent = r_refdef.scene.entities[renderentityindex]; + if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs)) + continue; + + R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence); + } +} + +typedef struct r_decalsystem_splatqueue_s +{ + vec3_t worldorigin; + vec3_t worldnormal; + float color[4]; + float tcrange[4]; + float worldsize; + int decalsequence; +} +r_decalsystem_splatqueue_t; + +int r_decalsystem_numqueued = 0; +r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE]; + +void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize) +{ + r_decalsystem_splatqueue_t *queue; + + if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE) + return; + + queue = &r_decalsystem_queue[r_decalsystem_numqueued++]; + VectorCopy(worldorigin, queue->worldorigin); + VectorCopy(worldnormal, queue->worldnormal); + Vector4Set(queue->color, r, g, b, a); + Vector4Set(queue->tcrange, s1, t1, s2, t2); + queue->worldsize = worldsize; + queue->decalsequence = cl.decalsequence++; +} + +static void R_DecalSystem_ApplySplatEntitiesQueue(void) +{ + int i; + r_decalsystem_splatqueue_t *queue; + + for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++) + R_DecalSystem_ApplySplatEntities(queue->worldorigin, queue->worldnormal, queue->color[0], queue->color[1], queue->color[2], queue->color[3], queue->tcrange[0], queue->tcrange[1], queue->tcrange[2], queue->tcrange[3], queue->worldsize, queue->decalsequence); + r_decalsystem_numqueued = 0; +} + +extern cvar_t cl_decals_max; +static void R_DrawModelDecals_FadeEntity(entity_render_t *ent) +{ + int i; + decalsystem_t *decalsystem = &ent->decalsystem; + int numdecals; + int killsequence; + tridecal_t *decal; + float frametime; + float lifetime; + + if (!decalsystem->numdecals) + return; + + if (r_showsurfaces.integer) + return; + + if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE)) + { + R_DecalSystem_Reset(decalsystem); + return; + } + + killsequence = cl.decalsequence - max(1, cl_decals_max.integer); + lifetime = cl_decals_time.value + cl_decals_fadetime.value; + + if (decalsystem->lastupdatetime) + frametime = (r_refdef.scene.time - decalsystem->lastupdatetime); + else + frametime = 0; + decalsystem->lastupdatetime = r_refdef.scene.time; + numdecals = decalsystem->numdecals; + + for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++) + { + if (decal->color4f[0][3]) + { + decal->lived += frametime; + if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime) + { + memset(decal, 0, sizeof(*decal)); + if (decalsystem->freedecal > i) + decalsystem->freedecal = i; + } + } + } + decal = decalsystem->decals; + while (numdecals > 0 && !decal[numdecals-1].color4f[0][3]) + numdecals--; + + // collapse the array by shuffling the tail decals into the gaps + for (;;) + { + while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3]) + decalsystem->freedecal++; + if (decalsystem->freedecal == numdecals) + break; + decal[decalsystem->freedecal] = decal[--numdecals]; + } + + decalsystem->numdecals = numdecals; + + if (numdecals <= 0) + { + // if there are no decals left, reset decalsystem + R_DecalSystem_Reset(decalsystem); + } +} + +extern skinframe_t *decalskinframe; +static void R_DrawModelDecals_Entity(entity_render_t *ent) +{ + int i; + decalsystem_t *decalsystem = &ent->decalsystem; + int numdecals; + tridecal_t *decal; + float faderate; + float alpha; + float *v3f; + float *c4f; + float *t2f; + const int *e; + const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL; + int numtris = 0; + + numdecals = decalsystem->numdecals; + if (!numdecals) + return; + + if (r_showsurfaces.integer) + return; + + if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE)) + { + R_DecalSystem_Reset(decalsystem); + return; + } + + // if the model is static it doesn't matter what value we give for + // wantnormals and wanttangents, so this logic uses only rules applicable + // to a model, knowing that they are meaningless otherwise + if (ent == r_refdef.scene.worldentity) + RSurf_ActiveWorldEntity(); + else + RSurf_ActiveModelEntity(ent, false, false, false); + + decalsystem->lastupdatetime = r_refdef.scene.time; + + faderate = 1.0f / max(0.001f, cl_decals_fadetime.value); + + // update vertex positions for animated models + v3f = decalsystem->vertex3f; + c4f = decalsystem->color4f; + t2f = decalsystem->texcoord2f; + for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++) + { + if (!decal->color4f[0][3]) + continue; + + if (surfacevisible && !surfacevisible[decal->surfaceindex]) + continue; + + // skip backfaces + if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3]) + continue; + + // update color values for fading decals + if (decal->lived >= cl_decals_time.value) + alpha = 1 - faderate * (decal->lived - cl_decals_time.value); + else + alpha = 1.0f; + + c4f[ 0] = decal->color4f[0][0] * alpha; + c4f[ 1] = decal->color4f[0][1] * alpha; + c4f[ 2] = decal->color4f[0][2] * alpha; + c4f[ 3] = 1; + c4f[ 4] = decal->color4f[1][0] * alpha; + c4f[ 5] = decal->color4f[1][1] * alpha; + c4f[ 6] = decal->color4f[1][2] * alpha; + c4f[ 7] = 1; + c4f[ 8] = decal->color4f[2][0] * alpha; + c4f[ 9] = decal->color4f[2][1] * alpha; + c4f[10] = decal->color4f[2][2] * alpha; + c4f[11] = 1; + + t2f[0] = decal->texcoord2f[0][0]; + t2f[1] = decal->texcoord2f[0][1]; + t2f[2] = decal->texcoord2f[1][0]; + t2f[3] = decal->texcoord2f[1][1]; + t2f[4] = decal->texcoord2f[2][0]; + t2f[5] = decal->texcoord2f[2][1]; + + // update vertex positions for animated models + if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles) + { + e = rsurface.modelelement3i + 3*decal->triangleindex; + VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f); + VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3); + VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6); + } + else + { + VectorCopy(decal->vertex3f[0], v3f); + VectorCopy(decal->vertex3f[1], v3f + 3); + VectorCopy(decal->vertex3f[2], v3f + 6); + } + + if (r_refdef.fogenabled) + { + alpha = RSurf_FogVertex(v3f); + VectorScale(c4f, alpha, c4f); + alpha = RSurf_FogVertex(v3f + 3); + VectorScale(c4f + 4, alpha, c4f + 4); + alpha = RSurf_FogVertex(v3f + 6); + VectorScale(c4f + 8, alpha, c4f + 8); + } + + v3f += 9; + c4f += 12; + t2f += 6; + numtris++; + } + + if (numtris > 0) + { + r_refdef.stats[r_stat_drawndecals] += numtris; + + // now render the decals all at once + // (this assumes they all use one particle font texture!) + RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, ent->shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false); +// R_Mesh_ResetTextureState(); + R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value); + GL_DepthTest(true); + GL_CullFace(GL_NONE); + GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false); + R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0); + } +} + +static void R_DrawModelDecals(void) +{ + int i, numdecals; + + // fade faster when there are too many decals + numdecals = r_refdef.scene.worldentity->decalsystem.numdecals; + for (i = 0;i < r_refdef.scene.numentities;i++) + numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals; + + R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity); + for (i = 0;i < r_refdef.scene.numentities;i++) + if (r_refdef.scene.entities[i]->decalsystem.numdecals) + R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]); + + R_DecalSystem_ApplySplatEntitiesQueue(); + + numdecals = r_refdef.scene.worldentity->decalsystem.numdecals; + for (i = 0;i < r_refdef.scene.numentities;i++) + numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals; + + r_refdef.stats[r_stat_totaldecals] += numdecals; + + if (r_showsurfaces.integer) + return; + + R_DrawModelDecals_Entity(r_refdef.scene.worldentity); + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + if (r_refdef.scene.entities[i]->decalsystem.numdecals) + R_DrawModelDecals_Entity(r_refdef.scene.entities[i]); + } +} + +extern cvar_t mod_collision_bih; +static void R_DrawDebugModel(void) +{ + entity_render_t *ent = rsurface.entity; + int i, j, k, l, flagsmask; + const msurface_t *surface; + dp_model_t *model = ent->model; + vec3_t v; + + if (!sv.active && !cls.demoplayback && ent != r_refdef.scene.worldentity) + return; + + if (r_showoverdraw.value > 0) + { + float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f; + flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL; + R_SetupShader_Generic_NoTexture(false, false); + GL_DepthTest(false); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_BlendFunc(GL_ONE, GL_ONE); + for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + { + if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) + continue; + rsurface.texture = R_GetCurrentTexture(surface->texture); + if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface); + GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back); + if (!rsurface.texture->currentlayers->depthmask) + GL_Color(c, 0, 0, 1.0f); + else if (ent == r_refdef.scene.worldentity) + GL_Color(c, c, c, 1.0f); + else + GL_Color(0, c, 0, 1.0f); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); + RSurf_DrawBatch(); + } + } + rsurface.texture = NULL; + } + + flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL; + +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(false, false); + GL_DepthRange(0, 1); + GL_DepthTest(!r_showdisabledepthtest.integer); + GL_DepthMask(false); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs) + { + int triangleindex; + int bihleafindex; + qboolean cullbox = false; + const q3mbrush_t *brush; + const bih_t *bih = &model->collision_bih; + const bih_leaf_t *bihleaf; + float vertex3f[3][3]; + GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value); + for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++) + { + if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs)) + continue; + switch (bihleaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes + bihleaf->itemindex; + if (brush->colbrushf && brush->colbrushf->numtriangles) + { + GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); + R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL); + R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0); + } + break; + case BIH_COLLISIONTRIANGLE: + triangleindex = bihleaf->itemindex; + VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]); + VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]); + VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]); + GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); + R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + break; + case BIH_RENDERTRIANGLE: + triangleindex = bihleaf->itemindex; + VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]); + VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]); + VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]); + GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); + R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + break; + } + } + } + + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + +#ifndef USE_GLES2 + if (r_showtris.integer && qglPolygonMode) + { + if (r_showdisabledepthtest.integer) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + } + else + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR + for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + { + if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) + continue; + rsurface.texture = R_GetCurrentTexture(surface->texture); + if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface); + if (!rsurface.texture->currentlayers->depthmask) + GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value); + else if (ent == r_refdef.scene.worldentity) + GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value); + else + GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); + RSurf_DrawBatch(); + } + } + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR + rsurface.texture = NULL; + } + + if (r_shownormals.value != 0 && qglBegin) + { + if (r_showdisabledepthtest.integer) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + } + else + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + } + for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + { + if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) + continue; + rsurface.texture = R_GetCurrentTexture(surface->texture); + if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface); + qglBegin(GL_LINES); + if (r_shownormals.value < 0 && rsurface.batchnormal3f) + { + for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++) + { + VectorCopy(rsurface.batchvertex3f + l * 3, v); + GL_Color(0, 0, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + } + } + if (r_shownormals.value > 0 && rsurface.batchsvector3f) + { + for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++) + { + VectorCopy(rsurface.batchvertex3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, 0, 0, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + } + } + if (r_shownormals.value > 0 && rsurface.batchtvector3f) + { + for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++) + { + VectorCopy(rsurface.batchvertex3f + l * 3, v); + GL_Color(0, r_refdef.view.colorscale, 0, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + } + } + if (r_shownormals.value > 0 && rsurface.batchnormal3f) + { + for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++) + { + VectorCopy(rsurface.batchvertex3f + l * 3, v); + GL_Color(0, 0, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1); + qglVertex3f(v[0], v[1], v[2]); + } + } + qglEnd(); + CHECKGLERROR + } + } + rsurface.texture = NULL; + } +#endif +} + +int r_maxsurfacelist = 0; +const msurface_t **r_surfacelist = NULL; +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass) +{ + int i, j, endj, flagsmask; + dp_model_t *model = r_refdef.scene.worldmodel; + msurface_t *surfaces; + unsigned char *update; + int numsurfacelist = 0; + if (model == NULL) + return; + + if (r_maxsurfacelist < model->num_surfaces) + { + r_maxsurfacelist = model->num_surfaces; + if (r_surfacelist) + Mem_Free((msurface_t**)r_surfacelist); + r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + } + + RSurf_ActiveWorldEntity(); + + surfaces = model->data_surfaces; + update = model->brushq1.lightmapupdateflags; + + // update light styles on this submodel + if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + { + model_brush_lightstyleinfo_t *style; + for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) + { + if (style->value != r_refdef.scene.lightstylevalue[style->style]) + { + int *list = style->surfacelist; + style->value = r_refdef.scene.lightstylevalue[style->style]; + for (j = 0;j < style->numsurfaces;j++) + update[list[j]] = true; + } + } + } + + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; + + if (debug) + { + R_DrawDebugModel(); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + return; + } + + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + rsurface.texture = NULL; + rsurface.rtlight = NULL; + numsurfacelist = 0; + // add visible surfaces to draw list + for (i = 0;i < model->nummodelsurfaces;i++) + { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + r_surfacelist[numsurfacelist++] = surfaces + j; + } + // update lightmaps if needed + if (model->brushq1.firstrender) + { + model->brushq1.firstrender = false; + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) + if (update[j]) + R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); + } + else if (update) + { + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) + if (r_refdef.viewcache.world_surfacevisible[j]) + if (update[j]) + R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); + } + // don't do anything if there were no surfaces + if (!numsurfacelist) + { + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + return; + } + R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass); + + // add to stats if desired + if (r_speeds.integer && !skysurfaces && !depthonly) + { + r_refdef.stats[r_stat_world_surfaces] += numsurfacelist; + for (j = 0;j < numsurfacelist;j++) + r_refdef.stats[r_stat_world_triangles] += r_surfacelist[j]->num_triangles; + } + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass) +{ + int i, j, endj, flagsmask; + dp_model_t *model = ent->model; + msurface_t *surfaces; + unsigned char *update; + int numsurfacelist = 0; + if (model == NULL) + return; + + if (r_maxsurfacelist < model->num_surfaces) + { + r_maxsurfacelist = model->num_surfaces; + if (r_surfacelist) + Mem_Free((msurface_t **)r_surfacelist); + r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + } + + // if the model is static it doesn't matter what value we give for + // wantnormals and wanttangents, so this logic uses only rules applicable + // to a model, knowing that they are meaningless otherwise + if (ent == r_refdef.scene.worldentity) + RSurf_ActiveWorldEntity(); + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) + RSurf_ActiveModelEntity(ent, false, false, false); + else if (prepass) + RSurf_ActiveModelEntity(ent, true, true, true); + else if (depthonly) + { + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + RSurf_ActiveModelEntity(ent, model->wantnormals, false, false); + break; + } + } + else + { + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + RSurf_ActiveModelEntity(ent, true, true, false); + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + RSurf_ActiveModelEntity(ent, true, false, false); + break; + } + } + + surfaces = model->data_surfaces; + update = model->brushq1.lightmapupdateflags; + + // update light styles + if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + { + model_brush_lightstyleinfo_t *style; + for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) + { + if (style->value != r_refdef.scene.lightstylevalue[style->style]) + { + int *list = style->surfacelist; + style->value = r_refdef.scene.lightstylevalue[style->style]; + for (j = 0;j < style->numsurfaces;j++) + update[list[j]] = true; + } + } + } + + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; + + if (debug) + { + R_DrawDebugModel(); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + return; + } + + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + rsurface.texture = NULL; + rsurface.rtlight = NULL; + numsurfacelist = 0; + // add visible surfaces to draw list + for (i = 0;i < model->nummodelsurfaces;i++) + r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i]; + // don't do anything if there were no surfaces + if (!numsurfacelist) + { + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + return; + } + // update lightmaps if needed + if (update) + { + int updated = 0; + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) + { + if (update[j]) + { + updated++; + R_BuildLightMap(ent, surfaces + j); + } + } + } + + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass); + + // add to stats if desired + if (r_speeds.integer && !skysurfaces && !depthonly) + { + r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist; + for (j = 0;j < numsurfacelist;j++) + r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles; + } + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass) +{ + static texture_t texture; + static msurface_t surface; + const msurface_t *surfacelist = &surface; + + // fake enough texture and surface state to render this geometry + + texture.update_lastrenderframe = -1; // regenerate this texture + texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL; + texture.currentskinframe = skinframe; + texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE + texture.offsetmapping = OFFSETMAPPING_OFF; + texture.offsetscale = 1; + texture.specularscalemod = 1; + texture.specularpowermod = 1; + texture.transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". + + surface.texture = &texture; + surface.num_triangles = numtriangles; + surface.num_firsttriangle = firsttriangle; + surface.num_vertices = numvertices; + surface.num_firstvertex = firstvertex; + + // now render it + rsurface.texture = R_GetCurrentTexture(surface.texture); + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass); +} + +void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass) +{ + static msurface_t surface; + const msurface_t *surfacelist = &surface; + + // fake enough texture and surface state to render this geometry + surface.texture = texture; + surface.num_triangles = numtriangles; + surface.num_firsttriangle = firsttriangle; + surface.num_vertices = numvertices; + surface.num_firstvertex = firstvertex; + + // now render it + rsurface.texture = R_GetCurrentTexture(surface.texture); + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; + R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass); +} diff --git a/app/jni/gl_rsurf.c b/app/jni/gl_rsurf.c new file mode 100644 index 0000000..17b183d --- /dev/null +++ b/app/jni/gl_rsurf.c @@ -0,0 +1,1645 @@ +/* +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_shadow.h" +#include "portals.h" +#include "csprogs.h" +#include "image.h" + +cvar_t r_ambient = {0, "r_ambient", "0", "brightens map, value is 0-128"}; +cvar_t r_lockpvs = {0, "r_lockpvs", "0", "disables pvs switching, allows you to walk around and inspect what is visible from a given location in the map (anything not visible from your current location will not be drawn)"}; +cvar_t r_lockvisibility = {0, "r_lockvisibility", "0", "disables visibility updates, allows you to walk around and inspect what is visible from a given viewpoint in the map (anything offscreen at the moment this is enabled will not be drawn)"}; +cvar_t r_useportalculling = {0, "r_useportalculling", "2", "improve framerate with r_novis 1 by using portal culling - still not as good as compiled visibility data in the map, but it helps (a value of 2 forces use of this even with vis data, which improves framerates in maps without too much complexity, but hurts in extremely complex maps, which is why 2 is not the default mode)"}; +cvar_t r_usesurfaceculling = {0, "r_usesurfaceculling", "1", "skip off-screen surfaces (1 = cull surfaces if the map is likely to benefit, 2 = always cull surfaces)"}; +cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0", "draws sky depth masking in q3 maps (as in q1 maps), this means for example that sky polygons can hide other things"}; + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the 8.8 format in blocklights +=============== +*/ +void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) +{ + int smax, tmax, i, size, size3, maps, l; + int *bl, scale; + unsigned char *lightmap, *out, *stain; + dp_model_t *model = ent->model; + int *intblocklights; + unsigned char *templight; + + smax = (surface->lightmapinfo->extents[0]>>4)+1; + tmax = (surface->lightmapinfo->extents[1]>>4)+1; + size = smax*tmax; + size3 = size*3; + + r_refdef.stats[r_stat_lightmapupdatepixels] += size; + r_refdef.stats[r_stat_lightmapupdates]++; + + if (cl.buildlightmapmemorysize < size*sizeof(int[3])) + { + cl.buildlightmapmemorysize = size*sizeof(int[3]); + if (cl.buildlightmapmemory) + Mem_Free(cl.buildlightmapmemory); + cl.buildlightmapmemory = (unsigned char *) Mem_Alloc(cls.levelmempool, cl.buildlightmapmemorysize); + } + + // these both point at the same buffer, templight is only used for final + // processing and can replace the intblocklights data as it goes + intblocklights = (int *)cl.buildlightmapmemory; + templight = (unsigned char *)cl.buildlightmapmemory; + + // update cached lighting info + model->brushq1.lightmapupdateflags[surface - model->data_surfaces] = false; + + lightmap = surface->lightmapinfo->samples; + +// set to full bright if no light data + bl = intblocklights; + if (!model->brushq1.lightdata) + { + for (i = 0;i < size3;i++) + bl[i] = 128*256; + } + else + { +// clear to no light + memset(bl, 0, size3*sizeof(*bl)); + +// add all the lightmaps + if (lightmap) + for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3) + for (scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++) + bl[i] += lightmap[i] * scale; + } + + stain = surface->lightmapinfo->stainsamples; + bl = intblocklights; + out = templight; + // the >> 16 shift adjusts down 8 bits to account for the stainmap + // scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will + // be doubled during rendering to achieve 2x overbright + // (0 = 0.0, 128 = 1.0, 256 = 2.0) + if (stain) + { + for (i = 0;i < size;i++, bl += 3, stain += 3, out += 4) + { + l = (bl[0] * stain[0]) >> 16;out[2] = min(l, 255); + l = (bl[1] * stain[1]) >> 16;out[1] = min(l, 255); + l = (bl[2] * stain[2]) >> 16;out[0] = min(l, 255); + out[3] = 255; + } + } + else + { + for (i = 0;i < size;i++, bl += 3, out += 4) + { + l = bl[0] >> 8;out[2] = min(l, 255); + l = bl[1] >> 8;out[1] = min(l, 255); + l = bl[2] >> 8;out[0] = min(l, 255); + out[3] = 255; + } + } + + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + Image_MakesRGBColorsFromLinear_Lightmap(templight, templight, size); + R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], 0, smax, tmax, 1); + + // update the surface's deluxemap if it has one + if (surface->deluxemaptexture != r_texture_blanknormalmap) + { + vec3_t n; + unsigned char *normalmap = surface->lightmapinfo->nmapsamples; + lightmap = surface->lightmapinfo->samples; + // clear to no normalmap + bl = intblocklights; + memset(bl, 0, size3*sizeof(*bl)); + // add all the normalmaps + if (lightmap && normalmap) + { + for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3, normalmap += size3) + { + for (scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size;i++) + { + // add the normalmap with weighting proportional to the style's lightmap intensity + l = (int)(VectorLength(lightmap + i*3) * scale); + bl[i*3+0] += ((int)normalmap[i*3+0] - 128) * l; + bl[i*3+1] += ((int)normalmap[i*3+1] - 128) * l; + bl[i*3+2] += ((int)normalmap[i*3+2] - 128) * l; + } + } + } + bl = intblocklights; + out = templight; + // we simply renormalize the weighted normals to get a valid deluxemap + for (i = 0;i < size;i++, bl += 3, out += 4) + { + VectorCopy(bl, n); + VectorNormalize(n); + l = (int)(n[0] * 128 + 128);out[2] = bound(0, l, 255); + l = (int)(n[1] * 128 + 128);out[1] = bound(0, l, 255); + l = (int)(n[2] * 128 + 128);out[0] = bound(0, l, 255); + out[3] = 255; + } + R_UpdateTexture(surface->deluxemaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], 0, smax, tmax, 1); + } +} + +static void R_StainNode (mnode_t *node, dp_model_t *model, const vec3_t origin, float radius, const float fcolor[8]) +{ + float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2; + msurface_t *surface, *endsurface; + int i, s, t, smax, tmax, smax3, impacts, impactt, stained; + unsigned char *bl; + vec3_t impact; + + maxdist = radius * radius; + invradius = 1.0f / radius; + +loc0: + if (!node->plane) + return; + ndist = PlaneDiff(origin, node->plane); + if (ndist > radius) + { + node = node->children[0]; + goto loc0; + } + if (ndist < -radius) + { + node = node->children[1]; + goto loc0; + } + + dist2 = ndist * ndist; + maxdist3 = maxdist - dist2; + + if (node->plane->type < 3) + { + VectorCopy(origin, impact); + impact[node->plane->type] -= ndist; + } + else + { + impact[0] = origin[0] - node->plane->normal[0] * ndist; + impact[1] = origin[1] - node->plane->normal[1] * ndist; + impact[2] = origin[2] - node->plane->normal[2] * ndist; + } + + for (surface = model->data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++) + { + if (surface->lightmapinfo->stainsamples) + { + smax = (surface->lightmapinfo->extents[0] >> 4) + 1; + tmax = (surface->lightmapinfo->extents[1] >> 4) + 1; + + impacts = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3] - surface->lightmapinfo->texturemins[0]); + impactt = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3] - surface->lightmapinfo->texturemins[1]); + + s = bound(0, impacts, smax * 16) - impacts; + t = bound(0, impactt, tmax * 16) - impactt; + i = (int)(s * s + t * t + dist2); + if ((i > maxdist) || (smax > (int)(sizeof(sdtable)/sizeof(sdtable[0])))) // smax overflow fix from Andreas Dehmel + continue; + + // reduce calculations + for (s = 0, i = impacts; s < smax; s++, i -= 16) + sdtable[s] = i * i + dist2; + + bl = surface->lightmapinfo->stainsamples; + smax3 = smax * 3; + stained = false; + + i = impactt; + for (t = 0;t < tmax;t++, i -= 16) + { + td = i * i; + // make sure some part of it is visible on this line + if (td < maxdist3) + { + maxdist2 = maxdist - td; + for (s = 0;s < smax;s++) + { + if (sdtable[s] < maxdist2) + { + ratio = lhrandom(0.0f, 1.0f); + a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius); + if (a >= (1.0f / 64.0f)) + { + if (a > 1) + a = 1; + bl[0] = (unsigned char) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0])); + bl[1] = (unsigned char) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1])); + bl[2] = (unsigned char) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2])); + stained = true; + } + } + bl += 3; + } + } + else // skip line + bl += smax3; + } + // force lightmap upload + if (stained) + model->brushq1.lightmapupdateflags[surface - model->data_surfaces] = true; + } + } + + if (node->children[0]->plane) + { + if (node->children[1]->plane) + { + R_StainNode(node->children[0], model, origin, radius, fcolor); + node = node->children[1]; + goto loc0; + } + else + { + node = node->children[0]; + goto loc0; + } + } + else if (node->children[1]->plane) + { + node = node->children[1]; + goto loc0; + } +} + +void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2) +{ + int n; + float fcolor[8]; + entity_render_t *ent; + dp_model_t *model; + vec3_t org; + if (r_refdef.scene.worldmodel == NULL || !r_refdef.scene.worldmodel->brush.data_nodes || !r_refdef.scene.worldmodel->brushq1.lightdata) + return; + fcolor[0] = cr1; + fcolor[1] = cg1; + fcolor[2] = cb1; + fcolor[3] = ca1 * (1.0f / 64.0f); + fcolor[4] = cr2 - cr1; + fcolor[5] = cg2 - cg1; + fcolor[6] = cb2 - cb1; + fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f); + + R_StainNode(r_refdef.scene.worldmodel->brush.data_nodes + r_refdef.scene.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.scene.worldmodel, origin, radius, fcolor); + + // look for embedded bmodels + for (n = 0;n < cl.num_brushmodel_entities;n++) + { + ent = &cl.entities[cl.brushmodel_entities[n]].render; + model = ent->model; + if (model && model->name[0] == '*') + { + if (model->brush.data_nodes) + { + Matrix4x4_Transform(&ent->inversematrix, origin, org); + R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor); + } + } + } +} + + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + // due to the hacky nature of this function's parameters, this is never + // called with a batch, so numsurfaces is always 1, and the surfacelist + // contains only a leaf number for coloring purposes + const mportal_t *portal = (mportal_t *)ent; + qboolean isvis; + int i, numpoints; + float *v; + float vertex3f[POLYGONELEMENTS_MAXPOINTS*3]; + CHECKGLERROR + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + GL_DepthTest(true); + GL_CullFace(GL_NONE); + R_EntityMatrix(&identitymatrix); + + numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS); + +// R_Mesh_ResetTextureState(); + + isvis = (portal->here->clusterindex >= 0 && portal->past->clusterindex >= 0 && portal->here->clusterindex != portal->past->clusterindex); + + i = surfacelist[0] >> 1; + GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale, + ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale, + ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale, + isvis ? 0.125f : 0.03125f); + for (i = 0, v = vertex3f;i < numpoints;i++, v += 3) + VectorCopy(portal->points[i].position, v); + R_Mesh_PrepareVertices_Generic_Arrays(numpoints, vertex3f, NULL, NULL); + R_SetupShader_Generic_NoTexture(false, false); + R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); +} + +// LordHavoc: this is just a nice debugging tool, very slow +void R_DrawPortals(void) +{ + int i, leafnum; + mportal_t *portal; + float center[3], f; + dp_model_t *model = r_refdef.scene.worldmodel; + if (model == NULL) + return; + for (leafnum = 0;leafnum < r_refdef.scene.worldmodel->brush.num_leafs;leafnum++) + { + if (r_refdef.viewcache.world_leafvisible[leafnum]) + { + //for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++) + for (portal = r_refdef.scene.worldmodel->brush.data_leafs[leafnum].portals;portal;portal = portal->next) + { + if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS) + if (!R_CullBox(portal->mins, portal->maxs)) + { + VectorClear(center); + for (i = 0;i < portal->numpoints;i++) + VectorAdd(center, portal->points[i].position, center); + f = ixtable[portal->numpoints]; + VectorScale(center, f, center); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawPortal_Callback, (entity_render_t *)portal, leafnum, rsurface.rtlight); + } + } + } + } +} + +static void R_View_WorldVisibility_CullSurfaces(void) +{ + int surfaceindex; + int surfaceindexstart; + int surfaceindexend; + unsigned char *surfacevisible; + msurface_t *surfaces; + dp_model_t *model = r_refdef.scene.worldmodel; + if (!model) + return; + if (r_trippy.integer) + return; + if (r_usesurfaceculling.integer < 1) + return; + surfaceindexstart = model->firstmodelsurface; + surfaceindexend = surfaceindexstart + model->nummodelsurfaces; + surfaces = model->data_surfaces; + surfacevisible = r_refdef.viewcache.world_surfacevisible; + for (surfaceindex = surfaceindexstart;surfaceindex < surfaceindexend;surfaceindex++) + if (surfacevisible[surfaceindex] && R_CullBox(surfaces[surfaceindex].mins, surfaces[surfaceindex].maxs)) + surfacevisible[surfaceindex] = 0; +} + +void R_View_WorldVisibility(qboolean forcenovis) +{ + int i, j, *mark; + mleaf_t *leaf; + mleaf_t *viewleaf; + dp_model_t *model = r_refdef.scene.worldmodel; + + if (!model) + return; + + if (r_refdef.view.usecustompvs) + { + // clear the visible surface and leaf flags arrays + memset(r_refdef.viewcache.world_surfacevisible, 0, model->num_surfaces); + memset(r_refdef.viewcache.world_leafvisible, 0, model->brush.num_leafs); + r_refdef.viewcache.world_novis = false; + + // simply cull each marked leaf to the frustum (view pyramid) + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) + { + // if leaf is in current pvs and on the screen, mark its surfaces + if (CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs)) + { + r_refdef.stats[r_stat_world_leafs]++; + r_refdef.viewcache.world_leafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_refdef.viewcache.world_surfacevisible[*mark] = true; + } + } + R_View_WorldVisibility_CullSurfaces(); + return; + } + + // if possible find the leaf the view origin is in + viewleaf = model->brush.PointInLeaf ? model->brush.PointInLeaf(model, r_refdef.view.origin) : NULL; + // if possible fetch the visible cluster bits + if (!r_lockpvs.integer && model->brush.FatPVS) + model->brush.FatPVS(model, r_refdef.view.origin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + + if (!r_lockvisibility.integer) + { + // clear the visible surface and leaf flags arrays + memset(r_refdef.viewcache.world_surfacevisible, 0, model->num_surfaces); + memset(r_refdef.viewcache.world_leafvisible, 0, model->brush.num_leafs); + + r_refdef.viewcache.world_novis = false; + + // if floating around in the void (no pvs data available, and no + // portals available), simply use all on-screen leafs. + if (!viewleaf || viewleaf->clusterindex < 0 || forcenovis || r_trippy.integer) + { + // no visibility method: (used when floating around in the void) + // simply cull each leaf to the frustum (view pyramid) + // similar to quake's RecursiveWorldNode but without cache misses + r_refdef.viewcache.world_novis = true; + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) + { + if (leaf->clusterindex < 0) + continue; + // if leaf is in current pvs and on the screen, mark its surfaces + if (!R_CullBox(leaf->mins, leaf->maxs)) + { + r_refdef.stats[r_stat_world_leafs]++; + r_refdef.viewcache.world_leafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_refdef.viewcache.world_surfacevisible[*mark] = true; + } + } + } + // just check if each leaf in the PVS is on screen + // (unless portal culling is enabled) + else if (!model->brush.data_portals || r_useportalculling.integer < 1 || (r_useportalculling.integer < 2 && !r_novis.integer)) + { + // pvs method: + // simply check if each leaf is in the Potentially Visible Set, + // and cull to frustum (view pyramid) + // similar to quake's RecursiveWorldNode but without cache misses + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) + { + if (leaf->clusterindex < 0) + continue; + // if leaf is in current pvs and on the screen, mark its surfaces + if (CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs)) + { + r_refdef.stats[r_stat_world_leafs]++; + r_refdef.viewcache.world_leafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_refdef.viewcache.world_surfacevisible[*mark] = true; + } + } + } + // if desired use a recursive portal flow, culling each portal to + // frustum and checking if the leaf the portal leads to is in the pvs + else + { + int leafstackpos; + mportal_t *p; + mleaf_t *leafstack[8192]; + // simple-frustum portal method: + // follows portals leading outward from viewleaf, does not venture + // offscreen or into leafs that are not visible, faster than + // Quake's RecursiveWorldNode and vastly better in unvised maps, + // often culls some surfaces that pvs alone would miss + // (such as a room in pvs that is hidden behind a wall, but the + // passage leading to the room is off-screen) + leafstack[0] = viewleaf; + leafstackpos = 1; + while (leafstackpos) + { + leaf = leafstack[--leafstackpos]; + if (r_refdef.viewcache.world_leafvisible[leaf - model->brush.data_leafs]) + continue; + if (leaf->clusterindex < 0) + continue; + r_refdef.stats[r_stat_world_leafs]++; + r_refdef.viewcache.world_leafvisible[leaf - model->brush.data_leafs] = true; + // mark any surfaces bounding this leaf + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_refdef.viewcache.world_surfacevisible[*mark] = true; + // follow portals into other leafs + // the checks are: + // if viewer is behind portal (portal faces outward into the scene) + // and the portal polygon's bounding box is on the screen + // and the leaf has not been visited yet + // and the leaf is visible in the pvs + // (the first two checks won't cause as many cache misses as the leaf checks) + for (p = leaf->portals;p;p = p->next) + { + r_refdef.stats[r_stat_world_portals]++; + if (DotProduct(r_refdef.view.origin, p->plane.normal) < (p->plane.dist + 1) + && !r_refdef.viewcache.world_leafvisible[p->past - model->brush.data_leafs] + && CHECKPVSBIT(r_refdef.viewcache.world_pvsbits, p->past->clusterindex) + && !R_CullBox(p->mins, p->maxs) + && leafstackpos < (int)(sizeof(leafstack) / sizeof(leafstack[0]))) + leafstack[leafstackpos++] = p->past; + } + } + } + } + + R_View_WorldVisibility_CullSurfaces(); +} + +void R_Q1BSP_DrawSky(entity_render_t *ent) +{ + if (ent->model == NULL) + return; + if (ent == r_refdef.scene.worldentity) + R_DrawWorldSurfaces(true, true, false, false, false); + else + R_DrawModelSurfaces(ent, true, true, false, false, false); +} + +void R_Q1BSP_DrawAddWaterPlanes(entity_render_t *ent) +{ + int i, j, n, flagsmask; + dp_model_t *model = ent->model; + msurface_t *surfaces; + if (model == NULL) + return; + + if (ent == r_refdef.scene.worldentity) + RSurf_ActiveWorldEntity(); + else + RSurf_ActiveModelEntity(ent, true, false, false); + + surfaces = model->data_surfaces; + flagsmask = MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA; + + // add visible surfaces to draw list + if (ent == r_refdef.scene.worldentity) + { + for (i = 0;i < model->nummodelsurfaces;i++) + { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + if (surfaces[j].texture->basematerialflags & flagsmask) + R_Water_AddWaterPlane(surfaces + j, 0); + } + } + else + { + if(ent->entitynumber >= MAX_EDICTS) // && CL_VM_TransformView(ent->entitynumber - MAX_EDICTS, NULL, NULL, NULL)) + n = ent->entitynumber; + else + n = 0; + for (i = 0;i < model->nummodelsurfaces;i++) + { + j = model->sortedmodelsurfaces[i]; + if (surfaces[j].texture->basematerialflags & flagsmask) + R_Water_AddWaterPlane(surfaces + j, n); + } + } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +void R_Q1BSP_Draw(entity_render_t *ent) +{ + dp_model_t *model = ent->model; + if (model == NULL) + return; + if (ent == r_refdef.scene.worldentity) + R_DrawWorldSurfaces(false, true, false, false, false); + else + R_DrawModelSurfaces(ent, false, true, false, false, false); +} + +void R_Q1BSP_DrawDepth(entity_render_t *ent) +{ + dp_model_t *model = ent->model; + if (model == NULL || model->surfmesh.isanimated) + return; + GL_ColorMask(0,0,0,0); + GL_Color(1,1,1,1); + GL_DepthTest(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); +// R_Mesh_ResetTextureState(); + if (ent == r_refdef.scene.worldentity) + R_DrawWorldSurfaces(false, false, true, false, false); + else + R_DrawModelSurfaces(ent, false, false, true, false, false); + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); +} + +void R_Q1BSP_DrawDebug(entity_render_t *ent) +{ + if (ent->model == NULL) + return; + if (ent == r_refdef.scene.worldentity) + R_DrawWorldSurfaces(false, false, false, true, false); + else + R_DrawModelSurfaces(ent, false, false, false, true, false); +} + +void R_Q1BSP_DrawPrepass(entity_render_t *ent) +{ + dp_model_t *model = ent->model; + if (model == NULL) + return; + if (ent == r_refdef.scene.worldentity) + R_DrawWorldSurfaces(false, true, false, false, true); + else + R_DrawModelSurfaces(ent, false, true, false, false, true); +} + +typedef struct r_q1bsp_getlightinfo_s +{ + dp_model_t *model; + vec3_t relativelightorigin; + float lightradius; + int *outleaflist; + unsigned char *outleafpvs; + int outnumleafs; + unsigned char *visitingleafpvs; + int *outsurfacelist; + unsigned char *outsurfacepvs; + unsigned char *tempsurfacepvs; + unsigned char *outshadowtrispvs; + unsigned char *outlighttrispvs; + int outnumsurfaces; + vec3_t outmins; + vec3_t outmaxs; + vec3_t lightmins; + vec3_t lightmaxs; + const unsigned char *pvs; + qboolean svbsp_active; + qboolean svbsp_insertoccluder; + int numfrustumplanes; + const mplane_t *frustumplanes; +} +r_q1bsp_getlightinfo_t; + +#define GETLIGHTINFO_MAXNODESTACK 4096 + +static void R_Q1BSP_RecursiveGetLightInfo_BSP(r_q1bsp_getlightinfo_t *info, qboolean skipsurfaces) +{ + // nodestack + mnode_t *nodestack[GETLIGHTINFO_MAXNODESTACK]; + int nodestackpos = 0; + // node processing + mplane_t *plane; + mnode_t *node; + int sides; + // leaf processing + mleaf_t *leaf; + const msurface_t *surface; + const msurface_t *surfaces = info->model->data_surfaces; + int numleafsurfaces; + int leafsurfaceindex; + int surfaceindex; + int triangleindex, t; + int currentmaterialflags; + qboolean castshadow; + const int *e; + const vec_t *v[3]; + float v2[3][3]; + qboolean insidebox; + qboolean frontsidecasting = r_shadow_frontsidecasting.integer != 0; + qboolean svbspactive = info->svbsp_active; + qboolean svbspinsertoccluder = info->svbsp_insertoccluder; + const int *leafsurfaceindices; + qboolean addedtris; + int i; + mportal_t *portal; + static float points[128][3]; + // push the root node onto our nodestack + nodestack[nodestackpos++] = info->model->brush.data_nodes; + // we'll be done when the nodestack is empty + while (nodestackpos) + { + // get a node from the stack to process + node = nodestack[--nodestackpos]; + // is it a node or a leaf? + plane = node->plane; + if (plane) + { + // node +#if 0 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) + continue; +#endif +#if 0 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(node->mins, node->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes)) + continue; +#endif + // axial planes can be processed much more quickly + if (plane->type < 3) + { + // axial plane + if (info->lightmins[plane->type] > plane->dist) + nodestack[nodestackpos++] = node->children[0]; + else if (info->lightmaxs[plane->type] < plane->dist) + nodestack[nodestackpos++] = node->children[1]; + else + { + // recurse front side first because the svbsp building prefers it + if (info->relativelightorigin[plane->type] >= plane->dist) + { + if (nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->children[0]; + nodestack[nodestackpos++] = node->children[1]; + } + else + { + if (nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->children[1]; + nodestack[nodestackpos++] = node->children[0]; + } + } + } + else + { + // sloped plane + sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, plane); + switch (sides) + { + default: + continue; // ERROR: NAN bounding box! + case 1: + nodestack[nodestackpos++] = node->children[0]; + break; + case 2: + nodestack[nodestackpos++] = node->children[1]; + break; + case 3: + // recurse front side first because the svbsp building prefers it + if (PlaneDist(info->relativelightorigin, plane) >= 0) + { + if (nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->children[0]; + nodestack[nodestackpos++] = node->children[1]; + } + else + { + if (nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->children[1]; + nodestack[nodestackpos++] = node->children[0]; + } + break; + } + } + } + else + { + // leaf + leaf = (mleaf_t *)node; +#if 1 + if (r_shadow_frontsidecasting.integer && info->pvs != NULL && !CHECKPVSBIT(info->pvs, leaf->clusterindex)) + continue; +#endif +#if 1 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, leaf->mins, leaf->maxs)) + continue; +#endif +#if 1 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(leaf->mins, leaf->maxs, info->numfrustumplanes, info->frustumplanes)) + continue; +#endif + + if (svbspactive) + { + // we can occlusion test the leaf by checking if all of its portals + // are occluded (unless the light is in this leaf - but that was + // already handled by the caller) + for (portal = leaf->portals;portal;portal = portal->next) + { + for (i = 0;i < portal->numpoints;i++) + VectorCopy(portal->points[i].position, points[i]); + if (SVBSP_AddPolygon(&r_svbsp, portal->numpoints, points[0], false, NULL, NULL, 0) & 2) + break; + } + if (leaf->portals && portal == NULL) + continue; // no portals of this leaf visible + } + + // add this leaf to the reduced light bounds + info->outmins[0] = min(info->outmins[0], leaf->mins[0]); + info->outmins[1] = min(info->outmins[1], leaf->mins[1]); + info->outmins[2] = min(info->outmins[2], leaf->mins[2]); + info->outmaxs[0] = max(info->outmaxs[0], leaf->maxs[0]); + info->outmaxs[1] = max(info->outmaxs[1], leaf->maxs[1]); + info->outmaxs[2] = max(info->outmaxs[2], leaf->maxs[2]); + + // mark this leaf as being visible to the light + if (info->outleafpvs) + { + int leafindex = leaf - info->model->brush.data_leafs; + if (!CHECKPVSBIT(info->outleafpvs, leafindex)) + { + SETPVSBIT(info->outleafpvs, leafindex); + info->outleaflist[info->outnumleafs++] = leafindex; + } + } + + // when using BIH, we skip the surfaces here + if (skipsurfaces) + continue; + + // iterate the surfaces linked by this leaf and check their triangles + leafsurfaceindices = leaf->firstleafsurface; + numleafsurfaces = leaf->numleafsurfaces; + if (svbspinsertoccluder) + { + for (leafsurfaceindex = 0;leafsurfaceindex < numleafsurfaces;leafsurfaceindex++) + { + surfaceindex = leafsurfaceindices[leafsurfaceindex]; + if (CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) + continue; + SETPVSBIT(info->outsurfacepvs, surfaceindex); + surface = surfaces + surfaceindex; + if (!BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs)) + continue; + currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; + castshadow = !(currentmaterialflags & MATERIALFLAG_NOSHADOW); + if (!castshadow) + continue; + insidebox = BoxInsideBox(surface->mins, surface->maxs, info->lightmins, info->lightmaxs); + for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = info->model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->num_triangles;triangleindex++, t++, e += 3) + { + v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; + VectorCopy(v[0], v2[0]); + VectorCopy(v[1], v2[1]); + VectorCopy(v[2], v2[2]); + if (insidebox || TriangleBBoxOverlapsBox(v2[0], v2[1], v2[2], info->lightmins, info->lightmaxs)) + SVBSP_AddPolygon(&r_svbsp, 3, v2[0], true, NULL, NULL, 0); + } + } + } + else + { + for (leafsurfaceindex = 0;leafsurfaceindex < numleafsurfaces;leafsurfaceindex++) + { + surfaceindex = leafsurfaceindices[leafsurfaceindex]; + if (CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) + continue; + SETPVSBIT(info->outsurfacepvs, surfaceindex); + surface = surfaces + surfaceindex; + if (!BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs)) + continue; + addedtris = false; + currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; + castshadow = !(currentmaterialflags & MATERIALFLAG_NOSHADOW); + insidebox = BoxInsideBox(surface->mins, surface->maxs, info->lightmins, info->lightmaxs); + for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = info->model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->num_triangles;triangleindex++, t++, e += 3) + { + v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; + VectorCopy(v[0], v2[0]); + VectorCopy(v[1], v2[1]); + VectorCopy(v[2], v2[2]); + if (!insidebox && !TriangleBBoxOverlapsBox(v2[0], v2[1], v2[2], info->lightmins, info->lightmaxs)) + continue; + if (svbspactive && !(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], false, NULL, NULL, 0) & 2)) + continue; + // we don't omit triangles from lighting even if they are + // backfacing, because when using shadowmapping they are often + // not fully occluded on the horizon of an edge + SETPVSBIT(info->outlighttrispvs, t); + addedtris = true; + if (castshadow) + { + if (currentmaterialflags & MATERIALFLAG_NOCULLFACE) + { + // if the material is double sided we + // can't cull by direction + SETPVSBIT(info->outshadowtrispvs, t); + } + else if (frontsidecasting) + { + // front side casting occludes backfaces, + // so they are completely useless as both + // casters and lit polygons + if (PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + else + { + // back side casting does not occlude + // anything so we can't cull lit polygons + if (!PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + } + } + if (addedtris) + info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; + } + } + } + } +} + +static void R_Q1BSP_RecursiveGetLightInfo_BIH(r_q1bsp_getlightinfo_t *info, const bih_t *bih) +{ + bih_leaf_t *leaf; + bih_node_t *node; + int nodenum; + int axis; + int surfaceindex; + int t; + int nodeleafindex; + int currentmaterialflags; + qboolean castshadow; + msurface_t *surface; + const int *e; + const vec_t *v[3]; + float v2[3][3]; + int nodestack[GETLIGHTINFO_MAXNODESTACK]; + int nodestackpos = 0; + // note: because the BSP leafs are not in the BIH tree, the _BSP function + // must be called to mark leafs visible for entity culling... + // we start at the root node + nodestack[nodestackpos++] = bih->rootnode; + // we'll be done when the stack is empty + while (nodestackpos) + { + // pop one off the stack to process + nodenum = nodestack[--nodestackpos]; + // node + node = bih->nodes + nodenum; + if (node->type == BIH_UNORDERED) + { + for (nodeleafindex = 0;nodeleafindex < BIH_MAXUNORDEREDCHILDREN && node->children[nodeleafindex] >= 0;nodeleafindex++) + { + leaf = bih->leafs + node->children[nodeleafindex]; + if (leaf->type != BIH_RENDERTRIANGLE) + continue; +#if 1 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, leaf->mins, leaf->maxs)) + continue; +#endif +#if 1 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(leaf->mins, leaf->maxs, info->numfrustumplanes, info->frustumplanes)) + continue; +#endif + surfaceindex = leaf->surfaceindex; + surface = info->model->data_surfaces + surfaceindex; + currentmaterialflags = R_GetCurrentTexture(surface->texture)->currentmaterialflags; + castshadow = !(currentmaterialflags & MATERIALFLAG_NOSHADOW); + t = leaf->itemindex + surface->num_firstshadowmeshtriangle - surface->num_firsttriangle; + e = info->model->brush.shadowmesh->element3i + t * 3; + v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; + VectorCopy(v[0], v2[0]); + VectorCopy(v[1], v2[1]); + VectorCopy(v[2], v2[2]); + if (info->svbsp_insertoccluder) + { + if (castshadow) + SVBSP_AddPolygon(&r_svbsp, 3, v2[0], true, NULL, NULL, 0); + continue; + } + if (info->svbsp_active && !(SVBSP_AddPolygon(&r_svbsp, 3, v2[0], false, NULL, NULL, 0) & 2)) + continue; + // we don't occlude triangles from lighting even + // if they are backfacing, because when using + // shadowmapping they are often not fully occluded + // on the horizon of an edge + SETPVSBIT(info->outlighttrispvs, t); + if (castshadow) + { + if (currentmaterialflags & MATERIALFLAG_NOCULLFACE) + { + // if the material is double sided we + // can't cull by direction + SETPVSBIT(info->outshadowtrispvs, t); + } + else if (r_shadow_frontsidecasting.integer) + { + // front side casting occludes backfaces, + // so they are completely useless as both + // casters and lit polygons + if (PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + else + { + // back side casting does not occlude + // anything so we can't cull lit polygons + if (!PointInfrontOfTriangle(info->relativelightorigin, v2[0], v2[1], v2[2])) + SETPVSBIT(info->outshadowtrispvs, t); + } + } + if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) + { + SETPVSBIT(info->outsurfacepvs, surfaceindex); + info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; + } + } + } + else + { + axis = node->type - BIH_SPLITX; +#if 0 + if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) + continue; +#endif +#if 0 + if (!r_shadow_compilingrtlight && R_CullBoxCustomPlanes(node->mins, node->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes)) + continue; +#endif + if (info->lightmins[axis] <= node->backmax) + { + if (info->lightmaxs[axis] >= node->frontmin && nodestackpos < GETLIGHTINFO_MAXNODESTACK) + nodestack[nodestackpos++] = node->front; + nodestack[nodestackpos++] = node->back; + continue; + } + else if (info->lightmaxs[axis] >= node->frontmin) + { + nodestack[nodestackpos++] = node->front; + continue; + } + else + continue; // light falls between children, nothing here + } + } +} + +static void R_Q1BSP_CallRecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, qboolean use_svbsp) +{ + extern cvar_t r_shadow_usebihculling; + if (use_svbsp) + { + float origin[3]; + VectorCopy(info->relativelightorigin, origin); + r_svbsp.maxnodes = max(r_svbsp.maxnodes, 1<<12); + r_svbsp.nodes = (svbsp_node_t*) R_FrameData_Alloc(r_svbsp.maxnodes * sizeof(svbsp_node_t)); + info->svbsp_active = true; + info->svbsp_insertoccluder = true; + for (;;) + { + SVBSP_Init(&r_svbsp, origin, r_svbsp.maxnodes, r_svbsp.nodes); + R_Q1BSP_RecursiveGetLightInfo_BSP(info, false); + // if that failed, retry with more nodes + if (r_svbsp.ranoutofnodes) + { + // an upper limit is imposed + if (r_svbsp.maxnodes >= 2<<22) + break; + r_svbsp.maxnodes *= 2; + r_svbsp.nodes = (svbsp_node_t*) R_FrameData_Alloc(r_svbsp.maxnodes * sizeof(svbsp_node_t)); + //Mem_Free(r_svbsp.nodes); + //r_svbsp.nodes = (svbsp_node_t*) Mem_Alloc(tempmempool, r_svbsp.maxnodes * sizeof(svbsp_node_t)); + } + else + break; + } + // now clear the visibility arrays because we need to redo it + info->outnumleafs = 0; + info->outnumsurfaces = 0; + memset(info->outleafpvs, 0, (info->model->brush.num_leafs + 7) >> 3); + memset(info->outsurfacepvs, 0, (info->model->nummodelsurfaces + 7) >> 3); + if (info->model->brush.shadowmesh) + memset(info->outshadowtrispvs, 0, (info->model->brush.shadowmesh->numtriangles + 7) >> 3); + else + memset(info->outshadowtrispvs, 0, (info->model->surfmesh.num_triangles + 7) >> 3); + memset(info->outlighttrispvs, 0, (info->model->surfmesh.num_triangles + 7) >> 3); + } + else + info->svbsp_active = false; + + // we HAVE to mark the leaf the light is in as lit, because portals are + // irrelevant to a leaf that the light source is inside of + // (and they are all facing away, too) + { + mnode_t *node = info->model->brush.data_nodes; + mleaf_t *leaf; + while (node->plane) + node = node->children[(node->plane->type < 3 ? info->relativelightorigin[node->plane->type] : DotProduct(info->relativelightorigin,node->plane->normal)) < node->plane->dist]; + leaf = (mleaf_t *)node; + info->outmins[0] = min(info->outmins[0], leaf->mins[0]); + info->outmins[1] = min(info->outmins[1], leaf->mins[1]); + info->outmins[2] = min(info->outmins[2], leaf->mins[2]); + info->outmaxs[0] = max(info->outmaxs[0], leaf->maxs[0]); + info->outmaxs[1] = max(info->outmaxs[1], leaf->maxs[1]); + info->outmaxs[2] = max(info->outmaxs[2], leaf->maxs[2]); + if (info->outleafpvs) + { + int leafindex = leaf - info->model->brush.data_leafs; + if (!CHECKPVSBIT(info->outleafpvs, leafindex)) + { + SETPVSBIT(info->outleafpvs, leafindex); + info->outleaflist[info->outnumleafs++] = leafindex; + } + } + } + + info->svbsp_insertoccluder = false; + // use BIH culling on single leaf maps (generally this only happens if running a model as a map), otherwise use BSP culling to make use of vis data + if (r_shadow_usebihculling.integer > 0 && (r_shadow_usebihculling.integer == 2 || info->model->brush.num_leafs == 1) && info->model->render_bih.leafs != NULL) + { + R_Q1BSP_RecursiveGetLightInfo_BSP(info, true); + R_Q1BSP_RecursiveGetLightInfo_BIH(info, &info->model->render_bih); + } + else + R_Q1BSP_RecursiveGetLightInfo_BSP(info, false); + // we're using temporary framedata memory, so this pointer will be invalid soon, clear it + r_svbsp.nodes = NULL; + if (developer_extra.integer && use_svbsp) + { + Con_DPrintf("GetLightInfo: svbsp built with %i nodes, polygon stats:\n", r_svbsp.numnodes); + Con_DPrintf("occluders: %i accepted, %i rejected, %i fragments accepted, %i fragments rejected.\n", r_svbsp.stat_occluders_accepted, r_svbsp.stat_occluders_rejected, r_svbsp.stat_occluders_fragments_accepted, r_svbsp.stat_occluders_fragments_rejected); + Con_DPrintf("queries : %i accepted, %i rejected, %i fragments accepted, %i fragments rejected.\n", r_svbsp.stat_queries_accepted, r_svbsp.stat_queries_rejected, r_svbsp.stat_queries_fragments_accepted, r_svbsp.stat_queries_fragments_rejected); + } +} + +static msurface_t *r_q1bsp_getlightinfo_surfaces; + +static int R_Q1BSP_GetLightInfo_comparefunc(const void *ap, const void *bp) +{ + int a = *(int*)ap; + int b = *(int*)bp; + const msurface_t *as = r_q1bsp_getlightinfo_surfaces + a; + const msurface_t *bs = r_q1bsp_getlightinfo_surfaces + b; + if (as->texture < bs->texture) + return -1; + if (as->texture > bs->texture) + return 1; + return a - b; +} + +extern cvar_t r_shadow_sortsurfaces; + +void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs, int numfrustumplanes, const mplane_t *frustumplanes) +{ + r_q1bsp_getlightinfo_t info; + VectorCopy(relativelightorigin, info.relativelightorigin); + info.lightradius = lightradius; + info.lightmins[0] = info.relativelightorigin[0] - info.lightradius; + info.lightmins[1] = info.relativelightorigin[1] - info.lightradius; + info.lightmins[2] = info.relativelightorigin[2] - info.lightradius; + info.lightmaxs[0] = info.relativelightorigin[0] + info.lightradius; + info.lightmaxs[1] = info.relativelightorigin[1] + info.lightradius; + info.lightmaxs[2] = info.relativelightorigin[2] + info.lightradius; + if (ent->model == NULL) + { + VectorCopy(info.lightmins, outmins); + VectorCopy(info.lightmaxs, outmaxs); + *outnumleafspointer = 0; + *outnumsurfacespointer = 0; + return; + } + info.model = ent->model; + info.outleaflist = outleaflist; + info.outleafpvs = outleafpvs; + info.outnumleafs = 0; + info.visitingleafpvs = visitingleafpvs; + info.outsurfacelist = outsurfacelist; + info.outsurfacepvs = outsurfacepvs; + info.outshadowtrispvs = outshadowtrispvs; + info.outlighttrispvs = outlighttrispvs; + info.outnumsurfaces = 0; + info.numfrustumplanes = numfrustumplanes; + info.frustumplanes = frustumplanes; + VectorCopy(info.relativelightorigin, info.outmins); + VectorCopy(info.relativelightorigin, info.outmaxs); + memset(visitingleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3); + memset(outleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3); + memset(outsurfacepvs, 0, (info.model->nummodelsurfaces + 7) >> 3); + if (info.model->brush.shadowmesh) + memset(outshadowtrispvs, 0, (info.model->brush.shadowmesh->numtriangles + 7) >> 3); + else + memset(outshadowtrispvs, 0, (info.model->surfmesh.num_triangles + 7) >> 3); + memset(outlighttrispvs, 0, (info.model->surfmesh.num_triangles + 7) >> 3); + if (info.model->brush.GetPVS && r_shadow_frontsidecasting.integer) + info.pvs = info.model->brush.GetPVS(info.model, info.relativelightorigin); + else + info.pvs = NULL; + RSurf_ActiveWorldEntity(); + + if (r_shadow_frontsidecasting.integer && r_shadow_compilingrtlight && r_shadow_realtime_world_compileportalculling.integer && info.model->brush.data_portals) + { + // use portal recursion for exact light volume culling, and exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs, info.visitingleafpvs); + } + else if (r_shadow_frontsidecasting.integer && r_shadow_realtime_dlight_portalculling.integer && info.model->brush.data_portals) + { + // use portal recursion for exact light volume culling, but not the expensive exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs, info.outshadowtrispvs, info.outlighttrispvs, info.visitingleafpvs); + } + else + { + // recurse the bsp tree, checking leafs and surfaces for visibility + // optionally using svbsp for exact culling of compiled lights + // (or if the user enables dlight svbsp culling, which is mostly for + // debugging not actual use) + R_Q1BSP_CallRecursiveGetLightInfo(&info, (r_shadow_compilingrtlight ? r_shadow_realtime_world_compilesvbsp.integer : r_shadow_realtime_dlight_svbspculling.integer) != 0); + } + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + + // limit combined leaf box to light boundaries + outmins[0] = max(info.outmins[0] - 1, info.lightmins[0]); + outmins[1] = max(info.outmins[1] - 1, info.lightmins[1]); + outmins[2] = max(info.outmins[2] - 1, info.lightmins[2]); + outmaxs[0] = min(info.outmaxs[0] + 1, info.lightmaxs[0]); + outmaxs[1] = min(info.outmaxs[1] + 1, info.lightmaxs[1]); + outmaxs[2] = min(info.outmaxs[2] + 1, info.lightmaxs[2]); + + *outnumleafspointer = info.outnumleafs; + *outnumsurfacespointer = info.outnumsurfaces; + + // now sort surfaces by texture for faster rendering + r_q1bsp_getlightinfo_surfaces = info.model->data_surfaces; + if (r_shadow_sortsurfaces.integer) + qsort(info.outsurfacelist, info.outnumsurfaces, sizeof(*info.outsurfacelist), R_Q1BSP_GetLightInfo_comparefunc); +} + +void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist) +{ + dp_model_t *model = ent->model; + msurface_t *surface; + int surfacelistindex; + float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value; + // if triangle neighbors are disabled, shadowvolumes are disabled + if (!model->brush.shadowmesh->neighbor3i) + return; + r_shadow_compilingrtlight->static_meshchain_shadow_zfail = Mod_ShadowMesh_Begin(r_main_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); + R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + surface = model->data_surfaces + surfacelist[surfacelistindex]; + if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW) + continue; + R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs); + } + R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs); + r_shadow_compilingrtlight->static_meshchain_shadow_zfail = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, false, false, true); +} + +extern cvar_t r_polygonoffset_submodel_factor; +extern cvar_t r_polygonoffset_submodel_offset; +void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs) +{ + dp_model_t *model = ent->model; + const msurface_t *surface; + int modelsurfacelistindex; + float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value; + // check the box in modelspace, it was already checked in worldspace + if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs)) + return; + R_FrameData_SetMark(); + if (ent->model->brush.submodel) + GL_PolygonOffset(r_refdef.shadowpolygonfactor + r_polygonoffset_submodel_factor.value, r_refdef.shadowpolygonoffset + r_polygonoffset_submodel_offset.value); + if (model->brush.shadowmesh) + { + // if triangle neighbors are disabled, shadowvolumes are disabled + if (!model->brush.shadowmesh->neighbor3i) + return; + R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) + { + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + if (R_GetCurrentTexture(surface->texture)->currentmaterialflags & MATERIALFLAG_NOSHADOW) + continue; + R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs); + } + R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs); + } + else + { + // if triangle neighbors are disabled, shadowvolumes are disabled + if (!model->surfmesh.data_neighbor3i) + return; + projectdistance = lightradius + model->radius*2; + R_Shadow_PrepareShadowMark(model->surfmesh.num_triangles); + // identify lit faces within the bounding box + for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) + { + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + rsurface.texture = R_GetCurrentTexture(surface->texture); + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW) + continue; + R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs); + } + R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.modelvertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs); + } + if (ent->model->brush.submodel) + GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset); + R_FrameData_ReturnToMark(); +} + +void R_Q1BSP_CompileShadowMap(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist) +{ + dp_model_t *model = ent->model; + msurface_t *surface; + int surfacelistindex; + int sidetotals[6] = { 0, 0, 0, 0, 0, 0 }, sidemasks = 0; + int i; + if (!model->brush.shadowmesh) + return; + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap = Mod_ShadowMesh_Begin(r_main_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); + R_Shadow_PrepareShadowSides(model->brush.shadowmesh->numtriangles); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + surface = model->data_surfaces + surfacelist[surfacelistindex]; + sidemasks |= R_Shadow_ChooseSidesFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, &r_shadow_compilingrtlight->matrix_worldtolight, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs, surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW ? NULL : sidetotals); + } + R_Shadow_ShadowMapFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, numshadowsides, sidetotals, shadowsides, shadowsideslist); + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, false, false, true); + r_shadow_compilingrtlight->static_shadowmap_receivers &= sidemasks; + for(i = 0;i<6;i++) + if(!sidetotals[i]) + r_shadow_compilingrtlight->static_shadowmap_casters &= ~(1 << i); +} + +#define RSURF_MAX_BATCHSURFACES 8192 + +static const msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES]; + +void R_Q1BSP_DrawShadowMap(int side, entity_render_t *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const unsigned char *surfacesides, const vec3_t lightmins, const vec3_t lightmaxs) +{ + dp_model_t *model = ent->model; + const msurface_t *surface; + int modelsurfacelistindex, batchnumsurfaces; + // check the box in modelspace, it was already checked in worldspace + if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs)) + return; + R_FrameData_SetMark(); + // identify lit faces within the bounding box + for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) + { + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + if (surfacesides && !(surfacesides[modelsurfacelistindex] && (1 << side))) + continue; + rsurface.texture = R_GetCurrentTexture(surface->texture); + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW) + continue; + if (!BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs)) + continue; + r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += surface->num_triangles; + r_refdef.stats[r_stat_lights_shadowtriangles] += surface->num_triangles; + batchsurfacelist[0] = surface; + batchnumsurfaces = 1; + while(++modelsurfacelistindex < modelnumsurfaces && batchnumsurfaces < RSURF_MAX_BATCHSURFACES) + { + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + if (surfacesides && !(surfacesides[modelsurfacelistindex] & (1 << side))) + continue; + if (surface->texture != batchsurfacelist[0]->texture) + break; + if (!BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs)) + continue; + r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += surface->num_triangles; + r_refdef.stats[r_stat_lights_shadowtriangles] += surface->num_triangles; + batchsurfacelist[batchnumsurfaces++] = surface; + } + --modelsurfacelistindex; + GL_CullFace(rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE ? GL_NONE : r_refdef.view.cullface_back); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, batchnumsurfaces, batchsurfacelist); + R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + RSurf_DrawBatch(); + } + R_FrameData_ReturnToMark(); +} + +#define BATCHSIZE 1024 + +static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int i, j, endsurface; + texture_t *t; + const msurface_t *surface; + R_FrameData_SetMark(); + // note: in practice this never actually receives batches + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight(rtlight); + R_Shadow_RenderMode_Lighting(false, true, false); + R_Shadow_SetupEntityLight(ent); + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + surface = rsurface.modelsurfaces + surfacelist[i]; + t = surface->texture; + rsurface.texture = R_GetCurrentTexture(t); + endsurface = min(j + BATCHSIZE, numsurfaces); + for (j = i;j < endsurface;j++) + { + surface = rsurface.modelsurfaces + surfacelist[j]; + if (t != surface->texture) + break; + R_Shadow_RenderLighting(1, &surface); + } + } + R_Shadow_RenderMode_End(); + R_FrameData_ReturnToMark(); +} + +extern qboolean r_shadow_usingdeferredprepass; +void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surfacelist, const unsigned char *lighttrispvs) +{ + dp_model_t *model = ent->model; + const msurface_t *surface; + int i, k, kend, l, endsurface, batchnumsurfaces, texturenumsurfaces; + const msurface_t **texturesurfacelist; + texture_t *tex; + CHECKGLERROR + R_FrameData_SetMark(); + // this is a double loop because non-visible surface skipping has to be + // fast, and even if this is not the world model (and hence no visibility + // checking) the input surface list and batch buffer are different formats + // so some processing is necessary. (luckily models have few surfaces) + for (i = 0;i < numsurfaces;) + { + batchnumsurfaces = 0; + endsurface = min(i + RSURF_MAX_BATCHSURFACES, numsurfaces); + if (ent == r_refdef.scene.worldentity) + { + for (;i < endsurface;i++) + if (r_refdef.viewcache.world_surfacevisible[surfacelist[i]]) + batchsurfacelist[batchnumsurfaces++] = model->data_surfaces + surfacelist[i]; + } + else + { + for (;i < endsurface;i++) + batchsurfacelist[batchnumsurfaces++] = model->data_surfaces + surfacelist[i]; + } + if (!batchnumsurfaces) + continue; + for (k = 0;k < batchnumsurfaces;k = kend) + { + surface = batchsurfacelist[k]; + tex = surface->texture; + rsurface.texture = R_GetCurrentTexture(tex); + // gather surfaces into a batch range + for (kend = k;kend < batchnumsurfaces && tex == batchsurfacelist[kend]->texture;kend++) + ; + // now figure out what to do with this particular range of surfaces + // VorteX: added MATERIALFLAG_NORTLIGHT + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL) + continue; + if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) + continue; + if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) + { + vec3_t tempcenter, center; + for (l = k;l < kend;l++) + { + surface = batchsurfacelist[l]; + if (r_transparent_sortsurfacesbynearest.integer) + { + tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]); + tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]); + tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]); + } + else + { + tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; + tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; + tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; + } + Matrix4x4_Transform(&rsurface.matrix, tempcenter, center); + if (ent->transparent_offset) // transparent offset + { + center[0] += r_refdef.view.forward[0]*ent->transparent_offset; + center[1] += r_refdef.view.forward[1]*ent->transparent_offset; + center[2] += r_refdef.view.forward[2]*ent->transparent_offset; + } + R_MeshQueue_AddTransparent((rsurface.entity->flags & RENDER_WORLDOBJECT) ? TRANSPARENTSORT_SKY : ((rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? TRANSPARENTSORT_HUD : rsurface.texture->transparentsort), center, R_Q1BSP_DrawLight_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight); + } + continue; + } + if (r_shadow_usingdeferredprepass) + continue; + texturenumsurfaces = kend - k; + texturesurfacelist = batchsurfacelist + k; + R_Shadow_RenderLighting(texturenumsurfaces, texturesurfacelist); + } + } + R_FrameData_ReturnToMark(); +} + +//Made by [515] +static void R_ReplaceWorldTexture (void) +{ + dp_model_t *m; + texture_t *t; + int i; + const char *r, *newt; + skinframe_t *skinframe; + if (!r_refdef.scene.worldmodel) + { + Con_Printf("There is no worldmodel\n"); + return; + } + m = r_refdef.scene.worldmodel; + + if(Cmd_Argc() < 2) + { + Con_Print("r_replacemaptexture - replaces texture\n"); + Con_Print("r_replacemaptexture - switch back to default texture\n"); + return; + } + if(!cl.islocalgame || !cl.worldmodel) + { + Con_Print("This command works only in singleplayer\n"); + return; + } + r = Cmd_Argv(1); + newt = Cmd_Argv(2); + if(!newt[0]) + newt = r; + for(i=0,t=m->data_textures;inum_textures;i++,t++) + { + if(/*t->width && !strcasecmp(t->name, r)*/ matchpattern( t->name, r, true ) ) + { + if ((skinframe = R_SkinFrame_LoadExternal(newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PICMIP, true))) + { +// t->skinframes[0] = skinframe; + t->currentskinframe = skinframe; + Con_Printf("%s replaced with %s\n", r, newt); + } + else + { + Con_Printf("%s was not found\n", newt); + return; + } + } + } +} + +//Made by [515] +static void R_ListWorldTextures (void) +{ + dp_model_t *m; + texture_t *t; + int i; + if (!r_refdef.scene.worldmodel) + { + Con_Printf("There is no worldmodel\n"); + return; + } + m = r_refdef.scene.worldmodel; + + Con_Print("Worldmodel textures :\n"); + for(i=0,t=m->data_textures;inum_textures;i++,t++) + if (t->numskinframes) + Con_Printf("%s\n", t->name); +} + +#if 0 +static void gl_surf_start(void) +{ +} + +static void gl_surf_shutdown(void) +{ +} + +static void gl_surf_newmap(void) +{ +} +#endif + +void GL_Surf_Init(void) +{ + + Cvar_RegisterVariable(&r_ambient); + Cvar_RegisterVariable(&r_lockpvs); + Cvar_RegisterVariable(&r_lockvisibility); + Cvar_RegisterVariable(&r_useportalculling); + Cvar_RegisterVariable(&r_usesurfaceculling); + Cvar_RegisterVariable(&r_q3bsp_renderskydepth); + + Cmd_AddCommand ("r_replacemaptexture", R_ReplaceWorldTexture, "override a map texture for testing purposes"); + Cmd_AddCommand ("r_listmaptextures", R_ListWorldTextures, "list all textures used by the current map"); + + //R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap); +} + diff --git a/app/jni/gl_textures.c b/app/jni/gl_textures.c new file mode 100644 index 0000000..8703bfe --- /dev/null +++ b/app/jni/gl_textures.c @@ -0,0 +1,2983 @@ + +#include "quakedef.h" +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +#endif +#include "image.h" +#include "jpeg.h" +#include "image_png.h" +#include "intoverflow.h" +#include "dpsoftrast.h" + +#ifndef GL_TEXTURE_3D +#define GL_TEXTURE_3D 0x806F +#endif + +cvar_t gl_max_size = {CVAR_SAVE, "gl_max_size", "2048", "maximum allowed texture size, can be used to reduce video memory usage, limited by hardware capabilities (typically 2048, 4096, or 8192)"}; +cvar_t gl_max_lightmapsize = {CVAR_SAVE, "gl_max_lightmapsize", "1024", "maximum allowed texture size for lightmap textures, use larger values to improve rendering speed, as long as there is enough video memory available (setting it too high for the hardware will cause very bad performance)"}; +cvar_t gl_picmip = {CVAR_SAVE, "gl_picmip", "0", "reduces resolution of textures by powers of 2, for example 1 will halve width/height, reducing texture memory usage by 75%"}; +cvar_t gl_picmip_world = {CVAR_SAVE, "gl_picmip_world", "0", "extra picmip level for world textures (may be negative, which will then reduce gl_picmip for these)"}; +cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too (setting this to 0 is a shorthand for gl_picmip_world -9999999)"}; +cvar_t gl_picmip_sprites = {CVAR_SAVE, "gl_picmip_sprites", "0", "extra picmip level for sprite textures (may be negative, which will then reduce gl_picmip for these)"}; +cvar_t r_picmipsprites = {CVAR_SAVE, "r_picmipsprites", "1", "make gl_picmip affect sprites too (saves some graphics memory in sprite heavy games) (setting this to 0 is a shorthand for gl_picmip_sprites -9999999)"}; +cvar_t gl_picmip_other = {CVAR_SAVE, "gl_picmip_other", "0", "extra picmip level for other textures (may be negative, which will then reduce gl_picmip for these)"}; +cvar_t r_lerpimages = {CVAR_SAVE, "r_lerpimages", "1", "bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)"}; +cvar_t gl_texture_anisotropy = {CVAR_SAVE, "gl_texture_anisotropy", "1", "anisotropic filtering quality (if supported by hardware), 1 sample (no anisotropy) and 8 sample (8 tap anisotropy) are recommended values"}; +cvar_t gl_texturecompression = {CVAR_SAVE, "gl_texturecompression", "0", "whether to compress textures, a value of 0 disables compression (even if the individual cvars are 1), 1 enables fast (low quality) compression at startup, 2 enables slow (high quality) compression at startup"}; +cvar_t gl_texturecompression_color = {CVAR_SAVE, "gl_texturecompression_color", "1", "whether to compress colormap (diffuse) textures"}; +cvar_t gl_texturecompression_normal = {CVAR_SAVE, "gl_texturecompression_normal", "0", "whether to compress normalmap (normalmap) textures"}; +cvar_t gl_texturecompression_gloss = {CVAR_SAVE, "gl_texturecompression_gloss", "1", "whether to compress glossmap (specular) textures"}; +cvar_t gl_texturecompression_glow = {CVAR_SAVE, "gl_texturecompression_glow", "1", "whether to compress glowmap (luma) textures"}; +cvar_t gl_texturecompression_2d = {CVAR_SAVE, "gl_texturecompression_2d", "0", "whether to compress 2d (hud/menu) textures other than the font"}; +cvar_t gl_texturecompression_q3bsplightmaps = {CVAR_SAVE, "gl_texturecompression_q3bsplightmaps", "0", "whether to compress lightmaps in q3bsp format levels"}; +cvar_t gl_texturecompression_q3bspdeluxemaps = {CVAR_SAVE, "gl_texturecompression_q3bspdeluxemaps", "0", "whether to compress deluxemaps in q3bsp format levels (only levels compiled with q3map2 -deluxe have these)"}; +cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0", "whether to compress sky textures"}; +cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"}; +cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"}; +cvar_t gl_texturecompression_sprites = {CVAR_SAVE, "gl_texturecompression_sprites", "1", "whether to compress sprites"}; +cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "0", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"}; +cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "1", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambiguous, 2: texture format only"}; +cvar_t r_texture_dds_load_logfailure = {0, "r_texture_dds_load_logfailure", "0", "log missing DDS textures to ddstexturefailures.log, 0: done log, 1: log with no optional textures (_norm, glow etc.). 2: log all"}; +cvar_t r_texture_dds_swdecode = {0, "r_texture_dds_swdecode", "0", "0: don't software decode DDS, 1: software decode DDS if unsupported, 2: always software decode DDS"}; + +qboolean gl_filter_force = false; +int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; +int gl_filter_mag = GL_LINEAR; +DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_mipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE; +DPSOFTRAST_TEXTURE_FILTER dpsoftrast_filter_nomipmap = DPSOFTRAST_TEXTURE_FILTER_LINEAR; + +#ifdef SUPPORTD3D +int d3d_filter_flatmin = D3DTEXF_LINEAR; +int d3d_filter_flatmag = D3DTEXF_LINEAR; +int d3d_filter_flatmix = D3DTEXF_POINT; +int d3d_filter_mipmin = D3DTEXF_LINEAR; +int d3d_filter_mipmag = D3DTEXF_LINEAR; +int d3d_filter_mipmix = D3DTEXF_LINEAR; +int d3d_filter_nomip = false; +#endif + + +static mempool_t *texturemempool; +static memexpandablearray_t texturearray; + +// note: this must not conflict with TEXF_ flags in r_textures.h +// bitmask for mismatch checking +#define GLTEXF_IMPORTANTBITS (0) +// dynamic texture (treat texnum == 0 differently) +#define GLTEXF_DYNAMIC 0x00080000 + +typedef struct textypeinfo_s +{ + const char *name; + textype_t textype; + int inputbytesperpixel; + int internalbytesperpixel; + float glinternalbytesperpixel; + int glinternalformat; + int glformat; + int gltype; +} +textypeinfo_t; + +#ifdef USE_GLES2 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83f2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83f3 +// framebuffer texture formats +// GLES2 devices rarely support depth textures, so we actually use a renderbuffer there +static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_OES , GL_DEPTH_COMPONENT24_OES, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_OES , GL_DEPTH_COMPONENT24_OES, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16 , GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_OES , GL_DEPTH_COMPONENT24_OES, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 2, 2, 2.0f, GL_DEPTH_COMPONENT , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_colorbuffer_32 = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE}; +static textypeinfo_t textype_colorbuffer16f_32 = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE}; +static textypeinfo_t textype_colorbuffer32f_32 = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE}; + +static textypeinfo_t textype_colorbuffer_16 = {"colorbuffer", TEXTYPE_COLORBUFFER , 2, 2, 2.0f, GL_RGB , GL_RGB , GL_UNSIGNED_SHORT_5_6_5}; +static textypeinfo_t textype_colorbuffer16f_16 = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 2, 2, 2.0f, GL_RGB , GL_RGB , GL_UNSIGNED_SHORT_5_6_5}; +static textypeinfo_t textype_colorbuffer32f_16 = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 2, 2, 2.0f, GL_RGB , GL_RGB , GL_UNSIGNED_SHORT_5_6_5}; + +// image formats: +static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 }; +#else +// framebuffer texture formats +static textypeinfo_t textype_shadowmap16_comp = {"shadowmap16_comp", TEXTYPE_SHADOWMAP16_COMP , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap16_raw = {"shadowmap16_raw", TEXTYPE_SHADOWMAP16_RAW , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_shadowmap24_comp = {"shadowmap24_comp", TEXTYPE_SHADOWMAP24_COMP , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_shadowmap24_raw = {"shadowmap24_raw", TEXTYPE_SHADOWMAP24_RAW , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_depth16 = {"depth16", TEXTYPE_DEPTHBUFFER16 , 2, 2, 2.0f, GL_DEPTH_COMPONENT16_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; +static textypeinfo_t textype_depth24 = {"depth24", TEXTYPE_DEPTHBUFFER24 , 4, 4, 4.0f, GL_DEPTH_COMPONENT24_ARB , GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; +static textypeinfo_t textype_depth24stencil8 = {"depth24stencil8", TEXTYPE_DEPTHBUFFER24STENCIL8, 4, 4, 4.0f, GL_DEPTH24_STENCIL8_EXT , GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT}; +static textypeinfo_t textype_colorbuffer = {"colorbuffer", TEXTYPE_COLORBUFFER , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_colorbuffer16f = {"colorbuffer16f", TEXTYPE_COLORBUFFER16F , 8, 8, 8.0f, GL_RGBA16F_ARB , GL_RGBA , GL_FLOAT }; +static textypeinfo_t textype_colorbuffer32f = {"colorbuffer32f", TEXTYPE_COLORBUFFER32F , 16, 16, 16.0f, GL_RGBA32F_ARB , GL_RGBA , GL_FLOAT }; + +// image formats: +static textypeinfo_t textype_alpha = {"alpha", TEXTYPE_ALPHA , 1, 4, 4.0f, GL_ALPHA , GL_ALPHA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette = {"palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_palette_alpha = {"palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba = {"rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGB , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha = {"rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_RGBA , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_compress = {"rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_rgba_alpha_compress = {"rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra = {"bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGB , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha = {"bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_RGBA , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_compress = {"bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_bgra_alpha_compress = {"bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_dxt1 = {"dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_RGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt1a = {"dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt3 = {"dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT , 0 , 0 }; +static textypeinfo_t textype_dxt5 = {"dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_palette = {"sRGB_palette", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_palette_alpha = {"sRGB_palette_alpha", TEXTYPE_PALETTE , 1, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba = {"sRGB_rgba", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha = {"sRGB_rgba_alpha", TEXTYPE_RGBA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_compress = {"sRGB_rgba_compress", TEXTYPE_RGBA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_rgba_alpha_compress = {"sRGB_rgba_alpha_compress", TEXTYPE_RGBA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra = {"sRGB_bgra", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha = {"sRGB_bgra_alpha", TEXTYPE_BGRA , 4, 4, 4.0f, GL_SRGB_ALPHA_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_compress = {"sRGB_bgra_compress", TEXTYPE_BGRA , 4, 4, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_bgra_alpha_compress = {"sRGB_bgra_alpha_compress", TEXTYPE_BGRA , 4, 4, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_BGRA , GL_UNSIGNED_BYTE }; +static textypeinfo_t textype_sRGB_dxt1 = {"sRGB_dxt1", TEXTYPE_DXT1 , 4, 0, 0.5f, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT , 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt1a = {"sRGB_dxt1a", TEXTYPE_DXT1A , 4, 0, 0.5f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt3 = {"sRGB_dxt3", TEXTYPE_DXT3 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 , 0 }; +static textypeinfo_t textype_sRGB_dxt5 = {"sRGB_dxt5", TEXTYPE_DXT5 , 4, 0, 1.0f, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 , 0 }; +#endif + +typedef enum gltexturetype_e +{ + GLTEXTURETYPE_2D, + GLTEXTURETYPE_3D, + GLTEXTURETYPE_CUBEMAP, + GLTEXTURETYPE_TOTAL +} +gltexturetype_t; + +static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP}; +static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {2, 3, 2}; +static int cubemapside[6] = +{ + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +typedef struct gltexture_s +{ + // this portion of the struct is exposed to the R_GetTexture macro for + // speed reasons, must be identical in rtexture_t! + int texnum; // GL texture slot number + int renderbuffernum; // GL renderbuffer slot number + qboolean dirty; // indicates that R_RealGetTexture should be called + qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT + int gltexturetypeenum; // used by R_Mesh_TexBind + // d3d stuff the backend needs + void *d3dtexture; + void *d3dsurface; +#ifdef SUPPORTD3D + qboolean d3disrendertargetsurface; + qboolean d3disdepthstencilsurface; + int d3dformat; + int d3dusage; + int d3dpool; + int d3daddressu; + int d3daddressv; + int d3daddressw; + int d3dmagfilter; + int d3dminfilter; + int d3dmipfilter; + int d3dmaxmiplevelfilter; + int d3dmipmaplodbias; + int d3dmaxmiplevel; +#endif + + // dynamic texture stuff [11/22/2007 Black] + updatecallback_t updatecallback; + void *updatacallback_data; + // --- [11/22/2007 Black] + + // stores backup copy of texture for deferred texture updates (gl_nopartialtextureupdates cvar) + unsigned char *bufferpixels; + qboolean buffermodified; + + // pointer to texturepool (check this to see if the texture is allocated) + struct gltexturepool_s *pool; + // pointer to next texture in texturepool chain + struct gltexture_s *chain; + // name of the texture (this might be removed someday), no duplicates + char identifier[MAX_QPATH + 32]; + // original data size in *inputtexels + int inputwidth, inputheight, inputdepth; + // copy of the original texture(s) supplied to the upload function, for + // delayed uploads (non-precached) + unsigned char *inputtexels; + // original data size in *inputtexels + int inputdatasize; + // flags supplied to the LoadTexture function + // (might be altered to remove TEXF_ALPHA), and GLTEXF_ private flags + int flags; + // picmip level + int miplevel; + // pointer to one of the textype_ structs + textypeinfo_t *textype; + // one of the GLTEXTURETYPE_ values + int texturetype; + // palette if the texture is TEXTYPE_PALETTE + const unsigned int *palette; + // actual stored texture size after gl_picmip and gl_max_size are applied + // (power of 2 if vid.support.arb_texture_non_power_of_two is not supported) + int tilewidth, tileheight, tiledepth; + // 1 or 6 depending on texturetype + int sides; + // how many mipmap levels in this texture + int miplevels; + // bytes per pixel + int bytesperpixel; + // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT + int glformat; + // 3 or 4 + int glinternalformat; + // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT + int gltype; +} +gltexture_t; + +#define TEXTUREPOOL_SENTINEL 0xC0DEDBAD + +typedef struct gltexturepool_s +{ + unsigned int sentinel; + struct gltexture_s *gltchain; + struct gltexturepool_s *next; +} +gltexturepool_t; + +static gltexturepool_t *gltexturepoolchain = NULL; + +static unsigned char *resizebuffer = NULL, *colorconvertbuffer; +static int resizebuffersize = 0; +static const unsigned char *texturebuffer; + +extern int is32bit; + +static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags) +{ + switch(textype) + { + case TEXTYPE_DXT1: return &textype_dxt1; + case TEXTYPE_DXT1A: return &textype_dxt1a; + case TEXTYPE_DXT3: return &textype_dxt3; + case TEXTYPE_DXT5: return &textype_dxt5; + case TEXTYPE_PALETTE: return (flags & TEXF_ALPHA) ? &textype_palette_alpha : &textype_palette; + case TEXTYPE_RGBA: return /*((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_rgba_alpha_compress : &textype_rgba_compress) : */((flags & TEXF_ALPHA) ? &textype_rgba_alpha : &textype_rgba); + case TEXTYPE_BGRA: return /*((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_bgra_alpha_compress : &textype_bgra_compress) : */((flags & TEXF_ALPHA) ? &textype_bgra_alpha : &textype_bgra); + case TEXTYPE_ALPHA: return &textype_alpha; + case TEXTYPE_COLORBUFFER: return (is32bit) ? &textype_colorbuffer_32 : &textype_colorbuffer_16; + case TEXTYPE_COLORBUFFER16F: return (is32bit) ? &textype_colorbuffer16f_32 : &textype_colorbuffer16f_16; + case TEXTYPE_COLORBUFFER32F: return (is32bit) ? &textype_colorbuffer32f_32 : &textype_colorbuffer32f_16; + case TEXTYPE_DEPTHBUFFER16: return &textype_depth16; + case TEXTYPE_DEPTHBUFFER24: return &textype_depth24; + case TEXTYPE_DEPTHBUFFER24STENCIL8: return &textype_depth24stencil8; + case TEXTYPE_SHADOWMAP16_COMP: return &textype_shadowmap16_comp; + case TEXTYPE_SHADOWMAP16_RAW: return &textype_shadowmap16_raw; + case TEXTYPE_SHADOWMAP24_COMP: return &textype_shadowmap24_comp; + case TEXTYPE_SHADOWMAP24_RAW: return &textype_shadowmap24_raw; + /*case TEXTYPE_SRGB_DXT1: return &textype_sRGB_dxt1; + case TEXTYPE_SRGB_DXT1A: return &textype_sRGB_dxt1a; + case TEXTYPE_SRGB_DXT3: return &textype_sRGB_dxt3; + case TEXTYPE_SRGB_DXT5: return &textype_sRGB_dxt5; + case TEXTYPE_SRGB_PALETTE: return (flags & TEXF_ALPHA) ? &textype_sRGB_palette_alpha : &textype_sRGB_palette; + case TEXTYPE_SRGB_RGBA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha_compress : &textype_sRGB_rgba_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_rgba_alpha : &textype_sRGB_rgba); + case TEXTYPE_SRGB_BGRA: return ((flags & TEXF_COMPRESS) && vid.support.ext_texture_compression_s3tc) ? ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha_compress : &textype_sRGB_bgra_compress) : ((flags & TEXF_ALPHA) ? &textype_sRGB_bgra_alpha : &textype_sRGB_bgra); + */ + default: + Host_Error("R_GetTexTypeInfo: unknown texture format"); + break; + } + return NULL; +} + +// dynamic texture code [11/22/2007 Black] +void R_MarkDirtyTexture(rtexture_t *rt) { + gltexture_t *glt = (gltexture_t*) rt; + if( !glt ) { + return; + } + + // dont do anything if the texture is already dirty (and make sure this *is* a dynamic texture after all!) + if (glt->flags & GLTEXF_DYNAMIC) + { + // mark it as dirty, so R_RealGetTexture gets called + glt->dirty = true; + } +} + +void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data) { + gltexture_t *glt = (gltexture_t*) rt; + if( !glt ) { + return; + } + + glt->flags |= GLTEXF_DYNAMIC; + glt->updatecallback = updatecallback; + glt->updatacallback_data = data; +} + +static void R_UpdateDynamicTexture(gltexture_t *glt) { + glt->dirty = false; + if( glt->updatecallback ) { + glt->updatecallback( (rtexture_t*) glt, glt->updatacallback_data ); + } +} + +void R_PurgeTexture(rtexture_t *rt) +{ + if(rt && !(((gltexture_t*) rt)->flags & TEXF_PERSISTENT)) { + R_FreeTexture(rt); + } +} + +void R_FreeTexture(rtexture_t *rt) +{ + gltexture_t *glt, **gltpointer; + + glt = (gltexture_t *)rt; + if (glt == NULL) + Host_Error("R_FreeTexture: texture == NULL"); + + for (gltpointer = &glt->pool->gltchain;*gltpointer && *gltpointer != glt;gltpointer = &(*gltpointer)->chain); + if (*gltpointer == glt) + *gltpointer = glt->chain; + else + Host_Error("R_FreeTexture: texture \"%s\" not linked in pool", glt->identifier); + + R_Mesh_ClearBindingsForTexture(glt->texnum); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (glt->texnum) + { + CHECKGLERROR + qglDeleteTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + } + if (glt->renderbuffernum) + { + CHECKGLERROR + qglDeleteRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (glt->d3dsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface); + else if (glt->tiledepth > 1) + IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture); + else if (glt->sides == 6) + IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture); + else + IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture); + glt->d3dtexture = NULL; + glt->d3dsurface = NULL; +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (glt->texnum) + DPSOFTRAST_Texture_Free(glt->texnum); + break; + } + + if (glt->inputtexels) + Mem_Free(glt->inputtexels); + Mem_ExpandableArray_FreeRecord(&texturearray, glt); +} + +rtexturepool_t *R_AllocTexturePool(void) +{ + gltexturepool_t *pool; + if (texturemempool == NULL) + return NULL; + pool = (gltexturepool_t *)Mem_Alloc(texturemempool, sizeof(gltexturepool_t)); + if (pool == NULL) + return NULL; + pool->next = gltexturepoolchain; + gltexturepoolchain = pool; + pool->sentinel = TEXTUREPOOL_SENTINEL; + return (rtexturepool_t *)pool; +} + +void R_FreeTexturePool(rtexturepool_t **rtexturepool) +{ + gltexturepool_t *pool, **poolpointer; + if (rtexturepool == NULL) + return; + if (*rtexturepool == NULL) + return; + pool = (gltexturepool_t *)(*rtexturepool); + *rtexturepool = NULL; + if (pool->sentinel != TEXTUREPOOL_SENTINEL) + Host_Error("R_FreeTexturePool: pool already freed"); + for (poolpointer = &gltexturepoolchain;*poolpointer && *poolpointer != pool;poolpointer = &(*poolpointer)->next); + if (*poolpointer == pool) + *poolpointer = pool->next; + else + Host_Error("R_FreeTexturePool: pool not linked"); + while (pool->gltchain) + R_FreeTexture((rtexture_t *)pool->gltchain); + Mem_Free(pool); +} + + +typedef struct glmode_s +{ + const char *name; + int minification, magnification; + DPSOFTRAST_TEXTURE_FILTER dpsoftrastfilter_mipmap, dpsoftrastfilter_nomipmap; +} +glmode_t; + +static glmode_t modes[6] = +{ + {"GL_NEAREST", GL_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST}, + {"GL_LINEAR", GL_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR}, + {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST}, + {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR}, + {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, DPSOFTRAST_TEXTURE_FILTER_NEAREST_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_NEAREST}, + {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, DPSOFTRAST_TEXTURE_FILTER_LINEAR_MIPMAP_TRIANGLE, DPSOFTRAST_TEXTURE_FILTER_LINEAR} +}; + +#ifdef SUPPORTD3D +typedef struct d3dmode_s +{ + const char *name; + int m1, m2; +} +d3dmode_t; + +static d3dmode_t d3dmodes[6] = +{ + {"GL_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT}, + {"GL_LINEAR", D3DTEXF_LINEAR, D3DTEXF_POINT}, + {"GL_NEAREST_MIPMAP_NEAREST", D3DTEXF_POINT, D3DTEXF_POINT}, + {"GL_LINEAR_MIPMAP_NEAREST", D3DTEXF_LINEAR, D3DTEXF_POINT}, + {"GL_NEAREST_MIPMAP_LINEAR", D3DTEXF_POINT, D3DTEXF_LINEAR}, + {"GL_LINEAR_MIPMAP_LINEAR", D3DTEXF_LINEAR, D3DTEXF_LINEAR} +}; +#endif + +static void GL_TextureMode_f (void) +{ + int i; + GLint oldbindtexnum; + gltexture_t *glt; + gltexturepool_t *pool; + + if (Cmd_Argc() == 1) + { + Con_Printf("Texture mode is %sforced\n", gl_filter_force ? "" : "not "); + for (i = 0;i < 6;i++) + { + if (gl_filter_min == modes[i].minification) + { + Con_Printf("%s\n", modes[i].name); + return; + } + } + Con_Print("current filter is unknown???\n"); + return; + } + + for (i = 0;i < (int)(sizeof(modes)/sizeof(*modes));i++) + if (!strcasecmp (modes[i].name, Cmd_Argv(1) ) ) + break; + if (i == 6) + { + Con_Print("bad filter name\n"); + return; + } + + gl_filter_min = modes[i].minification; + gl_filter_mag = modes[i].magnification; + gl_filter_force = ((Cmd_Argc() > 2) && !strcasecmp(Cmd_Argv(2), "force")); + + dpsoftrast_filter_mipmap = modes[i].dpsoftrastfilter_mipmap; + dpsoftrast_filter_nomipmap = modes[i].dpsoftrastfilter_nomipmap; + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // change all the existing mipmap texture objects + // FIXME: force renderer(/client/something?) restart instead? + CHECKGLERROR + GL_ActiveTexture(0); + for (pool = gltexturepoolchain;pool;pool = pool->next) + { + for (glt = pool->gltchain;glt;glt = glt->chain) + { + // only update already uploaded images + if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) + { + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR + } + else + { + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR + } + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } + } + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + d3d_filter_flatmin = d3dmodes[i].m1; + d3d_filter_flatmag = d3dmodes[i].m1; + d3d_filter_flatmix = D3DTEXF_POINT; + d3d_filter_mipmin = d3dmodes[i].m1; + d3d_filter_mipmag = d3dmodes[i].m1; + d3d_filter_mipmix = d3dmodes[i].m2; + d3d_filter_nomip = i < 2; + if (gl_texture_anisotropy.integer > 1 && i == 5) + d3d_filter_mipmin = d3d_filter_mipmag = D3DTEXF_ANISOTROPIC; + for (pool = gltexturepoolchain;pool;pool = pool->next) + { + for (glt = pool->gltchain;glt;glt = glt->chain) + { + // only update already uploaded images + if (glt->d3dtexture && !glt->d3dsurface && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) + { + if (glt->flags & TEXF_MIPMAP) + { + glt->d3dminfilter = d3d_filter_mipmin; + glt->d3dmagfilter = d3d_filter_mipmag; + glt->d3dmipfilter = d3d_filter_mipmix; + glt->d3dmaxmiplevelfilter = 0; + } + else + { + glt->d3dminfilter = d3d_filter_flatmin; + glt->d3dmagfilter = d3d_filter_flatmag; + glt->d3dmipfilter = d3d_filter_flatmix; + glt->d3dmaxmiplevelfilter = 0; + } + } + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + // change all the existing texture objects + for (pool = gltexturepoolchain;pool;pool = pool->next) + for (glt = pool->gltchain;glt;glt = glt->chain) + if (glt->texnum && (gl_filter_force || !(glt->flags & (TEXF_FORCENEAREST | TEXF_FORCELINEAR)))) + DPSOFTRAST_Texture_Filter(glt->texnum, (glt->flags & TEXF_MIPMAP) ? dpsoftrast_filter_mipmap : dpsoftrast_filter_nomipmap); + break; + } +} + +static void GL_Texture_CalcImageSize(int texturetype, int flags, int miplevel, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth, int *outmiplevels) +{ + int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1, miplevels = 1; + + switch (texturetype) + { + default: + case GLTEXTURETYPE_2D: + maxsize = vid.maxtexturesize_2d; + if (flags & TEXF_PICMIP) + { + maxsize = bound(1, gl_max_size.integer, maxsize); + picmip = miplevel; + } + break; + case GLTEXTURETYPE_3D: + maxsize = vid.maxtexturesize_3d; + break; + case GLTEXTURETYPE_CUBEMAP: + maxsize = vid.maxtexturesize_cubemap; + break; + } + + if (vid.support.arb_texture_non_power_of_two) + { + width2 = min(inwidth >> picmip, maxsize); + height2 = min(inheight >> picmip, maxsize); + depth2 = min(indepth >> picmip, maxsize); + } + else + { + for (width2 = 1;width2 < inwidth;width2 <<= 1); + for (width2 >>= picmip;width2 > maxsize;width2 >>= 1); + for (height2 = 1;height2 < inheight;height2 <<= 1); + for (height2 >>= picmip;height2 > maxsize;height2 >>= 1); + for (depth2 = 1;depth2 < indepth;depth2 <<= 1); + for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1); + } + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#if 0 + // for some reason the REF rasterizer (and hence the PIX debugger) does not like small textures... + if (texturetype == GLTEXTURETYPE_2D) + { + width2 = max(width2, 2); + height2 = max(height2, 2); + } +#endif + break; + } + + miplevels = 1; + if (flags & TEXF_MIPMAP) + { + int extent = max(width2, max(height2, depth2)); + while(extent >>= 1) + miplevels++; + } + + if (outwidth) + *outwidth = max(1, width2); + if (outheight) + *outheight = max(1, height2); + if (outdepth) + *outdepth = max(1, depth2); + if (outmiplevels) + *outmiplevels = miplevels; +} + + +static int R_CalcTexelDataSize (gltexture_t *glt) +{ + int width2, height2, depth2, size; + + GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &width2, &height2, &depth2, NULL); + + size = width2 * height2 * depth2; + + if (glt->flags & TEXF_MIPMAP) + { + while (width2 > 1 || height2 > 1 || depth2 > 1) + { + if (width2 > 1) + width2 >>= 1; + if (height2 > 1) + height2 >>= 1; + if (depth2 > 1) + depth2 >>= 1; + size += width2 * height2 * depth2; + } + } + + return (int)(size * glt->textype->glinternalbytesperpixel) * glt->sides; +} + +void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal) +{ + int glsize; + int isloaded; + int pooltotal = 0, pooltotalt = 0, pooltotalp = 0, poolloaded = 0, poolloadedt = 0, poolloadedp = 0; + int sumtotal = 0, sumtotalt = 0, sumtotalp = 0, sumloaded = 0, sumloadedt = 0, sumloadedp = 0; + gltexture_t *glt; + gltexturepool_t *pool; + if (printeach) + Con_Print("glsize input loaded mip alpha name\n"); + for (pool = gltexturepoolchain;pool;pool = pool->next) + { + pooltotal = 0; + pooltotalt = 0; + pooltotalp = 0; + poolloaded = 0; + poolloadedt = 0; + poolloadedp = 0; + for (glt = pool->gltchain;glt;glt = glt->chain) + { + glsize = R_CalcTexelDataSize(glt); + isloaded = glt->texnum != 0 || glt->renderbuffernum != 0 || glt->d3dtexture || glt->d3dsurface; + pooltotal++; + pooltotalt += glsize; + pooltotalp += glt->inputdatasize; + if (isloaded) + { + poolloaded++; + poolloadedt += glsize; + poolloadedp += glt->inputdatasize; + } + if (printeach) + Con_Printf("%c%4i%c%c%4i%c %-24s %s %s %s %s\n", isloaded ? '[' : ' ', (glsize + 1023) / 1024, isloaded ? ']' : ' ', glt->inputtexels ? '[' : ' ', (glt->inputdatasize + 1023) / 1024, glt->inputtexels ? ']' : ' ', glt->textype->name, isloaded ? "loaded" : " ", (glt->flags & TEXF_MIPMAP) ? "mip" : " ", (glt->flags & TEXF_ALPHA) ? "alpha" : " ", glt->identifier); + } + if (printpool) + Con_Printf("texturepool %10p total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", (void *)pool, pooltotal, pooltotalt / 1048576.0, pooltotalp / 1048576.0, poolloaded, poolloadedt / 1048576.0, poolloadedp / 1048576.0, pooltotal - poolloaded, (pooltotalt - poolloadedt) / 1048576.0, (pooltotalp - poolloadedp) / 1048576.0); + sumtotal += pooltotal; + sumtotalt += pooltotalt; + sumtotalp += pooltotalp; + sumloaded += poolloaded; + sumloadedt += poolloadedt; + sumloadedp += poolloadedp; + } + if (printtotal) + Con_Printf("textures total: %i (%.3fMB, %.3fMB original), uploaded %i (%.3fMB, %.3fMB original), upload on demand %i (%.3fMB, %.3fMB original)\n", sumtotal, sumtotalt / 1048576.0, sumtotalp / 1048576.0, sumloaded, sumloadedt / 1048576.0, sumloadedp / 1048576.0, sumtotal - sumloaded, (sumtotalt - sumloadedt) / 1048576.0, (sumtotalp - sumloadedp) / 1048576.0); +} + +static void R_TextureStats_f(void) +{ + R_TextureStats_Print(true, true, true); +} + +static void r_textures_start(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + // LordHavoc: allow any alignment + CHECKGLERROR + qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);CHECKGLERROR + qglPixelStorei(GL_PACK_ALIGNMENT, 1);CHECKGLERROR + break; + case RENDERPATH_D3D9: + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } + + texturemempool = Mem_AllocPool("texture management", 0, NULL); + Mem_ExpandableArray_NewArray(&texturearray, texturemempool, sizeof(gltexture_t), 512); + + // Disable JPEG screenshots if the DLL isn't loaded + if (! JPEG_OpenLibrary ()) + Cvar_SetValueQuick (&scr_screenshot_jpeg, 0); + if (! PNG_OpenLibrary ()) + Cvar_SetValueQuick (&scr_screenshot_png, 0); +} + +static void r_textures_shutdown(void) +{ + rtexturepool_t *temp; + + JPEG_CloseLibrary (); + + while(gltexturepoolchain) + { + temp = (rtexturepool_t *) gltexturepoolchain; + R_FreeTexturePool(&temp); + } + + resizebuffersize = 0; + resizebuffer = NULL; + colorconvertbuffer = NULL; + texturebuffer = NULL; + Mem_ExpandableArray_FreeArray(&texturearray); + Mem_FreePool(&texturemempool); +} + +static void r_textures_newmap(void) +{ +} + +static void r_textures_devicelost(void) +{ + int i, endindex; + gltexture_t *glt; + endindex = Mem_ExpandableArray_IndexRange(&texturearray); + for (i = 0;i < endindex;i++) + { + glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); + if (!glt || !(glt->flags & TEXF_RENDERTARGET)) + continue; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (glt->d3dsurface) + IDirect3DSurface9_Release((IDirect3DSurface9 *)glt->d3dsurface); + else if (glt->tiledepth > 1) + IDirect3DVolumeTexture9_Release((IDirect3DVolumeTexture9 *)glt->d3dtexture); + else if (glt->sides == 6) + IDirect3DCubeTexture9_Release((IDirect3DCubeTexture9 *)glt->d3dtexture); + else + IDirect3DTexture9_Release((IDirect3DTexture9 *)glt->d3dtexture); + glt->d3dtexture = NULL; + glt->d3dsurface = NULL; +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } + } +} + +static void r_textures_devicerestored(void) +{ + int i, endindex; + gltexture_t *glt; + endindex = Mem_ExpandableArray_IndexRange(&texturearray); + for (i = 0;i < endindex;i++) + { + glt = (gltexture_t *) Mem_ExpandableArray_RecordAtIndex(&texturearray, i); + if (!glt || !(glt->flags & TEXF_RENDERTARGET)) + continue; + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + HRESULT d3dresult; + if (glt->d3disrendertargetsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!"); + } + else if (glt->d3disdepthstencilsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); + } + else if (glt->tiledepth > 1) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!"); + } + else if (glt->sides == 6) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!"); + } + else + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateTexture failed!"); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + break; + } + } +} + + +void R_Textures_Init (void) +{ + Cmd_AddCommand("gl_texturemode", &GL_TextureMode_f, "set texture filtering mode (GL_NEAREST, GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, etc); an additional argument 'force' forces the texture mode even in cases where it may not be appropriate"); + Cmd_AddCommand("r_texturestats", R_TextureStats_f, "print information about all loaded textures and some statistics"); + Cvar_RegisterVariable (&gl_max_size); + Cvar_RegisterVariable (&gl_picmip); + Cvar_RegisterVariable (&gl_picmip_world); + Cvar_RegisterVariable (&r_picmipworld); + Cvar_RegisterVariable (&gl_picmip_sprites); + Cvar_RegisterVariable (&r_picmipsprites); + Cvar_RegisterVariable (&gl_picmip_other); + Cvar_RegisterVariable (&gl_max_lightmapsize); + Cvar_RegisterVariable (&r_lerpimages); + Cvar_RegisterVariable (&gl_texture_anisotropy); + Cvar_RegisterVariable (&gl_texturecompression); + Cvar_RegisterVariable (&gl_texturecompression_color); + Cvar_RegisterVariable (&gl_texturecompression_normal); + Cvar_RegisterVariable (&gl_texturecompression_gloss); + Cvar_RegisterVariable (&gl_texturecompression_glow); + Cvar_RegisterVariable (&gl_texturecompression_2d); + Cvar_RegisterVariable (&gl_texturecompression_q3bsplightmaps); + Cvar_RegisterVariable (&gl_texturecompression_q3bspdeluxemaps); + Cvar_RegisterVariable (&gl_texturecompression_sky); + Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps); + Cvar_RegisterVariable (&gl_texturecompression_reflectmask); + Cvar_RegisterVariable (&gl_texturecompression_sprites); + Cvar_RegisterVariable (&gl_nopartialtextureupdates); + Cvar_RegisterVariable (&r_texture_dds_load_alphamode); + Cvar_RegisterVariable (&r_texture_dds_load_logfailure); + Cvar_RegisterVariable (&r_texture_dds_swdecode); + + R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored); +} + +void R_Textures_Frame (void) +{ + static int old_aniso = 0; + + // could do procedural texture animation here, if we keep track of which + // textures were accessed this frame... + + // free the resize buffers + resizebuffersize = 0; + if (resizebuffer) + { + Mem_Free(resizebuffer); + resizebuffer = NULL; + } + if (colorconvertbuffer) + { + Mem_Free(colorconvertbuffer); + colorconvertbuffer = NULL; + } + + if (old_aniso != gl_texture_anisotropy.integer) + { + gltexture_t *glt; + gltexturepool_t *pool; + GLint oldbindtexnum; + + old_aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy); + + Cvar_SetValueQuick(&gl_texture_anisotropy, old_aniso); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + GL_ActiveTexture(0); + for (pool = gltexturepoolchain;pool;pool = pool->next) + { + for (glt = pool->gltchain;glt;glt = glt->chain) + { + // only update already uploaded images + if (glt->texnum && (glt->flags & TEXF_MIPMAP) == TEXF_MIPMAP) + { + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_ANISOTROPY_EXT, old_aniso); + CHECKGLERROR + + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } + } + } + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + break; + } + } +} + +static void R_MakeResizeBufferBigger(int size) +{ + if (resizebuffersize < size) + { + resizebuffersize = size; + if (resizebuffer) + Mem_Free(resizebuffer); + if (colorconvertbuffer) + Mem_Free(colorconvertbuffer); + resizebuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize); + colorconvertbuffer = (unsigned char *)Mem_Alloc(texturemempool, resizebuffersize); + if (!resizebuffer || !colorconvertbuffer) + Host_Error("R_Upload: out of memory"); + } +} + +static void GL_SetupTextureParameters(int flags, textype_t textype, int texturetype) +{ + int textureenum = gltexturetypeenums[texturetype]; + int wrapmode = (flags & TEXF_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT; + + CHECKGLERROR + + if (vid.support.ext_texture_filter_anisotropic && (flags & TEXF_MIPMAP)) + { + int aniso = bound(1, gl_texture_anisotropy.integer, (int)vid.max_anisotropy); + if (gl_texture_anisotropy.integer != aniso) + Cvar_SetValueQuick(&gl_texture_anisotropy, aniso); + qglTexParameteri(textureenum, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);CHECKGLERROR + } + qglTexParameteri(textureenum, GL_TEXTURE_WRAP_S, wrapmode);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_WRAP_T, wrapmode);CHECKGLERROR +#ifdef GL_TEXTURE_WRAP_R + if (gltexturetypedimensions[texturetype] >= 3) + { + qglTexParameteri(textureenum, GL_TEXTURE_WRAP_R, wrapmode);CHECKGLERROR + } +#endif + + CHECKGLERROR + if (!gl_filter_force && flags & TEXF_FORCENEAREST) + { + if (flags & TEXF_MIPMAP) + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);CHECKGLERROR + } + else + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_NEAREST);CHECKGLERROR + } + qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_NEAREST);CHECKGLERROR + } + else if (!gl_filter_force && flags & TEXF_FORCELINEAR) + { + if (flags & TEXF_MIPMAP) + { + if (gl_filter_min == GL_NEAREST_MIPMAP_LINEAR || gl_filter_min == GL_LINEAR_MIPMAP_LINEAR) + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);CHECKGLERROR + } + else + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);CHECKGLERROR + } + } + else + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, GL_LINEAR);CHECKGLERROR + } + qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, GL_LINEAR);CHECKGLERROR + } + else + { + if (flags & TEXF_MIPMAP) + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_min);CHECKGLERROR + } + else + { + qglTexParameteri(textureenum, GL_TEXTURE_MIN_FILTER, gl_filter_mag);CHECKGLERROR + } + qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR + } + + switch(textype) + { + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP24_COMP: + /*qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR + qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);*/CHECKGLERROR + break; + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_RAW: + /*qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR + qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR + qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);*/CHECKGLERROR + break; + default: + break; + } + + CHECKGLERROR +} + +static void R_UploadPartialTexture(gltexture_t *glt, const unsigned char *data, int fragx, int fragy, int fragz, int fragwidth, int fragheight, int fragdepth) +{ + if (data == NULL) + Sys_Error("R_UploadPartialTexture \"%s\": partial update with NULL pixels", glt->identifier); + + if (glt->texturetype != GLTEXTURETYPE_2D) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of type other than 2D", glt->identifier); + + if (glt->textype->textype == TEXTYPE_PALETTE) + Sys_Error("R_UploadPartialTexture \"%s\": partial update of paletted texture", glt->identifier); + + if (glt->flags & (TEXF_MIPMAP | TEXF_PICMIP)) + Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with MIPMAP or PICMIP flags", glt->identifier); + + if (glt->inputwidth != glt->tilewidth || glt->inputheight != glt->tileheight || glt->tiledepth != 1) + Sys_Error("R_UploadPartialTexture \"%s\": partial update not supported with stretched or special textures", glt->identifier); + + // update a portion of the image + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + { + int oldbindtexnum; + CHECKGLERROR + // we need to restore the texture binding after finishing the upload + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, data);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + RECT d3drect; + D3DLOCKED_RECT d3dlockedrect; + int y; + memset(&d3drect, 0, sizeof(d3drect)); + d3drect.left = fragx; + d3drect.top = fragy; + d3drect.right = fragx+fragwidth; + d3drect.bottom = fragy+fragheight; + if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, 0, &d3dlockedrect, &d3drect, 0) == D3D_OK && d3dlockedrect.pBits) + { + for (y = 0;y < fragheight;y++) + memcpy((unsigned char *)d3dlockedrect.pBits + d3dlockedrect.Pitch * y, data + fragwidth*glt->bytesperpixel * y, fragwidth*glt->bytesperpixel); + IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, 0); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + DPSOFTRAST_Texture_UpdatePartial(glt->texnum, 0, data, fragx, fragy, fragwidth, fragheight); + break; + } +} + +static void R_UploadFullTexture(gltexture_t *glt, const unsigned char *data) +{ + int i, mip = 0, width, height, depth; + GLint oldbindtexnum = 0; + const unsigned char *prevbuffer; + prevbuffer = data; + + // error out if a stretch is needed on special texture types + if (glt->texturetype != GLTEXTURETYPE_2D && (glt->tilewidth != glt->inputwidth || glt->tileheight != glt->inputheight || glt->tiledepth != glt->inputdepth)) + Sys_Error("R_UploadFullTexture \"%s\": stretch uploads allowed only on 2D textures\n", glt->identifier); + + // when picmip or maxsize is applied, we scale up to a power of 2 multiple + // of the target size and then use the mipmap reduction function to get + // high quality supersampled results + for (width = glt->tilewidth;width < glt->inputwidth ;width <<= 1); + for (height = glt->tileheight;height < glt->inputheight;height <<= 1); + for (depth = glt->tiledepth;depth < glt->inputdepth ;depth <<= 1); + R_MakeResizeBufferBigger(width * height * depth * glt->sides * glt->bytesperpixel); + + if (prevbuffer == NULL) + { + width = glt->tilewidth; + height = glt->tileheight; + depth = glt->tiledepth; +// memset(resizebuffer, 0, width * height * depth * glt->sides * glt->bytesperpixel); +// prevbuffer = resizebuffer; + } + else + { + if (glt->textype->textype == TEXTYPE_PALETTE) + { + // promote paletted to BGRA, so we only have to worry about BGRA in the rest of this code + Image_Copy8bitBGRA(prevbuffer, colorconvertbuffer, glt->inputwidth * glt->inputheight * glt->inputdepth * glt->sides, glt->palette); + prevbuffer = colorconvertbuffer; + } + if (glt->flags & TEXF_RGBMULTIPLYBYALPHA) + { + // multiply RGB channels by A channel before uploading + int alpha; + for (i = 0;i < glt->inputwidth*glt->inputheight*glt->inputdepth*4;i += 4) + { + alpha = prevbuffer[i+3]; + colorconvertbuffer[i] = (prevbuffer[i] * alpha) >> 8; + colorconvertbuffer[i+1] = (prevbuffer[i+1] * alpha) >> 8; + colorconvertbuffer[i+2] = (prevbuffer[i+2] * alpha) >> 8; + colorconvertbuffer[i+3] = alpha; + } + prevbuffer = colorconvertbuffer; + } + // scale up to a power of 2 size (if appropriate) + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; + } + // apply mipmap reduction algorithm to get down to picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); + prevbuffer = resizebuffer; + } + } + + // do the appropriate upload type... + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (glt->texnum) // not renderbuffers + { + CHECKGLERROR + + // we need to restore the texture binding after finishing the upload + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + +#ifdef GL_TEXTURE_COMPRESSION_HINT_ARB + if (qglGetCompressedTexImageARB) + { + if (gl_texturecompression.integer >= 2) + qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_NICEST); + else + qglHint(GL_TEXTURE_COMPRESSION_HINT_ARB, GL_FASTEST); + CHECKGLERROR + } +#endif + switch(glt->texturetype) + { + case GLTEXTURETYPE_2D: + qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } + } + break; + case GLTEXTURETYPE_3D: +#ifndef USE_GLES2 + qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } + } +#endif + break; + case GLTEXTURETYPE_CUBEMAP: + // convert and upload each side in turn, + // from a continuous block of input texels + texturebuffer = (unsigned char *)prevbuffer; + for (i = 0;i < 6;i++) + { + prevbuffer = texturebuffer; + texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; + } + // picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); + prevbuffer = resizebuffer; + } + mip = 0; + qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR + } + } + } + break; + } + GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + if (!(glt->flags & TEXF_RENDERTARGET) && glt->d3dtexture && !glt->d3dsurface) + { + D3DLOCKED_RECT d3dlockedrect; + D3DLOCKED_BOX d3dlockedbox; + switch(glt->texturetype) + { + case GLTEXTURETYPE_2D: + if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) + { + if (prevbuffer) + memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); + else + memset(d3dlockedrect.pBits, 255, width*height*glt->bytesperpixel); + IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); + } + mip++; + if ((glt->flags & TEXF_MIPMAP) && prevbuffer) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) + { + memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); + IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); + } + mip++; + } + } + break; + case GLTEXTURETYPE_3D: + if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits) + { + // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes + memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel); + IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip); + } + mip++; + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + if (IDirect3DVolumeTexture9_LockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip, &d3dlockedbox, NULL, 0) == D3D_OK && d3dlockedbox.pBits) + { + // we are not honoring the RowPitch or SlicePitch, hopefully this works with all sizes + memcpy(d3dlockedbox.pBits, prevbuffer, width*height*depth*glt->bytesperpixel); + IDirect3DVolumeTexture9_UnlockBox((IDirect3DVolumeTexture9*)glt->d3dtexture, mip); + } + mip++; + } + } + break; + case GLTEXTURETYPE_CUBEMAP: + // convert and upload each side in turn, + // from a continuous block of input texels + texturebuffer = (unsigned char *)prevbuffer; + for (i = 0;i < 6;i++) + { + prevbuffer = texturebuffer; + texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; + } + // picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); + prevbuffer = resizebuffer; + } + mip = 0; + if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) + { + memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); + IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip); + } + mip++; + if (glt->flags & TEXF_MIPMAP) + { + while (width > 1 || height > 1 || depth > 1) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1); + prevbuffer = resizebuffer; + if (IDirect3DCubeTexture9_LockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) + { + memcpy(d3dlockedrect.pBits, prevbuffer, width*height*glt->bytesperpixel); + IDirect3DCubeTexture9_UnlockRect((IDirect3DCubeTexture9*)glt->d3dtexture, (D3DCUBEMAP_FACES)i, mip); + } + mip++; + } + } + } + break; + } + } + glt->d3daddressw = 0; + if (glt->flags & TEXF_CLAMP) + { + glt->d3daddressu = D3DTADDRESS_CLAMP; + glt->d3daddressv = D3DTADDRESS_CLAMP; + if (glt->tiledepth > 1) + glt->d3daddressw = D3DTADDRESS_CLAMP; + } + else + { + glt->d3daddressu = D3DTADDRESS_WRAP; + glt->d3daddressv = D3DTADDRESS_WRAP; + if (glt->tiledepth > 1) + glt->d3daddressw = D3DTADDRESS_WRAP; + } + glt->d3dmipmaplodbias = 0; + glt->d3dmaxmiplevel = 0; + glt->d3dmaxmiplevelfilter = d3d_filter_nomip ? 0 : glt->d3dmaxmiplevel; + if (glt->flags & TEXF_FORCELINEAR) + { + glt->d3dminfilter = D3DTEXF_LINEAR; + glt->d3dmagfilter = D3DTEXF_LINEAR; + glt->d3dmipfilter = D3DTEXF_POINT; + } + else if (glt->flags & TEXF_FORCENEAREST) + { + glt->d3dminfilter = D3DTEXF_POINT; + glt->d3dmagfilter = D3DTEXF_POINT; + glt->d3dmipfilter = D3DTEXF_POINT; + } + else if (glt->flags & TEXF_MIPMAP) + { + glt->d3dminfilter = d3d_filter_mipmin; + glt->d3dmagfilter = d3d_filter_mipmag; + glt->d3dmipfilter = d3d_filter_mipmix; + } + else + { + glt->d3dminfilter = d3d_filter_flatmin; + glt->d3dmagfilter = d3d_filter_flatmag; + glt->d3dmipfilter = d3d_filter_flatmix; + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + switch(glt->texturetype) + { + case GLTEXTURETYPE_2D: + DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer); + break; + case GLTEXTURETYPE_3D: + DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer); + break; + case GLTEXTURETYPE_CUBEMAP: + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + unsigned char *combinedbuffer = (unsigned char *)Mem_Alloc(tempmempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel); + // convert and upload each side in turn, + // from a continuous block of input texels + // copy the results into combinedbuffer + texturebuffer = (unsigned char *)prevbuffer; + for (i = 0;i < 6;i++) + { + prevbuffer = texturebuffer; + texturebuffer += glt->inputwidth * glt->inputheight * glt->inputdepth * glt->textype->inputbytesperpixel; + if (glt->inputwidth != width || glt->inputheight != height || glt->inputdepth != depth) + { + Image_Resample32(prevbuffer, glt->inputwidth, glt->inputheight, glt->inputdepth, resizebuffer, width, height, depth, r_lerpimages.integer); + prevbuffer = resizebuffer; + } + // picmip/max_size + while (width > glt->tilewidth || height > glt->tileheight || depth > glt->tiledepth) + { + Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, glt->tilewidth, glt->tileheight, glt->tiledepth); + prevbuffer = resizebuffer; + } + memcpy(combinedbuffer + i*glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel, prevbuffer, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->bytesperpixel); + } + DPSOFTRAST_Texture_UpdateFull(glt->texnum, combinedbuffer); + Mem_Free(combinedbuffer); + } + else + DPSOFTRAST_Texture_UpdateFull(glt->texnum, prevbuffer); + break; + } + if (glt->flags & TEXF_FORCELINEAR) + DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR); + else if (glt->flags & TEXF_FORCENEAREST) + DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST); + else if (glt->flags & TEXF_MIPMAP) + DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap); + else + DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap); + break; + } +} + +static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, int sides, int flags, int miplevel, textype_t textype, int texturetype, const unsigned char *data, const unsigned int *palette) +{ + int i, size; + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo, *texinfo2; + unsigned char *temppixels = NULL; + qboolean swaprb; + + if (cls.state == ca_dedicated) + return NULL; + + // see if we need to swap red and blue (BGRA <-> RGBA conversion) + if (textype == TEXTYPE_PALETTE && vid.forcetextype == TEXTYPE_RGBA) + { + int numpixels = width * height * depth * sides; + size = numpixels * 4; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + if (data) + { + const unsigned char *p; + unsigned char *o = temppixels; + for (i = 0;i < numpixels;i++, o += 4) + { + p = (const unsigned char *)palette + 4*data[i]; + o[0] = p[2]; + o[1] = p[1]; + o[2] = p[0]; + o[3] = p[3]; + } + } + data = temppixels; + textype = TEXTYPE_RGBA; + } + swaprb = false; + switch(textype) + { + case TEXTYPE_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_BGRA;} break; + case TEXTYPE_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_RGBA;} break; + case TEXTYPE_SRGB_RGBA: if (vid.forcetextype == TEXTYPE_BGRA) {swaprb = true;textype = TEXTYPE_SRGB_BGRA;} break; + case TEXTYPE_SRGB_BGRA: if (vid.forcetextype == TEXTYPE_RGBA) {swaprb = true;textype = TEXTYPE_SRGB_RGBA;} break; + default: break; + } + if (swaprb) + { + // swap bytes + static int rgbaswapindices[4] = {2, 1, 0, 3}; + size = width * height * depth * sides * 4; + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + if (data) + Image_CopyMux(temppixels, data, width, height*depth*sides, false, false, false, 4, 4, rgbaswapindices); + data = temppixels; + } + + // if sRGB texture formats are not supported, convert input to linear and upload as normal types + if (!vid.support.ext_texture_srgb) + { + qboolean convertsRGB = false; + switch(textype) + { + case TEXTYPE_SRGB_DXT1: textype = TEXTYPE_DXT1 ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT1A: textype = TEXTYPE_DXT1A ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT3: textype = TEXTYPE_DXT3 ;convertsRGB = true;break; + case TEXTYPE_SRGB_DXT5: textype = TEXTYPE_DXT5 ;convertsRGB = true;break; + case TEXTYPE_SRGB_PALETTE: textype = TEXTYPE_PALETTE;/*convertsRGB = true;*/break; + case TEXTYPE_SRGB_RGBA: textype = TEXTYPE_RGBA ;convertsRGB = true;break; + case TEXTYPE_SRGB_BGRA: textype = TEXTYPE_BGRA ;convertsRGB = true;break; + default: + break; + } + if (convertsRGB && data) + { + size = width * height * depth * sides * 4; + if (!temppixels) + { + temppixels = (unsigned char *)Mem_Alloc(tempmempool, size); + memcpy(temppixels, data, size); + data = temppixels; + } + Image_MakeLinearColorsFromsRGB(temppixels, temppixels, width*height*depth*sides); + } + } + + if (texturetype == GLTEXTURETYPE_CUBEMAP && !vid.support.arb_texture_cube_map) + { + Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n"); + return NULL; + } + if (texturetype == GLTEXTURETYPE_3D && !vid.support.ext_texture_3d) + { + Con_Printf ("R_LoadTexture: 3d texture not supported by driver\n"); + return NULL; + } + + texinfo = R_GetTexTypeInfo(textype, flags); + size = width * height * depth * sides * texinfo->inputbytesperpixel; + if (size < 1) + { + Con_Printf ("R_LoadTexture: bogus texture size (%dx%dx%dx%dbppx%dsides = %d bytes)\n", width, height, depth, texinfo->inputbytesperpixel * 8, sides, size); + return NULL; + } + + // clear the alpha flag if the texture has no transparent pixels + switch(textype) + { + case TEXTYPE_PALETTE: + case TEXTYPE_SRGB_PALETTE: + if (flags & TEXF_ALPHA) + { + flags &= ~TEXF_ALPHA; + if (data) + { + for (i = 0;i < size;i++) + { + if (((unsigned char *)&palette[data[i]])[3] < 255) + { + flags |= TEXF_ALPHA; + break; + } + } + } + } + break; + case TEXTYPE_RGBA: + case TEXTYPE_BGRA: + case TEXTYPE_SRGB_RGBA: + case TEXTYPE_SRGB_BGRA: + if (flags & TEXF_ALPHA) + { + flags &= ~TEXF_ALPHA; + if (data) + { + for (i = 3;i < size;i += 4) + { + if (data[i] < 255) + { + flags |= TEXF_ALPHA; + break; + } + } + } + } + break; + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_COMP: + case TEXTYPE_SHADOWMAP24_RAW: + break; + case TEXTYPE_DXT1: + case TEXTYPE_SRGB_DXT1: + break; + case TEXTYPE_DXT1A: + case TEXTYPE_SRGB_DXT1A: + case TEXTYPE_DXT3: + case TEXTYPE_SRGB_DXT3: + case TEXTYPE_DXT5: + case TEXTYPE_SRGB_DXT5: + flags |= TEXF_ALPHA; + break; + case TEXTYPE_ALPHA: + flags |= TEXF_ALPHA; + break; + case TEXTYPE_COLORBUFFER: + case TEXTYPE_COLORBUFFER16F: + case TEXTYPE_COLORBUFFER32F: + flags |= TEXF_ALPHA; + break; + default: + Sys_Error("R_LoadTexture: unknown texture type"); + } + + texinfo2 = R_GetTexTypeInfo(textype, flags); + if(size == width * height * depth * sides * texinfo->inputbytesperpixel) + texinfo = texinfo2; + else + Con_Printf ("R_LoadTexture: input size changed after alpha fallback\n"); + + glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); + if (identifier) + strlcpy (glt->identifier, identifier, sizeof(glt->identifier)); + + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = width; + glt->inputheight = height; + glt->inputdepth = depth; + glt->flags = flags; + glt->miplevel = (miplevel < 0) ? R_PicmipForFlags(flags) : miplevel; // note: if miplevel is -1, we know the texture is in original size and we can picmip it normally + glt->textype = texinfo; + glt->texturetype = texturetype; + glt->inputdatasize = size; + glt->palette = palette; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1; + glt->texnum = 0; + glt->dirty = false; + glt->glisdepthstencil = false; + glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; + // init the dynamic texture attributes, too [11/22/2007 Black] + glt->updatecallback = NULL; + glt->updatacallback_data = NULL; + + GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels); + + // upload the texture + // data may be NULL (blank texture for dynamic rendering) + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DFORMAT d3dformat; + D3DPOOL d3dpool; + DWORD d3dusage; + HRESULT d3dresult; + d3dusage = 0; + d3dpool = D3DPOOL_MANAGED; + if (flags & TEXF_RENDERTARGET) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + d3dpool = D3DPOOL_DEFAULT; + } + switch(textype) + { + case TEXTYPE_PALETTE: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; + case TEXTYPE_RGBA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8B8G8R8 : D3DFMT_X8B8G8R8;break; + case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; + case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;break; + case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;break; + case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;break; + case TEXTYPE_ALPHA: d3dformat = D3DFMT_A8;break; + default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTexture: unsupported texture type %i when picking D3DFMT", (int)textype);break; + } + glt->d3dformat = d3dformat; + glt->d3dusage = d3dusage; + glt->d3dpool = d3dpool; + glt->d3disrendertargetsurface = false; + glt->d3disdepthstencilsurface = false; + if (glt->tiledepth > 1) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateVolumeTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->tiledepth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DVolumeTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateVolumeTexture failed!"); + } + else if (glt->sides == 6) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateCubeTexture(vid_d3d9dev, glt->tilewidth, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DCubeTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateCubeTexture failed!"); + } + else + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, glt->d3dusage, (D3DFORMAT)glt->d3dformat, (D3DPOOL)glt->d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL))) + Sys_Error("IDirect3DDevice9_CreateTexture failed!"); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + { + int tflags = 0; + switch(textype) + { + case TEXTYPE_PALETTE: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break; + case TEXTYPE_RGBA: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA8;break; + case TEXTYPE_BGRA: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break; + case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8;break; + case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F;break; + case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F;break; + case TEXTYPE_SHADOWMAP16_COMP: + case TEXTYPE_SHADOWMAP16_RAW: + case TEXTYPE_SHADOWMAP24_COMP: + case TEXTYPE_SHADOWMAP24_RAW: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break; + case TEXTYPE_DEPTHBUFFER16: + case TEXTYPE_DEPTHBUFFER24: + case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH;break; + case TEXTYPE_ALPHA: tflags = DPSOFTRAST_TEXTURE_FORMAT_ALPHA8;break; + default: Sys_Error("R_LoadTexture: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype); + } + if (glt->miplevels > 1) tflags |= DPSOFTRAST_TEXTURE_FLAG_MIPMAP; + if (flags & TEXF_ALPHA) tflags |= DPSOFTRAST_TEXTURE_FLAG_USEALPHA; + if (glt->sides == 6) tflags |= DPSOFTRAST_TEXTURE_FLAG_CUBEMAP; + if (glt->flags & TEXF_CLAMP) tflags |= DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE; + glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth); + } + break; + } + + R_UploadFullTexture(glt, data); + + if ((glt->flags & TEXF_ALLOWUPDATES) && gl_nopartialtextureupdates.integer) + glt->bufferpixels = (unsigned char *)Mem_Alloc(texturemempool, glt->tilewidth*glt->tileheight*glt->tiledepth*glt->sides*glt->bytesperpixel); + + // free any temporary processing buffer we allocated... + if (temppixels) + Mem_Free(temppixels); + + // texture converting and uploading can take a while, so make sure we're sending keepalives + // FIXME: this causes rendering during R_Shadow_DrawLights +// CL_KeepaliveMessage(false); + + return (rtexture_t *)glt; +} + +rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette) +{ + return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, flags, miplevel, textype, GLTEXTURETYPE_2D, data, palette); +} + +rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette) +{ + return R_SetupTexture(rtexturepool, identifier, width, height, depth, 1, flags, miplevel, textype, GLTEXTURETYPE_3D, data, palette); +} + +rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette) +{ + return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, miplevel, textype, GLTEXTURETYPE_CUBEMAP, data, palette); +} + +rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter) +{ + return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_RENDERTARGET | TEXF_CLAMP | (filter ? TEXF_FORCELINEAR : TEXF_FORCENEAREST), -1, textype, GLTEXTURETYPE_2D, NULL, NULL); +} + +rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype) +{ + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo; + + if (cls.state == ca_dedicated) + return NULL; + + texinfo = R_GetTexTypeInfo(textype, TEXF_RENDERTARGET | TEXF_CLAMP); + + glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); + if (identifier) + strlcpy (glt->identifier, identifier, sizeof(glt->identifier)); + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = width; + glt->inputheight = height; + glt->inputdepth = 1; + glt->flags = TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_FORCENEAREST; + glt->miplevel = 0; + glt->textype = texinfo; + glt->texturetype = textype; + glt->inputdatasize = width*height*texinfo->internalbytesperpixel; + glt->palette = NULL; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1; + glt->texnum = 0; + glt->dirty = false; + glt->glisdepthstencil = glt->texturetype == TEXTYPE_DEPTHBUFFER24STENCIL8; + glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; + // init the dynamic texture attributes, too [11/22/2007 Black] + glt->updatecallback = NULL; + glt->updatacallback_data = NULL; + + GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->miplevel, glt->inputwidth, glt->inputheight, glt->inputdepth, &glt->tilewidth, &glt->tileheight, &glt->tiledepth, &glt->miplevels); + + // upload the texture + // data may be NULL (blank texture for dynamic rendering) + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + qglGenRenderbuffers(1, (GLuint *)&glt->renderbuffernum);CHECKGLERROR + qglBindRenderbuffer(GL_RENDERBUFFER, glt->renderbuffernum);CHECKGLERROR + qglRenderbufferStorage(GL_RENDERBUFFER, glt->glinternalformat, glt->tilewidth, glt->tileheight);CHECKGLERROR + // note we can query the renderbuffer for info with glGetRenderbufferParameteriv for GL_WIDTH, GL_HEIGHt, GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_INTERNAL_FORMAT + qglBindRenderbuffer(GL_RENDERBUFFER, 0);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DFORMAT d3dformat; + HRESULT d3dresult; + glt->d3disrendertargetsurface = false; + glt->d3disdepthstencilsurface = false; + switch(textype) + { + case TEXTYPE_COLORBUFFER: d3dformat = D3DFMT_A8R8G8B8;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_COLORBUFFER16F: d3dformat = D3DFMT_A16B16G16R16F;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_COLORBUFFER32F: d3dformat = D3DFMT_A32B32G32R32F;glt->d3disrendertargetsurface = true;break; + case TEXTYPE_DEPTHBUFFER16: d3dformat = D3DFMT_D16;glt->d3disdepthstencilsurface = true;break; + case TEXTYPE_DEPTHBUFFER24: d3dformat = D3DFMT_D24X8;glt->d3disdepthstencilsurface = true;break; + case TEXTYPE_DEPTHBUFFER24STENCIL8: d3dformat = D3DFMT_D24S8;glt->d3disdepthstencilsurface = true;break; + default: d3dformat = D3DFMT_A8R8G8B8;Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking D3DFMT", (int)textype);break; + } + glt->d3dformat = d3dformat; + glt->d3dusage = 0; + glt->d3dpool = 0; + if (glt->d3disrendertargetsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateRenderTarget(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateRenderTarget failed!"); + } + else if (glt->d3disdepthstencilsurface) + { + if (FAILED(d3dresult = IDirect3DDevice9_CreateDepthStencilSurface(vid_d3d9dev, glt->tilewidth, glt->tileheight, (D3DFORMAT)glt->d3dformat, D3DMULTISAMPLE_NONE, 0, false, (IDirect3DSurface9 **)&glt->d3dsurface, NULL))) + Sys_Error("IDirect3DDevice9_CreateDepthStencilSurface failed!"); + } + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + { + int tflags = 0; + switch(textype) + { + case TEXTYPE_COLORBUFFER: tflags = DPSOFTRAST_TEXTURE_FORMAT_BGRA8 | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_COLORBUFFER16F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA16F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_COLORBUFFER32F: tflags = DPSOFTRAST_TEXTURE_FORMAT_RGBA32F | DPSOFTRAST_TEXTURE_FLAG_USEALPHA | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + case TEXTYPE_DEPTHBUFFER16: + case TEXTYPE_DEPTHBUFFER24: + case TEXTYPE_DEPTHBUFFER24STENCIL8: tflags = DPSOFTRAST_TEXTURE_FORMAT_DEPTH | DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE;break; + default: Sys_Error("R_LoadTextureRenderbuffer: unsupported texture type %i when picking DPSOFTRAST_TEXTURE_FLAGS", (int)textype); + } + glt->texnum = DPSOFTRAST_Texture_New(tflags, glt->tilewidth, glt->tileheight, glt->tiledepth); + } + break; + } + + return (rtexture_t *)glt; +} + +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha) +{ +#ifdef USE_GLES2 + return -1; // unsupported on this platform +#else + gltexture_t *glt = (gltexture_t *)rt; + unsigned char *dds; + int oldbindtexnum; + int bytesperpixel = 0; + int bytesperblock = 0; + int dds_flags; + int dds_format_flags; + int dds_caps1; + int dds_caps2; + int ret; + int mip; + int mipmaps; + int mipinfo[16][4]; + int ddssize = 128; + GLint internalformat; + const char *ddsfourcc; + if (!rt) + return -1; // NULL pointer + if (!strcmp(gl_version, "2.0.5885 WinXP Release")) + return -2; // broken driver - crashes on reading internal format + if (!qglGetTexLevelParameteriv) + return -2; + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + qglGetTexLevelParameteriv(gltexturetypeenums[glt->texturetype], 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat); + switch(internalformat) + { + default: ddsfourcc = NULL;bytesperpixel = 4;break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: ddsfourcc = "DXT1";bytesperblock = 8;break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT3";bytesperblock = 16;break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT5";bytesperblock = 16;break; + } + // if premultiplied alpha, say so in the DDS file + if(glt->flags & TEXF_RGBMULTIPLYBYALPHA) + { + switch(internalformat) + { + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: ddsfourcc = "DXT2";break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: ddsfourcc = "DXT4";break; + } + } + if (!bytesperblock && skipuncompressed) + return -3; // skipped + memset(mipinfo, 0, sizeof(mipinfo)); + mipinfo[0][0] = glt->tilewidth; + mipinfo[0][1] = glt->tileheight; + mipmaps = 1; + if ((glt->flags & TEXF_MIPMAP) && !(glt->tilewidth == 1 && glt->tileheight == 1)) + { + for (mip = 1;mip < 16;mip++) + { + mipinfo[mip][0] = mipinfo[mip-1][0] > 1 ? mipinfo[mip-1][0] >> 1 : 1; + mipinfo[mip][1] = mipinfo[mip-1][1] > 1 ? mipinfo[mip-1][1] >> 1 : 1; + if (mipinfo[mip][0] == 1 && mipinfo[mip][1] == 1) + { + mip++; + break; + } + } + mipmaps = mip; + } + for (mip = 0;mip < mipmaps;mip++) + { + mipinfo[mip][2] = bytesperblock ? ((mipinfo[mip][0]+3)/4)*((mipinfo[mip][1]+3)/4)*bytesperblock : mipinfo[mip][0]*mipinfo[mip][1]*bytesperpixel; + mipinfo[mip][3] = ddssize; + ddssize += mipinfo[mip][2]; + } + dds = (unsigned char *)Mem_Alloc(tempmempool, ddssize); + if (!dds) + return -4; + dds_caps1 = 0x1000; // DDSCAPS_TEXTURE + dds_caps2 = 0; + if (bytesperblock) + { + dds_flags = 0x81007; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_LINEARSIZE + dds_format_flags = 0x4; // DDPF_FOURCC + } + else + { + dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH + dds_format_flags = 0x40; // DDPF_RGB + } + if (mipmaps) + { + dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT + dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX + } + if(hasalpha) + dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS + memcpy(dds, "DDS ", 4); + StoreLittleLong(dds+4, 124); // http://msdn.microsoft.com/en-us/library/bb943982%28v=vs.85%29.aspx says so + StoreLittleLong(dds+8, dds_flags); + StoreLittleLong(dds+12, mipinfo[0][1]); // height + StoreLittleLong(dds+16, mipinfo[0][0]); // width + StoreLittleLong(dds+24, 0); // depth + StoreLittleLong(dds+28, mipmaps); // mipmaps + StoreLittleLong(dds+76, 32); // format size + StoreLittleLong(dds+80, dds_format_flags); + StoreLittleLong(dds+108, dds_caps1); + StoreLittleLong(dds+112, dds_caps2); + if (bytesperblock) + { + StoreLittleLong(dds+20, mipinfo[0][2]); // linear size + memcpy(dds+84, ddsfourcc, 4); + for (mip = 0;mip < mipmaps;mip++) + { + qglGetCompressedTexImageARB(gltexturetypeenums[glt->texturetype], mip, dds + mipinfo[mip][3]);CHECKGLERROR + } + } + else + { + StoreLittleLong(dds+20, mipinfo[0][0]*bytesperpixel); // pitch + StoreLittleLong(dds+88, bytesperpixel*8); // bits per pixel + dds[94] = dds[97] = dds[100] = dds[107] = 255; // bgra byte order masks + for (mip = 0;mip < mipmaps;mip++) + { + qglGetTexImage(gltexturetypeenums[glt->texturetype], mip, GL_BGRA, GL_UNSIGNED_BYTE, dds + mipinfo[mip][3]);CHECKGLERROR + } + } + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + ret = FS_WriteFile(filename, dds, ddssize); + Mem_Free(dds); + return ret ? ddssize : -5; +#endif +} + +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture) // DDS textures are opaque, so miplevel isn't a pointer but just seen as a hint +{ + int i, size, dds_format_flags, dds_miplevels, dds_width, dds_height; + //int dds_flags; + textype_t textype; + int bytesperblock, bytesperpixel; + int mipcomplete; + gltexture_t *glt; + gltexturepool_t *pool = (gltexturepool_t *)rtexturepool; + textypeinfo_t *texinfo; + int mip, mipwidth, mipheight, mipsize, mipsize_total; + unsigned int c, r, g, b; + GLint oldbindtexnum = 0; + unsigned char *mippixels; + unsigned char *mippixels_start; + unsigned char *ddspixels; + unsigned char *dds; + fs_offset_t ddsfilesize; + unsigned int ddssize; + qboolean force_swdecode, npothack; + + if (cls.state == ca_dedicated) + return NULL; + + dds = FS_LoadFile(filename, tempmempool, true, &ddsfilesize); + ddssize = ddsfilesize; + + if (!dds) + { + if (r_texture_dds_load_logfailure.integer && (r_texture_dds_load_logfailure.integer >= 2 || !optionaltexture)) + Log_Printf("ddstexturefailures.log", "%s\n", filename); + return NULL; // not found + } + + if (ddsfilesize <= 128 || memcmp(dds, "DDS ", 4) || ddssize < (unsigned int)BuffLittleLong(dds+4) || BuffLittleLong(dds+76) != 32) + { + Mem_Free(dds); + Con_Printf("^1%s: not a DDS image\n", filename); + return NULL; + } + + //dds_flags = BuffLittleLong(dds+8); + dds_format_flags = BuffLittleLong(dds+80); + dds_miplevels = (BuffLittleLong(dds+108) & 0x400000) ? BuffLittleLong(dds+28) : 1; + dds_width = BuffLittleLong(dds+16); + dds_height = BuffLittleLong(dds+12); + ddspixels = dds + 128; + + if(r_texture_dds_load_alphamode.integer == 0) + if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS + flags &= ~TEXF_ALPHA; + + //flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it! + if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32) + { + // very sloppy BGRA 32bit identification + textype = TEXTYPE_BGRA; + flags &= ~TEXF_COMPRESS; // don't let the textype be wrong + bytesperblock = 0; + bytesperpixel = 4; + size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(dds_width, dds_height), bytesperpixel); + if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize)) + { + Mem_Free(dds); + Con_Printf("^1%s: invalid BGRA DDS image\n", filename); + return NULL; + } + if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA)) + { + // check alpha + for (i = 3;i < size;i += 4) + if (ddspixels[i] < 255) + break; + if (i >= size) + flags &= ~TEXF_ALPHA; + } + } + else if (!memcmp(dds+84, "DXT1", 4)) + { + // we need to find out if this is DXT1 (opaque) or DXT1A (transparent) + // LordHavoc: it is my belief that this does not infringe on the + // patent because it is not decoding pixels... + textype = TEXTYPE_DXT1; + bytesperblock = 8; + bytesperpixel = 0; + //size = ((dds_width+3)/4)*((dds_height+3)/4)*bytesperblock; + size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock); + if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize)) + { + Mem_Free(dds); + Con_Printf("^1%s: invalid DXT1 DDS image\n", filename); + return NULL; + } + if (flags & TEXF_ALPHA) + { + if (r_texture_dds_load_alphamode.integer == 1) + { + // check alpha + for (i = 0;i < size;i += bytesperblock) + if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256) + { + // NOTE: this assumes sizeof(unsigned int) == 4 + unsigned int data = * (unsigned int *) &(ddspixels[i+4]); + // check if data, in base 4, contains a digit 3 (DXT1: transparent pixel) + if(data & (data<<1) & 0xAAAAAAAA)//rgh + break; + } + if (i < size) + textype = TEXTYPE_DXT1A; + else + flags &= ~TEXF_ALPHA; + } + else if (r_texture_dds_load_alphamode.integer == 0) + textype = TEXTYPE_DXT1A; + else + { + flags &= ~TEXF_ALPHA; + } + } + } + else if (!memcmp(dds+84, "DXT3", 4) || !memcmp(dds+84, "DXT2", 4)) + { + if(!memcmp(dds+84, "DXT2", 4)) + { + if(!(flags & TEXF_RGBMULTIPLYBYALPHA)) + { + Con_Printf("^1%s: expecting DXT3 image without premultiplied alpha, got DXT2 image with premultiplied alpha\n", filename); + } + } + else + { + if(flags & TEXF_RGBMULTIPLYBYALPHA) + { + Con_Printf("^1%s: expecting DXT2 image without premultiplied alpha, got DXT3 image without premultiplied alpha\n", filename); + } + } + textype = TEXTYPE_DXT3; + bytesperblock = 16; + bytesperpixel = 0; + size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock); + if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize)) + { + Mem_Free(dds); + Con_Printf("^1%s: invalid DXT3 DDS image\n", filename); + return NULL; + } + // we currently always assume alpha + } + else if (!memcmp(dds+84, "DXT5", 4) || !memcmp(dds+84, "DXT4", 4)) + { + if(!memcmp(dds+84, "DXT4", 4)) + { + if(!(flags & TEXF_RGBMULTIPLYBYALPHA)) + { + Con_Printf("^1%s: expecting DXT5 image without premultiplied alpha, got DXT4 image with premultiplied alpha\n", filename); + } + } + else + { + if(flags & TEXF_RGBMULTIPLYBYALPHA) + { + Con_Printf("^1%s: expecting DXT4 image without premultiplied alpha, got DXT5 image without premultiplied alpha\n", filename); + } + } + textype = TEXTYPE_DXT5; + bytesperblock = 16; + bytesperpixel = 0; + size = INTOVERFLOW_MUL(INTOVERFLOW_MUL(INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_width, 3), 4), INTOVERFLOW_DIV(INTOVERFLOW_ADD(dds_height, 3), 4)), bytesperblock); + if(INTOVERFLOW_ADD(128, size) > INTOVERFLOW_NORMALIZE(ddsfilesize)) + { + Mem_Free(dds); + Con_Printf("^1%s: invalid DXT5 DDS image\n", filename); + return NULL; + } + // we currently always assume alpha + } + else + { + Mem_Free(dds); + Con_Printf("^1%s: unrecognized/unsupported DDS format\n", filename); + return NULL; + } + + // when requesting a non-alpha texture and we have DXT3/5, convert to DXT1 + if(!(flags & TEXF_ALPHA) && (textype == TEXTYPE_DXT3 || textype == TEXTYPE_DXT5)) + { + textype = TEXTYPE_DXT1; + bytesperblock = 8; + ddssize -= 128; + ddssize /= 2; + for (i = 0;i < (int)ddssize;i += bytesperblock) + memcpy(&ddspixels[i], &ddspixels[(i<<1)+8], 8); + ddssize += 128; + } + + force_swdecode = false; + npothack = + (!vid.support.arb_texture_non_power_of_two && + ( + (dds_width & (dds_width - 1)) + || + (dds_height & (dds_height - 1)) + ) + ); + if(bytesperblock) + { + if(vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && !npothack) + { + if(r_texture_dds_swdecode.integer > 1) + force_swdecode = true; + } + else + { + if(r_texture_dds_swdecode.integer < 1) + { + // unsupported + Mem_Free(dds); + return NULL; + } + force_swdecode = true; + } + } + + // return whether this texture is transparent + if (hasalphaflag) + *hasalphaflag = (flags & TEXF_ALPHA) != 0; + + // if we SW decode, choose 2 sizes bigger + if(force_swdecode) + { + // this is quarter res, so do not scale down more than we have to + miplevel -= 2; + + if(miplevel < 0) + Con_DPrintf("WARNING: fake software decoding of compressed texture %s degraded quality\n", filename); + } + + // this is where we apply gl_picmip + mippixels_start = ddspixels; + mipwidth = dds_width; + mipheight = dds_height; + while(miplevel >= 1 && dds_miplevels >= 1) + { + if (mipwidth <= 1 && mipheight <= 1) + break; + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + mippixels_start += mipsize; // just skip + --dds_miplevels; + --miplevel; + if (mipwidth > 1) + mipwidth >>= 1; + if (mipheight > 1) + mipheight >>= 1; + } + mipsize_total = ddssize - 128 - (mippixels_start - ddspixels); + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + + // from here on, we do not need the ddspixels and ddssize any more (apart from the statistics entry in glt) + + // fake decode S3TC if needed + if(force_swdecode) + { + int mipsize_new = mipsize_total / bytesperblock * 4; + unsigned char *mipnewpixels = (unsigned char *) Mem_Alloc(tempmempool, mipsize_new); + unsigned char *p = mipnewpixels; + for (i = bytesperblock == 16 ? 8 : 0;i < (int)mipsize_total;i += bytesperblock, p += 4) + { + c = mippixels_start[i] + 256*mippixels_start[i+1] + 65536*mippixels_start[i+2] + 16777216*mippixels_start[i+3]; + p[2] = (((c >> 11) & 0x1F) + ((c >> 27) & 0x1F)) * (0.5f / 31.0f * 255.0f); + p[1] = (((c >> 5) & 0x3F) + ((c >> 21) & 0x3F)) * (0.5f / 63.0f * 255.0f); + p[0] = (((c ) & 0x1F) + ((c >> 16) & 0x1F)) * (0.5f / 31.0f * 255.0f); + if(textype == TEXTYPE_DXT5) + p[3] = (0.5 * mippixels_start[i-8] + 0.5 * mippixels_start[i-7]); + else if(textype == TEXTYPE_DXT3) + p[3] = ( + (mippixels_start[i-8] & 0x0F) + + (mippixels_start[i-8] >> 4) + + (mippixels_start[i-7] & 0x0F) + + (mippixels_start[i-7] >> 4) + + (mippixels_start[i-6] & 0x0F) + + (mippixels_start[i-6] >> 4) + + (mippixels_start[i-5] & 0x0F) + + (mippixels_start[i-5] >> 4) + ) * (0.125f / 15.0f * 255.0f); + else + p[3] = 255; + } + + textype = TEXTYPE_BGRA; + bytesperblock = 0; + bytesperpixel = 4; + + // as each block becomes a pixel, we must use pixel count for this + mipwidth = (mipwidth + 3) / 4; + mipheight = (mipheight + 3) / 4; + mipsize = bytesperpixel * mipwidth * mipheight; + mippixels_start = mipnewpixels; + mipsize_total = mipsize_new; + } + + // start mip counting + mippixels = mippixels_start; + + // calculate average color if requested + if (avgcolor) + { + float f; + Vector4Clear(avgcolor); + if (bytesperblock) + { + for (i = bytesperblock == 16 ? 8 : 0;i < mipsize;i += bytesperblock) + { + c = mippixels[i] + 256*mippixels[i+1] + 65536*mippixels[i+2] + 16777216*mippixels[i+3]; + avgcolor[0] += ((c >> 11) & 0x1F) + ((c >> 27) & 0x1F); + avgcolor[1] += ((c >> 5) & 0x3F) + ((c >> 21) & 0x3F); + avgcolor[2] += ((c ) & 0x1F) + ((c >> 16) & 0x1F); + if(textype == TEXTYPE_DXT5) + avgcolor[3] += (mippixels[i-8] + (int) mippixels[i-7]) * (0.5f / 255.0f); + else if(textype == TEXTYPE_DXT3) + avgcolor[3] += ( + (mippixels_start[i-8] & 0x0F) + + (mippixels_start[i-8] >> 4) + + (mippixels_start[i-7] & 0x0F) + + (mippixels_start[i-7] >> 4) + + (mippixels_start[i-6] & 0x0F) + + (mippixels_start[i-6] >> 4) + + (mippixels_start[i-5] & 0x0F) + + (mippixels_start[i-5] >> 4) + ) * (0.125f / 15.0f); + else + avgcolor[3] += 1.0f; + } + f = (float)bytesperblock / mipsize; + avgcolor[0] *= (0.5f / 31.0f) * f; + avgcolor[1] *= (0.5f / 63.0f) * f; + avgcolor[2] *= (0.5f / 31.0f) * f; + avgcolor[3] *= f; + } + else + { + for (i = 0;i < mipsize;i += 4) + { + avgcolor[0] += mippixels[i+2]; + avgcolor[1] += mippixels[i+1]; + avgcolor[2] += mippixels[i]; + avgcolor[3] += mippixels[i+3]; + } + f = (1.0f / 255.0f) * bytesperpixel / mipsize; + avgcolor[0] *= f; + avgcolor[1] *= f; + avgcolor[2] *= f; + avgcolor[3] *= f; + } + } + + // if we want sRGB, convert now + if(srgb) + { + if (vid.support.ext_texture_srgb) + { + switch(textype) + { + case TEXTYPE_DXT1: textype = TEXTYPE_SRGB_DXT1 ;break; + case TEXTYPE_DXT1A: textype = TEXTYPE_SRGB_DXT1A ;break; + case TEXTYPE_DXT3: textype = TEXTYPE_SRGB_DXT3 ;break; + case TEXTYPE_DXT5: textype = TEXTYPE_SRGB_DXT5 ;break; + case TEXTYPE_RGBA: textype = TEXTYPE_SRGB_RGBA ;break; + default: + break; + } + } + else + { + switch(textype) + { + case TEXTYPE_DXT1: + case TEXTYPE_DXT1A: + case TEXTYPE_DXT3: + case TEXTYPE_DXT5: + { + for (i = bytesperblock == 16 ? 8 : 0;i < mipsize_total;i += bytesperblock) + { + int c0, c1, c0new, c1new; + c0 = mippixels_start[i] + 256*mippixels_start[i+1]; + r = ((c0 >> 11) & 0x1F); + g = ((c0 >> 5) & 0x3F); + b = ((c0 ) & 0x1F); + r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + c0new = (r << 11) | (g << 5) | b; + c1 = mippixels_start[i+2] + 256*mippixels_start[i+3]; + r = ((c1 >> 11) & 0x1F); + g = ((c1 >> 5) & 0x3F); + b = ((c1 ) & 0x1F); + r = floor(Image_LinearFloatFromsRGB(r * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + g = floor(Image_LinearFloatFromsRGB(g * (255.0f / 63.0f)) * 63.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + b = floor(Image_LinearFloatFromsRGB(b * (255.0f / 31.0f)) * 31.0f + 0.5f); // these multiplications here get combined with multiplications in Image_LinearFloatFromsRGB + c1new = (r << 11) | (g << 5) | b; + // swap the colors if needed to fix order + if(c0 > c1) // thirds + { + if(c0new < c1new) + { + c = c0new; + c0new = c1new; + c1new = c; + if(c0new == c1new) + mippixels_start[i+4] ^= 0x55; + mippixels_start[i+5] ^= 0x55; + mippixels_start[i+6] ^= 0x55; + mippixels_start[i+7] ^= 0x55; + } + else if(c0new == c1new) + { + mippixels_start[i+4] = 0x00; + mippixels_start[i+5] = 0x00; + mippixels_start[i+6] = 0x00; + mippixels_start[i+7] = 0x00; + } + } + else // half + transparent + { + if(c0new > c1new) + { + c = c0new; + c0new = c1new; + c1new = c; + mippixels_start[i+4] ^= (~mippixels_start[i+4] >> 1) & 0x55; + mippixels_start[i+5] ^= (~mippixels_start[i+5] >> 1) & 0x55; + mippixels_start[i+6] ^= (~mippixels_start[i+6] >> 1) & 0x55; + mippixels_start[i+7] ^= (~mippixels_start[i+7] >> 1) & 0x55; + } + } + mippixels_start[i] = c0new & 255; + mippixels_start[i+1] = c0new >> 8; + mippixels_start[i+2] = c1new & 255; + mippixels_start[i+3] = c1new >> 8; + } + } + break; + case TEXTYPE_RGBA: + Image_MakeLinearColorsFromsRGB(mippixels, mippixels, mipsize_total / bytesperblock); + break; + default: + break; + } + } + } + + // when not requesting mipmaps, do not load them + if(!(flags & TEXF_MIPMAP)) + dds_miplevels = 0; + + if (dds_miplevels >= 1) + flags |= TEXF_MIPMAP; + else + flags &= ~TEXF_MIPMAP; + + texinfo = R_GetTexTypeInfo(textype, flags); + + glt = (gltexture_t *)Mem_ExpandableArray_AllocRecord(&texturearray); + strlcpy (glt->identifier, filename, sizeof(glt->identifier)); + glt->pool = pool; + glt->chain = pool->gltchain; + pool->gltchain = glt; + glt->inputwidth = mipwidth; + glt->inputheight = mipheight; + glt->inputdepth = 1; + glt->flags = flags; + glt->textype = texinfo; + glt->texturetype = GLTEXTURETYPE_2D; + glt->inputdatasize = ddssize; + glt->glinternalformat = texinfo->glinternalformat; + glt->glformat = texinfo->glformat; + glt->gltype = texinfo->gltype; + glt->bytesperpixel = texinfo->internalbytesperpixel; + glt->sides = 1; + glt->gltexturetypeenum = gltexturetypeenums[glt->texturetype]; + glt->tilewidth = mipwidth; + glt->tileheight = mipheight; + glt->tiledepth = 1; + glt->miplevels = dds_miplevels; + + if(npothack) + { + for (glt->tilewidth = 1;glt->tilewidth < mipwidth;glt->tilewidth <<= 1); + for (glt->tileheight = 1;glt->tileheight < mipheight;glt->tileheight <<= 1); + } + + // texture uploading can take a while, so make sure we're sending keepalives + CL_KeepaliveMessage(false); + + // create the texture object + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + CHECKGLERROR + GL_ActiveTexture(0); + oldbindtexnum = R_Mesh_TexBound(0, gltexturetypeenums[glt->texturetype]); + qglGenTextures(1, (GLuint *)&glt->texnum);CHECKGLERROR + qglBindTexture(gltexturetypeenums[glt->texturetype], glt->texnum);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DFORMAT d3dformat; + D3DPOOL d3dpool; + DWORD d3dusage; + switch(textype) + { + case TEXTYPE_BGRA: d3dformat = (flags & TEXF_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8;break; + case TEXTYPE_DXT1: case TEXTYPE_DXT1A: d3dformat = D3DFMT_DXT1;break; + case TEXTYPE_DXT3: d3dformat = D3DFMT_DXT3;break; + case TEXTYPE_DXT5: d3dformat = D3DFMT_DXT5;break; + default: d3dformat = D3DFMT_A8R8G8B8;Host_Error("R_LoadTextureDDSFile: unsupported texture type %i when picking D3DFMT", (int)textype);break; + } + d3dusage = 0; + d3dpool = D3DPOOL_MANAGED; + IDirect3DDevice9_CreateTexture(vid_d3d9dev, glt->tilewidth, glt->tileheight, glt->miplevels, d3dusage, d3dformat, d3dpool, (IDirect3DTexture9 **)&glt->d3dtexture, NULL); + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + glt->texnum = DPSOFTRAST_Texture_New(((glt->flags & TEXF_CLAMP) ? DPSOFTRAST_TEXTURE_FLAG_CLAMPTOEDGE : 0) | (dds_miplevels > 1 ? DPSOFTRAST_TEXTURE_FLAG_MIPMAP : 0), glt->tilewidth, glt->tileheight, glt->tiledepth); + break; + } + + // upload the texture + // we need to restore the texture binding after finishing the upload + mipcomplete = false; + + for (mip = 0;mip <= dds_miplevels;mip++) // <= to include the not-counted "largest" miplevel + { + unsigned char *upload_mippixels = mippixels; + int upload_mipwidth = mipwidth; + int upload_mipheight = mipheight; + mipsize = bytesperblock ? ((mipwidth+3)/4)*((mipheight+3)/4)*bytesperblock : mipwidth*mipheight*bytesperpixel; + if (mippixels + mipsize > mippixels_start + mipsize_total) + break; + if(npothack) + { + upload_mipwidth = (glt->tilewidth >> mip); + upload_mipheight = (glt->tileheight >> mip); + if(upload_mipwidth != mipwidth || upload_mipheight != mipheight) + // I _think_ they always mismatch, but I was too lazy + // to properly check, and this test here is really + // harmless + { + upload_mippixels = (unsigned char *) Mem_Alloc(tempmempool, 4 * upload_mipwidth * upload_mipheight); + Image_Resample32(mippixels, mipwidth, mipheight, 1, upload_mippixels, upload_mipwidth, upload_mipheight, 1, r_lerpimages.integer); + } + } + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + if (bytesperblock) + { + qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, mipsize, upload_mippixels);CHECKGLERROR + } + else + { + qglTexImage2D(GL_TEXTURE_2D, mip, glt->glinternalformat, upload_mipwidth, upload_mipheight, 0, glt->glformat, glt->gltype, upload_mippixels);CHECKGLERROR + } + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + { + D3DLOCKED_RECT d3dlockedrect; + if (IDirect3DTexture9_LockRect((IDirect3DTexture9*)glt->d3dtexture, mip, &d3dlockedrect, NULL, 0) == D3D_OK && d3dlockedrect.pBits) + { + memcpy(d3dlockedrect.pBits, upload_mippixels, mipsize); + IDirect3DTexture9_UnlockRect((IDirect3DTexture9*)glt->d3dtexture, mip); + } + break; + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (bytesperblock) + Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + else + DPSOFTRAST_Texture_UpdateFull(glt->texnum, upload_mippixels); + // DPSOFTRAST calculates its own mipmaps + mip = dds_miplevels; + break; + } + if(upload_mippixels != mippixels) + Mem_Free(upload_mippixels); + mippixels += mipsize; + if (mipwidth <= 1 && mipheight <= 1) + { + mipcomplete = true; + break; + } + if (mipwidth > 1) + mipwidth >>= 1; + if (mipheight > 1) + mipheight >>= 1; + } + + // after upload we have to set some parameters... + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef GL_TEXTURE_MAX_LEVEL + if (dds_miplevels >= 1 && !mipcomplete) + { + // need to set GL_TEXTURE_MAX_LEVEL + qglTexParameteri(gltexturetypeenums[glt->texturetype], GL_TEXTURE_MAX_LEVEL, dds_miplevels - 1);CHECKGLERROR + } +#endif + GL_SetupTextureParameters(glt->flags, glt->textype->textype, glt->texturetype); + qglBindTexture(gltexturetypeenums[glt->texturetype], oldbindtexnum);CHECKGLERROR + break; + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + glt->d3daddressw = 0; + if (glt->flags & TEXF_CLAMP) + { + glt->d3daddressu = D3DTADDRESS_CLAMP; + glt->d3daddressv = D3DTADDRESS_CLAMP; + if (glt->tiledepth > 1) + glt->d3daddressw = D3DTADDRESS_CLAMP; + } + else + { + glt->d3daddressu = D3DTADDRESS_WRAP; + glt->d3daddressv = D3DTADDRESS_WRAP; + if (glt->tiledepth > 1) + glt->d3daddressw = D3DTADDRESS_WRAP; + } + glt->d3dmipmaplodbias = 0; + glt->d3dmaxmiplevel = 0; + glt->d3dmaxmiplevelfilter = 0; + if (glt->flags & TEXF_MIPMAP) + { + glt->d3dminfilter = d3d_filter_mipmin; + glt->d3dmagfilter = d3d_filter_mipmag; + glt->d3dmipfilter = d3d_filter_mipmix; + } + else + { + glt->d3dminfilter = d3d_filter_flatmin; + glt->d3dmagfilter = d3d_filter_flatmag; + glt->d3dmipfilter = d3d_filter_flatmix; + } +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + if (glt->flags & TEXF_FORCELINEAR) + DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_LINEAR); + else if (glt->flags & TEXF_FORCENEAREST) + DPSOFTRAST_Texture_Filter(glt->texnum, DPSOFTRAST_TEXTURE_FILTER_NEAREST); + else if (glt->flags & TEXF_MIPMAP) + DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_mipmap); + else + DPSOFTRAST_Texture_Filter(glt->texnum, dpsoftrast_filter_nomipmap); + break; + } + + Mem_Free(dds); + if(force_swdecode) + Mem_Free((unsigned char *) mippixels_start); + return (rtexture_t *)glt; +} + +int R_TextureWidth(rtexture_t *rt) +{ + return rt ? ((gltexture_t *)rt)->inputwidth : 0; +} + +int R_TextureHeight(rtexture_t *rt) +{ + return rt ? ((gltexture_t *)rt)->inputheight : 0; +} + +int R_TextureFlags(rtexture_t *rt) +{ + return rt ? ((gltexture_t *)rt)->flags : 0; +} + +void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth) +{ + gltexture_t *glt = (gltexture_t *)rt; + if (data == NULL) + Host_Error("R_UpdateTexture: no data supplied"); + if (glt == NULL) + Host_Error("R_UpdateTexture: no texture supplied"); + if (!glt->texnum && !glt->d3dtexture) + { + Con_DPrintf("R_UpdateTexture: texture %p \"%s\" in pool %p has not been uploaded yet\n", (void *)glt, glt->identifier, (void *)glt->pool); + return; + } + // update part of the texture + if (glt->bufferpixels) + { + int j; + int bpp = glt->bytesperpixel; + int inputskip = width*bpp; + int outputskip = glt->tilewidth*bpp; + const unsigned char *input = data; + unsigned char *output = glt->bufferpixels; + if (glt->inputdepth != 1 || glt->sides != 1) + Sys_Error("R_UpdateTexture on buffered texture that is not 2D\n"); + if (x < 0) + { + width += x; + input -= x*bpp; + x = 0; + } + if (y < 0) + { + height += y; + input -= y*inputskip; + y = 0; + } + if (width > glt->tilewidth - x) + width = glt->tilewidth - x; + if (height > glt->tileheight - y) + height = glt->tileheight - y; + if (width < 1 || height < 1) + return; + glt->dirty = true; + glt->buffermodified = true; + output += y*outputskip + x*bpp; + for (j = 0;j < height;j++, output += outputskip, input += inputskip) + memcpy(output, input, width*bpp); + } + else if (x || y || z || width != glt->inputwidth || height != glt->inputheight || depth != glt->inputdepth) + R_UploadPartialTexture(glt, data, x, y, z, width, height, depth); + else + R_UploadFullTexture(glt, data); +} + +int R_RealGetTexture(rtexture_t *rt) +{ + if (rt) + { + gltexture_t *glt; + glt = (gltexture_t *)rt; + if (glt->flags & GLTEXF_DYNAMIC) + R_UpdateDynamicTexture(glt); + if (glt->buffermodified && glt->bufferpixels) + { + glt->buffermodified = false; + R_UploadFullTexture(glt, glt->bufferpixels); + } + glt->dirty = false; + return glt->texnum; + } + else + return 0; +} + +void R_ClearTexture (rtexture_t *rt) +{ + gltexture_t *glt = (gltexture_t *)rt; + + R_UploadFullTexture(glt, NULL); +} + +int R_PicmipForFlags(int flags) +{ + int miplevel = 0; + if(flags & TEXF_PICMIP) + { + miplevel += gl_picmip.integer; + if (flags & TEXF_ISWORLD) + { + if (r_picmipworld.integer) + miplevel += gl_picmip_world.integer; + else + miplevel = 0; + } + else if (flags & TEXF_ISSPRITE) + { + if (r_picmipsprites.integer) + miplevel += gl_picmip_sprites.integer; + else + miplevel = 0; + } + else + miplevel += gl_picmip_other.integer; + } + return max(0, miplevel); +} diff --git a/app/jni/glquake.h b/app/jni/glquake.h new file mode 100644 index 0000000..4b68d27 --- /dev/null +++ b/app/jni/glquake.h @@ -0,0 +1,1347 @@ +/* +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_H +#define GLQUAKE_H + +#ifdef USE_GLES2 +#ifdef __IPHONEOS__ +#include +#else +#include +#include +//Hack to avoid compile errors and don't break the code +#define GL_STEREO 0x0000 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_BGRA 0x000080e1 +//#include +#endif +// used in R_SetupShader_Generic calls, not actually passed to GL +#ifndef GL_MODULATE +#define GL_MODULATE 0x2100 +#define GL_DECAL 0x2101 +#define GL_ADD 0x0104 +#endif +#endif + +// disable data conversion warnings + +#ifdef _MSC_VER +#pragma warning(disable : 4310) // LordHavoc: MSVC++ 2008 x86: cast truncates constant value +#pragma warning(disable : 4245) // LordHavoc: MSVC++ 2008 x86: 'initializing' : conversion from 'int' to 'unsigned char', signed/unsigned mismatch +#pragma warning(disable : 4204) // LordHavoc: MSVC++ 2008 x86: nonstandard extension used : non-constant aggregate initializer +#pragma warning(disable : 4267) // LordHavoc: MSVC++ 2008 x64, conversion from 'size_t' to 'int', possible loss of data +//#pragma warning(disable : 4244) // LordHavoc: MSVC++ 4 x86, double/float +//#pragma warning(disable : 4305) // LordHavoc: MSVC++ 6 x86, double/float +//#pragma warning(disable : 4706) // LordHavoc: MSVC++ 2008 x86, assignment within conditional expression +//#pragma warning(disable : 4127) // LordHavoc: MSVC++ 2008 x86, conditional expression is constant +//#pragma warning(disable : 4100) // LordHavoc: MSVC++ 2008 x86, unreferenced formal parameter +//#pragma warning(disable : 4055) // LordHavoc: MSVC++ 2008 x86, 'type cast' from data pointer to function pointer +//#pragma warning(disable : 4054) // LordHavoc: MSVC++ 2008 x86, 'type cast' from function pointer to data pointer +#endif + + +//==================================================== + +#ifndef USE_GLES2 +// wgl uses APIENTRY +#ifndef APIENTRY +#define APIENTRY +#endif + +// for platforms (wgl) that do not use GLAPIENTRY +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifndef GL_PROJECTION +#include + +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +// 1-byte signed +typedef signed char GLbyte; +// 2-byte signed +typedef short GLshort; +// 4-byte signed +typedef int GLint; +// 1-byte unsigned +typedef unsigned char GLubyte; +// 2-byte unsigned +typedef unsigned short GLushort; +// 4-byte unsigned +typedef unsigned int GLuint; +// 4-byte signed +typedef int GLsizei; +// single precision float +typedef float GLfloat; +// single precision float in [0,1] +typedef float GLclampf; +// double precision float +typedef double GLdouble; +// double precision float in [0,1] +typedef double GLclampd; +// int whose size is the same as a pointer (?) +typedef ptrdiff_t GLintptrARB; +// int whose size is the same as a pointer (?) +typedef ptrdiff_t GLsizeiptrARB; + +#define GL_STEREO 0x0C33 + +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_TEXTURE_MATRIX 0x0BA8 + +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 + +#define GL_DEPTH_TEST 0x0B71 + +#define GL_CULL_FACE 0x0B44 + +#define GL_BLEND 0x0BE2 +#define GL_ALPHA_TEST 0x0BC0 + +#define GL_ZERO 0x0 +#define GL_ONE 0x1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 + +#define GL_TEXTURE_ENV 0x2300 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D + +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 + +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 + +#define GL_ADD 0x0104 +#define GL_DECAL 0x2101 +#define GL_MODULATE 0x2100 + +#define GL_REPEAT 0x2901 +#define GL_CLAMP 0x2900 + +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 + +#define GL_FALSE 0x0 +#define GL_TRUE 0x1 + +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 + +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +//#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +//#define GL_EDGE_FLAG_ARRAY 0x8079 + +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C + +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + +#define GL_NO_ERROR 0x0 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 + +#define GL_DITHER 0x0BD0 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 + +#define GL_MAX_TEXTURE_SIZE 0x0D33 + +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_DEPTH_TEST 0x0B71 + +#define GL_RED_SCALE 0x0D14 +#define GL_GREEN_SCALE 0x0D18 +#define GL_BLUE_SCALE 0x0D1A +#define GL_ALPHA_SCALE 0x0D1C + +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 + +#define GL_STENCIL_TEST 0x0B90 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 + +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 + +#define GL_POINT_SMOOTH 0x0B10 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_POLYGON_SMOOTH 0x0B41 + +#define GL_POLYGON_STIPPLE 0x0B42 + +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 + +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_VIEWPORT 0x0BA2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_LUMINANCE 0x1909 +#define GL_INTENSITY 0x8049 + +#endif + +//GL_EXT_texture_filter_anisotropic +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +// GL_ARB_depth_texture +#ifndef GL_DEPTH_COMPONENT32_ARB +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif + +// GL_ARB_shadow +#ifndef GL_TEXTURE_COMPARE_MODE_ARB +#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#endif + +// GL_ARB_multitexture +extern void qglMultiTexCoord1f(GLenum, GLfloat); +extern void qglMultiTexCoord2f(GLenum, GLfloat, GLfloat); +extern void qglMultiTexCoord3f(GLenum, GLfloat, GLfloat, GLfloat); +extern void qglMultiTexCoord4f(GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +extern void qglClientActiveTexture(GLenum); +#ifndef GL_ACTIVE_TEXTURE +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#endif + +// GL_ARB_texture_env_combine +#ifndef GL_COMBINE +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#endif + +#ifndef GL_MAX_ELEMENTS_VERTICES +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#endif +#ifndef GL_MAX_ELEMENTS_INDICES +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#endif + + +#ifndef GL_TEXTURE_3D +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_TEXTURE_BINDING_3D 0x806A +extern void qglTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void qglTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +extern void qglCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif + +#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#endif + +#ifndef GL_DEPTH_COMPONENT16_ARB +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif + +#ifndef GL_SCISSOR_TEST +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SCISSOR_BOX 0x0C10 +#endif + +// GL_SGIS_texture_edge_clamp or GL_EXT_texture_edge_clamp +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif + +//GL_ATI_separate_stencil +#ifndef GL_STENCIL_BACK_FUNC +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#endif +extern void qglStencilOpSeparate(GLenum, GLenum, GLenum, GLenum); +extern void qglStencilFuncSeparate(GLenum, GLenum, GLint, GLuint); + +//GL_EXT_stencil_two_side +#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +extern void qglActiveStencilFaceEXT(GLenum); + +//GL_EXT_blend_minmax +#ifndef GL_FUNC_ADD +#define GL_FUNC_ADD 0x8006 // also supplied by GL_blend_subtract +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BLEND_EQUATION 0x8009 // also supplied by GL_blend_subtract +extern void qglBlendEquationEXT(GLenum); // also supplied by GL_blend_subtract +#endif + +//GL_EXT_blend_subtract +#ifndef GL_FUNC_SUBTRACT +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +extern void qglBlendEquationEXT(GLenum); // also supplied by GL_blend_subtract +#endif + +//GL_ARB_texture_non_power_of_two + +//GL_ARB_vertex_buffer_object +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#endif +extern void qglBindBufferARB(GLenum target, GLuint buffer); +extern void qglDeleteBuffersARB(GLsizei n, const GLuint *buffers); +extern void qglGenBuffersARB(GLsizei n, GLuint *buffers); +extern GLboolean qglIsBufferARB(GLuint buffer); +extern GLvoid qglMapBufferARB(GLenum target, GLenum access); +extern GLboolean qglUnmapBufferARB(GLenum target); +extern void qglBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +extern void qglBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + +//GL_ARB_framebuffer_object +// (slight differences from GL_EXT_framebuffer_object as this integrates GL_EXT_packed_depth_stencil) +#ifndef GL_FRAMEBUFFER +#define GL_FRAMEBUFFER 0x8D40 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_RENDERBUFFER 0x8D41 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_SRGB 0x8C40 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_INDEX 0x8222 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_SAMPLES 0x8D57 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 // alias DRAW_FRAMEBUFFER_BINDING +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#endif +extern GLboolean qglIsRenderbuffer(GLuint renderbuffer); +extern GLvoid qglBindRenderbuffer(GLenum target, GLuint renderbuffer); +extern GLvoid qglDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); +extern GLvoid qglGenRenderbuffers(GLsizei n, GLuint *renderbuffers); +extern GLvoid qglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +extern GLvoid qglRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +extern GLvoid qglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params); +extern GLboolean qglIsFramebuffer(GLuint framebuffer); +extern GLvoid qglBindFramebuffer(GLenum target, GLuint framebuffer); +extern GLvoid qglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers); +extern GLvoid qglGenFramebuffers(GLsizei n, GLuint *framebuffers); +extern GLenum qglCheckFramebufferStatus(GLenum target); +extern GLvoid qglFramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +extern GLvoid qglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +extern GLvoid qglFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer); +extern GLvoid qglFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +extern GLvoid qglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +extern GLvoid qglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params); +extern GLvoid qglBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +extern GLvoid qglGenerateMipmap(GLenum target); + +// GL_ARB_draw_buffers +#ifndef GL_MAX_DRAW_BUFFERS_ARB +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +#endif +extern void qglDrawBuffersARB(GLsizei n, const GLenum *bufs); + +// GL_ARB_texture_float +#ifndef GL_RGBA32F_ARB +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif + +// GL_EXT_texture_sRGB +#ifndef GL_SRGB_EXT +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif + +// GL_ARB_uniform_buffer_object +#ifndef GL_UNIFORM_BUFFER +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +#endif +extern void qglGetUniformIndices(GLuint program, GLsizei uniformCount, const char** uniformNames, GLuint* uniformIndices); +extern void qglGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +extern void qglGetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, char* uniformName); +extern GLuint qglGetUniformBlockIndex(GLuint program, const char* uniformBlockName); +extern void qglGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +extern void qglGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, char* uniformBlockName); +extern void qglBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptrARB offset, GLsizeiptrARB size); +extern void qglBindBufferBase(GLenum target, GLuint index, GLuint buffer); +extern void qglGetIntegeri_v(GLenum target, GLuint index, GLint* data); +extern void qglUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + +extern void qglScissor(GLint x, GLint y, GLsizei width, GLsizei height); + +extern void qglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + +extern void qglClear(GLbitfield mask); + +extern void qglAlphaFunc(GLenum func, GLclampf ref); +extern void qglBlendFunc(GLenum sfactor, GLenum dfactor); +extern void qglCullFace(GLenum mode); + +extern void qglDrawBuffer(GLenum mode); +extern void qglReadBuffer(GLenum mode); +extern void qglEnable(GLenum cap); +extern void qglDisable(GLenum cap); +extern GLboolean qglIsEnabled(GLenum cap); + +extern void qglEnableClientState(GLenum cap); +extern void qglDisableClientState(GLenum cap); + +extern void qglGetBooleanv(GLenum pname, GLboolean *params); +extern void qglGetDoublev(GLenum pname, GLdouble *params); +extern void qglGetFloatv(GLenum pname, GLfloat *params); +extern void qglGetIntegerv(GLenum pname, GLint *params); + +extern GLenum qglGetError(void); +extern const GLubyte* qglGetString(GLenum name); +extern void qglFinish(void); +extern void qglFlush(void); + +extern void qglClearDepth(GLclampd depth); +extern void qglDepthFunc(GLenum func); +extern void qglDepthMask(GLboolean flag); +extern void qglDepthRange(GLclampd near_val, GLclampd far_val); +extern void qglDepthRangef(GLclampf near_val, GLclampf far_val); +extern void qglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + +extern void qglDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +extern void qglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +extern void qglDrawArrays(GLenum mode, GLint first, GLsizei count); +extern void qglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +extern void qglNormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr); +extern void qglColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +extern void qglTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +extern void qglArrayElement(GLint i); + +extern void qglColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +extern void qglColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +extern void qglTexCoord1f(GLfloat s); +extern void qglTexCoord2f(GLfloat s, GLfloat t); +extern void qglTexCoord3f(GLfloat s, GLfloat t, GLfloat r); +extern void qglTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +extern void qglVertex2f(GLfloat x, GLfloat y); +extern void qglVertex3f(GLfloat x, GLfloat y, GLfloat z); +extern void qglVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +extern void qglBegin(GLenum mode); +extern void qglEnd(void); + +extern void qglMatrixMode(GLenum mode); +//extern void qglOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +//extern void qglFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +extern void qglViewport(GLint x, GLint y, GLsizei width, GLsizei height); +//extern void qglPushMatrix(void); +//extern void qglPopMatrix(void); +extern void qglLoadIdentity(void); +//extern void qglLoadMatrixd)(const GLdouble *m); +extern void qglLoadMatrixf(const GLfloat *m); +//extern void qglMultMatrixd)(const GLdouble *m); +//extern void qglMultMatrixf)(const GLfloat *m); +//extern void qglRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +//extern void qglRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +//extern void qglScaled(GLdouble x, GLdouble y, GLdouble z); +//extern void qglScalef(GLfloat x, GLfloat y, GLfloat z); +//extern void qglTranslated(GLdouble x, GLdouble y, GLdouble z); +//extern void qglTranslatef(GLfloat x, GLfloat y, GLfloat z); + +extern void qglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); + +extern void qglStencilFunc(GLenum func, GLint ref, GLuint mask); +extern void qglStencilMask(GLuint mask); +extern void qglStencilOp(GLenum fail, GLenum zfail, GLenum zpass); +extern void qglClearStencil(GLint s); + +extern void qglTexEnvf(GLenum target, GLenum pname, GLfloat param); +extern void qglTexEnvfv(GLenum target, GLenum pname, const GLfloat *params); +extern void qglTexEnvi(GLenum target, GLenum pname, GLint param); +extern void qglTexParameterf(GLenum target, GLenum pname, GLfloat param); +extern void qglTexParameterfv(GLenum target, GLenum pname, GLfloat *params); +extern void qglTexParameteri(GLenum target, GLenum pname, GLint param); +extern void qglGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); +extern void qglGetTexParameteriv(GLenum target, GLenum pname, GLint *params); +extern void qglGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params); +extern void qglGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params); +extern void qglGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +extern void qglHint(GLenum target, GLenum mode); + +extern void qglGenTextures(GLsizei n, GLuint *textures); +extern void qglDeleteTextures(GLsizei n, const GLuint *textures); +extern void qglBindTexture(GLenum target, GLuint texture); +//extern void qglPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities); +//extern GLboolean qglAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences); +//extern GLboolean qglIsTexture(GLuint texture); +//extern void qglPixelStoref(GLenum pname, GLfloat param); +extern void qglPixelStorei(GLenum pname, GLint param); + +//extern void qglTexImage1D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +extern void qglTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +//extern void qglTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +extern void qglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +//extern void qglCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +extern void qglCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +//extern void qglCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +extern void qglCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + +extern void qglPolygonOffset(GLfloat factor, GLfloat units); +extern void qglPolygonMode(GLenum face, GLenum mode); + +//extern void qglClipPlane(GLenum plane, const GLdouble *equation); +//extern void qglGetClipPlane(GLenum plane, GLdouble *equation); + +//[515]: added on 29.07.2005 +extern void qglLineWidth(GLfloat width); +extern void qglPointSize(GLfloat size); + +// GL 2.0 shader objects +#ifndef GL_PROGRAM_OBJECT +// 1-byte character string +typedef char GLchar; +#endif +extern void qglDeleteShader(GLuint obj); +extern void qglDeleteProgram(GLuint obj); +//extern GLuint qglGetHandle(GLenum pname); +extern void qglDetachShader(GLuint containerObj, GLuint attachedObj); +extern GLuint qglCreateShader(GLenum shaderType); +extern void qglShaderSource(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length); +extern void qglCompileShader(GLuint shaderObj); +extern GLuint qglCreateProgram(void); +extern void qglAttachShader(GLuint containerObj, GLuint obj); +extern void qglLinkProgram(GLuint programObj); +extern void qglUseProgram(GLuint programObj); +extern void qglValidateProgram(GLuint programObj); +extern void qglUniform1f(GLint location, GLfloat v0); +extern void qglUniform2f(GLint location, GLfloat v0, GLfloat v1); +extern void qglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +extern void qglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +extern void qglUniform1i(GLint location, GLint v0); +extern void qglUniform2i(GLint location, GLint v0, GLint v1); +extern void qglUniform3i(GLint location, GLint v0, GLint v1, GLint v2); +extern void qglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +extern void qglUniform1fv(GLint location, GLsizei count, const GLfloat *value); +extern void qglUniform2fv(GLint location, GLsizei count, const GLfloat *value); +extern void qglUniform3fv(GLint location, GLsizei count, const GLfloat *value); +extern void qglUniform4fv(GLint location, GLsizei count, const GLfloat *value); +extern void qglUniform1iv(GLint location, GLsizei count, const GLint *value); +extern void qglUniform2iv(GLint location, GLsizei count, const GLint *value); +extern void qglUniform3iv(GLint location, GLsizei count, const GLint *value); +extern void qglUniform4iv(GLint location, GLsizei count, const GLint *value); +extern void qglUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +extern void qglUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +extern void qglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +extern void qglGetShaderiv(GLuint obj, GLenum pname, GLint *params); +extern void qglGetProgramiv(GLuint obj, GLenum pname, GLint *params); +extern void qglGetShaderInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog); +extern void qglGetProgramInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog); +extern void qglGetAttachedShaders(GLuint containerObj, GLsizei maxCount, GLsizei *count, GLuint *obj); +extern GLint qglGetUniformLocation(GLuint programObj, const GLchar *name); +extern void qglGetActiveUniform(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +extern void qglGetUniformfv(GLuint programObj, GLint location, GLfloat *params); +extern void qglGetUniformiv(GLuint programObj, GLint location, GLint *params); +extern void qglGetShaderSource(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *source); +extern void qglPolygonStipple(const GLubyte *mask); +#ifndef GL_PROGRAM_OBJECT +#define GL_PROGRAM_OBJECT 0x8B40 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_OBJECT 0x8B48 +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT 0x1406 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT 0x1404 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#endif + +// GL 2.0 vertex shader +extern void qglVertexAttrib1f(GLuint index, GLfloat v0); +extern void qglVertexAttrib1s(GLuint index, GLshort v0); +extern void qglVertexAttrib1d(GLuint index, GLdouble v0); +extern void qglVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1); +extern void qglVertexAttrib2s(GLuint index, GLshort v0, GLshort v1); +extern void qglVertexAttrib2d(GLuint index, GLdouble v0, GLdouble v1); +extern void qglVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2); +extern void qglVertexAttrib3s(GLuint index, GLshort v0, GLshort v1, GLshort v2); +extern void qglVertexAttrib3d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2); +extern void qglVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +extern void qglVertexAttrib4s(GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3); +extern void qglVertexAttrib4d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +extern void qglVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +extern void qglVertexAttrib1fv(GLuint index, const GLfloat *v); +extern void qglVertexAttrib1sv(GLuint index, const GLshort *v); +extern void qglVertexAttrib1dv(GLuint index, const GLdouble *v); +extern void qglVertexAttrib2fv(GLuint index, const GLfloat *v); +extern void qglVertexAttrib2sv(GLuint index, const GLshort *v); +extern void qglVertexAttrib2dv(GLuint index, const GLdouble *v); +extern void qglVertexAttrib3fv(GLuint index, const GLfloat *v); +extern void qglVertexAttrib3sv(GLuint index, const GLshort *v); +extern void qglVertexAttrib3dv(GLuint index, const GLdouble *v); +extern void qglVertexAttrib4fv(GLuint index, const GLfloat *v); +extern void qglVertexAttrib4sv(GLuint index, const GLshort *v); +extern void qglVertexAttrib4dv(GLuint index, const GLdouble *v); +extern void qglVertexAttrib4iv(GLuint index, const GLint *v); +extern void qglVertexAttrib4bv(GLuint index, const GLbyte *v); +extern void qglVertexAttrib4ubv(GLuint index, const GLubyte *v); +extern void qglVertexAttrib4usv(GLuint index, const GLushort *v); +extern void qglVertexAttrib4uiv(GLuint index, const GLuint *v); +extern void qglVertexAttrib4Nbv(GLuint index, const GLbyte *v); +extern void qglVertexAttrib4Nsv(GLuint index, const GLshort *v); +extern void qglVertexAttrib4Niv(GLuint index, const GLint *v); +extern void qglVertexAttrib4Nubv(GLuint index, const GLubyte *v); +extern void qglVertexAttrib4Nusv(GLuint index, const GLushort *v); +extern void qglVertexAttrib4Nuiv(GLuint index, const GLuint *v); +extern void qglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +extern void qglEnableVertexAttribArray(GLuint index); +extern void qglDisableVertexAttribArray(GLuint index); +extern void qglBindAttribLocation(GLuint programObj, GLuint index, const GLchar *name); +extern void qglBindFragDataLocation(GLuint programObj, GLuint index, const GLchar *name); +extern void qglGetActiveAttrib(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +extern GLint qglGetAttribLocation(GLuint programObj, const GLchar *name); +extern void qglGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params); +extern void qglGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); +extern void qglGetVertexAttribiv(GLuint index, GLenum pname, GLint *params); +extern void qglGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer); +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_FLOAT 0x1406 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#endif + +// GL 2.0 fragment shader +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#endif + +// GL 2.0 shading language 100 +#ifndef GL_SHADING_LANGUAGE_VERSION +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#endif + +// GL_ARB_texture_compression +extern void qglCompressedTexImage3DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +extern void qglCompressedTexImage2DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +//extern void qglCompressedTexImage1DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +extern void qglCompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +extern void qglCompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +//extern void qglCompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +extern void qglGetCompressedTexImageARB(GLenum target, GLint lod, void *img); +#ifndef GL_COMPRESSED_RGB_ARB +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +#endif + +// GL_EXT_texture_compression_s3tc +#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + +// GL_ARB_occlusion_query +extern void qglGenQueriesARB(GLsizei n, GLuint *ids); +extern void qglDeleteQueriesARB(GLsizei n, const GLuint *ids); +extern GLboolean qglIsQueryARB(GLuint qid); +extern void qglBeginQueryARB(GLenum target, GLuint qid); +extern void qglEndQueryARB(GLenum target); +extern void qglGetQueryivARB(GLenum target, GLenum pname, GLint *params); +extern void qglGetQueryObjectivARB(GLuint qid, GLenum pname, GLint *params); +extern void qglGetQueryObjectuivARB(GLuint qid, GLenum pname, GLuint *params); +#ifndef GL_SAMPLES_PASSED_ARB +#define GL_SAMPLES_PASSED_ARB 0x8914 +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#endif + +// GL_EXT_bgr +#define GL_BGR 0x80E0 + +// GL_EXT_bgra +#define GL_BGRA 0x80E1 + +//GL_AMD_texture_texture4 + +//GL_ARB_texture_gather + +//GL_ARB_multisample +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +extern void qglSampleCoverageARB(GLclampf value, GLboolean invert); + +extern void qglPointSize(GLfloat size); + +//GL_EXT_packed_depth_stencil +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 + +#endif + +#define DEBUGGL + +#ifdef DEBUGGL +#ifdef USE_GLES2 +#define CHECKGLERROR {if (gl_paranoid.integer){if (gl_printcheckerror.integer) Con_Printf("CHECKGLERROR at %s:%d\n", __FILE__, __LINE__);errornumber = glGetError();if (errornumber) GL_PrintError(errornumber, __FILE__, __LINE__);}} +#else +#define CHECKGLERROR {if (gl_paranoid.integer){if (gl_printcheckerror.integer) Con_Printf("CHECKGLERROR at %s:%d\n", __FILE__, __LINE__);errornumber = qglGetError ? qglGetError() : 0;if (errornumber) GL_PrintError(errornumber, __FILE__, __LINE__);}} +#endif +extern int errornumber; +void GL_PrintError(int errornumber, const char *filename, int linenumber); +#else +#define CHECKGLERROR +#endif + +#ifdef USE_GLES2 +#define qglIsBufferARB glIsBuffer +#define qglIsEnabled glIsEnabled +#define qglIsFramebufferEXT glIsFramebuffer +//#define qglIsQueryARB glIsQuery +#define qglIsRenderbufferEXT glIsRenderbuffer +//#define qglUnmapBufferARB glUnmapBuffer +#define qglCheckFramebufferStatusEXT glCheckFramebufferStatus +#define qglGetError glGetError +#define qglCreateProgram glCreateProgram +#define qglCreateShader glCreateShader +//#define qglGetHandleARB glGetHandle +#define qglGetAttribLocation glGetAttribLocation +#define qglGetUniformLocation glGetUniformLocation +//#define qglMapBufferARB glMapBuffer +#define qglGetString glGetString +//#define qglActiveStencilFaceEXT glActiveStencilFace +#define qglActiveTexture glActiveTexture +#define qglAlphaFunc glAlphaFunc +#define qglArrayElement glArrayElement +#define qglAttachShader glAttachShader +//#define qglBegin glBegin +//#define qglBeginQueryARB glBeginQuery +#define qglBindAttribLocation glBindAttribLocation +//#define qglBindFragDataLocation glBindFragDataLocation +#define qglBindBufferARB glBindBuffer +#define qglBindFramebufferEXT glBindFramebuffer +#define qglBindRenderbufferEXT glBindRenderbuffer +#define qglBindTexture glBindTexture +#define qglBlendEquationEXT glBlendEquation +#define qglBlendFunc glBlendFunc +#define qglBufferDataARB glBufferData +#define qglBufferSubDataARB glBufferSubData +#define qglClear glClear +#define qglClearColor glClearColor +#define qglClearDepthf glClearDepthf +#define qglClearStencil glClearStencil +#define qglClientActiveTexture glClientActiveTexture +#define qglColor4f glColor4f +#define qglColor4ub glColor4ub +#define qglColorMask glColorMask +#define qglColorPointer glColorPointer +#define qglCompileShader glCompileShader +#define qglCompressedTexImage2DARB glCompressedTexImage2D +#define qglCompressedTexImage3DARB glCompressedTexImage3D +#define qglCompressedTexSubImage2DARB glCompressedTexSubImage2D +#define qglCompressedTexSubImage3DARB glCompressedTexSubImage3D +#define qglCopyTexImage2D glCopyTexImage2D +#define qglCopyTexSubImage2D glCopyTexSubImage2D +#define qglCopyTexSubImage3D glCopyTexSubImage3D +#define qglCullFace glCullFace +#define qglDeleteBuffersARB glDeleteBuffers +#define qglDeleteFramebuffersEXT glDeleteFramebuffers +#define qglDeleteProgram glDeleteProgram +#define qglDeleteShader glDeleteShader +//#define qglDeleteQueriesARB glDeleteQueries +#define qglDeleteRenderbuffersEXT glDeleteRenderbuffers +#define qglDeleteTextures glDeleteTextures +#define qglDepthFunc glDepthFunc +#define qglDepthMask glDepthMask +#define qglDepthRangef glDepthRangef +#define qglDetachShader glDetachShader +#define qglDisable glDisable +#define qglDisableClientState glDisableClientState +#define qglDisableVertexAttribArray glDisableVertexAttribArray +#define qglDrawArrays glDrawArrays +//#define qglDrawBuffer glDrawBuffer +//#define qglDrawBuffersARB glDrawBuffers +#define qglDrawElements glDrawElements +//#define qglDrawRangeElements glDrawRangeElements +#define qglEnable glEnable +#define qglEnableClientState glEnableClientState +#define qglEnableVertexAttribArray glEnableVertexAttribArray +//#define qglEnd glEnd +//#define qglEndQueryARB glEndQuery +#define qglFinish glFinish +#define qglFlush glFlush +#define qglFramebufferRenderbuffer glFramebufferRenderbuffer +#define qglFramebufferTexture2D glFramebufferTexture2D +#define qglFramebufferTexture3DEXT glFramebufferTexture3D +#define qglGenBuffersARB glGenBuffers +#define qglGenFramebuffersEXT glGenFramebuffers +//#define qglGenQueriesARB glGenQueries +#define qglGenRenderbuffersEXT glGenRenderbuffers +#define qglGenTextures glGenTextures +#define qglGenerateMipmapEXT glGenerateMipmap +#define qglGetActiveAttrib glGetActiveAttrib +#define qglGetActiveUniform glGetActiveUniform +#define qglGetAttachedShaders glGetAttachedShaders +#define qglGetBooleanv glGetBooleanv +//#define qglGetCompressedTexImageARB glGetCompressedTexImage +#define qglGetDoublev glGetDoublev +#define qglGetFloatv glGetFloatv +#define qglGetFramebufferAttachmentParameterivEXT glGetFramebufferAttachmentParameteriv +#define qglGetProgramInfoLog glGetProgramInfoLog +#define qglGetShaderInfoLog glGetShaderInfoLog +#define qglGetIntegerv glGetIntegerv +#define qglGetShaderiv glGetShaderiv +#define qglGetProgramiv glGetProgramiv +//#define qglGetQueryObjectivARB glGetQueryObjectiv +//#define qglGetQueryObjectuivARB glGetQueryObjectuiv +//#define qglGetQueryivARB glGetQueryiv +#define qglGetRenderbufferParameterivEXT glGetRenderbufferParameteriv +#define qglGetShaderSource glGetShaderSource +#define qglGetTexImage glGetTexImage +#define qglGetTexLevelParameterfv glGetTexLevelParameterfv +#define qglGetTexLevelParameteriv glGetTexLevelParameteriv +#define qglGetTexParameterfv glGetTexParameterfv +#define qglGetTexParameteriv glGetTexParameteriv +#define qglGetUniformfv glGetUniformfv +#define qglGetUniformiv glGetUniformiv +#define qglHint glHint +#define qglLineWidth glLineWidth +#define qglLinkProgram glLinkProgram +#define qglLoadIdentity glLoadIdentity +#define qglLoadMatrixf glLoadMatrixf +#define qglMatrixMode glMatrixMode +#define qglMultiTexCoord1f glMultiTexCoord1f +#define qglMultiTexCoord2f glMultiTexCoord2f +#define qglMultiTexCoord3f glMultiTexCoord3f +#define qglMultiTexCoord4f glMultiTexCoord4f +#define qglNormalPointer glNormalPointer +#define qglPixelStorei glPixelStorei +#define qglPointSize glPointSize +//#define qglPolygonMode glPolygonMode +#define qglPolygonOffset glPolygonOffset +//#define qglPolygonStipple glPolygonStipple +#define qglReadBuffer glReadBuffer +#define qglReadPixels glReadPixels +#define qglRenderbufferStorageEXT glRenderbufferStorage +#define qglScissor glScissor +#define qglShaderSource glShaderSource +#define qglStencilFunc glStencilFunc +#define qglStencilFuncSeparate glStencilFuncSeparate +#define qglStencilMask glStencilMask +#define qglStencilOp glStencilOp +#define qglStencilOpSeparate glStencilOpSeparate +#define qglTexCoord1f glTexCoord1f +#define qglTexCoord2f glTexCoord2f +#define qglTexCoord3f glTexCoord3f +#define qglTexCoord4f glTexCoord4f +#define qglTexCoordPointer glTexCoordPointer +#define qglTexEnvf glTexEnvf +#define qglTexEnvfv glTexEnvfv +#define qglTexEnvi glTexEnvi +#define qglTexImage2D glTexImage2D +#define qglTexImage3D glTexImage3D +#define qglTexParameterf glTexParameterf +#define qglTexParameterfv glTexParameterfv +#define qglTexParameteri glTexParameteri +#define qglTexSubImage2D glTexSubImage2D +#define qglTexSubImage3D glTexSubImage3D +#define qglUniform1f glUniform1f +#define qglUniform1fv glUniform1fv +#define qglUniform1i glUniform1i +#define qglUniform1iv glUniform1iv +#define qglUniform2f glUniform2f +#define qglUniform2fv glUniform2fv +#define qglUniform2i glUniform2i +#define qglUniform2iv glUniform2iv +#define qglUniform3f glUniform3f +#define qglUniform3fv glUniform3fv +#define qglUniform3i glUniform3i +#define qglUniform3iv glUniform3iv +#define qglUniform4f glUniform4f +#define qglUniform4fv glUniform4fv +#define qglUniform4i glUniform4i +#define qglUniform4iv glUniform4iv +#define qglUniformMatrix2fv glUniformMatrix2fv +#define qglUniformMatrix3fv glUniformMatrix3fv +#define qglUniformMatrix4fv glUniformMatrix4fv +#define qglUseProgram glUseProgram +#define qglValidateProgram glValidateProgram +#define qglVertex2f glVertex2f +#define qglVertex3f glVertex3f +#define qglVertex4f glVertex4f +#define qglVertexAttribPointer glVertexAttribPointer +#define qglVertexPointer glVertexPointer +#define qglViewport glViewport +#define qglVertexAttrib1f glVertexAttrib1f +//#define qglVertexAttrib1s glVertexAttrib1s +//#define qglVertexAttrib1d glVertexAttrib1d +#define qglVertexAttrib2f glVertexAttrib2f +//#define qglVertexAttrib2s glVertexAttrib2s +//#define qglVertexAttrib2d glVertexAttrib2d +#define qglVertexAttrib3f glVertexAttrib3f +//#define qglVertexAttrib3s glVertexAttrib3s +//#define qglVertexAttrib3d glVertexAttrib3d +#define qglVertexAttrib4f glVertexAttrib4f +//#define qglVertexAttrib4s glVertexAttrib4s +//#define qglVertexAttrib4d glVertexAttrib4d +//#define qglVertexAttrib4Nub glVertexAttrib4Nub +#define qglVertexAttrib1fv glVertexAttrib1fv +//#define qglVertexAttrib1sv glVertexAttrib1sv +//#define qglVertexAttrib1dv glVertexAttrib1dv +#define qglVertexAttrib2fv glVertexAttrib2fv +//#define qglVertexAttrib2sv glVertexAttrib2sv +//#define qglVertexAttrib2dv glVertexAttrib2dv +#define qglVertexAttrib3fv glVertexAttrib3fv +//#define qglVertexAttrib3sv glVertexAttrib3sv +//#define qglVertexAttrib3dv glVertexAttrib3dv +#define qglVertexAttrib4fv glVertexAttrib4fv +//#define qglVertexAttrib4sv glVertexAttrib4sv +//#define qglVertexAttrib4dv glVertexAttrib4dv +//#define qglVertexAttrib4iv glVertexAttrib4iv +//#define qglVertexAttrib4bv glVertexAttrib4bv +//#define qglVertexAttrib4ubv glVertexAttrib4ubv +//#define qglVertexAttrib4usv glVertexAttrib4usv +//#define qglVertexAttrib4uiv glVertexAttrib4uiv +//#define qglVertexAttrib4Nbv glVertexAttrib4Nbv +//#define qglVertexAttrib4Nsv glVertexAttrib4Nsv +//#define qglVertexAttrib4Niv glVertexAttrib4Niv +//#define qglVertexAttrib4Nubv glVertexAttrib4Nubv +//#define qglVertexAttrib4Nusv glVertexAttrib4Nusv +//#define qglVertexAttrib4Nuiv glVertexAttrib4Nuiv +//#define qglGetVertexAttribdv glGetVertexAttribdv +#define qglGetVertexAttribfv glGetVertexAttribfv +#define qglGetVertexAttribiv glGetVertexAttribiv +#define qglGetVertexAttribPointerv glGetVertexAttribPointerv +#endif + +#endif + diff --git a/app/jni/hmac.c b/app/jni/hmac.c new file mode 100644 index 0000000..e740632 --- /dev/null +++ b/app/jni/hmac.c @@ -0,0 +1,61 @@ +#include "quakedef.h" +#include "hmac.h" + +qboolean hmac( + hashfunc_t hfunc, int hlen, int hblock, + unsigned char *out, + const unsigned char *in, int n, + const unsigned char *key, int k +) +{ + unsigned char hashbuf[32]; + unsigned char k_xor_ipad[128]; + unsigned char k_xor_opad[128]; + unsigned char *catbuf; + int i; + + if(sizeof(hashbuf) < (size_t) hlen) + return false; + if(sizeof(k_xor_ipad) < (size_t) hblock) + return false; + if(sizeof(k_xor_ipad) < (size_t) hlen) + return false; + + catbuf = (unsigned char *)Mem_Alloc(tempmempool, (size_t) hblock + max((size_t) hlen, (size_t) n)); + + if(k > hblock) + { + // hash the key if it is too long + hfunc(k_xor_opad, key, k); + key = k_xor_opad; + k = hlen; + } + + if(k < hblock) + { + // zero pad the key if it is too short + if(key != k_xor_opad) + memcpy(k_xor_opad, key, k); + for(i = k; i < hblock; ++i) + k_xor_opad[i] = 0; + key = k_xor_opad; + k = hblock; + } + + for(i = 0; i < hblock; ++i) + { + k_xor_ipad[i] = key[i] ^ 0x36; + k_xor_opad[i] = key[i] ^ 0x5c; + } + + memcpy(catbuf, k_xor_ipad, hblock); + memcpy(catbuf + hblock, in, n); + hfunc(hashbuf, catbuf, hblock + n); + memcpy(catbuf, k_xor_opad, hblock); + memcpy(catbuf + hblock, hashbuf, hlen); + hfunc(out, catbuf, hblock + hlen); + + Mem_Free(catbuf); + + return true; +} diff --git a/app/jni/hmac.h b/app/jni/hmac.h new file mode 100644 index 0000000..4493900 --- /dev/null +++ b/app/jni/hmac.h @@ -0,0 +1,15 @@ +#ifndef HMAC_H +#define HMAC_H + +typedef void (*hashfunc_t) (unsigned char *out, const unsigned char *in, int n); +qboolean hmac( + hashfunc_t hfunc, int hlen, int hblock, + unsigned char *out, + const unsigned char *in, int n, + const unsigned char *key, int k +); + +#define HMAC_MDFOUR_16BYTES(out, in, n, key, k) hmac(mdfour, 16, 64, out, in, n, key, k) +#define HMAC_SHA256_32BYTES(out, in, n, key, k) hmac(sha256, 32, 64, out, in, n, key, k) + +#endif diff --git a/app/jni/host.c b/app/jni/host.c new file mode 100644 index 0000000..d578379 --- /dev/null +++ b/app/jni/host.c @@ -0,0 +1,1460 @@ +/* +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 +#include "libcurl.h" +#include "cdaudio.h" +#include "cl_video.h" +#include "progsvm.h" +#include "csprogs.h" +#include "sv_demo.h" +#include "snd_main.h" +#include "thread.h" +#include "utf8lib.h" + +/* + +A server can always 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. + +*/ + +// how many frames have occurred +// (checked by Host_Error and Host_SaveConfig_f) +int host_framecount = 0; +// LordHavoc: set when quit is executed +qboolean host_shuttingdown = false; + +// the accumulated mainloop time since application started (with filtering), without any slowmo or clamping +double realtime; +// the main loop wall time for this frame +double host_dirtytime; + +// current client +client_t *host_client; + +jmp_buf host_abortframe; + +extern int r_stereo_side; + +// pretend frames take this amount of time (in seconds), 0 = realtime +cvar_t host_framerate = {0, "host_framerate","0", "locks frame timing to this value in seconds, 0.05 is 20fps for example, note that this can easily run too fast, use cl_maxfps if you want to limit your framerate instead, or sys_ticrate to limit server speed"}; +cvar_t cl_maxphysicsframesperserverframe = {0, "cl_maxphysicsframesperserverframe","10", "maximum number of physics frames per server frame"}; +// shows time used by certain subsystems +cvar_t host_speeds = {0, "host_speeds","0", "reports how much time is used in server/graphics/sound"}; +cvar_t host_maxwait = {0, "host_maxwait","1000", "maximum sleep time requested from the operating system in millisecond. Larger sleeps will be done using multiple host_maxwait length sleeps. Lowering this value will increase CPU load, but may help working around problems with accuracy of sleep times."}; +cvar_t cl_minfps = {CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"}; +cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"}; +cvar_t cl_minfps_qualitymax = {CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"}; +cvar_t cl_minfps_qualitymin = {CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"}; +cvar_t cl_minfps_qualitymultiply = {CVAR_SAVE, "cl_minfps_qualitymultiply", "0.2", "multiplier for quality changes in quality change per second render time (1 assumes linearity of quality and render time)"}; +cvar_t cl_minfps_qualityhysteresis = {CVAR_SAVE, "cl_minfps_qualityhysteresis", "0.05", "reduce all quality increments by this to reduce flickering"}; +cvar_t cl_minfps_qualitystepmax = {CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"}; +cvar_t cl_minfps_force = {0, "cl_minfps_force", "0", "also apply quality reductions in timedemo/capturevideo"}; +cvar_t cl_maxfps = {CVAR_SAVE, "cl_maxfps", "0", "maximum fps cap, 0 = unlimited, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"}; +cvar_t cl_maxfps_alwayssleep = {0, "cl_maxfps_alwayssleep","1", "gives up some processing time to other applications each frame, value in milliseconds, disabled if cl_maxfps is 0"}; +cvar_t cl_maxidlefps = {CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"}; + +cvar_t developer = {CVAR_SAVE, "developer","0", "shows debugging messages and information (recommended for all developers and level designers); the value -1 also suppresses buffering and logging these messages"}; +cvar_t developer_extra = {0, "developer_extra", "0", "prints additional debugging messages, often very verbose!"}; +cvar_t developer_insane = {0, "developer_insane", "0", "prints huge streams of information about internal workings, entire contents of files being read/written, etc. Not recommended!"}; +cvar_t developer_loadfile = {0, "developer_loadfile","0", "prints name and size of every file loaded via the FS_LoadFile function (which is almost everything)"}; +cvar_t developer_loading = {0, "developer_loading","0", "prints information about files as they are loaded or unloaded successfully"}; +cvar_t developer_entityparsing = {0, "developer_entityparsing", "0", "prints detailed network entities information each time a packet is received"}; + +cvar_t timestamps = {CVAR_SAVE, "timestamps", "0", "prints timestamps on console messages"}; +cvar_t timeformat = {CVAR_SAVE, "timeformat", "[%Y-%m-%d %H:%M:%S] ", "time format to use on timestamped console messages"}; + +cvar_t sessionid = {CVAR_READONLY, "sessionid", "", "ID of the current session (use the -sessionid parameter to set it); this is always either empty or begins with a dot (.)"}; +cvar_t locksession = {0, "locksession", "0", "Lock the session? 0 = no, 1 = yes and abort on failure, 2 = yes and continue on failure"}; + +/* +================ +Host_AbortCurrentFrame + +aborts the current host frame and goes on with the next one +================ +*/ +void Host_AbortCurrentFrame(void) DP_FUNC_NORETURN; +void Host_AbortCurrentFrame(void) +{ + // in case we were previously nice, make us mean again + Sys_MakeProcessMean(); + + longjmp (host_abortframe, 1); +} + +/* +================ +Host_Error + +This shuts down both the client and server +================ +*/ +void Host_Error (const char *error, ...) +{ + static char hosterrorstring1[MAX_INPUTLINE]; // THREAD UNSAFE + static char hosterrorstring2[MAX_INPUTLINE]; // THREAD UNSAFE + static qboolean hosterror = false; + va_list argptr; + + // turn off rcon redirect if it was active when the crash occurred + // to prevent loops when it is a networking problem + Con_Rcon_Redirect_Abort(); + + va_start (argptr,error); + dpvsnprintf (hosterrorstring1,sizeof(hosterrorstring1),error,argptr); + va_end (argptr); + + Con_Printf("Host_Error: %s\n", hosterrorstring1); + + // LordHavoc: if crashing very early, or currently shutting down, do + // Sys_Error instead + if (host_framecount < 3 || host_shuttingdown) + Sys_Error ("Host_Error: %s", hosterrorstring1); + + if (hosterror) + Sys_Error ("Host_Error: recursively entered (original error was: %s new error is: %s)", hosterrorstring2, hosterrorstring1); + hosterror = true; + + strlcpy(hosterrorstring2, hosterrorstring1, sizeof(hosterrorstring2)); + + CL_Parse_DumpPacket(); + + CL_Parse_ErrorCleanUp(); + + //PR_Crash(); + + // print out where the crash happened, if it was caused by QC (and do a cleanup) + PRVM_Crash(SVVM_prog); + PRVM_Crash(CLVM_prog); + PRVM_Crash(MVM_prog); + + cl.csqc_loaded = false; + Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); + + SV_LockThreadMutex(); + Host_ShutdownServer (); + SV_UnlockThreadMutex(); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_Error: %s",hosterrorstring2); // dedicated servers exit + + CL_Disconnect (); + cls.demonum = -1; + + hosterror = false; + + Host_AbortCurrentFrame(); +} + +static void Host_ServerOptions (void) +{ + int i; + + // general default + svs.maxclients = 8; + +// COMMANDLINEOPTION: Server: -dedicated [playerlimit] starts a dedicated server (with a command console), default playerlimit is 8 +// COMMANDLINEOPTION: Server: -listen [playerlimit] starts a multiplayer server with graphical client, like singleplayer but other players can connect, default playerlimit is 8 + // if no client is in the executable or -dedicated is specified on + // commandline, start a dedicated server + i = COM_CheckParm ("-dedicated"); + if (i || !cl_available) + { + cls.state = ca_dedicated; + // check for -dedicated specifying how many players + if (i && i + 1 < com_argc && atoi (com_argv[i+1]) >= 1) + svs.maxclients = atoi (com_argv[i+1]); + if (COM_CheckParm ("-listen")) + Con_Printf ("Only one of -dedicated or -listen can be specified\n"); + // default sv_public on for dedicated servers (often hosted by serious administrators), off for listen servers (often hosted by clueless users) + Cvar_SetValue("sv_public", 1); + } + else if (cl_available) + { + // client exists and not dedicated, check if -listen is specified + cls.state = ca_disconnected; + i = COM_CheckParm ("-listen"); + if (i) + { + // default players unless specified + if (i + 1 < com_argc && atoi (com_argv[i+1]) >= 1) + svs.maxclients = atoi (com_argv[i+1]); + } + else + { + // default players in some games, singleplayer in most + if (gamemode != GAME_GOODVSBAD2 && gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC && gamemode != GAME_BATTLEMECH) + svs.maxclients = 1; + } + } + + svs.maxclients = svs.maxclients_next = bound(1, svs.maxclients, MAX_SCOREBOARD); + + svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients); + + if (svs.maxclients > 1 && !deathmatch.integer && !coop.integer) + Cvar_SetValueQuick(&deathmatch, 1); +} + +/* +======================= +Host_InitLocal +====================== +*/ +void Host_SaveConfig_f(void); +void Host_LoadConfig_f(void); +extern cvar_t sv_writepicture_quality; +extern cvar_t r_texture_jpeg_fastpicmip; +static void Host_InitLocal (void) +{ + Cmd_AddCommand("saveconfig", Host_SaveConfig_f, "save settings to config.cfg (or a specified filename) immediately (also automatic when quitting)"); + Cmd_AddCommand("loadconfig", Host_LoadConfig_f, "reset everything and reload configs"); + + Cvar_RegisterVariable (&cl_maxphysicsframesperserverframe); + Cvar_RegisterVariable (&host_framerate); + Cvar_RegisterVariable (&host_speeds); + Cvar_RegisterVariable (&host_maxwait); + Cvar_RegisterVariable (&cl_minfps); + Cvar_RegisterVariable (&cl_minfps_fade); + Cvar_RegisterVariable (&cl_minfps_qualitymax); + Cvar_RegisterVariable (&cl_minfps_qualitymin); + Cvar_RegisterVariable (&cl_minfps_qualitystepmax); + Cvar_RegisterVariable (&cl_minfps_qualityhysteresis); + Cvar_RegisterVariable (&cl_minfps_qualitymultiply); + Cvar_RegisterVariable (&cl_minfps_force); + Cvar_RegisterVariable (&cl_maxfps); + Cvar_RegisterVariable (&cl_maxfps_alwayssleep); + Cvar_RegisterVariable (&cl_maxidlefps); + + Cvar_RegisterVariable (&developer); + Cvar_RegisterVariable (&developer_extra); + Cvar_RegisterVariable (&developer_insane); + Cvar_RegisterVariable (&developer_loadfile); + Cvar_RegisterVariable (&developer_loading); + Cvar_RegisterVariable (&developer_entityparsing); + + Cvar_RegisterVariable (×tamps); + Cvar_RegisterVariable (&timeformat); + + Cvar_RegisterVariable (&sv_writepicture_quality); + Cvar_RegisterVariable (&r_texture_jpeg_fastpicmip); +} + + +/* +=============== +Host_SaveConfig_f + +Writes key bindings and archived cvars to config.cfg +=============== +*/ +static void Host_SaveConfig_to(const char *file) +{ + qfile_t *f; + +// dedicated servers initialize the host but don't parse and set the +// config.cfg cvars + // LordHavoc: don't save a config if it crashed in startup + if (host_framecount >= 3 && cls.state != ca_dedicated && !COM_CheckParm("-benchmark") && !COM_CheckParm("-capturedemo")) + { + f = FS_OpenRealFile(file, "wb", false); + if (!f) + { + Con_Printf("Couldn't write %s.\n", file); + return; + } + + Key_WriteBindings (f); + Cvar_WriteVariables (f); + + FS_Close (f); + } +} +void Host_SaveConfig(void) +{ + Host_SaveConfig_to(CONFIGFILENAME); +} +void Host_SaveConfig_f(void) +{ + const char *file = CONFIGFILENAME; + + if(Cmd_Argc() >= 2) { + file = Cmd_Argv(1); + Con_Printf("Saving to %s\n", file); + } + + Host_SaveConfig_to(file); +} + +static void Host_AddConfigText(void) +{ + // set up the default startmap_sp and startmap_dm aliases (mods can + // override these) and then execute the quake.rc startup script + if (gamemode == GAME_NEHAHRA) + Cbuf_InsertText("alias startmap_sp \"map nehstart\"\nalias startmap_dm \"map nehstart\"\nexec " STARTCONFIGFILENAME "\n"); + else if (gamemode == GAME_TRANSFUSION) + Cbuf_InsertText("alias startmap_sp \"map e1m1\"\n""alias startmap_dm \"map bb1\"\nexec " STARTCONFIGFILENAME "\n"); + else if (gamemode == GAME_TEU) + Cbuf_InsertText("alias startmap_sp \"map start\"\nalias startmap_dm \"map start\"\nexec teu.rc\n"); + else + Cbuf_InsertText("alias startmap_sp \"map start\"\nalias startmap_dm \"map start\"\nexec " STARTCONFIGFILENAME "\n"); +} + +/* +=============== +Host_LoadConfig_f + +Resets key bindings and cvars to defaults and then reloads scripts +=============== +*/ +void Host_LoadConfig_f(void) +{ + // reset all cvars, commands and aliases to init values + Cmd_RestoreInitState(); + // prepend a menu restart command to execute after the config + Cbuf_InsertText("\nmenu_restart\n"); + // reset cvars to their defaults, and then exec startup scripts again + Host_AddConfigText(); +} + +/* +================= +SV_ClientPrint + +Sends text across to be displayed +FIXME: make this just a stuffed echo? +================= +*/ +void SV_ClientPrint(const char *msg) +{ + if (host_client->netconnection) + { + MSG_WriteByte(&host_client->netconnection->message, svc_print); + MSG_WriteString(&host_client->netconnection->message, msg); + } +} + +/* +================= +SV_ClientPrintf + +Sends text across to be displayed +FIXME: make this just a stuffed echo? +================= +*/ +void SV_ClientPrintf(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + SV_ClientPrint(msg); +} + +/* +================= +SV_BroadcastPrint + +Sends text to all active clients +================= +*/ +void SV_BroadcastPrint(const char *msg) +{ + int i; + client_t *client; + + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (client->active && client->netconnection) + { + MSG_WriteByte(&client->netconnection->message, svc_print); + MSG_WriteString(&client->netconnection->message, msg); + } + } + + if (sv_echobprint.integer && cls.state == ca_dedicated) + Con_Print(msg); +} + +/* +================= +SV_BroadcastPrintf + +Sends text to all active clients +================= +*/ +void SV_BroadcastPrintf(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + SV_BroadcastPrint(msg); +} + +/* +================= +Host_ClientCommands + +Send text over to the client to be executed +================= +*/ +void Host_ClientCommands(const char *fmt, ...) +{ + va_list argptr; + char string[MAX_INPUTLINE]; + + if (!host_client->netconnection) + return; + + va_start(argptr,fmt); + dpvsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + MSG_WriteByte(&host_client->netconnection->message, svc_stufftext); + MSG_WriteString(&host_client->netconnection->message, string); +} + +/* +===================== +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) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + Con_Printf("Client \"%s\" dropped\n", host_client->name); + + SV_StopDemoRecording(host_client); + + // make sure edict is not corrupt (from a level change for example) + host_client->edict = PRVM_EDICT_NUM(host_client - svs.clients + 1); + + if (host_client->netconnection) + { + // tell the client to be gone + if (!crash) + { + // LordHavoc: no opportunity for resending, so use unreliable 3 times + unsigned char bufdata[8]; + sizebuf_t buf; + memset(&buf, 0, sizeof(buf)); + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + MSG_WriteByte(&buf, svc_disconnect); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); + } + } + + // call qc ClientDisconnect function + // LordHavoc: don't call QC if server is dead (avoids recursive + // Host_Error in some mods when they run out of edicts) + if (host_client->clientconnectcalled && sv.active && host_client->edict) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + int saveSelf = PRVM_serverglobaledict(self); + host_client->clientconnectcalled = false; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing"); + PRVM_serverglobaledict(self) = saveSelf; + } + + if (host_client->netconnection) + { + // break the net connection + NetConn_Close(host_client->netconnection); + host_client->netconnection = NULL; + } + + // if a download is active, close it + if (host_client->download_file) + { + Con_DPrintf("Download of %s aborted when %s dropped\n", host_client->download_name, host_client->name); + FS_Close(host_client->download_file); + host_client->download_file = NULL; + host_client->download_name[0] = 0; + host_client->download_expectedposition = 0; + host_client->download_started = false; + } + + // remove leaving player from scoreboard + host_client->name[0] = 0; + host_client->colors = 0; + host_client->frags = 0; + // send notification to all clients + // get number of client manually just to make sure we get it right... + i = host_client - svs.clients; + MSG_WriteByte (&sv.reliable_datagram, svc_updatename); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteString (&sv.reliable_datagram, host_client->name); + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteByte (&sv.reliable_datagram, host_client->colors); + MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteShort (&sv.reliable_datagram, host_client->frags); + + // free the client now + if (host_client->entitydatabase) + EntityFrame_FreeDatabase(host_client->entitydatabase); + if (host_client->entitydatabase4) + EntityFrame4_FreeDatabase(host_client->entitydatabase4); + if (host_client->entitydatabase5) + EntityFrame5_FreeDatabase(host_client->entitydatabase5); + + if (sv.active) + { + // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags + PRVM_ED_ClearEdict(prog, host_client->edict); + } + + // clear the client struct (this sets active to false) + memset(host_client, 0, sizeof(*host_client)); + + // update server listing on the master because player count changed + // (which the master uses for filtering empty/full servers) + NetConn_Heartbeat(1); + + if (sv.loadgame) + { + for (i = 0;i < svs.maxclients;i++) + if (svs.clients[i].active && !svs.clients[i].spawned) + break; + if (i == svs.maxclients) + { + Con_Printf("Loaded game, everyone rejoined - unpausing\n"); + sv.paused = sv.loadgame = false; // we're basically done with loading now + } + } +} + +/* +================== +Host_ShutdownServer + +This only happens at the end of a game, not between levels +================== +*/ +void Host_ShutdownServer(void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + + Con_DPrintf("Host_ShutdownServer\n"); + + if (!sv.active) + return; + + NetConn_Heartbeat(2); + NetConn_Heartbeat(2); + +// make sure all the clients know we're disconnecting + World_End(&sv.world); + if(prog->loaded) + { + if(PRVM_serverfunction(SV_Shutdown)) + { + func_t s = PRVM_serverfunction(SV_Shutdown); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again + prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); + } + } + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if (host_client->active) + SV_DropClient(false); // server shutdown + + NetConn_CloseServerPorts(); + + sv.active = false; +// +// clear structures +// + memset(&sv, 0, sizeof(sv)); + memset(svs.clients, 0, svs.maxclients*sizeof(client_t)); + + cl.islocalgame = false; +} + + +//============================================================================ + +/* +=================== +Host_GetConsoleCommands + +Add them exactly as if they had been typed at the console +=================== +*/ +static void Host_GetConsoleCommands (void) +{ + char *cmd; + + while (1) + { + cmd = Sys_ConsoleInput (); + if (!cmd) + break; + Cbuf_AddText (cmd); + } +} + +/* +================== +Host_TimeReport + +Returns a time report string, for example for +================== +*/ +const char *Host_TimingReport(char *buf, size_t buflen) +{ + return va(buf, buflen, "%.1f%% CPU, %.2f%% lost, offset avg %.1fms, max %.1fms, sdev %.1fms", svs.perf_cpuload * 100, svs.perf_lost * 100, svs.perf_offset_avg * 1000, svs.perf_offset_max * 1000, svs.perf_offset_sdev * 1000); +} + +/* +================== +Host_Frame + +Runs all active servers +================== +*/ +static void Host_Init(void); + +double time1 = 0; +double time2 = 0; +double time3 = 0; +double cl_timer = 0, sv_timer = 0; +double clframetime, deltacleantime, olddirtytime, dirtytime; +double wait; +int pass1, pass2, pass3, i; +char vabuf[1024]; +qboolean playing; +void Host_BeginFrame(void) +{ + if (setjmp(host_abortframe)) + { + SCR_ClearLoadingScreen(false); + return; + } + + olddirtytime = host_dirtytime; + dirtytime = Sys_DirtyTime(); + deltacleantime = dirtytime - olddirtytime; + if (deltacleantime < 0) + { + // warn if it's significant + if (deltacleantime < -0.01) + Con_Printf("Host_Mingled: time stepped backwards (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); + deltacleantime = 0; + } + else if (deltacleantime >= 1800) + { + Con_Printf("Host_Mingled: time stepped forward (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); + deltacleantime = 0; + } + realtime += deltacleantime; + host_dirtytime = dirtytime; + + cl_timer += deltacleantime; + sv_timer += deltacleantime; + + if (!svs.threaded) + { + svs.perf_acc_realtime += deltacleantime; + + // Look for clients who have spawned + playing = false; + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if(host_client->begun) + if(host_client->netconnection) + playing = true; + if(sv.time < 10) + { + // don't accumulate time for the first 10 seconds of a match + // so things can settle + svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; + } + else if(svs.perf_acc_realtime > 5) + { + svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime; + svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime; + if(svs.perf_acc_offset_samples > 0) + { + svs.perf_offset_max = svs.perf_acc_offset_max; + svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples; + svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); + } + if(svs.perf_lost > 0 && developer_extra.integer) + if(playing) // only complain if anyone is looking + Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; + } + } + + if (slowmo.value < 0.00001 && slowmo.value != 0) + Cvar_SetValue("slowmo", 0); + if (host_framerate.value < 0.00001 && host_framerate.value != 0) + Cvar_SetValue("host_framerate", 0); + + // keep the random time dependent, but not when playing demos/benchmarking + if(!*sv_random_seed.string && !cls.demoplayback) + rand(); + + // get new key events + Key_EventQueue_Unblock(); + SndSys_SendKeyEvents(); + Sys_SendKeyEvents(); + + NetConn_UpdateSockets(); + + Log_DestBuffer_Flush(); + + // receive packets on each main loop iteration, as the main loop may + // be undersleeping due to select() detecting a new packet + if (sv.active && !svs.threaded) + NetConn_ServerFrame(); + + Curl_Run(); + + // check for commands typed to the host + Host_GetConsoleCommands(); + + // when a server is running we only execute console commands on server frames + // (this mainly allows frikbot .way config files to work properly by staying in sync with the server qc) + // otherwise we execute them on client frames + if (sv.active ? sv_timer > 0 : cl_timer > 0) + { + // process console commands +// R_TimeReport("preconsole"); + CL_VM_PreventInformationLeaks(); + Cbuf_Frame(); +// R_TimeReport("console"); + } + + //Con_Printf("%6.0f %6.0f\n", cl_timer * 1000000.0, sv_timer * 1000000.0); + + // if the accumulators haven't become positive yet, wait a while + if (cls.state == ca_dedicated) + wait = sv_timer * -1000000.0; + else if (!sv.active || svs.threaded) + wait = cl_timer * -1000000.0; + else + wait = max(cl_timer, sv_timer) * -1000000.0; + + if (!cls.timedemo && wait >= 1) + { + double time0, delta; + + if(host_maxwait.value <= 0) + wait = min(wait, 1000000.0); + else + wait = min(wait, host_maxwait.value * 1000.0); + if(wait < 1) + wait = 1; // because we cast to int + + time0 = Sys_DirtyTime(); + if (sv_checkforpacketsduringsleep.integer && !sys_usenoclockbutbenchmark.integer && !svs.threaded) + NetConn_SleepMicroseconds((int)wait); + else + Sys_Sleep((int)wait); + delta = Sys_DirtyTime() - time0; + if (delta < 0 || delta >= 1800) delta = 0; + if (!svs.threaded) + svs.perf_acc_sleeptime += delta; +// R_TimeReport("sleep"); + return; + } + + // limit the frametime steps to no more than 100ms each + if (cl_timer > 0.1) + cl_timer = 0.1; + if (sv_timer > 0.1) + { + if (!svs.threaded) + svs.perf_acc_lost += (sv_timer - 0.1); + sv_timer = 0.1; + } + + R_TimeReport("---"); + + //------------------- + // + // server operations + // + //------------------- + + // limit the frametime steps to no more than 100ms each + if (sv.active && sv_timer > 0 && !svs.threaded) + { + // execute one or more server frames, with an upper limit on how much + // execution time to spend on server frames to avoid freezing the game if + // the server is overloaded, this execution time limit means the game will + // slow down if the server is taking too long. + int framecount, framelimit = 1; + double advancetime, aborttime = 0; + float offset; + prvm_prog_t *prog = SVVM_prog; + + // run the world state + // don't allow simulation to run too fast or too slow or logic glitches can occur + + // stop running server frames if the wall time reaches this value + if (sys_ticrate.value <= 0) + advancetime = sv_timer; + else if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) + { + // synchronize to the client frametime, but no less than 10ms and no more than 100ms + advancetime = bound(0.01, cl_timer, 0.1); + } + else + { + advancetime = sys_ticrate.value; + // listen servers can run multiple server frames per client frame + framelimit = cl_maxphysicsframesperserverframe.integer; + aborttime = Sys_DirtyTime() + 0.1; + } + if(slowmo.value > 0 && slowmo.value < 1) + advancetime = min(advancetime, 0.1 / slowmo.value); + else + advancetime = min(advancetime, 0.1); + + if(advancetime > 0) + { + offset = Sys_DirtyTime() - dirtytime;if (offset < 0 || offset >= 1800) offset = 0; + offset += sv_timer; + ++svs.perf_acc_offset_samples; + svs.perf_acc_offset += offset; + svs.perf_acc_offset_squared += offset * offset; + if(svs.perf_acc_offset_max < offset) + svs.perf_acc_offset_max = offset; + } + + // only advance time if not paused + // the game also pauses in singleplayer when menu or console is used + sv.frametime = advancetime * slowmo.value; + if (host_framerate.value) + sv.frametime = host_framerate.value; + if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) + sv.frametime = 0; + + for (framecount = 0;framecount < framelimit && sv_timer > 0;framecount++) + { + sv_timer -= advancetime; + + // move things around and think unless paused + if (sv.frametime) + SV_Physics(); + + // if this server frame took too long, break out of the loop + if (framelimit > 1 && Sys_DirtyTime() >= aborttime) + break; + } + R_TimeReport("serverphysics"); + + // send all messages to the clients + SV_SendClientMessages(); + + if (sv.paused == 1 && realtime > sv.pausedstart && sv.pausedstart > 0) { + prog->globals.fp[OFS_PARM0] = realtime - sv.pausedstart; + PRVM_serverglobalfloat(time) = sv.time; + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing"); + } + + // send an heartbeat if enough time has passed since the last one + NetConn_Heartbeat(0); + R_TimeReport("servernetwork"); + } + else if (!svs.threaded) + { + // don't let r_speeds display jump around + R_TimeReport("serverphysics"); + R_TimeReport("servernetwork"); + } + + //------------------- + // + // client operations + // + //------------------- + + if (cls.state != ca_dedicated && (cl_timer > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) + { + R_TimeReport("---"); + Collision_Cache_NewFrame(); + R_TimeReport("photoncache"); + // decide the simulation time + if (cls.capturevideo.active) + { + //*** + if (cls.capturevideo.realtime) + clframetime = cl.realframetime = max(cl_timer, 1.0 / cls.capturevideo.framerate); + else + { + clframetime = 1.0 / cls.capturevideo.framerate; + cl.realframetime = max(cl_timer, clframetime); + } + } + else if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) + { + clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxfps.value); + // when running slow, we need to sleep to keep input responsive + wait = bound(0, cl_maxfps_alwayssleep.value * 1000, 100000); + if (wait > 0) + Sys_Sleep((int)wait); + } + else if (!vid_activewindow && cl_maxidlefps.value >= 1 && !cls.timedemo) + clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxidlefps.value); + else + clframetime = cl.realframetime = cl_timer; + + // apply slowmo scaling + clframetime *= cl.movevars_timescale; + // scale playback speed of demos by slowmo cvar + if (cls.demoplayback) + { + clframetime *= slowmo.value; + // if demo playback is paused, don't advance time at all + if (cls.demopaused) + clframetime = 0; + } + else + { + // host_framerate overrides all else + if (host_framerate.value) + clframetime = host_framerate.value; + + if (cl.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) + clframetime = 0; + } + + if (cls.timedemo) + clframetime = cl.realframetime = cl_timer; + + // deduct the frame time from the accumulator + cl_timer -= cl.realframetime; + + cl.oldtime = cl.time; + cl.time += clframetime; + + // update video + if (host_speeds.integer) + time1 = Sys_DirtyTime(); + R_TimeReport("pre-input"); + + // Collect input into cmd + CL_Input(); + + R_TimeReport("input"); + + // check for new packets + NetConn_ClientFrame(); + + // read a new frame from a demo if needed + CL_ReadDemoMessage(); + R_TimeReport("clientnetwork"); + + // now that packets have been read, send input to server + CL_SendMove(); + R_TimeReport("sendmove"); + + // update client world (interpolate entities, create trails, etc) + CL_UpdateWorld(); + R_TimeReport("lerpworld"); + + CL_Video_Frame(); + + R_TimeReport("client"); + } + + CL_BeginUpdateScreen(); +} + +void Host_Frame(int eye, int x, int y) +{ + r_stereo_side = eye; + + SCR_DrawScreen(x, y); + + R_TimeReport("render"); +} + +void Host_EndFrame(void) +{ + CL_EndUpdateScreen(); + + if (cls.state != ca_dedicated && (cl_timer > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) + { + if (host_speeds.integer) + time2 = Sys_DirtyTime(); + + // update audio + if(cl.csqc_usecsqclistener) + { + S_Update(&cl.csqc_listenermatrix); + cl.csqc_usecsqclistener = false; + } + else + S_Update(&r_refdef.view.matrix); + + CDAudio_Update(); + R_TimeReport("audio"); + + // reset gathering of mouse input + in_mouse_x = in_mouse_y = 0; + + if (host_speeds.integer) + { + pass1 = (int)((time1 - time3)*1000000); + time3 = Sys_DirtyTime(); + pass2 = (int)((time2 - time1)*1000000); + pass3 = (int)((time3 - time2)*1000000); + Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n", + pass1+pass2+pass3, pass1, pass2, pass3); + } + } + +#if MEMPARANOIA + Mem_CheckSentinelsGlobal(); +#else + if (developer_memorydebug.integer) + Mem_CheckSentinelsGlobal(); +#endif + + // if there is some time remaining from this frame, reset the timers + if (cl_timer >= 0) + cl_timer = 0; + if (sv_timer >= 0) + { + if (!svs.threaded) + svs.perf_acc_lost += sv_timer; + sv_timer = 0; + } + + host_framecount++; +} + +void Host_Main(void) +{ + Host_Init(); + + realtime = 0; +} + +//============================================================================ + +qboolean vid_opened = false; +void Host_StartVideo(void) +{ + if (!vid_opened && cls.state != ca_dedicated) + { + vid_opened = true; + // make sure we open sockets before opening video because the Windows Firewall "unblock?" dialog can screw up the graphics context on some graphics drivers + NetConn_UpdateSockets(); + VID_Start(); + CDAudio_Startup(); + } +} + +char engineversion[128]; + +qboolean sys_nostdout = false; + +extern qboolean host_stuffcmdsrun; + +static qfile_t *locksession_fh = NULL; +static qboolean locksession_run = false; +static void Host_InitSession(void) +{ + int i; + Cvar_RegisterVariable(&sessionid); + Cvar_RegisterVariable(&locksession); + + // load the session ID into the read-only cvar + if ((i = COM_CheckParm("-sessionid")) && (i + 1 < com_argc)) + { + char vabuf[1024]; + if(com_argv[i+1][0] == '.') + Cvar_SetQuick(&sessionid, com_argv[i+1]); + else + Cvar_SetQuick(&sessionid, va(vabuf, sizeof(vabuf), ".%s", com_argv[i+1])); + } +} +void Host_LockSession(void) +{ + if(locksession_run) + return; + locksession_run = true; + if(locksession.integer != 0 && !COM_CheckParm("-readonly")) + { + char vabuf[1024]; + char *p = va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string); + FS_CreatePath(p); + locksession_fh = FS_SysOpen(p, "wl", false); + // TODO maybe write the pid into the lockfile, while we are at it? may help server management tools + if(!locksession_fh) + { + if(locksession.integer == 2) + { + Con_Printf("WARNING: session lock %s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", p); + } + else + { + Sys_Error("session lock %s could not be acquired. Please run with -sessionid and an unique session name.\n", p); + } + } + } +} +void Host_UnlockSession(void) +{ + if(!locksession_run) + return; + locksession_run = false; + + if(locksession_fh) + { + FS_Close(locksession_fh); + // NOTE: we can NOT unlink the lock here, as doing so would + // create a race condition if another process created it + // between our close and our unlink + locksession_fh = NULL; + } +} + +/* +==================== +Host_Init +==================== +*/ +static void Host_Init (void) +{ + int i; + const char* os; + char vabuf[1024]; + + if (COM_CheckParm("-profilegameonly")) + Sys_AllowProfiling(false); + + // LordHavoc: quake never seeded the random number generator before... heh + if (COM_CheckParm("-benchmark")) + srand(0); // predictable random sequence for -benchmark + else + srand((unsigned int)time(NULL)); + + // FIXME: this is evil, but possibly temporary + // LordHavoc: doesn't seem very temporary... + // LordHavoc: made this a saved cvar +// COMMANDLINEOPTION: Console: -developer enables warnings and other notices (RECOMMENDED for mod developers) + if (COM_CheckParm("-developer")) + { + developer.value = developer.integer = 1; + developer.string = "1"; + } + + if (COM_CheckParm("-developer2") || COM_CheckParm("-developer3")) + { + developer.value = developer.integer = 1; + developer.string = "1"; + developer_extra.value = developer_extra.integer = 1; + developer_extra.string = "1"; + developer_insane.value = developer_insane.integer = 1; + developer_insane.string = "1"; + developer_memory.value = developer_memory.integer = 1; + developer_memory.string = "1"; + developer_memorydebug.value = developer_memorydebug.integer = 1; + developer_memorydebug.string = "1"; + } + + if (COM_CheckParm("-developer3")) + { + gl_paranoid.integer = 1;gl_paranoid.string = "1"; + gl_printcheckerror.integer = 1;gl_printcheckerror.string = "1"; + } + +// COMMANDLINEOPTION: Console: -nostdout disables text output to the terminal the game was launched from + if (COM_CheckParm("-nostdout")) + sys_nostdout = 1; + + // used by everything + Memory_Init(); + + // initialize console command/cvar/alias/command execution systems + Cmd_Init(); + + // initialize memory subsystem cvars/commands + Memory_Init_Commands(); + + // initialize console and logging and its cvars/commands + Con_Init(); + + // initialize various cvars that could not be initialized earlier + u8_Init(); + Curl_Init_Commands(); + Cmd_Init_Commands(); + Sys_Init_Commands(); + COM_Init_Commands(); + FS_Init_Commands(); + + // initialize console window (only used by sys_win.c) + Sys_InitConsole(); + + // initialize the self-pack (must be before COM_InitGameType as it may add command line options) + FS_Init_SelfPack(); + + // detect gamemode from commandline options or executable name + COM_InitGameType(); + + // construct a version string for the corner of the console + os = DP_OS_NAME; + dpsnprintf (engineversion, sizeof (engineversion), "%s %s %s", gamename, os, buildstring); + Con_Printf("%s\n", engineversion); + + // initialize process nice level + Sys_InitProcessNice(); + + // initialize ixtable + Mathlib_Init(); + + // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name) + FS_Init(); + + // register the cvars for session locking + Host_InitSession(); + + // must be after FS_Init + Crypto_Init(); + Crypto_Init_Commands(); + + NetConn_Init(); + Curl_Init(); + //PR_Init(); + //PR_Cmd_Init(); + PRVM_Init(); + Mod_Init(); + World_Init(); + SV_Init(); + V_Init(); // some cvars needed by server player physics (cl_rollangle etc) + Host_InitCommands(); + Host_InitLocal(); + Host_ServerOptions(); + + Thread_Init(); + + if (cls.state == ca_dedicated) + Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server (or disconnect all clients if running a server)"); + else + { + Con_DPrintf("Initializing client\n"); + + R_Modules_Init(); + Palette_Init(); + MR_Init_Commands(); + VID_Shared_Init(); + VID_Init(); + Render_Init(); + S_Init(); + CDAudio_Init(); + Key_Init(); + CL_Init(); + } + + // save off current state of aliases, commands and cvars for later restore if FS_GameDir_f is called + // NOTE: menu commands are freed by Cmd_RestoreInitState + Cmd_SaveInitState(); + + // FIXME: put this into some neat design, but the menu should be allowed to crash + // without crashing the whole game, so this should just be a short-time solution + + // here comes the not so critical stuff + if (setjmp(host_abortframe)) { + return; + } + + Host_AddConfigText(); + Cbuf_Execute(); + + // if stuffcmds wasn't run, then quake.rc is probably missing, use default + if (!host_stuffcmdsrun) + { + Cbuf_AddText("exec default.cfg\nexec " CONFIGFILENAME "\nexec autoexec.cfg\nstuffcmds\n"); + Cbuf_Execute(); + } + + // put up the loading image so the user doesn't stare at a black screen... + SCR_BeginLoadingPlaque(true); + + if (cls.state != ca_dedicated) + { + MR_Init(); + } + + // check for special benchmark mode +// COMMANDLINEOPTION: Client: -benchmark runs a timedemo and quits, results of any timedemo can be found in gamedir/benchmark.log (for example id1/benchmark.log) + i = COM_CheckParm("-benchmark"); + if (i && i + 1 < com_argc) + if (!sv.active && !cls.demoplayback && !cls.connect_trying) + { + Cbuf_AddText(va(vabuf, sizeof(vabuf), "timedemo %s\n", com_argv[i + 1])); + Cbuf_Execute(); + } + + // check for special demo mode +// COMMANDLINEOPTION: Client: -demo runs a playdemo and quits + i = COM_CheckParm("-demo"); + if (i && i + 1 < com_argc) + if (!sv.active && !cls.demoplayback && !cls.connect_trying) + { + Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\n", com_argv[i + 1])); + Cbuf_Execute(); + } + +// COMMANDLINEOPTION: Client: -capturedemo captures a playdemo and quits + i = COM_CheckParm("-capturedemo"); + if (i && i + 1 < com_argc) + if (!sv.active && !cls.demoplayback && !cls.connect_trying) + { + Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\ncl_capturevideo 1\n", com_argv[i + 1])); + Cbuf_Execute(); + } + + if (cls.state == ca_dedicated || COM_CheckParm("-listen")) + if (!sv.active && !cls.demoplayback && !cls.connect_trying) + { + Cbuf_AddText("startmap_dm\n"); + Cbuf_Execute(); + } + + if (!sv.active && !cls.demoplayback && !cls.connect_trying) + { + Cbuf_AddText("togglemenu 1\n"); + Cbuf_Execute(); + } + + Con_DPrint("========Initialized=========\n"); + + //Host_StartVideo(); + + if (cls.state != ca_dedicated) + SV_StartThread(); +} + + +/* +=============== +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) + { + Con_Print("recursive shutdown\n"); + return; + } + if (setjmp(host_abortframe)) + { + Con_Print("aborted the quitting frame?!?\n"); + return; + } + isdown = true; + + // be quiet while shutting down + S_StopAllSounds(); + + // end the server thread + if (svs.threaded) + SV_StopThread(); + + // disconnect client from server if active + CL_Disconnect(); + + // shut down local server if active + SV_LockThreadMutex(); + Host_ShutdownServer (); + SV_UnlockThreadMutex(); + + // Shutdown menu + if(MR_Shutdown) + MR_Shutdown(); + + // AK shutdown PRVM + // AK hmm, no PRVM_Shutdown(); yet + + //Don't need to do this, we don't own the video side of things + //CL_Video_Shutdown(); + + Host_SaveConfig(); + + //CDAudio_Shutdown (); + S_Terminate (); + Curl_Shutdown (); + NetConn_Shutdown (); + //PR_Shutdown (); + + if (cls.state != ca_dedicated) + { + R_Modules_Shutdown(); + VID_Shutdown(); + } + + SV_StopThread(); + Thread_Shutdown(); + Cmd_Shutdown(); + Key_Shutdown(); + CL_Shutdown(); + Sys_Shutdown(); + Log_Close(); + Crypto_Shutdown(); + + Host_UnlockSession(); + + S_Shutdown(); + Con_Shutdown(); + Memory_Shutdown(); +} + diff --git a/app/jni/host_cmd.c b/app/jni/host_cmd.c new file mode 100644 index 0000000..6a0b991 --- /dev/null +++ b/app/jni/host_cmd.c @@ -0,0 +1,3051 @@ +/* +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 "sv_demo.h" +#include "image.h" + +#include "utf8lib.h" + +// for secure rcon authentication +#include "hmac.h" +#include "mdfour.h" +#include + +int current_skill; +cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; +cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admin messages instead of host name"}; +cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"}; +cvar_t sv_status_show_qcstatus = {CVAR_SAVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."}; +cvar_t sv_namechangetimer = {CVAR_SAVE, "sv_namechangetimer", "5", "how often to allow name changes, in seconds (prevents people from using animated names and other tricks"}; +cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"}; +cvar_t rcon_secure = {CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"}; +cvar_t rcon_secure_challengetimeout = {0, "rcon_secure_challengetimeout", "5", "challenge-based secure rcon: time out requests if no challenge came within this time interval"}; +cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"}; +cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"}; +cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"}; +cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"}; +cvar_t r_fixtrans_auto = {0, "r_fixtrans_auto", "0", "automatically fixtrans textures (when set to 2, it also saves the fixed versions to a fixtrans directory)"}; +qboolean allowcheats = false; + +extern qboolean host_shuttingdown; +extern cvar_t developer_entityparsing; + +/* +================== +Host_Quit_f +================== +*/ + +void Host_Quit_f (void) +{ + if(host_shuttingdown) + Con_Printf("shutting down already!\n"); + else + Sys_Quit (0); +} + +/* +================== +Host_Status_f +================== +*/ +static void Host_Status_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + char qcstatus[256]; + client_t *client; + int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0; + void (*print) (const char *fmt, ...); + char ip[48]; // can contain a full length v6 address with [] and a port + int frags; + char vabuf[1024]; + + if (cmd_source == src_command) + { + // if running a client, try to send over network so the client's status report parser will see the report + if (cls.state == ca_connected) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + if (!sv.active) + return; + + in = 0; + if (Cmd_Argc() == 2) + { + if (strcmp(Cmd_Argv(1), "1") == 0) + in = 1; + else if (strcmp(Cmd_Argv(1), "2") == 0) + in = 2; + } + + for (players = 0, i = 0;i < svs.maxclients;i++) + if (svs.clients[i].active) + players++; + print ("host: %s\n", Cvar_VariableString ("hostname")); + print ("version: %s build %s\n", gamename, buildstring); + print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol)); + print ("map: %s\n", sv.name); + print ("timing: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + print ("players: %i active (%i max)\n\n", players, svs.maxclients); + + if (in == 1) + print ("^2IP %%pl ping time frags no name\n"); + else if (in == 2) + print ("^5IP no name\n"); + + for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (!client->active) + continue; + + ++k; + + if (in == 0 || in == 1) + { + seconds = (int)(realtime - client->connecttime); + minutes = seconds / 60; + if (minutes) + { + seconds -= (minutes * 60); + hours = minutes / 60; + if (hours) + minutes -= (hours * 60); + } + else + hours = 0; + + packetloss = 0; + if (client->netconnection) + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET) + packetloss++; + packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS; + ping = bound(0, (int)floor(client->ping*1000+0.5), 9999); + } + + if(sv_status_privacy.integer && cmd_source != src_command) + strlcpy(ip, client->netconnection ? "hidden" : "botclient", 48); + else + strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 48); + + frags = client->frags; + + if(sv_status_show_qcstatus.integer) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(i + 1); + const char *str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus)); + if(str && *str) + { + char *p; + const char *q; + p = qcstatus; + for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q) + if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q)) + *p++ = *q; + *p = 0; + if(*qcstatus) + frags = atoi(qcstatus); + } + } + + if (in == 0) // default layout + { + if (sv.protocol == PROTOCOL_QUAKE && svs.maxclients <= 99) + { + // LordHavoc: this is very touchy because we must maintain ProQuake compatible status output + print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds); + print (" %s\n", ip); + } + else + { + // LordHavoc: no real restrictions here, not a ProQuake-compatible protocol anyway... + print ("#%-3u %-16.16s %4i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds); + print (" %s\n", ip); + } + } + else if (in == 1) // extended layout + { + print ("%s%-47s %2i %4i %2i:%02i:%02i %4i #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, packetloss, ping, hours, minutes, seconds, frags, i+1, client->name); + } + else if (in == 2) // reduced layout + { + print ("%s%-47s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name); + } + } +} + + +/* +================== +Host_God_f + +Sets client to godmode +================== +*/ +static void Host_God_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (!allowcheats) + { + SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n"); + return; + } + + PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_GODMODE; + if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_GODMODE) ) + SV_ClientPrint("godmode OFF\n"); + else + SV_ClientPrint("godmode ON\n"); +} + +static void Host_Notarget_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (!allowcheats) + { + SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n"); + return; + } + + PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) ^ FL_NOTARGET; + if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_NOTARGET) ) + SV_ClientPrint("notarget OFF\n"); + else + SV_ClientPrint("notarget ON\n"); +} + +qboolean noclip_anglehack; + +static void Host_Noclip_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (!allowcheats) + { + SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n"); + return; + } + + if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP) + { + noclip_anglehack = true; + PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_NOCLIP; + SV_ClientPrint("noclip ON\n"); + } + else + { + noclip_anglehack = false; + PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK; + SV_ClientPrint("noclip OFF\n"); + } +} + +/* +================== +Host_Fly_f + +Sets client to flymode +================== +*/ +static void Host_Fly_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (!allowcheats) + { + SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n"); + return; + } + + if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_FLY) + { + PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_FLY; + SV_ClientPrint("flymode ON\n"); + } + else + { + PRVM_serveredictfloat(host_client->edict, movetype) = MOVETYPE_WALK; + SV_ClientPrint("flymode OFF\n"); + } +} + + +/* +================== +Host_Ping_f + +================== +*/ +void Host_Pings_f (void); // called by Host_Ping_f +static void Host_Ping_f (void) +{ + int i; + client_t *client; + void (*print) (const char *fmt, ...); + + if (cmd_source == src_command) + { + // if running a client, try to send over network so the client's ping report parser will see the report + if (cls.state == ca_connected) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + if (!sv.active) + return; + + print("Client ping times:\n"); + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (!client->active) + continue; + print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name); + } + + // now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report) + // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console) + //Host_Pings_f(); +} + +/* +=============================================================================== + +SERVER TRANSITIONS + +=============================================================================== +*/ + +/* +====================== +Host_Map_f + +handle a +map +command from the console. Active clients are kicked off. +====================== +*/ +static void Host_Map_f (void) +{ + char level[MAX_QPATH]; + + if (Cmd_Argc() != 2) + { + Con_Print("map : start a new game (kicks off all players)\n"); + return; + } + + // GAME_DELUXEQUAKE - clear warpmark (used by QC) + if (gamemode == GAME_DELUXEQUAKE) + Cvar_Set("warpmark", ""); + + cls.demonum = -1; // stop demo loop in case this fails + + CL_Disconnect (); + Host_ShutdownServer(); + + if(svs.maxclients != svs.maxclients_next) + { + svs.maxclients = svs.maxclients_next; + if (svs.clients) + Mem_Free(svs.clients); + svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients); + } + + // remove menu + if (key_dest == key_menu || key_dest == key_menu_grabbed) + MR_ToggleMenu(0); + key_dest = key_game; + + svs.serverflags = 0; // haven't completed an episode yet + allowcheats = sv_cheats.integer != 0; + strlcpy(level, Cmd_Argv(1), sizeof(level)); + SV_SpawnServer(level); + if (sv.active && cls.state == ca_disconnected) + CL_EstablishConnection("local:1", -2); +} + +/* +================== +Host_Changelevel_f + +Goes to a new map, taking all clients along +================== +*/ +static void Host_Changelevel_f (void) +{ + char level[MAX_QPATH]; + + if (Cmd_Argc() != 2) + { + Con_Print("changelevel : continue game on a new level\n"); + return; + } + // HACKHACKHACK + if (!sv.active) { + Host_Map_f(); + return; + } + + // remove menu + if (key_dest == key_menu || key_dest == key_menu_grabbed) + MR_ToggleMenu(0); + key_dest = key_game; + + SV_SaveSpawnparms (); + allowcheats = sv_cheats.integer != 0; + strlcpy(level, Cmd_Argv(1), sizeof(level)); + SV_SpawnServer(level); + if (sv.active && cls.state == ca_disconnected) + CL_EstablishConnection("local:1", -2); +} + +/* +================== +Host_Restart_f + +Restarts the current server for a dead player +================== +*/ +static void Host_Restart_f (void) +{ + char mapname[MAX_QPATH]; + + if (Cmd_Argc() != 1) + { + Con_Print("restart : restart current level\n"); + return; + } + if (!sv.active) + { + Con_Print("Only the server may restart\n"); + return; + } + + // remove menu + if (key_dest == key_menu || key_dest == key_menu_grabbed) + MR_ToggleMenu(0); + key_dest = key_game; + + allowcheats = sv_cheats.integer != 0; + strlcpy(mapname, sv.name, sizeof(mapname)); + SV_SpawnServer(mapname); + if (sv.active && cls.state == ca_disconnected) + CL_EstablishConnection("local:1", -2); +} + +/* +================== +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) +{ + char temp[128]; + // if not connected, reconnect to the most recent server + if (!cls.netcon) + { + // if we have connected to a server recently, the userinfo + // will still contain its IP address, so get the address... + InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp)); + if (temp[0]) + CL_EstablishConnection(temp, -1); + else + Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n"); + return; + } + // if connected, do something based on protocol + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + // quakeworld can just re-login + if (cls.qw_downloadmemory) // don't change when downloading + return; + + S_StopAllSounds(); + + if (cls.state == ca_connected && cls.signon < SIGNONS) + { + Con_Printf("reconnecting...\n"); + MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "new"); + } + } + else + { + // netquake uses reconnect on level changes (silly) + if (Cmd_Argc() != 1) + { + Con_Print("reconnect : wait for signon messages again\n"); + return; + } + if (!cls.signon) + { + Con_Print("reconnect: no signon, ignoring reconnect\n"); + return; + } + cls.signon = 0; // need new connection messages + } +} + +/* +===================== +Host_Connect_f + +User command to connect to server +===================== +*/ +static void Host_Connect_f (void) +{ + if (Cmd_Argc() < 2) + { + Con_Print("connect [ ...]: connect to a multiplayer game\n"); + return; + } + // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command + if(rcon_secure.integer <= 0) + Cvar_SetQuick(&rcon_password, ""); + CL_EstablishConnection(Cmd_Argv(1), 2); +} + + +/* +=============================================================================== + +LOAD / SAVE GAME + +=============================================================================== +*/ + +#define SAVEGAME_VERSION 5 + +void Host_Savegame_to(prvm_prog_t *prog, const char *name) +{ + qfile_t *f; + int i, k, l, numbuffers, lightstyles = 64; + char comment[SAVEGAME_COMMENT_LENGTH+1]; + char line[MAX_INPUTLINE]; + qboolean isserver; + char *s; + + // first we have to figure out if this can be saved in 64 lightstyles + // (for Quake compatibility) + for (i=64 ; iedicts, message)), (int)PRVM_serverglobalfloat(killed_monsters), (int)PRVM_serverglobalfloat(total_monsters)); + else + dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", prog->name); + // convert space to _ to make stdio happy + // LordHavoc: convert control characters to _ as well + for (i=0 ; inum_edicts ; i++) + { + FS_Printf(f,"// edict %d\n", i); + //Con_Printf("edict %d...\n", i); + PRVM_ED_Write (prog, f, PRVM_EDICT_NUM(i)); + } + +#if 1 + FS_Printf(f,"/*\n"); + FS_Printf(f,"// DarkPlaces extended savegame\n"); + // darkplaces extension - extra lightstyles, support for color lightstyles + for (i=0 ; istringbuffersarray); + for (i = 0; i < numbuffers; i++) + { + prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i); + if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED)) + { + FS_Printf(f,"sv.buffer %i %i \"string\"\n", i, stringbuffer->flags & STRINGBUFFER_QCFLAGS); + for(k = 0; k < stringbuffer->num_strings; k++) + { + if (!stringbuffer->strings[k]) + continue; + // Parse the string a bit to turn special characters + // (like newline, specifically) into escape codes + s = stringbuffer->strings[k]; + for (l = 0;l < (int)sizeof(line) - 2 && *s;) + { + if (*s == '\n') + { + line[l++] = '\\'; + line[l++] = 'n'; + } + else if (*s == '\r') + { + line[l++] = '\\'; + line[l++] = 'r'; + } + else if (*s == '\\') + { + line[l++] = '\\'; + line[l++] = '\\'; + } + else if (*s == '"') + { + line[l++] = '\\'; + line[l++] = '"'; + } + else + line[l++] = *s; + s++; + } + line[l] = '\0'; + FS_Printf(f,"sv.bufstr %i %i \"%s\"\n", i, k, line); + } + } + } + FS_Printf(f,"*/\n"); +#endif + + FS_Close (f); + Con_Print("done.\n"); +} + +/* +=============== +Host_Savegame_f +=============== +*/ +static void Host_Savegame_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + char name[MAX_QPATH]; + qboolean deadflag = false; + + if (!sv.active) + { + Con_Print("Can't save - no server running.\n"); + return; + } + + deadflag = cl.islocalgame && svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag); + + if (cl.islocalgame) + { + // singleplayer checks + if (cl.intermission) + { + Con_Print("Can't save in intermission.\n"); + return; + } + + if (deadflag) + { + Con_Print("Can't savegame with a dead player\n"); + return; + } + } + else + Con_Print("Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n"); + + if (Cmd_Argc() != 2) + { + Con_Print("save : save a game\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Print("Relative pathnames are not allowed.\n"); + return; + } + + strlcpy (name, Cmd_Argv(1), sizeof (name)); + FS_DefaultExtension (name, ".sav", sizeof (name)); + + Host_Savegame_to(prog, name); +} + + +/* +=============== +Host_Loadgame_f +=============== +*/ + +prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, int flags, char *format); +void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str); +void BufStr_Del(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer); +void BufStr_Flush(prvm_prog_t *prog); + +static void Host_Loadgame_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + char filename[MAX_QPATH]; + char mapname[MAX_QPATH]; + float time; + const char *start; + const char *end; + const char *t; + char *text; + prvm_edict_t *ent; + int i, k, numbuffers; + int entnum; + int version; + float spawn_parms[NUM_SPAWN_PARMS]; + prvm_stringbuffer_t *stringbuffer; + + if (Cmd_Argc() != 2) + { + Con_Print("load : load a game\n"); + return; + } + + strlcpy (filename, Cmd_Argv(1), sizeof(filename)); + FS_DefaultExtension (filename, ".sav", sizeof (filename)); + + Con_Printf("Loading game from %s...\n", filename); + + // stop playing demos + if (cls.demoplayback) + CL_Disconnect (); + + // remove menu + if (key_dest == key_menu || key_dest == key_menu_grabbed) + MR_ToggleMenu(0); + key_dest = key_game; + + cls.demonum = -1; // stop demo loop in case this fails + + t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL); + if (!text) + { + Con_Print("ERROR: couldn't open.\n"); + return; + } + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading version\n"); + + // version + COM_ParseToken_Simple(&t, false, false, true); + version = atoi(com_token); + if (version != SAVEGAME_VERSION) + { + Mem_Free(text); + Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return; + } + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading description\n"); + + // description + COM_ParseToken_Simple(&t, false, false, true); + + for (i = 0;i < NUM_SPAWN_PARMS;i++) + { + COM_ParseToken_Simple(&t, false, false, true); + spawn_parms[i] = atof(com_token); + } + // skill + COM_ParseToken_Simple(&t, false, false, true); +// this silliness is so we can load 1.06 save files, which have float skill values + current_skill = (int)(atof(com_token) + 0.5); + Cvar_SetValue ("skill", (float)current_skill); + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading mapname\n"); + + // mapname + COM_ParseToken_Simple(&t, false, false, true); + strlcpy (mapname, com_token, sizeof(mapname)); + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading time\n"); + + // time + COM_ParseToken_Simple(&t, false, false, true); + time = atof(com_token); + + allowcheats = sv_cheats.integer != 0; + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: spawning server\n"); + + SV_SpawnServer (mapname); + if (!sv.active) + { + Mem_Free(text); + Con_Print("Couldn't load map\n"); + return; + } + sv.paused = true; // pause until all clients connect + sv.loadgame = true; + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading light styles\n"); + +// load the light styles + + // -1 is the globals + entnum = -1; + + for (i = 0;i < MAX_LIGHTSTYLES;i++) + { + // light style + start = t; + COM_ParseToken_Simple(&t, false, false, true); + // if this is a 64 lightstyle savegame produced by Quake, stop now + // we have to check this because darkplaces may save more than 64 + if (com_token[0] == '{') + { + t = start; + break; + } + strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i])); + } + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: skipping until globals\n"); + + // now skip everything before the first opening brace + // (this is for forward compatibility, so that older versions (at + // least ones with this fix) can load savegames with extra data before the + // first brace, as might be produced by a later engine version) + for (;;) + { + start = t; + if (!COM_ParseToken_Simple(&t, false, false, true)) + break; + if (com_token[0] == '{') + { + t = start; + break; + } + } + + // unlink all entities + World_UnlinkAll(&sv.world); + +// load the edicts out of the savegame file + end = t; + for (;;) + { + start = t; + while (COM_ParseToken_Simple(&t, false, false, true)) + if (!strcmp(com_token, "}")) + break; + if (!COM_ParseToken_Simple(&start, false, false, true)) + { + // end of file + break; + } + if (strcmp(com_token,"{")) + { + Mem_Free(text); + Host_Error ("First token isn't a brace"); + } + + if (entnum == -1) + { + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading globals\n"); + + // parse the global vars + PRVM_ED_ParseGlobals (prog, start); + + // restore the autocvar globals + Cvar_UpdateAllAutoCvars(); + } + else + { + // parse an edict + if (entnum >= MAX_EDICTS) + { + Mem_Free(text); + Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS); + } + while (entnum >= prog->max_edicts) + PRVM_MEM_IncreaseEdicts(prog); + ent = PRVM_EDICT_NUM(entnum); + memset(ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); + ent->priv.server->free = false; + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum); + + PRVM_ED_ParseEdict (prog, start, ent); + + // link it into the bsp tree + if (!ent->priv.server->free) + SV_LinkEdict(ent); + } + + end = t; + entnum++; + } + + prog->num_edicts = entnum; + sv.time = time; + + for (i = 0;i < NUM_SPAWN_PARMS;i++) + svs.clients[0].spawn_parms[i] = spawn_parms[i]; + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: skipping until extended data\n"); + + // read extended data if present + // the extended data is stored inside a /* */ comment block, which the + // parser intentionally skips, so we have to check for it manually here + if(end) + { + while (*end == '\r' || *end == '\n') + end++; + if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n')) + { + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: loading extended data\n"); + + Con_Printf("Loading extended DarkPlaces savegame\n"); + t = end + 2; + memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles)); + memset(sv.model_precache[0], 0, sizeof(sv.model_precache)); + memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache)); + BufStr_Flush(prog); + + while (COM_ParseToken_Simple(&t, false, false, true)) + { + if (!strcmp(com_token, "sv.lightstyles")) + { + COM_ParseToken_Simple(&t, false, false, true); + i = atoi(com_token); + COM_ParseToken_Simple(&t, false, false, true); + if (i >= 0 && i < MAX_LIGHTSTYLES) + strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i])); + else + Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token); + } + else if (!strcmp(com_token, "sv.model_precache")) + { + COM_ParseToken_Simple(&t, false, false, true); + i = atoi(com_token); + COM_ParseToken_Simple(&t, false, false, true); + if (i >= 0 && i < MAX_MODELS) + { + strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i])); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.worldname : NULL); + } + else + Con_Printf("unsupported model %i \"%s\"\n", i, com_token); + } + else if (!strcmp(com_token, "sv.sound_precache")) + { + COM_ParseToken_Simple(&t, false, false, true); + i = atoi(com_token); + COM_ParseToken_Simple(&t, false, false, true); + if (i >= 0 && i < MAX_SOUNDS) + strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i])); + else + Con_Printf("unsupported sound %i \"%s\"\n", i, com_token); + } + else if (!strcmp(com_token, "sv.buffer")) + { + if (COM_ParseToken_Simple(&t, false, false, true)) + { + i = atoi(com_token); + if (i >= 0) + { + k = STRINGBUFFER_SAVED; + if (COM_ParseToken_Simple(&t, false, false, true)) + k |= atoi(com_token); + if (!BufStr_FindCreateReplace(prog, i, k, "string")) + Con_Printf("failed to create stringbuffer %i\n", i); + } + else + Con_Printf("unsupported stringbuffer index %i \"%s\"\n", i, com_token); + } + else + Con_Printf("unexpected end of line when parsing sv.buffer (expected buffer index)\n"); + } + else if (!strcmp(com_token, "sv.bufstr")) + { + if (!COM_ParseToken_Simple(&t, false, false, true)) + Con_Printf("unexpected end of line when parsing sv.bufstr\n"); + else + { + i = atoi(com_token); + stringbuffer = BufStr_FindCreateReplace(prog, i, STRINGBUFFER_SAVED, "string"); + if (stringbuffer) + { + if (COM_ParseToken_Simple(&t, false, false, true)) + { + k = atoi(com_token); + if (COM_ParseToken_Simple(&t, false, false, true)) + BufStr_Set(prog, stringbuffer, k, com_token); + else + Con_Printf("unexpected end of line when parsing sv.bufstr (expected string)\n"); + } + else + Con_Printf("unexpected end of line when parsing sv.bufstr (expected strindex)\n"); + } + else + Con_Printf("failed to create stringbuffer %i \"%s\"\n", i, com_token); + } + } + // skip any trailing text or unrecognized commands + while (COM_ParseToken_Simple(&t, true, false, true) && strcmp(com_token, "\n")) + ; + } + } + } + Mem_Free(text); + + // remove all temporary flagged string buffers (ones created with BufStr_FindCreateReplace) + numbuffers = Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); + for (i = 0; i < numbuffers; i++) + { + if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) ) + if (stringbuffer->flags & STRINGBUFFER_TEMP) + BufStr_Del(prog, stringbuffer); + } + + if(developer_entityparsing.integer) + Con_Printf("Host_Loadgame_f: finished\n"); + + // make sure we're connected to loopback + if (sv.active && cls.state == ca_disconnected) + CL_EstablishConnection("local:1", -2); +} + +//============================================================================ + +/* +====================== +Host_Name_f +====================== +*/ +cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"}; +static void Host_Name_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, j; + qboolean valid_colors; + const char *newNameSource; + char newName[sizeof(host_client->name)]; + + if (Cmd_Argc () == 1) + { + Con_Printf("name: %s\n", cl_name.string); + return; + } + + if (Cmd_Argc () == 2) + newNameSource = Cmd_Argv(1); + else + newNameSource = Cmd_Args(); + + strlcpy(newName, newNameSource, sizeof(newName)); + + if (cmd_source == src_command) + { + Cvar_Set ("_cl_name", newName); + if (strlen(newNameSource) >= sizeof(newName)) // overflowed + { + Con_Printf("Your name is longer than %i chars! It has been truncated.\n", (int) (sizeof(newName) - 1)); + Con_Printf("name: %s\n", cl_name.string); + } + return; + } + + if (realtime < host_client->nametime) + { + SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value)); + return; + } + + host_client->nametime = realtime + max(0.0f, sv_namechangetimer.value); + + // point the string back at updateclient->name to keep it safe + strlcpy (host_client->name, newName, sizeof (host_client->name)); + + for (i = 0, j = 0;host_client->name[i];i++) + if (host_client->name[i] != '\r' && host_client->name[i] != '\n') + host_client->name[j++] = host_client->name[i]; + host_client->name[j] = 0; + + if(host_client->name[0] == 1 || host_client->name[0] == 2) + // may interfere with chat area, and will needlessly beep; so let's add a ^7 + { + memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2); + host_client->name[sizeof(host_client->name) - 1] = 0; + host_client->name[0] = STRING_COLOR_TAG; + host_client->name[1] = '0' + STRING_COLOR_DEFAULT; + } + + u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors); + if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string + { + size_t l; + l = strlen(host_client->name); + if(l < sizeof(host_client->name) - 1) + { + // duplicate the color tag to escape it + host_client->name[i] = STRING_COLOR_TAG; + host_client->name[i+1] = 0; + //Con_DPrintf("abuse detected, adding another trailing color tag\n"); + } + else + { + // remove the last character to fix the color code + host_client->name[l-1] = 0; + //Con_DPrintf("abuse detected, removing a trailing color tag\n"); + } + } + + // find the last color tag offset and decide if we need to add a reset tag + for (i = 0, j = -1;host_client->name[i];i++) + { + if (host_client->name[i] == STRING_COLOR_TAG) + { + if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9') + { + j = i; + // if this happens to be a reset tag then we don't need one + if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT) + j = -1; + i++; + continue; + } + if (host_client->name[i+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4])) + { + j = i; + i += 4; + continue; + } + if (host_client->name[i+1] == STRING_COLOR_TAG) + { + i++; + continue; + } + } + } + // does not end in the default color string, so add it + if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2) + memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1); + + PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name); + if (strcmp(host_client->old_name, host_client->name)) + { + if (host_client->begun) + SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name); + strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name)); + // 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); + SV_WriteNetnameIntoDemo(host_client); + } +} + +/* +====================== +Host_Playermodel_f +====================== +*/ +cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz/Xonotic (changed by playermodel command)"}; +// the old cl_playermodel in cl_main has been renamed to __cl_playermodel +static void Host_Playermodel_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, j; + char newPath[sizeof(host_client->playermodel)]; + + if (Cmd_Argc () == 1) + { + Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string); + return; + } + + if (Cmd_Argc () == 2) + strlcpy (newPath, Cmd_Argv(1), sizeof (newPath)); + else + strlcpy (newPath, Cmd_Args(), sizeof (newPath)); + + for (i = 0, j = 0;newPath[i];i++) + if (newPath[i] != '\r' && newPath[i] != '\n') + newPath[j++] = newPath[i]; + newPath[j] = 0; + + if (cmd_source == src_command) + { + Cvar_Set ("_cl_playermodel", newPath); + return; + } + + /* + if (realtime < host_client->nametime) + { + SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n"); + return; + } + + host_client->nametime = realtime + 5; + */ + + // point the string back at updateclient->name to keep it safe + strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel)); + PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel); + if (strcmp(host_client->old_model, host_client->playermodel)) + { + strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model)); + /*// send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/ + } +} + +/* +====================== +Host_Playerskin_f +====================== +*/ +cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz/Xonotic (changed by playerskin command)"}; +static void Host_Playerskin_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, j; + char newPath[sizeof(host_client->playerskin)]; + + if (Cmd_Argc () == 1) + { + Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string); + return; + } + + if (Cmd_Argc () == 2) + strlcpy (newPath, Cmd_Argv(1), sizeof (newPath)); + else + strlcpy (newPath, Cmd_Args(), sizeof (newPath)); + + for (i = 0, j = 0;newPath[i];i++) + if (newPath[i] != '\r' && newPath[i] != '\n') + newPath[j++] = newPath[i]; + newPath[j] = 0; + + if (cmd_source == src_command) + { + Cvar_Set ("_cl_playerskin", newPath); + return; + } + + /* + if (realtime < host_client->nametime) + { + SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n"); + return; + } + + host_client->nametime = realtime + 5; + */ + + // point the string back at updateclient->name to keep it safe + strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin)); + PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin); + if (strcmp(host_client->old_skin, host_client->playerskin)) + { + //if (host_client->begun) + // SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin); + strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin)); + /*// send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/ + } +} + +static void Host_Version_f (void) +{ + Con_Printf("Version: %s build %s\n", gamename, buildstring); +} + +static void Host_Say(qboolean teamonly) +{ + prvm_prog_t *prog = SVVM_prog; + client_t *save; + int j, quoted; + const char *p1; + char *p2; + // LordHavoc: long say messages + char text[1024]; + 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; + + if (!teamplay.integer) + teamonly = false; + + p1 = Cmd_Args(); + quoted = false; + if (*p1 == '\"') + { + quoted = true; + p1++; + } + // note this uses the chat prefix \001 + if (!fromServer && !teamonly) + dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1); + else if (!fromServer && teamonly) + dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1); + else if(*(sv_adminnick.string)) + dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1); + else + dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1); + p2 = text + strlen(text); + while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted))) + { + if (p2[-1] == '\"' && quoted) + quoted = false; + p2[-1] = 0; + p2--; + } + strlcat(text, "\n", sizeof(text)); + + // note: save is not a valid edict if fromServer is true + save = host_client; + for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++) + if (host_client->active && (!teamonly || PRVM_serveredictfloat(host_client->edict, team) == PRVM_serveredictfloat(save->edict, team))) + SV_ClientPrint(text); + host_client = save; + + if (cls.state == ca_dedicated) + Con_Print(&text[1]); +} + + +static void Host_Say_f(void) +{ + Host_Say(false); +} + + +static void Host_Say_Team_f(void) +{ + Host_Say(true); +} + + +static void Host_Tell_f(void) +{ + const char *playername_start = NULL; + size_t playername_length = 0; + int playernumber = 0; + client_t *save; + int j; + const char *p1, *p2; + char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64) + qboolean fromServer = false; + + if (cmd_source == src_command) + { + if (cls.state == ca_dedicated) + fromServer = true; + else + { + Cmd_ForwardToServer (); + return; + } + } + + if (Cmd_Argc () < 2) + return; + + // note this uses the chat prefix \001 + if (!fromServer) + dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name); + else if(*(sv_adminnick.string)) + dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string); + else + dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string); + + p1 = Cmd_Args(); + p2 = p1 + strlen(p1); + // remove the target name + while (p1 < p2 && *p1 == ' ') + p1++; + if(*p1 == '#') + { + ++p1; + while (p1 < p2 && *p1 == ' ') + p1++; + while (p1 < p2 && isdigit(*p1)) + { + playernumber = playernumber * 10 + (*p1 - '0'); + p1++; + } + --playernumber; + } + else if(*p1 == '"') + { + ++p1; + playername_start = p1; + while (p1 < p2 && *p1 != '"') + p1++; + playername_length = p1 - playername_start; + if(p1 < p2) + p1++; + } + else + { + playername_start = p1; + while (p1 < p2 && *p1 != ' ') + p1++; + playername_length = p1 - playername_start; + } + while (p1 < p2 && *p1 == ' ') + p1++; + if(playername_start) + { + // set playernumber to the right client + char namebuf[128]; + if(playername_length >= sizeof(namebuf)) + { + if (fromServer) + Con_Print("Host_Tell: too long player name/ID\n"); + else + SV_ClientPrint("Host_Tell: too long player name/ID\n"); + return; + } + memcpy(namebuf, playername_start, playername_length); + namebuf[playername_length] = 0; + for (playernumber = 0; playernumber < svs.maxclients; playernumber++) + { + if (!svs.clients[playernumber].active) + continue; + if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0) + break; + } + } + if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active)) + { + if (fromServer) + Con_Print("Host_Tell: invalid player name/ID\n"); + else + SV_ClientPrint("Host_Tell: invalid player name/ID\n"); + return; + } + // remove trailing newlines + while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r')) + p2--; + // remove quotes if present + if (*p1 == '"') + { + p1++; + if (p2[-1] == '"') + p2--; + else if (fromServer) + Con_Print("Host_Tell: missing end quote\n"); + else + SV_ClientPrint("Host_Tell: missing end quote\n"); + } + while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r')) + p2--; + if(p1 == p2) + return; // empty say + for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;) + text[j++] = *p1++; + text[j++] = '\n'; + text[j++] = 0; + + save = host_client; + host_client = svs.clients + playernumber; + SV_ClientPrint(text); + host_client = save; +} + + +/* +================== +Host_Color_f +================== +*/ +cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"}; +static void Host_Color(int changetop, int changebottom) +{ + prvm_prog_t *prog = SVVM_prog; + int top, bottom, playercolor; + + // get top and bottom either from the provided values or the current values + // (allows changing only top or bottom, or both at once) + top = changetop >= 0 ? changetop : (cl_color.integer >> 4); + bottom = changebottom >= 0 ? changebottom : cl_color.integer; + + top &= 15; + bottom &= 15; + // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out + //if (top > 13) + // top = 13; + //if (bottom > 13) + // bottom = 13; + + playercolor = top*16 + bottom; + + if (cmd_source == src_command) + { + Cvar_SetValueQuick(&cl_color, playercolor); + return; + } + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + return; + + if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam)) + { + Con_DPrint("Calling SV_ChangeTeam\n"); + prog->globals.fp[OFS_PARM0] = playercolor; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing"); + } + else + { + if (host_client->edict) + { + PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor; + PRVM_serveredictfloat(host_client->edict, team) = bottom + 1; + } + host_client->colors = playercolor; + if (host_client->old_colors != host_client->colors) + { + host_client->old_colors = host_client->colors; + // 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); + } + } +} + +static void Host_Color_f(void) +{ + int top, bottom; + + if (Cmd_Argc() == 1) + { + Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15); + Con_Print("color <0-15> [0-15]\n"); + return; + } + + if (Cmd_Argc() == 2) + top = bottom = atoi(Cmd_Argv(1)); + else + { + top = atoi(Cmd_Argv(1)); + bottom = atoi(Cmd_Argv(2)); + } + Host_Color(top, bottom); +} + +static void Host_TopColor_f(void) +{ + if (Cmd_Argc() == 1) + { + Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15); + Con_Print("topcolor <0-15>\n"); + return; + } + + Host_Color(atoi(Cmd_Argv(1)), -1); +} + +static void Host_BottomColor_f(void) +{ + if (Cmd_Argc() == 1) + { + Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15); + Con_Print("bottomcolor <0-15>\n"); + return; + } + + Host_Color(-1, atoi(Cmd_Argv(1))); +} + +cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"}; +static void Host_Rate_f(void) +{ + int rate; + + if (Cmd_Argc() != 2) + { + Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer); + Con_Print("rate \n"); + return; + } + + rate = atoi(Cmd_Argv(1)); + + if (cmd_source == src_command) + { + Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate)); + return; + } + + host_client->rate = rate; +} + +/* +================== +Host_Kill_f +================== +*/ +static void Host_Kill_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (PRVM_serveredictfloat(host_client->edict, health) <= 0) + { + SV_ClientPrint("Can't suicide -- already dead!\n"); + return; + } + + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(ClientKill), "QC function ClientKill is missing"); +} + + +/* +================== +Host_Pause_f +================== +*/ +static void Host_Pause_f (void) +{ + void (*print) (const char *fmt, ...); + if (cmd_source == src_command) + { + // if running a client, try to send over network so the pause is handled by the server + if (cls.state == ca_connected) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + if (!pausable.integer) + { + if (cmd_source == src_client) + { + if(cls.state == ca_dedicated || host_client != &svs.clients[0]) // non-admin + { + print("Pause not allowed.\n"); + return; + } + } + } + + sv.paused ^= 1; + SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un"); + // send notification to all clients + MSG_WriteByte(&sv.reliable_datagram, svc_setpause); + MSG_WriteByte(&sv.reliable_datagram, sv.paused); +} + +/* +====================== +Host_PModel_f +LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen. +LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility. +====================== +*/ +cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"}; +static void Host_PModel_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + + if (Cmd_Argc () == 1) + { + Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string); + return; + } + i = atoi(Cmd_Argv(1)); + + if (cmd_source == src_command) + { + if (cl_pmodel.integer == i) + return; + Cvar_SetValue ("_cl_pmodel", i); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + PRVM_serveredictfloat(host_client->edict, pmodel) = i; +} + +//=========================================================================== + + +/* +================== +Host_PreSpawn_f +================== +*/ +static void Host_PreSpawn_f (void) +{ + if (host_client->prespawned) + { + Con_Print("prespawn not valid -- already prespawned\n"); + return; + } + host_client->prespawned = true; + + if (host_client->netconnection) + { + SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize); + MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); + MSG_WriteByte (&host_client->netconnection->message, 2); + host_client->sendsignon = 0; // enable unlimited sends again + } + + // reset the name change timer because the client will send name soon + host_client->nametime = 0; +} + +/* +================== +Host_Spawn_f +================== +*/ +static void Host_Spawn_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + client_t *client; + int stats[MAX_CL_STATS]; + + if (!host_client->prespawned) + { + Con_Print("Spawn not valid -- not yet prespawned\n"); + return; + } + if (host_client->spawned) + { + Con_Print("Spawn not valid -- already spawned\n"); + return; + } + host_client->spawned = true; + + // reset name change timer again because they might want to change name + // again in the first 5 seconds after connecting + host_client->nametime = 0; + + // LordHavoc: moved this above the QC calls at FrikaC's request + // LordHavoc: commented this out + //if (host_client->netconnection) + // SZ_Clear (&host_client->netconnection->message); + + // run the entrance script + if (sv.loadgame) + { + // loaded games are fully initialized already + if (PRVM_serverfunction(RestoreGame)) + { + Con_DPrint("Calling RestoreGame\n"); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(RestoreGame), "QC function RestoreGame is missing"); + } + } + else + { + //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, host_client->edict->netname = %s, host_client->name = %s\n", PRVM_GetString(PRVM_serveredictstring(host_client->edict, netname)), PRVM_GetString(PRVM_serveredictstring(host_client->edict, netname)), host_client->name); + + // copy spawn parms out of the client_t + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&PRVM_serverglobalfloat(parm1))[i] = host_client->spawn_parms[i]; + + // call the spawn function + host_client->clientconnectcalled = true; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing"); + + if (cls.state == ca_dedicated) + Con_Printf("%s connected\n", host_client->name); + + PRVM_serverglobalfloat(time) = sv.time; + prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing"); + } + + if (!host_client->netconnection) + return; + + // send time of update + MSG_WriteByte (&host_client->netconnection->message, svc_time); + MSG_WriteFloat (&host_client->netconnection->message, sv.time); + + // send all current names, colors, and frag counts + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (!client->active) + continue; + MSG_WriteByte (&host_client->netconnection->message, svc_updatename); + MSG_WriteByte (&host_client->netconnection->message, i); + MSG_WriteString (&host_client->netconnection->message, client->name); + MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags); + MSG_WriteByte (&host_client->netconnection->message, i); + MSG_WriteShort (&host_client->netconnection->message, client->frags); + MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors); + MSG_WriteByte (&host_client->netconnection->message, i); + MSG_WriteByte (&host_client->netconnection->message, client->colors); + } + + // send all current light styles + for (i=0 ; inetconnection->message, svc_lightstyle); + MSG_WriteByte (&host_client->netconnection->message, (char)i); + MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]); + } + } + + // send some stats + MSG_WriteByte (&host_client->netconnection->message, svc_updatestat); + MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS); + MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(total_secrets)); + + MSG_WriteByte (&host_client->netconnection->message, svc_updatestat); + MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS); + MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(total_monsters)); + + MSG_WriteByte (&host_client->netconnection->message, svc_updatestat); + MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS); + MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(found_secrets)); + + MSG_WriteByte (&host_client->netconnection->message, svc_updatestat); + MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS); + MSG_WriteLong (&host_client->netconnection->message, (int)PRVM_serverglobalfloat(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 + if (sv.loadgame) + { + MSG_WriteByte (&host_client->netconnection->message, svc_setangle); + MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[0], sv.protocol); + MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, v_angle)[1], sv.protocol); + MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol); + } + else + { + MSG_WriteByte (&host_client->netconnection->message, svc_setangle); + MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[0], sv.protocol); + MSG_WriteAngle (&host_client->netconnection->message, PRVM_serveredictvector(host_client->edict, angles)[1], sv.protocol); + MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol); + } + + SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats); + + MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); + MSG_WriteByte (&host_client->netconnection->message, 3); +} + +/* +================== +Host_Begin_f +================== +*/ +static void Host_Begin_f (void) +{ + if (!host_client->spawned) + { + Con_Print("Begin not valid -- not yet spawned\n"); + return; + } + if (host_client->begun) + { + Con_Print("Begin not valid -- already begun\n"); + return; + } + host_client->begun = true; + + // LordHavoc: note: this code also exists in SV_DropClient + if (sv.loadgame) + { + int i; + for (i = 0;i < svs.maxclients;i++) + if (svs.clients[i].active && !svs.clients[i].spawned) + break; + if (i == svs.maxclients) + { + Con_Printf("Loaded game, everyone rejoined - unpausing\n"); + sv.paused = sv.loadgame = false; // we're basically done with loading now + } + } +} + +//=========================================================================== + + +/* +================== +Host_Kick_f + +Kicks a user off of the server +================== +*/ +static void Host_Kick_f (void) +{ + const char *who; + const char *message = NULL; + client_t *save; + int i; + qboolean byNumber = false; + + if (!sv.active) + return; + + save = host_client; + + if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0) + { + i = (int)(atof(Cmd_Argv(2)) - 1); + if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active) + return; + byNumber = true; + } + else + { + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + if (!host_client->active) + continue; + if (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 = Cmd_Args(); + COM_ParseToken_Simple(&message, false, false, true); + if (byNumber) + { + message++; // skip the # + while (*message == ' ') // skip white space + message++; + message += 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); // kicked + } + + host_client = save; +} + +/* +=============================================================================== + +DEBUGGING TOOLS + +=============================================================================== +*/ + +/* +================== +Host_Give_f +================== +*/ +static void Host_Give_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + const char *t; + int v; + + if (!allowcheats) + { + SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n"); + 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 (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) + { + if (t[0] == '6') + { + if (t[1] == 'a') + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_PROXIMITY_GUN; + else + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | IT_GRENADE_LAUNCHER; + } + else if (t[0] == '9') + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_LASER_CANNON; + else if (t[0] == '0') + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | HIT_MJOLNIR; + else if (t[0] >= '2') + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2')); + } + else + { + if (t[0] >= '2') + PRVM_serveredictfloat(host_client->edict, items) = (int)PRVM_serveredictfloat(host_client->edict, items) | (IT_SHOTGUN << (t[0] - '2')); + } + break; + + case 's': + if (gamemode == GAME_ROGUE) + PRVM_serveredictfloat(host_client->edict, ammo_shells1) = v; + + PRVM_serveredictfloat(host_client->edict, ammo_shells) = v; + break; + case 'n': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_nails1) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_nails) = v; + } + else + { + PRVM_serveredictfloat(host_client->edict, ammo_nails) = v; + } + break; + case 'l': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_lava_nails) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_nails) = v; + } + break; + case 'r': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_rockets1) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v; + } + else + { + PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v; + } + break; + case 'm': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_multi_rockets) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_rockets) = v; + } + break; + case 'h': + PRVM_serveredictfloat(host_client->edict, health) = v; + break; + case 'c': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_cells1) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) <= IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_cells) = v; + } + else + { + PRVM_serveredictfloat(host_client->edict, ammo_cells) = v; + } + break; + case 'p': + if (gamemode == GAME_ROGUE) + { + PRVM_serveredictfloat(host_client->edict, ammo_plasma) = v; + if (PRVM_serveredictfloat(host_client->edict, weapon) > IT_LIGHTNING) + PRVM_serveredictfloat(host_client->edict, ammo_cells) = v; + } + break; + } +} + +static prvm_edict_t *FindViewthing(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *e; + + for (i=0 ; inum_edicts ; i++) + { + e = PRVM_EDICT_NUM(i); + if (!strcmp (PRVM_GetString(prog, PRVM_serveredictstring(e, classname)), "viewthing")) + return e; + } + Con_Print("No viewthing on map\n"); + return NULL; +} + +/* +================== +Host_Viewmodel_f +================== +*/ +static void Host_Viewmodel_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *e; + dp_model_t *m; + + if (!sv.active) + return; + + e = FindViewthing(prog); + if (e) + { + m = Mod_ForName (Cmd_Argv(1), false, true, NULL); + if (m && m->loaded && m->Draw) + { + PRVM_serveredictfloat(e, frame) = 0; + cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)] = m; + } + else + Con_Printf("viewmodel: can't load %s\n", Cmd_Argv(1)); + } +} + +/* +================== +Host_Viewframe_f +================== +*/ +static void Host_Viewframe_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *e; + int f; + dp_model_t *m; + + if (!sv.active) + return; + + e = FindViewthing(prog); + if (e) + { + m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)]; + + f = atoi(Cmd_Argv(1)); + if (f >= m->numframes) + f = m->numframes-1; + + PRVM_serveredictfloat(e, frame) = f; + } +} + + +static void PrintFrameName (dp_model_t *m, int frame) +{ + if (m->animscenes) + Con_Printf("frame %i: %s\n", frame, m->animscenes[frame].name); + else + Con_Printf("frame %i\n", frame); +} + +/* +================== +Host_Viewnext_f +================== +*/ +static void Host_Viewnext_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *e; + dp_model_t *m; + + if (!sv.active) + return; + + e = FindViewthing(prog); + if (e) + { + m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)]; + + PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) + 1; + if (PRVM_serveredictfloat(e, frame) >= m->numframes) + PRVM_serveredictfloat(e, frame) = m->numframes - 1; + + PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame)); + } +} + +/* +================== +Host_Viewprev_f +================== +*/ +static void Host_Viewprev_f (void) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *e; + dp_model_t *m; + + if (!sv.active) + return; + + e = FindViewthing(prog); + if (e) + { + m = cl.model_precache[(int)PRVM_serveredictfloat(e, modelindex)]; + + PRVM_serveredictfloat(e, frame) = PRVM_serveredictfloat(e, frame) - 1; + if (PRVM_serveredictfloat(e, frame) < 0) + PRVM_serveredictfloat(e, frame) = 0; + + PrintFrameName (m, (int)PRVM_serveredictfloat(e, frame)); + } +} + +/* +=============================================================================== + +DEMO LOOP CONTROL + +=============================================================================== +*/ + + +/* +================== +Host_Startdemos_f +================== +*/ +static void Host_Startdemos_f (void) +{ + int i, c; + + if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo")) + return; + + c = Cmd_Argc() - 1; + if (c > MAX_DEMOS) + { + Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS); + c = MAX_DEMOS; + } + Con_DPrintf("%i demo(s) in loop\n", c); + + for (i=1 ; iflags & CVAR_PRIVATE)) + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "sentcvar %s", cvarname)); + else + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "sentcvar %s \"%s\"", c->name, c->string)); + return; + } + if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand)) + return; + + old = host_client; + if (cls.state != ca_dedicated) + i = 1; + else + i = 0; + for(;i 0) + { + Con_Printf ("You must set rcon_password before issuing an pqrcon command, and rcon_secure must be 0.\n"); + return; + } + + e = strchr(rcon_password.string, ' '); + n = e ? e-rcon_password.string : (int)strlen(rcon_password.string); + + if (cls.netcon) + { + InfoString_GetValue(cls.userinfo, "*ip", peer_address, sizeof(peer_address)); + } + else + { + if (!rcon_address.string[0]) + { + Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n"); + return; + } + strlcpy(peer_address, rcon_address.string, strlen(rcon_address.string)+1); + } + LHNETADDRESS_FromString(&to, peer_address, sv_netport.integer); + mysocket = NetConn_ChooseClientSocketForAddress(&to); + if (mysocket) + { + sizebuf_t buf; + unsigned char bufdata[64]; + buf.data = bufdata; + SZ_Clear(&buf); + MSG_WriteLong(&buf, 0); + MSG_WriteByte(&buf, CCREQ_RCON); + SZ_Write(&buf, (const unsigned char*)rcon_password.string, n); + MSG_WriteByte(&buf, 0); // terminate the (possibly partial) string + MSG_WriteString(&buf, Cmd_Args()); + StoreBigLong(buf.data, NETFLAG_CTL | (buf.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, buf.data, buf.cursize, &to); + SZ_Clear(&buf); + } +} + +//============================================================================= + +// QuakeWorld commands + +/* +===================== +Host_Rcon_f + + Send the rest of the command line over as + an unconnected command. +===================== +*/ +static void Host_Rcon_f (void) // credit: taken from QuakeWorld +{ + int i, n; + const char *e; + lhnetaddress_t to; + lhnetsocket_t *mysocket; + char vabuf[1024]; + + if (Cmd_Argc() == 1) + { + Con_Printf("%s: Usage: %s command\n", Cmd_Argv(0), Cmd_Argv(0)); + return; + } + + if (!rcon_password.string || !rcon_password.string[0]) + { + Con_Printf ("You must set rcon_password before issuing an rcon command.\n"); + return; + } + + e = strchr(rcon_password.string, ' '); + n = e ? e-rcon_password.string : (int)strlen(rcon_password.string); + + if (cls.netcon) + to = cls.netcon->peeraddress; + else + { + if (!rcon_address.string[0]) + { + Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n"); + return; + } + LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer); + } + mysocket = NetConn_ChooseClientSocketForAddress(&to); + if (mysocket && Cmd_Args()[0]) + { + // simply put together the rcon packet and send it + if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer > 1) + { + if(cls.rcon_commands[cls.rcon_ringpos][0]) + { + char s[128]; + LHNETADDRESS_ToString(&cls.rcon_addresses[cls.rcon_ringpos], s, sizeof(s), true); + Con_Printf("rcon to %s (for command %s) failed: too many buffered commands (possibly increase MAX_RCONS)\n", s, cls.rcon_commands[cls.rcon_ringpos]); + cls.rcon_commands[cls.rcon_ringpos][0] = 0; + --cls.rcon_trying; + } + for (i = 0;i < MAX_RCONS;i++) + if(cls.rcon_commands[i][0]) + if (!LHNETADDRESS_Compare(&to, &cls.rcon_addresses[i])) + break; + ++cls.rcon_trying; + if(i >= MAX_RCONS) + NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", &to); // otherwise we'll request the challenge later + strlcpy(cls.rcon_commands[cls.rcon_ringpos], Cmd_Args(), sizeof(cls.rcon_commands[cls.rcon_ringpos])); + cls.rcon_addresses[cls.rcon_ringpos] = to; + cls.rcon_timeout[cls.rcon_ringpos] = realtime + rcon_secure_challengetimeout.value; + cls.rcon_ringpos = (cls.rcon_ringpos + 1) % MAX_RCONS; + } + else if(rcon_secure.integer > 0) + { + char buf[1500]; + char argbuf[1500]; + dpsnprintf(argbuf, sizeof(argbuf), "%ld.%06d %s", (long) time(NULL), (int) (rand() % 1000000), Cmd_Args()); + memcpy(buf, "\377\377\377\377srcon HMAC-MD4 TIME ", 24); + if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 24), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, n)) + { + buf[40] = ' '; + strlcpy(buf + 41, argbuf, sizeof(buf) - 41); + NetConn_Write(mysocket, buf, 41 + strlen(buf + 41), &to); + } + } + else + { + NetConn_WriteString(mysocket, va(vabuf, sizeof(vabuf), "\377\377\377\377rcon %.*s %s", n, rcon_password.string, Cmd_Args()), &to); + } + } +} + +/* +==================== +Host_User_f + +user + +Dump userdata / masterdata for a user +==================== +*/ +static void Host_User_f (void) // credit: taken from QuakeWorld +{ + int uid; + int i; + + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: user \n"); + return; + } + + uid = atoi(Cmd_Argv(1)); + + for (i = 0;i < cl.maxclients;i++) + { + if (!cl.scores[i].name[0]) + continue; + if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1))) + { + InfoString_Print(cl.scores[i].qw_userinfo); + return; + } + } + Con_Printf ("User not in server.\n"); +} + +/* +==================== +Host_Users_f + +Dump userids for all current players +==================== +*/ +static void Host_Users_f (void) // credit: taken from QuakeWorld +{ + int i; + int c; + + c = 0; + Con_Printf ("userid frags name\n"); + Con_Printf ("------ ----- ----\n"); + for (i = 0;i < cl.maxclients;i++) + { + if (cl.scores[i].name[0]) + { + Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name); + c++; + } + } + + Con_Printf ("%i total users\n", c); +} + +/* +================== +Host_FullServerinfo_f + +Sent by server when serverinfo changes +================== +*/ +// TODO: shouldn't this be a cvar instead? +static void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld +{ + char temp[512]; + if (Cmd_Argc() != 2) + { + Con_Printf ("usage: fullserverinfo \n"); + return; + } + + strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo)); + InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp)); + cl.qw_teamplay = atoi(temp); +} + +/* +================== +Host_FullInfo_f + +Allow clients to change userinfo +================== +Casey was here :) +*/ +static void Host_FullInfo_f (void) // credit: taken from QuakeWorld +{ + char key[512]; + char value[512]; + char *o; + const char *s; + + if (Cmd_Argc() != 2) + { + Con_Printf ("fullinfo \n"); + return; + } + + s = Cmd_Argv(1); + if (*s == '\\') + s++; + while (*s) + { + o = key; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + + if (!*s) + { + Con_Printf ("MISSING VALUE\n"); + return; + } + + o = value; + s++; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + + if (*s) + s++; + + CL_SetInfo(key, value, false, false, false, false); + } +} + +/* +================== +CL_SetInfo_f + +Allow clients to change userinfo +================== +*/ +static void Host_SetInfo_f (void) // credit: taken from QuakeWorld +{ + if (Cmd_Argc() == 1) + { + InfoString_Print(cls.userinfo); + return; + } + if (Cmd_Argc() != 3) + { + Con_Printf ("usage: setinfo [ ]\n"); + return; + } + CL_SetInfo(Cmd_Argv(1), Cmd_Argv(2), true, false, false, false); +} + +/* +==================== +Host_Packet_f + +packet + +Contents allows \n escape character +==================== +*/ +static void Host_Packet_f (void) // credit: taken from QuakeWorld +{ + char send[2048]; + int i, l; + const char *in; + char *out; + lhnetaddress_t address; + lhnetsocket_t *mysocket; + + if (Cmd_Argc() != 3) + { + Con_Printf ("packet \n"); + return; + } + + if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer)) + { + Con_Printf ("Bad address\n"); + return; + } + + in = Cmd_Argv(2); + out = send+4; + send[0] = send[1] = send[2] = send[3] = -1; + + l = (int)strlen (in); + for (i=0 ; i= send + sizeof(send) - 1) + break; + if (in[i] == '\\' && in[i+1] == 'n') + { + *out++ = '\n'; + i++; + } + else if (in[i] == '\\' && in[i+1] == '0') + { + *out++ = '\0'; + i++; + } + else if (in[i] == '\\' && in[i+1] == 't') + { + *out++ = '\t'; + i++; + } + else if (in[i] == '\\' && in[i+1] == 'r') + { + *out++ = '\r'; + i++; + } + else if (in[i] == '\\' && in[i+1] == '"') + { + *out++ = '\"'; + i++; + } + else + *out++ = in[i]; + } + + mysocket = NetConn_ChooseClientSocketForAddress(&address); + if (!mysocket) + mysocket = NetConn_ChooseServerSocketForAddress(&address); + if (mysocket) + NetConn_Write(mysocket, send, out - send, &address); +} + +/* +==================== +Host_Pings_f + +Send back ping and packet loss update for all current players to this player +==================== +*/ +void Host_Pings_f (void) +{ + int i, j, ping, packetloss, movementloss; + char temp[128]; + + if (!host_client->netconnection) + return; + + if (sv.protocol != PROTOCOL_QUAKEWORLD) + { + MSG_WriteByte(&host_client->netconnection->message, svc_stufftext); + MSG_WriteUnterminatedString(&host_client->netconnection->message, "pingplreport"); + } + for (i = 0;i < svs.maxclients;i++) + { + packetloss = 0; + movementloss = 0; + if (svs.clients[i].netconnection) + { + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (svs.clients[i].netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET) + packetloss++; + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (svs.clients[i].movement_count[j] < 0) + movementloss++; + } + packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS; + movementloss = (movementloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS; + ping = (int)floor(svs.clients[i].ping*1000+0.5); + ping = bound(0, ping, 9999); + if (sv.protocol == PROTOCOL_QUAKEWORLD) + { + // send qw_svc_updateping and qw_svc_updatepl messages + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updateping); + MSG_WriteShort(&host_client->netconnection->message, ping); + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatepl); + MSG_WriteByte(&host_client->netconnection->message, packetloss); + } + else + { + // write the string into the packet as multiple unterminated strings to avoid needing a local buffer + if(movementloss) + dpsnprintf(temp, sizeof(temp), " %d %d,%d", ping, packetloss, movementloss); + else + dpsnprintf(temp, sizeof(temp), " %d %d", ping, packetloss); + MSG_WriteUnterminatedString(&host_client->netconnection->message, temp); + } + } + if (sv.protocol != PROTOCOL_QUAKEWORLD) + MSG_WriteString(&host_client->netconnection->message, "\n"); +} + +static void Host_PingPLReport_f(void) +{ + char *errbyte; + int i; + int l = Cmd_Argc(); + if (l > cl.maxclients) + l = cl.maxclients; + for (i = 0;i < l;i++) + { + cl.scores[i].qw_ping = atoi(Cmd_Argv(1+i*2)); + cl.scores[i].qw_packetloss = strtol(Cmd_Argv(1+i*2+1), &errbyte, 0); + if(errbyte && *errbyte == ',') + cl.scores[i].qw_movementloss = atoi(errbyte + 1); + else + cl.scores[i].qw_movementloss = 0; + } +} + +//============================================================================= + +/* +================== +Host_InitCommands +================== +*/ +void Host_InitCommands (void) +{ + dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp"); + + Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information"); + Cmd_AddCommand ("quit", Host_Quit_f, "quit the game"); + Cmd_AddCommand_WithClientCommand ("god", NULL, Host_God_f, "god mode (invulnerability)"); + Cmd_AddCommand_WithClientCommand ("notarget", NULL, Host_Notarget_f, "notarget mode (monsters do not see you)"); + Cmd_AddCommand_WithClientCommand ("fly", NULL, Host_Fly_f, "fly mode (flight)"); + Cmd_AddCommand_WithClientCommand ("noclip", NULL, Host_Noclip_f, "noclip mode (flight without collisions, move through walls)"); + Cmd_AddCommand_WithClientCommand ("give", NULL, Host_Give_f, "alter inventory"); + Cmd_AddCommand ("map", Host_Map_f, "kick everyone off the server and start a new level"); + Cmd_AddCommand ("restart", Host_Restart_f, "restart current level"); + Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients"); + Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname"); + Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reconnect to the last server you were on, or resets a quakeworld connection (do not use if currently playing on a netquake server)"); + Cmd_AddCommand ("version", Host_Version_f, "print engine version"); + Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server"); + Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server"); + Cmd_AddCommand_WithClientCommand ("tell", Host_Tell_f, Host_Tell_f, "send a chat message to only one person on the server"); + Cmd_AddCommand_WithClientCommand ("kill", NULL, Host_Kill_f, "die instantly"); + Cmd_AddCommand_WithClientCommand ("pause", Host_Pause_f, Host_Pause_f, "pause the game (if the server allows pausing)"); + Cmd_AddCommand ("kick", Host_Kick_f, "kick a player off the server by number or name"); + Cmd_AddCommand_WithClientCommand ("ping", Host_Ping_f, Host_Ping_f, "print ping times of all players on the server"); + Cmd_AddCommand ("load", Host_Loadgame_f, "load a saved game file"); + Cmd_AddCommand ("save", Host_Savegame_f, "save the game to a file"); + + Cmd_AddCommand ("startdemos", Host_Startdemos_f, "start playing back the selected demos sequentially (used at end of startup script)"); + Cmd_AddCommand ("demos", Host_Demos_f, "restart looping demos defined by the last startdemos command"); + Cmd_AddCommand ("stopdemo", Host_Stopdemo_f, "stop playing or recording demo (like stop command) and return to looping demos"); + + Cmd_AddCommand ("viewmodel", Host_Viewmodel_f, "change model of viewthing entity in current level"); + Cmd_AddCommand ("viewframe", Host_Viewframe_f, "change animation frame of viewthing entity in current level"); + Cmd_AddCommand ("viewnext", Host_Viewnext_f, "change to next animation frame of viewthing entity in current level"); + Cmd_AddCommand ("viewprev", Host_Viewprev_f, "change to previous animation frame of viewthing entity in current level"); + + Cvar_RegisterVariable (&cl_name); + Cmd_AddCommand_WithClientCommand ("name", Host_Name_f, Host_Name_f, "change your player name"); + Cvar_RegisterVariable (&cl_color); + Cmd_AddCommand_WithClientCommand ("color", Host_Color_f, Host_Color_f, "change your player shirt and pants colors"); + Cvar_RegisterVariable (&cl_rate); + Cmd_AddCommand_WithClientCommand ("rate", Host_Rate_f, Host_Rate_f, "change your network connection speed"); + Cvar_RegisterVariable (&cl_pmodel); + Cmd_AddCommand_WithClientCommand ("pmodel", Host_PModel_f, Host_PModel_f, "(Nehahra-only) change your player model choice"); + + // BLACK: This isnt game specific anymore (it was GAME_NEXUIZ at first) + Cvar_RegisterVariable (&cl_playermodel); + Cmd_AddCommand_WithClientCommand ("playermodel", Host_Playermodel_f, Host_Playermodel_f, "change your player model"); + Cvar_RegisterVariable (&cl_playerskin); + Cmd_AddCommand_WithClientCommand ("playerskin", Host_Playerskin_f, Host_Playerskin_f, "change your player skin number"); + + Cmd_AddCommand_WithClientCommand ("prespawn", NULL, Host_PreSpawn_f, "signon 1 (client acknowledges that server information has been received)"); + Cmd_AddCommand_WithClientCommand ("spawn", NULL, Host_Spawn_f, "signon 2 (client has sent player information, and is asking server to send scoreboard rankings)"); + Cmd_AddCommand_WithClientCommand ("begin", NULL, Host_Begin_f, "signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)"); + Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once"); + + Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC"); + + Cvar_RegisterVariable (&rcon_password); + Cvar_RegisterVariable (&rcon_address); + Cvar_RegisterVariable (&rcon_secure); + Cvar_RegisterVariable (&rcon_secure_challengetimeout); + Cmd_AddCommand ("rcon", Host_Rcon_f, "sends a command to the server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's); note: if rcon_secure is set, client and server clocks must be synced e.g. via NTP"); + Cmd_AddCommand ("srcon", Host_Rcon_f, "sends a command to the server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's); this always works as if rcon_secure is set; note: client and server clocks must be synced e.g. via NTP"); + Cmd_AddCommand ("pqrcon", Host_PQRcon_f, "sends a command to a proquake server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's)"); + Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard"); + Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard"); + Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string"); + Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo"); + Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo"); + Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string"); + Cmd_AddCommand ("topcolor", Host_TopColor_f, "QW command to set top color without changing bottom color"); + Cmd_AddCommand ("bottomcolor", Host_BottomColor_f, "QW command to set bottom color without changing top color"); + + Cmd_AddCommand_WithClientCommand ("pings", NULL, Host_Pings_f, "command sent by clients to request updated ping and packetloss of players on scoreboard (originally from QW, but also used on NQ servers)"); + Cmd_AddCommand ("pingplreport", Host_PingPLReport_f, "command sent by server containing client ping and packet loss values for scoreboard, triggered by pings command from client (not used by QW servers)"); + + Cmd_AddCommand ("fixtrans", Image_FixTransparentPixels_f, "change alpha-zero pixels in an image file to sensible values, and write out a new TGA (warning: SLOW)"); + Cvar_RegisterVariable (&r_fixtrans_auto); + + Cvar_RegisterVariable (&team); + Cvar_RegisterVariable (&skin); + Cvar_RegisterVariable (&noaim); + + Cvar_RegisterVariable(&sv_cheats); + Cvar_RegisterVariable(&sv_adminnick); + Cvar_RegisterVariable(&sv_status_privacy); + Cvar_RegisterVariable(&sv_status_show_qcstatus); + Cvar_RegisterVariable(&sv_namechangetimer); +} + +void Host_NoOperation_f(void) +{ +} diff --git a/app/jni/image.c b/app/jni/image.c new file mode 100644 index 0000000..366e80d --- /dev/null +++ b/app/jni/image.c @@ -0,0 +1,1588 @@ + +#include "quakedef.h" +#include "image.h" +#include "jpeg.h" +#include "image_png.h" +#include "r_shadow.h" + +int image_width; +int image_height; + +static void Image_CopyAlphaFromBlueBGRA(unsigned char *outpixels, const unsigned char *inpixels, int w, int h) +{ + int i, n; + n = w * h; + for(i = 0; i < n; ++i) + outpixels[4*i+3] = inpixels[4*i]; // blue channel +} + +#if 1 +// written by LordHavoc in a readable way, optimized by Vic, further optimized by LordHavoc (the non-special index case), readable version preserved below this +void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices) +{ + int index, c, x, y; + const unsigned char *in, *line; + int row_inc = (inputflipy ? -inputwidth : inputwidth) * numinputcomponents, col_inc = (inputflipx ? -1 : 1) * numinputcomponents; + int row_ofs = (inputflipy ? (inputheight - 1) * inputwidth * numinputcomponents : 0), col_ofs = (inputflipx ? (inputwidth - 1) * numinputcomponents : 0); + + for (c = 0; c < numoutputcomponents; c++) + if (outputinputcomponentindices[c] & 0x80000000) + break; + if (c < numoutputcomponents) + { + // special indices used + if (inputflipdiagonal) + { + for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc) + for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents) + for (c = 0; c < numoutputcomponents; c++) + outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index]; + } + else + { + for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc) + for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents) + for (c = 0; c < numoutputcomponents; c++) + outpixels[c] = ((index = outputinputcomponentindices[c]) & 0x80000000) ? index : in[index]; + } + } + else + { + // special indices not used + if (inputflipdiagonal) + { + for (x = 0, line = inpixels + col_ofs; x < inputwidth; x++, line += col_inc) + for (y = 0, in = line + row_ofs; y < inputheight; y++, in += row_inc, outpixels += numoutputcomponents) + for (c = 0; c < numoutputcomponents; c++) + outpixels[c] = in[outputinputcomponentindices[c]]; + } + else + { + for (y = 0, line = inpixels + row_ofs; y < inputheight; y++, line += row_inc) + for (x = 0, in = line + col_ofs; x < inputwidth; x++, in += col_inc, outpixels += numoutputcomponents) + for (c = 0; c < numoutputcomponents; c++) + outpixels[c] = in[outputinputcomponentindices[c]]; + } + } +} +#else +// intentionally readable version +void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices) +{ + int index, c, x, y; + const unsigned char *in, *inrow, *incolumn; + if (inputflipdiagonal) + { + for (x = 0;x < inputwidth;x++) + { + for (y = 0;y < inputheight;y++) + { + in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents; + for (c = 0;c < numoutputcomponents;c++) + { + index = outputinputcomponentindices[c]; + if (index & 0x80000000) + *outpixels++ = index; + else + *outpixels++ = in[index]; + } + } + } + } + else + { + for (y = 0;y < inputheight;y++) + { + for (x = 0;x < inputwidth;x++) + { + in = inpixels + ((inputflipy ? inputheight - 1 - y : y) * inputwidth + (inputflipx ? inputwidth - 1 - x : x)) * numinputcomponents; + for (c = 0;c < numoutputcomponents;c++) + { + index = outputinputcomponentindices[c]; + if (index & 0x80000000) + *outpixels++ = index; + else + *outpixels++ = in[index]; + } + } + } + } +} +#endif + +void Image_GammaRemapRGB(const unsigned char *in, unsigned char *out, int pixels, const unsigned char *gammar, const unsigned char *gammag, const unsigned char *gammab) +{ + while (pixels--) + { + out[0] = gammar[in[0]]; + out[1] = gammag[in[1]]; + out[2] = gammab[in[2]]; + in += 3; + out += 3; + } +} + +// note: pal must be 32bit color +void Image_Copy8bitBGRA(const unsigned char *in, unsigned char *out, int pixels, const unsigned int *pal) +{ + int *iout = (int *)out; + while (pixels >= 8) + { + iout[0] = pal[in[0]]; + iout[1] = pal[in[1]]; + iout[2] = pal[in[2]]; + iout[3] = pal[in[3]]; + iout[4] = pal[in[4]]; + iout[5] = pal[in[5]]; + iout[6] = pal[in[6]]; + iout[7] = pal[in[7]]; + in += 8; + iout += 8; + pixels -= 8; + } + if (pixels & 4) + { + iout[0] = pal[in[0]]; + iout[1] = pal[in[1]]; + iout[2] = pal[in[2]]; + iout[3] = pal[in[3]]; + in += 4; + iout += 4; + } + if (pixels & 2) + { + iout[0] = pal[in[0]]; + iout[1] = pal[in[1]]; + in += 2; + iout += 2; + } + if (pixels & 1) + iout[0] = pal[in[0]]; +} + +/* +================================================================= + + PCX Loading + +================================================================= +*/ + +typedef struct pcx_s +{ + 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]; +} pcx_t; + +/* +============ +LoadPCX +============ +*/ +static unsigned char* LoadPCX_BGRA (const unsigned char *f, int filesize, int *miplevel) +{ + pcx_t pcx; + unsigned char *a, *b, *image_buffer, *pbuf; + const unsigned char *palette, *fin, *enddata; + int x, y, x2, dataByte; + + if (filesize < (int)sizeof(pcx) + 768) + { + Con_Print("Bad pcx file\n"); + return NULL; + } + + fin = f; + + memcpy(&pcx, fin, sizeof(pcx)); + fin += sizeof(pcx); + + // LordHavoc: big-endian support ported from QF newtree + pcx.xmax = LittleShort (pcx.xmax); + pcx.xmin = LittleShort (pcx.xmin); + pcx.ymax = LittleShort (pcx.ymax); + pcx.ymin = LittleShort (pcx.ymin); + pcx.hres = LittleShort (pcx.hres); + pcx.vres = LittleShort (pcx.vres); + pcx.bytes_per_line = LittleShort (pcx.bytes_per_line); + pcx.palette_type = LittleShort (pcx.palette_type); + + image_width = pcx.xmax + 1 - pcx.xmin; + image_height = pcx.ymax + 1 - pcx.ymin; + if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0) + { + Con_Print("Bad pcx file\n"); + return NULL; + } + + palette = f + filesize - 768; + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height*4); + if (!image_buffer) + { + Con_Printf("LoadPCX: not enough memory for %i by %i image\n", image_width, image_height); + return NULL; + } + pbuf = image_buffer + image_width*image_height*3; + enddata = palette; + + for (y = 0;y < image_height && fin < enddata;y++) + { + a = pbuf + y * image_width; + for (x = 0;x < image_width && fin < enddata;) + { + dataByte = *fin++; + if(dataByte >= 0xC0) + { + if (fin >= enddata) + break; + x2 = x + (dataByte & 0x3F); + dataByte = *fin++; + if (x2 > image_width) + x2 = image_width; // technically an error + while(x < x2) + a[x++] = dataByte; + } + else + a[x++] = dataByte; + } + while(x < image_width) + a[x++] = 0; + } + + a = image_buffer; + b = pbuf; + + for(x = 0;x < image_width*image_height;x++) + { + y = *b++ * 3; + *a++ = palette[y+2]; + *a++ = palette[y+1]; + *a++ = palette[y]; + *a++ = 255; + } + + return image_buffer; +} + +/* +============ +LoadPCX +============ +*/ +qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight) +{ + pcx_t pcx; + unsigned char *a; + const unsigned char *fin, *enddata; + int x, y, x2, dataByte, pcxwidth, pcxheight; + + if (filesize < (int)sizeof(pcx) + 768) + return false; + + image_width = outwidth; + image_height = outheight; + fin = f; + + memcpy(&pcx, fin, sizeof(pcx)); + fin += sizeof(pcx); + + // LordHavoc: big-endian support ported from QF newtree + pcx.xmax = LittleShort (pcx.xmax); + pcx.xmin = LittleShort (pcx.xmin); + pcx.ymax = LittleShort (pcx.ymax); + pcx.ymin = LittleShort (pcx.ymin); + pcx.hres = LittleShort (pcx.hres); + pcx.vres = LittleShort (pcx.vres); + pcx.bytes_per_line = LittleShort (pcx.bytes_per_line); + pcx.palette_type = LittleShort (pcx.palette_type); + + pcxwidth = pcx.xmax + 1 - pcx.xmin; + pcxheight = pcx.ymax + 1 - pcx.ymin; + if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcxwidth > 4096 || pcxheight > 4096 || pcxwidth <= 0 || pcxheight <= 0) + return false; + + enddata = f + filesize - 768; + + for (y = 0;y < outheight && fin < enddata;y++) + { + a = pixels + y * outwidth; + // pad the output with blank lines if needed + if (y >= pcxheight) + { + memset(a, 0, outwidth); + continue; + } + for (x = 0;x < pcxwidth;) + { + if (fin >= enddata) + return false; + dataByte = *fin++; + if(dataByte >= 0xC0) + { + x2 = x + (dataByte & 0x3F); + if (fin >= enddata) + return false; + if (x2 > pcxwidth) + return false; + dataByte = *fin++; + for (;x < x2;x++) + if (x < outwidth) + a[x] = dataByte; + } + else + { + if (x < outwidth) // truncate to destination width + a[x] = dataByte; + x++; + } + } + while(x < outwidth) + a[x++] = 0; + } + + return true; +} + +/* +========================================================= + +TARGA LOADING + +========================================================= +*/ + +typedef struct _TargaHeader +{ + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} +TargaHeader; + +static void PrintTargaHeader(TargaHeader *t) +{ + Con_Printf("TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes); +} + +/* +============= +LoadTGA +============= +*/ +unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel) +{ + int x, y, pix_inc, row_inci, runlen, alphabits; + unsigned char *image_buffer; + unsigned int *pixbufi; + const unsigned char *fin, *enddata; + TargaHeader targa_header; + unsigned int palettei[256]; + union + { + unsigned int i; + unsigned char b[4]; + } + bgra; + + if (filesize < 19) + return NULL; + + enddata = f + filesize; + + targa_header.id_length = f[0]; + targa_header.colormap_type = f[1]; + targa_header.image_type = f[2]; + + targa_header.colormap_index = f[3] + f[4] * 256; + targa_header.colormap_length = f[5] + f[6] * 256; + targa_header.colormap_size = f[7]; + targa_header.x_origin = f[8] + f[9] * 256; + targa_header.y_origin = f[10] + f[11] * 256; + targa_header.width = image_width = f[12] + f[13] * 256; + targa_header.height = image_height = f[14] + f[15] * 256; + targa_header.pixel_size = f[16]; + targa_header.attributes = f[17]; + + if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0) + { + Con_Print("LoadTGA: invalid size\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + + // advance to end of header + fin = f + 18; + + // skip TARGA image comment (usually 0 bytes) + fin += targa_header.id_length; + + // read/skip the colormap if present (note: according to the TARGA spec it + // can be present even on truecolor or greyscale images, just not used by + // the image data) + if (targa_header.colormap_type) + { + if (targa_header.colormap_length > 256) + { + Con_Print("LoadTGA: only up to 256 colormap_length supported\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + if (targa_header.colormap_index) + { + Con_Print("LoadTGA: colormap_index not supported\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + if (targa_header.colormap_size == 24) + { + for (x = 0;x < targa_header.colormap_length;x++) + { + bgra.b[0] = *fin++; + bgra.b[1] = *fin++; + bgra.b[2] = *fin++; + bgra.b[3] = 255; + palettei[x] = bgra.i; + } + } + else if (targa_header.colormap_size == 32) + { + memcpy(palettei, fin, targa_header.colormap_length*4); + fin += targa_header.colormap_length * 4; + } + else + { + Con_Print("LoadTGA: Only 32 and 24 bit colormap_size supported\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + } + + // check our pixel_size restrictions according to image_type + switch (targa_header.image_type & ~8) + { + case 2: + if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32) + { + Con_Print("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + break; + case 3: + // set up a palette to make the loader easier + for (x = 0;x < 256;x++) + { + bgra.b[0] = bgra.b[1] = bgra.b[2] = x; + bgra.b[3] = 255; + palettei[x] = bgra.i; + } + // fall through to colormap case + case 1: + if (targa_header.pixel_size != 8) + { + Con_Print("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n"); + PrintTargaHeader(&targa_header); + return NULL; + } + break; + default: + Con_Printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type); + PrintTargaHeader(&targa_header); + return NULL; + } + + if (targa_header.attributes & 0x10) + { + Con_Print("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n"); + return NULL; + } + + // number of attribute bits per pixel, we only support 0 or 8 + alphabits = targa_header.attributes & 0x0F; + if (alphabits != 8 && alphabits != 0) + { + Con_Print("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n"); + return NULL; + } + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + if (!image_buffer) + { + Con_Printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height); + return NULL; + } + + // If bit 5 of attributes isn't set, the image has been stored from bottom to top + if ((targa_header.attributes & 0x20) == 0) + { + pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width; + row_inci = -image_width*2; + } + else + { + pixbufi = (unsigned int*)image_buffer; + row_inci = 0; + } + + pix_inc = 1; + if ((targa_header.image_type & ~8) == 2) + pix_inc = (targa_header.pixel_size + 7) / 8; + switch (targa_header.image_type) + { + case 1: // colormapped, uncompressed + case 3: // greyscale, uncompressed + if (fin + image_width * image_height * pix_inc > enddata) + break; + for (y = 0;y < image_height;y++, pixbufi += row_inci) + for (x = 0;x < image_width;x++) + *pixbufi++ = palettei[*fin++]; + break; + case 2: + // BGR or BGRA, uncompressed + if (fin + image_width * image_height * pix_inc > enddata) + break; + if (targa_header.pixel_size == 32 && alphabits) + { + for (y = 0;y < image_height;y++) + memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4); + } + else + { + for (y = 0;y < image_height;y++, pixbufi += row_inci) + { + for (x = 0;x < image_width;x++, fin += pix_inc) + { + bgra.b[0] = fin[0]; + bgra.b[1] = fin[1]; + bgra.b[2] = fin[2]; + bgra.b[3] = 255; + *pixbufi++ = bgra.i; + } + } + } + break; + case 9: // colormapped, RLE + case 11: // greyscale, RLE + for (y = 0;y < image_height;y++, pixbufi += row_inci) + { + for (x = 0;x < image_width;) + { + if (fin >= enddata) + break; // error - truncated file + runlen = *fin++; + if (runlen & 0x80) + { + // RLE - all pixels the same color + runlen += 1 - 0x80; + if (fin + pix_inc > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + bgra.i = palettei[*fin++]; + for (;runlen--;x++) + *pixbufi++ = bgra.i; + } + else + { + // uncompressed - all pixels different color + runlen++; + if (fin + pix_inc * runlen > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + for (;runlen--;x++) + *pixbufi++ = palettei[*fin++]; + } + } + + if (x != image_width) + { + // pixbufi is useless now + Con_Printf("LoadTGA: corrupt file\n"); + break; + } + } + break; + case 10: + // BGR or BGRA, RLE + if (targa_header.pixel_size == 32 && alphabits) + { + for (y = 0;y < image_height;y++, pixbufi += row_inci) + { + for (x = 0;x < image_width;) + { + if (fin >= enddata) + break; // error - truncated file + runlen = *fin++; + if (runlen & 0x80) + { + // RLE - all pixels the same color + runlen += 1 - 0x80; + if (fin + pix_inc > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + bgra.b[0] = fin[0]; + bgra.b[1] = fin[1]; + bgra.b[2] = fin[2]; + bgra.b[3] = fin[3]; + fin += pix_inc; + for (;runlen--;x++) + *pixbufi++ = bgra.i; + } + else + { + // uncompressed - all pixels different color + runlen++; + if (fin + pix_inc * runlen > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + for (;runlen--;x++) + { + bgra.b[0] = fin[0]; + bgra.b[1] = fin[1]; + bgra.b[2] = fin[2]; + bgra.b[3] = fin[3]; + fin += pix_inc; + *pixbufi++ = bgra.i; + } + } + } + + if (x != image_width) + { + // pixbufi is useless now + Con_Printf("LoadTGA: corrupt file\n"); + break; + } + } + } + else + { + for (y = 0;y < image_height;y++, pixbufi += row_inci) + { + for (x = 0;x < image_width;) + { + if (fin >= enddata) + break; // error - truncated file + runlen = *fin++; + if (runlen & 0x80) + { + // RLE - all pixels the same color + runlen += 1 - 0x80; + if (fin + pix_inc > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + bgra.b[0] = fin[0]; + bgra.b[1] = fin[1]; + bgra.b[2] = fin[2]; + bgra.b[3] = 255; + fin += pix_inc; + for (;runlen--;x++) + *pixbufi++ = bgra.i; + } + else + { + // uncompressed - all pixels different color + runlen++; + if (fin + pix_inc * runlen > enddata) + break; // error - truncated file + if (x + runlen > image_width) + break; // error - line exceeds width + for (;runlen--;x++) + { + bgra.b[0] = fin[0]; + bgra.b[1] = fin[1]; + bgra.b[2] = fin[2]; + bgra.b[3] = 255; + fin += pix_inc; + *pixbufi++ = bgra.i; + } + } + } + + if (x != image_width) + { + // pixbufi is useless now + Con_Printf("LoadTGA: corrupt file\n"); + break; + } + } + } + break; + default: + // unknown image_type + break; + } + + return image_buffer; +} + +typedef struct q2wal_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} q2wal_t; + +static unsigned char *LoadWAL_BGRA (const unsigned char *f, int filesize, int *miplevel) +{ + unsigned char *image_buffer; + const q2wal_t *inwal = (const q2wal_t *)f; + + if (filesize < (int) sizeof(q2wal_t)) + { + Con_Print("LoadWAL: invalid WAL file\n"); + return NULL; + } + + image_width = LittleLong(inwal->width); + image_height = LittleLong(inwal->height); + if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0) + { + Con_Printf("LoadWAL: invalid size %ix%i\n", image_width, image_height); + return NULL; + } + + if (filesize < (int) sizeof(q2wal_t) + (int) LittleLong(inwal->offsets[0]) + image_width * image_height) + { + Con_Print("LoadWAL: invalid WAL file\n"); + return NULL; + } + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + if (!image_buffer) + { + Con_Printf("LoadWAL: not enough memory for %i by %i image\n", image_width, image_height); + return NULL; + } + Image_Copy8bitBGRA(f + LittleLong(inwal->offsets[0]), image_buffer, image_width * image_height, palette_bgra_complete); + return image_buffer; +} + + +void Image_StripImageExtension (const char *in, char *out, size_t size_out) +{ + const char *ext; + + if (size_out == 0) + return; + + ext = FS_FileExtension(in); + if (ext && (!strcmp(ext, "tga") || !strcmp(ext, "pcx") || !strcmp(ext, "lmp") || !strcmp(ext, "png") || !strcmp(ext, "jpg"))) + FS_StripExtension(in, out, size_out); + else + strlcpy(out, in, size_out); +} + +static unsigned char image_linearfromsrgb[256]; +static unsigned char image_srgbfromlinear_lightmap[256]; + +void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels) +{ + int i; + // this math from http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt + if (!image_linearfromsrgb[255]) + for (i = 0;i < 256;i++) + image_linearfromsrgb[i] = (unsigned char)floor(Image_LinearFloatFromsRGB(i) * 255.0f + 0.5f); + for (i = 0;i < numpixels;i++) + { + pout[i*4+0] = image_linearfromsrgb[pin[i*4+0]]; + pout[i*4+1] = image_linearfromsrgb[pin[i*4+1]]; + pout[i*4+2] = image_linearfromsrgb[pin[i*4+2]]; + pout[i*4+3] = pin[i*4+3]; + } +} + +void Image_MakesRGBColorsFromLinear_Lightmap(unsigned char *pout, const unsigned char *pin, int numpixels) +{ + int i; + // this math from http://www.opengl.org/registry/specs/EXT/texture_sRGB.txt + if (!image_srgbfromlinear_lightmap[255]) + for (i = 0;i < 256;i++) + image_srgbfromlinear_lightmap[i] = (unsigned char)floor(bound(0.0f, Image_sRGBFloatFromLinear_Lightmap(i), 1.0f) * 255.0f + 0.5f); + for (i = 0;i < numpixels;i++) + { + pout[i*4+0] = image_srgbfromlinear_lightmap[pin[i*4+0]]; + pout[i*4+1] = image_srgbfromlinear_lightmap[pin[i*4+1]]; + pout[i*4+2] = image_srgbfromlinear_lightmap[pin[i*4+2]]; + pout[i*4+3] = pin[i*4+3]; + } +} + +typedef struct imageformat_s +{ + const char *formatstring; + unsigned char *(*loadfunc)(const unsigned char *f, int filesize, int *miplevel); +} +imageformat_t; + +// GAME_TENEBRAE only +imageformat_t imageformats_tenebrae[] = +{ + {"override/%s.tga", LoadTGA_BGRA}, + {"override/%s.png", PNG_LoadImage_BGRA}, + {"override/%s.jpg", JPEG_LoadImage_BGRA}, + {"override/%s.pcx", LoadPCX_BGRA}, + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {NULL, NULL} +}; + +imageformat_t imageformats_nopath[] = +{ + {"override/%s.tga", LoadTGA_BGRA}, + {"override/%s.png", PNG_LoadImage_BGRA}, + {"override/%s.jpg", JPEG_LoadImage_BGRA}, + {"textures/%s.tga", LoadTGA_BGRA}, + {"textures/%s.png", PNG_LoadImage_BGRA}, + {"textures/%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {NULL, NULL} +}; + +// GAME_DELUXEQUAKE only +// VorteX: the point why i use such messy texture paths is +// that GtkRadiant can't detect normal/gloss textures +// and exclude them from texture browser +// so i just use additional folder to store this textures +imageformat_t imageformats_dq[] = +{ + {"%s.tga", LoadTGA_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"texturemaps/%s.tga", LoadTGA_BGRA}, + {"texturemaps/%s.jpg", JPEG_LoadImage_BGRA}, + {NULL, NULL} +}; + +imageformat_t imageformats_textures[] = +{ + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {"%s.wal", LoadWAL_BGRA}, + {NULL, NULL} +}; + +imageformat_t imageformats_gfx[] = +{ + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {NULL, NULL} +}; + +imageformat_t imageformats_other[] = +{ + {"%s.tga", LoadTGA_BGRA}, + {"%s.png", PNG_LoadImage_BGRA}, + {"%s.jpg", JPEG_LoadImage_BGRA}, + {"%s.pcx", LoadPCX_BGRA}, + {NULL, NULL} +}; + +int fixtransparentpixels(unsigned char *data, int w, int h); +unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB, int *miplevel) +{ + fs_offset_t filesize; + imageformat_t *firstformat, *format; + unsigned char *f, *data = NULL, *data2 = NULL; + char basename[MAX_QPATH], name[MAX_QPATH], name2[MAX_QPATH], *c; + char vabuf[1024]; + //if (developer_memorydebug.integer) + // Mem_CheckSentinelsGlobal(); + if (developer_texturelogging.integer) + Log_Printf("textures.log", "%s\n", filename); + Image_StripImageExtension(filename, basename, sizeof(basename)); // strip filename extensions to allow replacement by other types + // replace *'s with #, so commandline utils don't get confused when dealing with the external files + for (c = basename;*c;c++) + if (*c == '*') + *c = '#'; + name[0] = 0; + if (strchr(basename, '/')) + { + int i; + for (i = 0;i < (int)sizeof(name)-1 && basename[i] != '/';i++) + name[i] = basename[i]; + name[i] = 0; + } + if (gamemode == GAME_TENEBRAE) + firstformat = imageformats_tenebrae; + else if (gamemode == GAME_DELUXEQUAKE) + firstformat = imageformats_dq; + else if (!strcasecmp(name, "textures")) + firstformat = imageformats_textures; + else if (!strcasecmp(name, "gfx")) + firstformat = imageformats_gfx; + else if (!strchr(basename, '/')) + firstformat = imageformats_nopath; + else + firstformat = imageformats_other; + // now try all the formats in the selected list + for (format = firstformat;format->formatstring;format++) + { + dpsnprintf (name, sizeof(name), format->formatstring, basename); + f = FS_LoadFile(name, tempmempool, true, &filesize); + if (f) + { + int mymiplevel = miplevel ? *miplevel : 0; + data = format->loadfunc(f, (int)filesize, &mymiplevel); + Mem_Free(f); + if (data) + { + if(format->loadfunc == JPEG_LoadImage_BGRA) // jpeg can't do alpha, so let's simulate it by loading another jpeg + { + dpsnprintf (name2, sizeof(name2), format->formatstring, va(vabuf, sizeof(vabuf), "%s_alpha", basename)); + f = FS_LoadFile(name2, tempmempool, true, &filesize); + if(f) + { + int mymiplevel2 = miplevel ? *miplevel : 0; + data2 = format->loadfunc(f, (int)filesize, &mymiplevel2); + if(data2 && mymiplevel == mymiplevel2) + Image_CopyAlphaFromBlueBGRA(data, data2, image_width, image_height); + else + Con_Printf("loadimagepixelsrgba: corrupt or invalid alpha image %s_alpha\n", basename); + if(data2) + Mem_Free(data2); + Mem_Free(f); + } + } + if (developer_loading.integer) + Con_DPrintf("loaded image %s (%dx%d)\n", name, image_width, image_height); + if(miplevel) + *miplevel = mymiplevel; + //if (developer_memorydebug.integer) + // Mem_CheckSentinelsGlobal(); + if(allowFixtrans && r_fixtrans_auto.integer) + { + int n = fixtransparentpixels(data, image_width, image_height); + if(n) + { + Con_Printf("- had to fix %s (%d pixels changed)\n", name, n); + if(r_fixtrans_auto.integer >= 2) + { + char outfilename[MAX_QPATH], buf[MAX_QPATH]; + Image_StripImageExtension(name, buf, sizeof(buf)); + dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf); + Image_WriteTGABGRA(outfilename, image_width, image_height, data); + Con_Printf("- %s written.\n", outfilename); + } + } + } + if (convertsRGB) + Image_MakeLinearColorsFromsRGB(data, data, image_width * image_height); + return data; + } + else + Con_DPrintf("Error loading image %s (file loaded but decode failed)\n", name); + } + } + if (complain) + { + Con_Printf("Couldn't load %s using ", filename); + for (format = firstformat;format->formatstring;format++) + { + dpsnprintf (name, sizeof(name), format->formatstring, basename); + Con_Printf(format == firstformat ? "\"%s\"" : (format[1].formatstring ? ", \"%s\"" : " or \"%s\".\n"), format->formatstring); + } + } + + // texture loading can take a while, so make sure we're sending keepalives + CL_KeepaliveMessage(false); + + //if (developer_memorydebug.integer) + // Mem_CheckSentinelsGlobal(); + return NULL; +} + +extern cvar_t gl_picmip; +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB) +{ + unsigned char *data; + rtexture_t *rt; + int miplevel = R_PicmipForFlags(flags); + if (!(data = loadimagepixelsbgra (filename, complain, allowFixtrans, false, &miplevel))) + return 0; + rt = R_LoadTexture2D(pool, filename, image_width, image_height, data, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, flags, miplevel, NULL); + Mem_Free(data); + return rt; +} + +int fixtransparentpixels(unsigned char *data, int w, int h) +{ + int const FIXTRANS_NEEDED = 1; + int const FIXTRANS_HAS_L = 2; + int const FIXTRANS_HAS_R = 4; + int const FIXTRANS_HAS_U = 8; + int const FIXTRANS_HAS_D = 16; + int const FIXTRANS_FIXED = 32; + unsigned char *fixMask = (unsigned char *) Mem_Alloc(tempmempool, w * h); + int fixPixels = 0; + int changedPixels = 0; + int x, y; + +#define FIXTRANS_PIXEL (y*w+x) +#define FIXTRANS_PIXEL_U (((y+h-1)%h)*w+x) +#define FIXTRANS_PIXEL_D (((y+1)%h)*w+x) +#define FIXTRANS_PIXEL_L (y*w+((x+w-1)%w)) +#define FIXTRANS_PIXEL_R (y*w+((x+1)%w)) + + memset(fixMask, 0, w * h); + for(y = 0; y < h; ++y) + for(x = 0; x < w; ++x) + { + if(data[FIXTRANS_PIXEL * 4 + 3] == 0) + { + fixMask[FIXTRANS_PIXEL] |= FIXTRANS_NEEDED; + ++fixPixels; + } + else + { + fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U; + fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D; + fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L; + fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R; + } + } + if(fixPixels == w * h) + return 0; // sorry, can't do anything about this + while(fixPixels) + { + for(y = 0; y < h; ++y) + for(x = 0; x < w; ++x) + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_NEEDED) + { + unsigned int sumR = 0, sumG = 0, sumB = 0, sumA = 0, sumRA = 0, sumGA = 0, sumBA = 0, cnt = 0; + unsigned char r, g, b, a, r0, g0, b0; + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_U) + { + r = data[FIXTRANS_PIXEL_U * 4 + 2]; + g = data[FIXTRANS_PIXEL_U * 4 + 1]; + b = data[FIXTRANS_PIXEL_U * 4 + 0]; + a = data[FIXTRANS_PIXEL_U * 4 + 3]; + sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt; + } + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_D) + { + r = data[FIXTRANS_PIXEL_D * 4 + 2]; + g = data[FIXTRANS_PIXEL_D * 4 + 1]; + b = data[FIXTRANS_PIXEL_D * 4 + 0]; + a = data[FIXTRANS_PIXEL_D * 4 + 3]; + sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt; + } + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_L) + { + r = data[FIXTRANS_PIXEL_L * 4 + 2]; + g = data[FIXTRANS_PIXEL_L * 4 + 1]; + b = data[FIXTRANS_PIXEL_L * 4 + 0]; + a = data[FIXTRANS_PIXEL_L * 4 + 3]; + sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt; + } + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_HAS_R) + { + r = data[FIXTRANS_PIXEL_R * 4 + 2]; + g = data[FIXTRANS_PIXEL_R * 4 + 1]; + b = data[FIXTRANS_PIXEL_R * 4 + 0]; + a = data[FIXTRANS_PIXEL_R * 4 + 3]; + sumR += r; sumG += g; sumB += b; sumA += a; sumRA += r*a; sumGA += g*a; sumBA += b*a; ++cnt; + } + if(!cnt) + continue; + r0 = data[FIXTRANS_PIXEL * 4 + 2]; + g0 = data[FIXTRANS_PIXEL * 4 + 1]; + b0 = data[FIXTRANS_PIXEL * 4 + 0]; + if(sumA) + { + // there is a surrounding non-alpha pixel + r = (sumRA + sumA / 2) / sumA; + g = (sumGA + sumA / 2) / sumA; + b = (sumBA + sumA / 2) / sumA; + } + else + { + // need to use a "regular" average + r = (sumR + cnt / 2) / cnt; + g = (sumG + cnt / 2) / cnt; + b = (sumB + cnt / 2) / cnt; + } + if(r != r0 || g != g0 || b != b0) + ++changedPixels; + data[FIXTRANS_PIXEL * 4 + 2] = r; + data[FIXTRANS_PIXEL * 4 + 1] = g; + data[FIXTRANS_PIXEL * 4 + 0] = b; + fixMask[FIXTRANS_PIXEL] |= FIXTRANS_FIXED; + } + for(y = 0; y < h; ++y) + for(x = 0; x < w; ++x) + if(fixMask[FIXTRANS_PIXEL] & FIXTRANS_FIXED) + { + fixMask[FIXTRANS_PIXEL] &= ~(FIXTRANS_NEEDED | FIXTRANS_FIXED); + fixMask[FIXTRANS_PIXEL_D] |= FIXTRANS_HAS_U; + fixMask[FIXTRANS_PIXEL_U] |= FIXTRANS_HAS_D; + fixMask[FIXTRANS_PIXEL_R] |= FIXTRANS_HAS_L; + fixMask[FIXTRANS_PIXEL_L] |= FIXTRANS_HAS_R; + --fixPixels; + } + } + return changedPixels; +} + +void Image_FixTransparentPixels_f(void) +{ + const char *filename, *filename_pattern; + fssearch_t *search; + int i, n; + char outfilename[MAX_QPATH], buf[MAX_QPATH]; + unsigned char *data; + if(Cmd_Argc() != 2) + { + Con_Printf("Usage: %s imagefile\n", Cmd_Argv(0)); + return; + } + filename_pattern = Cmd_Argv(1); + search = FS_Search(filename_pattern, true, true); + if(!search) + return; + for(i = 0; i < search->numfilenames; ++i) + { + filename = search->filenames[i]; + Con_Printf("Processing %s... ", filename); + Image_StripImageExtension(filename, buf, sizeof(buf)); + dpsnprintf(outfilename, sizeof(outfilename), "fixtrans/%s.tga", buf); + if(!(data = loadimagepixelsbgra(filename, true, false, false, NULL))) + return; + if((n = fixtransparentpixels(data, image_width, image_height))) + { + Image_WriteTGABGRA(outfilename, image_width, image_height, data); + Con_Printf("%s written (%d pixels changed).\n", outfilename, n); + } + else + Con_Printf("unchanged.\n"); + Mem_Free(data); + } + FS_FreeSearch(search); +} + +qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data) +{ + qboolean ret; + unsigned char buffer[18]; + const void *buffers[2]; + fs_offset_t sizes[2]; + + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = (width >> 0) & 0xFF; + buffer[13] = (width >> 8) & 0xFF; + buffer[14] = (height >> 0) & 0xFF; + buffer[15] = (height >> 8) & 0xFF; + buffer[16] = 24; // pixel size + + buffers[0] = buffer; + sizes[0] = 18; + buffers[1] = data; + sizes[1] = width*height*3; + ret = FS_WriteFileInBlocks(filename, buffers, sizes, 2); + + return ret; +} + +qboolean Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data) +{ + int y; + unsigned char *buffer, *out; + const unsigned char *in, *end; + qboolean ret; + + buffer = (unsigned char *)Mem_Alloc(tempmempool, width*height*4 + 18); + + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = (width >> 0) & 0xFF; + buffer[13] = (width >> 8) & 0xFF; + buffer[14] = (height >> 0) & 0xFF; + buffer[15] = (height >> 8) & 0xFF; + + for (y = 3;y < width*height*4;y += 4) + if (data[y] < 255) + break; + + if (y < width*height*4) + { + // save the alpha channel + buffer[16] = 32; // pixel size + buffer[17] = 8; // 8 bits of alpha + + // flip upside down + out = buffer + 18; + for (y = height - 1;y >= 0;y--) + { + memcpy(out, data + y * width * 4, width * 4); + out += width*4; + } + } + else + { + // save only the color channels + buffer[16] = 24; // pixel size + buffer[17] = 0; // 8 bits of alpha + + // truncate bgra to bgr and flip upside down + out = buffer + 18; + for (y = height - 1;y >= 0;y--) + { + in = data + y * width * 4; + end = in + width * 4; + for (;in < end;in += 4) + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + } + } + } + ret = FS_WriteFile (filename, buffer, out - buffer); + + Mem_Free(buffer); + + return ret; +} + +static void Image_Resample32LerpLine (const unsigned char *in, unsigned char *out, int inwidth, int outwidth) +{ + int j, xi, oldx = 0, f, fstep, endx, lerp; + fstep = (int) (inwidth*65536.0f/outwidth); + endx = (inwidth-1); + for (j = 0,f = 0;j < outwidth;j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 4; + oldx = xi; + } + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (unsigned char) ((((in[4] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (unsigned char) ((((in[5] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (unsigned char) ((((in[6] - in[2]) * lerp) >> 16) + in[2]); + *out++ = (unsigned char) ((((in[7] - in[3]) * lerp) >> 16) + in[3]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + *out++ = in[3]; + } + } +} + +#define LERPBYTE(i) r = resamplerow1[i];out[i] = (unsigned char) ((((resamplerow2[i] - r) * lerp) >> 16) + r) +static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4; + unsigned char *out; + const unsigned char *inrow; + unsigned char *resamplerow1; + unsigned char *resamplerow2; + out = (unsigned char *)outdata; + fstep = (int) (inheight*65536.0f/outheight); + + resamplerow1 = (unsigned char *)Mem_Alloc(tempmempool, outwidth*4*2); + resamplerow2 = resamplerow1 + outwidth*4; + + inrow = (const unsigned char *)indata; + oldy = 0; + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth); + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (unsigned char *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth4); + else + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + LERPBYTE(12); + LERPBYTE(13); + LERPBYTE(14); + LERPBYTE(15); + out += 16; + resamplerow1 += 16; + resamplerow2 += 16; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + out += 8; + resamplerow1 += 8; + resamplerow2 += 8; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + out += 4; + resamplerow1 += 4; + resamplerow2 += 4; + } + resamplerow1 -= outwidth4; + resamplerow2 -= outwidth4; + } + else + { + if (yi != oldy) + { + inrow = (unsigned char *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth4); + else + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + oldy = yi; + } + memcpy(out, resamplerow1, outwidth4); + } + } + + Mem_Free(resamplerow1); + resamplerow1 = NULL; + resamplerow2 = NULL; +} + +static void Image_Resample32Nolerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j; + unsigned frac, fracstep; + // relies on int being 4 bytes + int *inrow, *out; + out = (int *)outdata; + + fracstep = inwidth*0x10000/outwidth; + for (i = 0;i < outheight;i++) + { + inrow = (int *)indata + inwidth*(i*inheight/outheight); + frac = fracstep >> 1; + j = outwidth - 4; + while (j >= 0) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out[1] = inrow[frac >> 16];frac += fracstep; + out[2] = inrow[frac >> 16];frac += fracstep; + out[3] = inrow[frac >> 16];frac += fracstep; + out += 4; + j -= 4; + } + if (j & 2) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out[1] = inrow[frac >> 16];frac += fracstep; + out += 2; + } + if (j & 1) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out += 1; + } + } +} + +/* +================ +Image_Resample +================ +*/ +void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality) +{ + if (indepth != 1 || outdepth != 1) + { + Con_Printf ("Image_Resample: 3D resampling not supported\n"); + return; + } + if (quality) + Image_Resample32Lerp(indata, inwidth, inheight, outdata, outwidth, outheight); + else + Image_Resample32Nolerp(indata, inwidth, inheight, outdata, outwidth, outheight); +} + +// in can be the same as out +void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth) +{ + const unsigned char *inrow; + int x, y, nextrow; + if (*depth != 1 || destdepth != 1) + { + Con_Printf ("Image_Resample: 3D resampling not supported\n"); + if (*width > destwidth) + *width >>= 1; + if (*height > destheight) + *height >>= 1; + if (*depth > destdepth) + *depth >>= 1; + return; + } + // note: if given odd width/height this discards the last row/column of + // pixels, rather than doing a proper box-filter scale down + inrow = in; + nextrow = *width * 4; + if (*width > destwidth) + { + *width >>= 1; + if (*height > destheight) + { + // reduce both + *height >>= 1; + for (y = 0;y < *height;y++, inrow += nextrow * 2) + { + for (in = inrow, x = 0;x < *width;x++) + { + out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2); + out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2); + out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2); + out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2); + out += 4; + in += 8; + } + } + } + else + { + // reduce width + for (y = 0;y < *height;y++, inrow += nextrow) + { + for (in = inrow, x = 0;x < *width;x++) + { + out[0] = (unsigned char) ((in[0] + in[4]) >> 1); + out[1] = (unsigned char) ((in[1] + in[5]) >> 1); + out[2] = (unsigned char) ((in[2] + in[6]) >> 1); + out[3] = (unsigned char) ((in[3] + in[7]) >> 1); + out += 4; + in += 8; + } + } + } + } + else + { + if (*height > destheight) + { + // reduce height + *height >>= 1; + for (y = 0;y < *height;y++, inrow += nextrow * 2) + { + for (in = inrow, x = 0;x < *width;x++) + { + out[0] = (unsigned char) ((in[0] + in[nextrow ]) >> 1); + out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1); + out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1); + out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1); + out += 4; + in += 4; + } + } + } + else + Con_Printf ("Image_MipReduce: desired size already achieved\n"); + } +} + +void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned char *outpixels, int width, int height, int clamp, float bumpscale) +{ + int x, y, x1, x2, y1, y2; + const unsigned char *b, *row[3]; + int p[5]; + unsigned char *out; + float ibumpscale, n[3]; + ibumpscale = (255.0f * 6.0f) / bumpscale; + out = outpixels; + for (y = 0, y1 = height-1;y < height;y1 = y, y++) + { + y2 = y + 1;if (y2 >= height) y2 = 0; + row[0] = inpixels + (y1 * width) * 4; + row[1] = inpixels + (y * width) * 4; + row[2] = inpixels + (y2 * width) * 4; + for (x = 0, x1 = width-1;x < width;x1 = x, x++) + { + x2 = x + 1;if (x2 >= width) x2 = 0; + // left, right + b = row[1] + x1 * 4;p[0] = (b[0] + b[1] + b[2]); + b = row[1] + x2 * 4;p[1] = (b[0] + b[1] + b[2]); + // above, below + b = row[0] + x * 4;p[2] = (b[0] + b[1] + b[2]); + b = row[2] + x * 4;p[3] = (b[0] + b[1] + b[2]); + // center + b = row[1] + x * 4;p[4] = (b[0] + b[1] + b[2]); + // calculate a normal from the slopes + n[0] = p[0] - p[1]; + n[1] = p[3] - p[2]; + n[2] = ibumpscale; + VectorNormalize(n); + // turn it into a dot3 rgb vector texture + out[2] = (int)(128.0f + n[0] * 127.0f); + out[1] = (int)(128.0f + n[1] * 127.0f); + out[0] = (int)(128.0f + n[2] * 127.0f); + out[3] = (p[4]) / 3; + out += 4; + } + } +} diff --git a/app/jni/image.h b/app/jni/image.h new file mode 100644 index 0000000..9153577 --- /dev/null +++ b/app/jni/image.h @@ -0,0 +1,62 @@ + +#ifndef IMAGE_H +#define IMAGE_H + +extern int image_width, image_height; + + +// swizzle components (even converting number of components) and flip images +// (warning: input must be different than output due to non-linear read/write) +// (tip: component indices can contain values | 0x80000000 to tell it to +// store them directly into output, so 255 | 0x80000000 would write 255) +void Image_CopyMux(unsigned char *outpixels, const unsigned char *inpixels, int inputwidth, int inputheight, qboolean inputflipx, qboolean inputflipy, qboolean inputflipdiagonal, int numoutputcomponents, int numinputcomponents, int *outputinputcomponentindices); + +// applies gamma correction to RGB pixels, in can be the same as out +void Image_GammaRemapRGB(const unsigned char *in, unsigned char *out, int pixels, const unsigned char *gammar, const unsigned char *gammag, const unsigned char *gammab); + +// converts 8bit image data to BGRA, in can not be the same as out +void Image_Copy8bitBGRA(const unsigned char *in, unsigned char *out, int pixels, const unsigned int *pal); + +void Image_StripImageExtension (const char *in, char *out, size_t size_out); + +// called by conchars.tga loader in gl_draw.c, otherwise private +unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize, int *miplevel); + +// loads a texture, as pixel data +unsigned char *loadimagepixelsbgra (const char *filename, qboolean complain, qboolean allowFixtrans, qboolean convertsRGB, int *miplevel); + +// loads an 8bit pcx image into a 296x194x8bit buffer, with cropping as needed +qboolean LoadPCX_QWSkin(const unsigned char *f, int filesize, unsigned char *pixels, int outwidth, int outheight); + +// loads a texture, as a texture +rtexture_t *loadtextureimage (rtexturepool_t *pool, const char *filename, qboolean complain, int flags, qboolean allowFixtrans, qboolean sRGB); + +// writes an upside down BGR image into a TGA +qboolean Image_WriteTGABGR_preflipped (const char *filename, int width, int height, const unsigned char *data); + +// writes a BGRA image into a TGA file +qboolean Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data); + +// resizes the image (in can not be the same as out) +void Image_Resample32(const void *indata, int inwidth, int inheight, int indepth, void *outdata, int outwidth, int outheight, int outdepth, int quality); + +// scales the image down by a power of 2 (in can be the same as out) +void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int *depth, int destwidth, int destheight, int destdepth); + +void Image_HeightmapToNormalmap_BGRA(const unsigned char *inpixels, unsigned char *outpixels, int width, int height, int clamp, float bumpscale); + +// console command to fix the colors of transparent pixels (to prevent weird borders) +void Image_FixTransparentPixels_f(void); +extern cvar_t r_fixtrans_auto; + +#define Image_LinearFloatFromsRGBFloat(c) (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f)) +#define Image_sRGBFloatFromLinearFloat(c) (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f) +#define Image_LinearFloatFromsRGB(c) Image_LinearFloatFromsRGBFloat((c) * (1.0f / 255.0f)) +#define Image_sRGBFloatFromLinear(c) Image_sRGBFloatFromLinearFloat((c) * (1.0f / 255.0f)) +#define Image_sRGBFloatFromLinear_Lightmap(c) Image_sRGBFloatFromLinearFloat((c) * (2.0f / 255.0f)) * 0.5f + +void Image_MakeLinearColorsFromsRGB(unsigned char *pout, const unsigned char *pin, int numpixels); +void Image_MakesRGBColorsFromLinear_Lightmap(unsigned char *pout, const unsigned char *pin, int numpixels); + +#endif + diff --git a/app/jni/image_png.c b/app/jni/image_png.c new file mode 100644 index 0000000..04419bd --- /dev/null +++ b/app/jni/image_png.c @@ -0,0 +1,559 @@ +/* + Copyright (C) 2006 Serge "(515)" Ziryukin, Forest "LordHavoc" Hale + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +//[515]: png implemented into DP ONLY FOR TESTING 2d stuff with csqc +// so delete this bullshit :D +// +//LordHavoc: rewrote most of this. + +#include "quakedef.h" +#include "image.h" +#include "image_png.h" + + +static void (*qpng_set_sig_bytes) (void*, int); +static int (*qpng_sig_cmp) (const unsigned char*, size_t, size_t); +static void* (*qpng_create_read_struct) (const char*, void*, void(*)(void *png, const char *message), void(*)(void *png, const char *message)); +static void* (*qpng_create_write_struct) (const char*, void*, void(*)(void *png, const char *message), void(*)(void *png, const char *message)); +static void* (*qpng_create_info_struct) (void*); +static void (*qpng_read_info) (void*, void*); +static void (*qpng_set_compression_level) (void*, int); +static void (*qpng_set_filter) (void*, int, int); +static void (*qpng_set_expand) (void*); +static void (*qpng_set_palette_to_rgb) (void*); +static void (*qpng_set_tRNS_to_alpha) (void*); +static void (*qpng_set_gray_to_rgb) (void*); +static void (*qpng_set_filler) (void*, unsigned int, int); +static void (*qpng_set_IHDR) (void*, void*, unsigned long, unsigned long, int, int, int, int, int); +static void (*qpng_set_packing) (void*); +static void (*qpng_set_bgr) (void*); +static int (*qpng_set_interlace_handling) (void*); +static void (*qpng_read_update_info) (void*, void*); +static void (*qpng_read_image) (void*, unsigned char**); +static void (*qpng_read_end) (void*, void*); +static void (*qpng_destroy_read_struct) (void**, void**, void**); +static void (*qpng_destroy_write_struct) (void**, void**); +static void (*qpng_set_read_fn) (void*, void*, void(*)(void *png, unsigned char *data, size_t length)); +static void (*qpng_set_write_fn) (void*, void*, void(*)(void *png, unsigned char *data, size_t length), void(*)(void *png)); +static unsigned int (*qpng_get_valid) (void*, void*, unsigned int); +static unsigned int (*qpng_get_rowbytes) (void*, void*); +static unsigned char (*qpng_get_channels) (void*, void*); +static unsigned char (*qpng_get_bit_depth) (void*, void*); +static unsigned int (*qpng_get_IHDR) (void*, void*, unsigned long*, unsigned long*, int *, int *, int *, int *, int *); +static unsigned int (*qpng_access_version_number) (void); // FIXME is this return type right? It is a png_uint_32 in libpng +static void (*qpng_write_info) (void*, void*); +static void (*qpng_write_row) (void*, unsigned char*); +static void (*qpng_write_end) (void*, void*); + +// libpng 1.4+ longjmp hack +typedef void (*qpng_longjmp_ptr) (jmp_buf, int); +static jmp_buf* (*qpng_set_longjmp_fn) (void *, qpng_longjmp_ptr, size_t); +#define qpng_jmpbuf_14(png_ptr) (*qpng_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) + +// libpng 1.2 longjmp hack +#define qpng_jmpbuf_12(png_ptr) (*((jmp_buf *) png_ptr)) + +// all version support +#define qpng_jmpbuf(png_ptr) \ + (qpng_set_longjmp_fn ? qpng_jmpbuf_14(png_ptr) : qpng_jmpbuf_12(png_ptr)) + +static dllfunction_t pngfuncs[] = +{ + {"png_set_sig_bytes", (void **) &qpng_set_sig_bytes}, + {"png_sig_cmp", (void **) &qpng_sig_cmp}, + {"png_create_read_struct", (void **) &qpng_create_read_struct}, + {"png_create_write_struct", (void **) &qpng_create_write_struct}, + {"png_create_info_struct", (void **) &qpng_create_info_struct}, + {"png_read_info", (void **) &qpng_read_info}, + {"png_set_compression_level", (void **) &qpng_set_compression_level}, + {"png_set_filter", (void **) &qpng_set_filter}, + {"png_set_expand", (void **) &qpng_set_expand}, + {"png_set_palette_to_rgb", (void **) &qpng_set_palette_to_rgb}, + {"png_set_tRNS_to_alpha", (void **) &qpng_set_tRNS_to_alpha}, + {"png_set_gray_to_rgb", (void **) &qpng_set_gray_to_rgb}, + {"png_set_filler", (void **) &qpng_set_filler}, + {"png_set_IHDR", (void **) &qpng_set_IHDR}, + {"png_set_packing", (void **) &qpng_set_packing}, + {"png_set_bgr", (void **) &qpng_set_bgr}, + {"png_set_interlace_handling", (void **) &qpng_set_interlace_handling}, + {"png_read_update_info", (void **) &qpng_read_update_info}, + {"png_read_image", (void **) &qpng_read_image}, + {"png_read_end", (void **) &qpng_read_end}, + {"png_destroy_read_struct", (void **) &qpng_destroy_read_struct}, + {"png_destroy_write_struct", (void **) &qpng_destroy_write_struct}, + {"png_set_read_fn", (void **) &qpng_set_read_fn}, + {"png_set_write_fn", (void **) &qpng_set_write_fn}, + {"png_get_valid", (void **) &qpng_get_valid}, + {"png_get_rowbytes", (void **) &qpng_get_rowbytes}, + {"png_get_channels", (void **) &qpng_get_channels}, + {"png_get_bit_depth", (void **) &qpng_get_bit_depth}, + {"png_get_IHDR", (void **) &qpng_get_IHDR}, + {"png_access_version_number", (void **) &qpng_access_version_number}, + {"png_write_info", (void **) &qpng_write_info}, + {"png_write_row", (void **) &qpng_write_row}, + {"png_write_end", (void **) &qpng_write_end}, + {NULL, NULL} +}; +static dllfunction_t png14funcs[] = +{ + {"png_set_longjmp_fn", (void **) &qpng_set_longjmp_fn}, + {NULL, NULL} +}; + +// Handle for PNG DLL +dllhandle_t png_dll = NULL; +dllhandle_t png14_dll = NULL; + + +/* +================================================================= + + DLL load & unload + +================================================================= +*/ + +/* +==================== +PNG_OpenLibrary + +Try to load the PNG DLL +==================== +*/ +qboolean PNG_OpenLibrary (void) +{ + const char* dllnames [] = + { +#if WIN32 + "libpng16.dll", + "libpng16-16.dll", + "libpng15-15.dll", + "libpng15.dll", + "libpng14-14.dll", + "libpng14.dll", + "libpng12.dll", +#elif defined(MACOSX) + "libpng16.16.dylib", + "libpng15.15.dylib", + "libpng14.14.dylib", + "libpng12.0.dylib", +#else + "libpng16.so.16", + "libpng15.so.15", // WTF libtool guidelines anyone? + "libpng14.so.14", // WTF libtool guidelines anyone? + "libpng12.so.0", + "libpng.so", // FreeBSD +#endif + NULL + }; + + // Already loaded? + if (png_dll) + return true; + + // Load the DLL + if(!Sys_LoadLibrary (dllnames, &png_dll, pngfuncs)) + return false; + if(qpng_access_version_number() / 100 >= 104) + if(!Sys_LoadLibrary (dllnames, &png14_dll, png14funcs)) + { + Sys_UnloadLibrary (&png_dll); + return false; + } + return true; +} + + +/* +==================== +PNG_CloseLibrary + +Unload the PNG DLL +==================== +*/ +void PNG_CloseLibrary (void) +{ + Sys_UnloadLibrary (&png14_dll); + Sys_UnloadLibrary (&png_dll); +} + +/* +================================================================= + + PNG decompression + +================================================================= +*/ + +#define PNG_LIBPNG_VER_STRING_12 "1.2.4" +#define PNG_LIBPNG_VER_STRING_14 "1.4.0" +#define PNG_LIBPNG_VER_STRING_15 "1.5.0" +#define PNG_LIBPNG_VER_STRING_16 "1.6.0" + +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) + +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +#define PNG_INFO_tRNS 0x0010 + +// this struct is only used for status information during loading +static struct +{ + const unsigned char *tmpBuf; + int tmpBuflength; + int tmpi; + //int FBgColor; + //int FTransparent; + unsigned int FRowBytes; + //double FGamma; + //double FScreenGamma; + unsigned char **FRowPtrs; + unsigned char *Data; + //char *Title; + //char *Author; + //char *Description; + int BitDepth; + int BytesPerPixel; + int ColorType; + unsigned long Height; // retarded libpng 1.2 pngconf.h uses long (64bit/32bit depending on arch) + unsigned long Width; // retarded libpng 1.2 pngconf.h uses long (64bit/32bit depending on arch) + int Interlace; + int Compression; + int Filter; + //double LastModified; + //int Transparent; + qfile_t *outfile; +} my_png; + +//LordHavoc: removed __cdecl prefix, added overrun protection, and rewrote this to be more efficient +static void PNG_fReadData(void *png, unsigned char *data, size_t length) +{ + size_t l; + l = my_png.tmpBuflength - my_png.tmpi; + if (l < length) + { + Con_Printf("PNG_fReadData: overrun by %i bytes\n", (int)(length - l)); + // a read going past the end of the file, fill in the remaining bytes + // with 0 just to be consistent + memset(data + l, 0, length - l); + length = l; + } + memcpy(data, my_png.tmpBuf + my_png.tmpi, length); + my_png.tmpi += (int)length; + //Com_HexDumpToConsole(data, (int)length); +} + +static void PNG_fWriteData(void *png, unsigned char *data, size_t length) +{ + FS_Write(my_png.outfile, data, length); +} + +static void PNG_fFlushData(void *png) +{ +} + +static void PNG_error_fn(void *png, const char *message) +{ + Con_Printf("PNG_LoadImage: error: %s\n", message); +} + +static void PNG_warning_fn(void *png, const char *message) +{ + Con_Printf("PNG_LoadImage: warning: %s\n", message); +} + +unsigned char *PNG_LoadImage_BGRA (const unsigned char *raw, int filesize, int *miplevel) +{ + unsigned int c; + unsigned int y; + void *png, *pnginfo; + unsigned char *imagedata = NULL; + unsigned char ioBuffer[8192]; + + // FIXME: register an error handler so that abort() won't be called on error + + // No DLL = no PNGs + if (!png_dll) + return NULL; + + if(qpng_sig_cmp(raw, 0, filesize)) + return NULL; + png = (void *)qpng_create_read_struct( + (qpng_access_version_number() / 100 == 102) ? PNG_LIBPNG_VER_STRING_12 : + (qpng_access_version_number() / 100 == 104) ? PNG_LIBPNG_VER_STRING_14 : + (qpng_access_version_number() / 100 == 105) ? PNG_LIBPNG_VER_STRING_15 : + PNG_LIBPNG_VER_STRING_16, // nasty hack... whatever + 0, PNG_error_fn, PNG_warning_fn + ); + if(!png) + return NULL; + + // this must be memset before the setjmp error handler, because it relies + // on the fields in this struct for cleanup + memset(&my_png, 0, sizeof(my_png)); + + // NOTE: this relies on jmp_buf being the first thing in the png structure + // created by libpng! (this is correct for libpng 1.2.x) + if (setjmp(qpng_jmpbuf(png))) + { + if (my_png.Data) + Mem_Free(my_png.Data); + my_png.Data = NULL; + if (my_png.FRowPtrs) + Mem_Free(my_png.FRowPtrs); + my_png.FRowPtrs = NULL; + qpng_destroy_read_struct(&png, &pnginfo, 0); + return NULL; + } + // + + pnginfo = qpng_create_info_struct(png); + if(!pnginfo) + { + qpng_destroy_read_struct(&png, &pnginfo, 0); + return NULL; + } + qpng_set_sig_bytes(png, 0); + + my_png.tmpBuf = raw; + my_png.tmpBuflength = filesize; + my_png.tmpi = 0; + //my_png.Data = NULL; + //my_png.FRowPtrs = NULL; + //my_png.Height = 0; + //my_png.Width = 0; + my_png.ColorType = PNG_COLOR_TYPE_RGB; + //my_png.Interlace = 0; + //my_png.Compression = 0; + //my_png.Filter = 0; + qpng_set_read_fn(png, ioBuffer, PNG_fReadData); + qpng_read_info(png, pnginfo); + qpng_get_IHDR(png, pnginfo, &my_png.Width, &my_png.Height,&my_png.BitDepth, &my_png.ColorType, &my_png.Interlace, &my_png.Compression, &my_png.Filter); + + // this check guards against pngconf.h with unsigned int *width/height parameters on big endian systems by detecting the strange values and shifting them down 32bits + // (if it's little endian the unwritten bytes are the most significant + // ones and we don't worry about that) + // + // this is only necessary because of retarded 64bit png_uint_32 types in libpng 1.2, which can (conceivably) vary by platform +#if LONG_MAX > 4000000000 + if (my_png.Width > LONG_MAX || my_png.Height > LONG_MAX) + { + my_png.Width >>= 32; + my_png.Height >>= 32; + } +#endif + + if (my_png.ColorType == PNG_COLOR_TYPE_PALETTE) + qpng_set_palette_to_rgb(png); + if (my_png.ColorType == PNG_COLOR_TYPE_GRAY || my_png.ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) + qpng_set_gray_to_rgb(png); + if (qpng_get_valid(png, pnginfo, PNG_INFO_tRNS)) + qpng_set_tRNS_to_alpha(png); + if (my_png.BitDepth == 8 && !(my_png.ColorType & PNG_COLOR_MASK_ALPHA)) + qpng_set_filler(png, 255, 1); + if (( my_png.ColorType == PNG_COLOR_TYPE_GRAY) || (my_png.ColorType == PNG_COLOR_TYPE_GRAY_ALPHA )) + qpng_set_gray_to_rgb(png); + if (my_png.BitDepth < 8) + qpng_set_expand(png); + + qpng_read_update_info(png, pnginfo); + + my_png.FRowBytes = qpng_get_rowbytes(png, pnginfo); + my_png.BytesPerPixel = qpng_get_channels(png, pnginfo); + + my_png.FRowPtrs = (unsigned char **)Mem_Alloc(tempmempool, my_png.Height * sizeof(*my_png.FRowPtrs)); + if (my_png.FRowPtrs) + { + imagedata = (unsigned char *)Mem_Alloc(tempmempool, my_png.Height * my_png.FRowBytes); + if(imagedata) + { + my_png.Data = imagedata; + for(y = 0;y < my_png.Height;y++) + my_png.FRowPtrs[y] = my_png.Data + y * my_png.FRowBytes; + qpng_read_image(png, my_png.FRowPtrs); + } + else + { + Con_Printf("PNG_LoadImage : not enough memory\n"); + qpng_destroy_read_struct(&png, &pnginfo, 0); + Mem_Free(my_png.FRowPtrs); + return NULL; + } + Mem_Free(my_png.FRowPtrs); + my_png.FRowPtrs = NULL; + } + else + { + Con_Printf("PNG_LoadImage : not enough memory\n"); + qpng_destroy_read_struct(&png, &pnginfo, 0); + return NULL; + } + + qpng_read_end(png, pnginfo); + qpng_destroy_read_struct(&png, &pnginfo, 0); + + image_width = (int)my_png.Width; + image_height = (int)my_png.Height; + + if (my_png.BitDepth != 8) + { + Con_Printf ("PNG_LoadImage : bad color depth\n"); + Mem_Free(imagedata); + return NULL; + } + + // swizzle RGBA to BGRA + for (y = 0;y < (unsigned int)(image_width*image_height*4);y += 4) + { + c = imagedata[y+0]; + imagedata[y+0] = imagedata[y+2]; + imagedata[y+2] = c; + } + + return imagedata; +} + +/* +================================================================= + + PNG compression + +================================================================= +*/ + +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define PNG_INTERLACE_NONE 0 +#define PNG_INTERLACE_ADAM7 1 +#define PNG_FILTER_TYPE_BASE 0 +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE +#define PNG_COMPRESSION_TYPE_BASE 0 +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* +==================== +PNG_SaveImage_preflipped + +Save a preflipped PNG image to a file +==================== +*/ +qboolean PNG_SaveImage_preflipped (const char *filename, int width, int height, qboolean has_alpha, unsigned char *data) +{ + unsigned int offset, linesize; + qfile_t* file = NULL; + void *png, *pnginfo; + unsigned char ioBuffer[8192]; + int passes, i, j; + + // No DLL = no JPEGs + if (!png_dll) + { + Con_Print("You need the libpng library to save PNG images\n"); + return false; + } + + png = (void *)qpng_create_write_struct( + (qpng_access_version_number() / 100 == 102) ? PNG_LIBPNG_VER_STRING_12 : + (qpng_access_version_number() / 100 == 104) ? PNG_LIBPNG_VER_STRING_14 : + (qpng_access_version_number() / 100 == 105) ? PNG_LIBPNG_VER_STRING_15 : + PNG_LIBPNG_VER_STRING_16, // nasty hack... whatever + 0, PNG_error_fn, PNG_warning_fn + ); + if(!png) + return false; + pnginfo = (void *)qpng_create_info_struct(png); + if(!pnginfo) + { + qpng_destroy_write_struct(&png, NULL); + return false; + } + + // this must be memset before the setjmp error handler, because it relies + // on the fields in this struct for cleanup + memset(&my_png, 0, sizeof(my_png)); + + // NOTE: this relies on jmp_buf being the first thing in the png structure + // created by libpng! (this is correct for libpng 1.2.x) +#ifdef __cplusplus +#ifdef WIN64 + if (setjmp((_JBTYPE *)png)) +#elif defined(MACOSX) || defined(WIN32) + if (setjmp((int *)png)) +#else + if (setjmp((__jmp_buf_tag *)png)) +#endif +#else + if (setjmp(png)) +#endif + { + qpng_destroy_write_struct(&png, &pnginfo); + return false; + } + + // Open the file + file = FS_OpenRealFile(filename, "wb", true); + if (!file) + return false; + my_png.outfile = file; + qpng_set_write_fn(png, ioBuffer, PNG_fWriteData, PNG_fFlushData); + + //qpng_set_compression_level(png, Z_BEST_COMPRESSION); + qpng_set_compression_level(png, Z_BEST_SPEED); + qpng_set_IHDR(png, pnginfo, width, height, 8, has_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_ADAM7, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + qpng_set_filter(png, 0, PNG_NO_FILTERS); + qpng_write_info(png, pnginfo); + qpng_set_packing(png); + qpng_set_bgr(png); + + passes = qpng_set_interlace_handling(png); + + linesize = width * (has_alpha ? 4 : 3); + offset = linesize * (height - 1); + for(i = 0; i < passes; ++i) + for(j = 0; j < height; ++j) + qpng_write_row(png, &data[offset - j * linesize]); + + qpng_write_end(png, NULL); + qpng_destroy_write_struct(&png, &pnginfo); + + FS_Close (file); + + return true; +} diff --git a/app/jni/image_png.h b/app/jni/image_png.h new file mode 100644 index 0000000..d290d98 --- /dev/null +++ b/app/jni/image_png.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2006 Serge "(515)" Ziryukin + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef PNG_H +#define PNG_H + +qboolean PNG_OpenLibrary (void); +void PNG_CloseLibrary (void); +unsigned char* PNG_LoadImage_BGRA (const unsigned char *f, int filesize, int *miplevel); +qboolean PNG_SaveImage_preflipped (const char *filename, int width, int height, qboolean has_alpha, unsigned char *data); + +#endif + diff --git a/app/jni/input.h b/app/jni/input.h new file mode 100644 index 0000000..e157294 --- /dev/null +++ b/app/jni/input.h @@ -0,0 +1,53 @@ +/* +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. + +*/ +/// \file input.h -- external (non-keyboard) input devices + +#ifndef INPUT_H +#define INPUT_H + +extern cvar_t in_pitch_min; +extern cvar_t in_pitch_max; + +extern qboolean in_client_mouse; +extern float in_windowmouse_x, in_windowmouse_y; +extern float in_mouse_x, in_mouse_y; + +//enum input_dest_e {input_game,input_message,input_menu} input_dest; + +void IN_Move (void); +// add additional movement on top of the keyboard move cmd + +#define IN_BESTWEAPON_MAX 32 +typedef struct +{ + char name[32]; + int impulse; + int activeweaponcode; + int weaponbit; + int ammostat; + int ammomin; + /// \TODO add a parameter for the picture to be used by the sbar, and use it there +} +in_bestweapon_info_t; +extern in_bestweapon_info_t in_bestweapon_info[IN_BESTWEAPON_MAX]; +void IN_BestWeapon_ResetData(void); ///< call before each map so QC can start from a clean state + +#endif + diff --git a/app/jni/intoverflow.h b/app/jni/intoverflow.h new file mode 100644 index 0000000..df90616 --- /dev/null +++ b/app/jni/intoverflow.h @@ -0,0 +1,22 @@ +#ifndef INTOVERFLOW_H +#define INTOVERFLOW_H + +// simple safe library to handle integer overflows when doing buffer size calculations +// Usage: +// - calculate data size using INTOVERFLOW_??? macros +// - compare: calculated-size <= INTOVERFLOW_NORMALIZE(buffersize) +// Functionality: +// - all overflows (values > INTOVERFLOW_MAX) and errors are mapped to INTOVERFLOW_MAX +// - if any input of an operation is INTOVERFLOW_MAX, INTOVERFLOW_MAX will be returned +// - otherwise, regular arithmetics apply + +#define INTOVERFLOW_MAX 2147483647 + +#define INTOVERFLOW_ADD(a,b) (((a) < INTOVERFLOW_MAX && (b) < INTOVERFLOW_MAX && (a) < INTOVERFLOW_MAX - (b)) ? ((a) + (b)) : INTOVERFLOW_MAX) +#define INTOVERFLOW_SUB(a,b) (((a) < INTOVERFLOW_MAX && (b) < INTOVERFLOW_MAX && (b) <= (a)) ? ((a) - (b)) : INTOVERFLOW_MAX) +#define INTOVERFLOW_MUL(a,b) (((a) < INTOVERFLOW_MAX && (b) < INTOVERFLOW_MAX && (a) < INTOVERFLOW_MAX / (b)) ? ((a) * (b)) : INTOVERFLOW_MAX) +#define INTOVERFLOW_DIV(a,b) (((a) < INTOVERFLOW_MAX && (b) < INTOVERFLOW_MAX && (b) > 0) ? ((a) / (b)) : INTOVERFLOW_MAX) + +#define INTOVERFLOW_NORMALIZE(a) (((a) < INTOVERFLOW_MAX) ? (a) : (INTOVERFLOW_MAX - 1)) + +#endif diff --git a/app/jni/jpeg.c b/app/jni/jpeg.c new file mode 100644 index 0000000..4b276d2 --- /dev/null +++ b/app/jni/jpeg.c @@ -0,0 +1,1108 @@ +/* + Copyright (C) 2002 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + + +#include "quakedef.h" +#include "image.h" +#include "jpeg.h" +#include "image_png.h" + +cvar_t sv_writepicture_quality = {CVAR_SAVE, "sv_writepicture_quality", "10", "WritePicture quality offset (higher means better quality, but slower)"}; +cvar_t r_texture_jpeg_fastpicmip = {CVAR_SAVE, "r_texture_jpeg_fastpicmip", "1", "perform gl_picmip during decompression for JPEG files (faster)"}; + +// jboolean is unsigned char instead of int on Win32 +#ifdef WIN32 +typedef unsigned char jboolean; +#else +typedef int jboolean; +#endif + +#ifdef LINK_TO_LIBJPEG +#include +#define qjpeg_create_compress jpeg_create_compress +#define qjpeg_create_decompress jpeg_create_decompress +#define qjpeg_destroy_compress jpeg_destroy_compress +#define qjpeg_destroy_decompress jpeg_destroy_decompress +#define qjpeg_finish_compress jpeg_finish_compress +#define qjpeg_finish_decompress jpeg_finish_decompress +#define qjpeg_resync_to_restart jpeg_resync_to_restart +#define qjpeg_read_header jpeg_read_header +#define qjpeg_read_scanlines jpeg_read_scanlines +#define qjpeg_set_defaults jpeg_set_defaults +#define qjpeg_set_quality jpeg_set_quality +#define qjpeg_start_compress jpeg_start_compress +#define qjpeg_start_decompress jpeg_start_decompress +#define qjpeg_std_error jpeg_std_error +#define qjpeg_write_scanlines jpeg_write_scanlines +#define qjpeg_simple_progression jpeg_simple_progression +#define jpeg_dll true +#else +/* +================================================================= + + Minimal set of definitions from the JPEG lib + + WARNING: for a matter of simplicity, several pointer types are + casted to "void*", and most enumerated values are not included + +================================================================= +*/ + +typedef void *j_common_ptr; +typedef struct jpeg_compress_struct *j_compress_ptr; +typedef struct jpeg_decompress_struct *j_decompress_ptr; + +#define JPEG_LIB_VERSION 62 // Version 6b + +typedef enum +{ + JCS_UNKNOWN, + JCS_GRAYSCALE, + JCS_RGB, + JCS_YCbCr, + JCS_CMYK, + JCS_YCCK +} J_COLOR_SPACE; +typedef enum {JPEG_DUMMY1} J_DCT_METHOD; +typedef enum {JPEG_DUMMY2} J_DITHER_MODE; +typedef unsigned int JDIMENSION; + +#define JPOOL_PERMANENT 0 // lasts until master record is destroyed +#define JPOOL_IMAGE 1 // lasts until done with image/datastream + +#define JPEG_EOI 0xD9 // EOI marker code + +#define JMSG_STR_PARM_MAX 80 + +#define DCTSIZE2 64 +#define NUM_QUANT_TBLS 4 +#define NUM_HUFF_TBLS 4 +#define NUM_ARITH_TBLS 16 +#define MAX_COMPS_IN_SCAN 4 +#define C_MAX_BLOCKS_IN_MCU 10 +#define D_MAX_BLOCKS_IN_MCU 10 + +struct jpeg_memory_mgr +{ + void* (*alloc_small) (j_common_ptr cinfo, int pool_id, size_t sizeofobject); + void (*_reserve_space_for_alloc_large) (void *dummy, ...); + void (*_reserve_space_for_alloc_sarray) (void *dummy, ...); + void (*_reserve_space_for_alloc_barray) (void *dummy, ...); + void (*_reserve_space_for_request_virt_sarray) (void *dummy, ...); + void (*_reserve_space_for_request_virt_barray) (void *dummy, ...); + void (*_reserve_space_for_realize_virt_arrays) (void *dummy, ...); + void (*_reserve_space_for_access_virt_sarray) (void *dummy, ...); + void (*_reserve_space_for_access_virt_barray) (void *dummy, ...); + void (*_reserve_space_for_free_pool) (void *dummy, ...); + void (*_reserve_space_for_self_destruct) (void *dummy, ...); + + long max_memory_to_use; + long max_alloc_chunk; +}; + +struct jpeg_error_mgr +{ + void (*error_exit) (j_common_ptr cinfo); + void (*emit_message) (j_common_ptr cinfo, int msg_level); + void (*output_message) (j_common_ptr cinfo); + void (*format_message) (j_common_ptr cinfo, char * buffer); + void (*reset_error_mgr) (j_common_ptr cinfo); + int msg_code; + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + int trace_level; + long num_warnings; + const char * const * jpeg_message_table; + int last_jpeg_message; + const char * const * addon_message_table; + int first_addon_message; + int last_addon_message; +}; + +struct jpeg_source_mgr +{ + const unsigned char *next_input_byte; + size_t bytes_in_buffer; + + void (*init_source) (j_decompress_ptr cinfo); + jboolean (*fill_input_buffer) (j_decompress_ptr cinfo); + void (*skip_input_data) (j_decompress_ptr cinfo, long num_bytes); + jboolean (*resync_to_restart) (j_decompress_ptr cinfo, int desired); + void (*term_source) (j_decompress_ptr cinfo); +}; + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + jboolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + void *quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + +struct jpeg_decompress_struct +{ + struct jpeg_error_mgr *err; // USED + struct jpeg_memory_mgr *mem; // USED + + void *progress; + void *client_data; + jboolean is_decompressor; + int global_state; + + struct jpeg_source_mgr *src; // USED + JDIMENSION image_width; // USED + JDIMENSION image_height; // USED + + int num_components; + J_COLOR_SPACE jpeg_color_space; + J_COLOR_SPACE out_color_space; + unsigned int scale_num, scale_denom; + double output_gamma; + jboolean buffered_image; + jboolean raw_data_out; + J_DCT_METHOD dct_method; + jboolean do_fancy_upsampling; + jboolean do_block_smoothing; + jboolean quantize_colors; + J_DITHER_MODE dither_mode; + jboolean two_pass_quantize; + int desired_number_of_colors; + jboolean enable_1pass_quant; + jboolean enable_external_quant; + jboolean enable_2pass_quant; + JDIMENSION output_width; + + JDIMENSION output_height; // USED + + int out_color_components; + + int output_components; // USED + + int rec_outbuf_height; + int actual_number_of_colors; + void *colormap; + + JDIMENSION output_scanline; // USED + + int input_scan_number; + JDIMENSION input_iMCU_row; + int output_scan_number; + JDIMENSION output_iMCU_row; + int (*coef_bits)[DCTSIZE2]; + void *quant_tbl_ptrs[NUM_QUANT_TBLS]; + void *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + void *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + int data_precision; + jpeg_component_info *comp_info; + jboolean progressive_mode; + jboolean arith_code; + unsigned char arith_dc_L[NUM_ARITH_TBLS]; + unsigned char arith_dc_U[NUM_ARITH_TBLS]; + unsigned char arith_ac_K[NUM_ARITH_TBLS]; + unsigned int restart_interval; + jboolean saw_JFIF_marker; + unsigned char JFIF_major_version; + unsigned char JFIF_minor_version; + unsigned char density_unit; + unsigned short X_density; + unsigned short Y_density; + jboolean saw_Adobe_marker; + unsigned char Adobe_transform; + jboolean CCIR601_sampling; + void *marker_list; + int max_h_samp_factor; + int max_v_samp_factor; + int min_DCT_scaled_size; + JDIMENSION total_iMCU_rows; + void *sample_range_limit; + int comps_in_scan; + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + JDIMENSION MCUs_per_row; + JDIMENSION MCU_rows_in_scan; + int blocks_in_MCU; + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + int Ss, Se, Ah, Al; + int unread_marker; + void *master; + void *main; + void *coef; + void *post; + void *inputctl; + void *marker; + void *entropy; + void *idct; + void *upsample; + void *cconvert; + void *cquantize; +}; + + +struct jpeg_compress_struct +{ + struct jpeg_error_mgr *err; + struct jpeg_memory_mgr *mem; + void *progress; + void *client_data; + jboolean is_decompressor; + int global_state; + + void *dest; + JDIMENSION image_width; + JDIMENSION image_height; + int input_components; + J_COLOR_SPACE in_color_space; + double input_gamma; + int data_precision; + + int num_components; + J_COLOR_SPACE jpeg_color_space; + jpeg_component_info *comp_info; + void *quant_tbl_ptrs[NUM_QUANT_TBLS]; + void *dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + void *ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + unsigned char arith_dc_L[NUM_ARITH_TBLS]; + unsigned char arith_dc_U[NUM_ARITH_TBLS]; + unsigned char arith_ac_K[NUM_ARITH_TBLS]; + + int num_scans; + const void *scan_info; + jboolean raw_data_in; + jboolean arith_code; + jboolean optimize_coding; + jboolean CCIR601_sampling; + int smoothing_factor; + J_DCT_METHOD dct_method; + + unsigned int restart_interval; + int restart_in_rows; + + jboolean write_JFIF_header; + unsigned char JFIF_major_version; + unsigned char JFIF_minor_version; + unsigned char density_unit; + unsigned short X_density; + unsigned short Y_density; + jboolean write_Adobe_marker; + JDIMENSION next_scanline; + + jboolean progressive_mode; + int max_h_samp_factor; + int max_v_samp_factor; + JDIMENSION total_iMCU_rows; + int comps_in_scan; + jpeg_component_info *cur_comp_info[MAX_COMPS_IN_SCAN]; + JDIMENSION MCUs_per_row; + JDIMENSION MCU_rows_in_scan; + int blocks_in_MCU; + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + int Ss, Se, Ah, Al; + + void *master; + void *main; + void *prep; + void *coef; + void *marker; + void *cconvert; + void *downsample; + void *fdct; + void *entropy; + void *script_space; + int script_space_size; +}; + +struct jpeg_destination_mgr +{ + unsigned char* next_output_byte; + size_t free_in_buffer; + + void (*init_destination) (j_compress_ptr cinfo); + jboolean (*empty_output_buffer) (j_compress_ptr cinfo); + void (*term_destination) (j_compress_ptr cinfo); +}; + + +/* +================================================================= + + DarkPlaces definitions + +================================================================= +*/ + +// Functions exported from libjpeg +#define qjpeg_create_compress(cinfo) \ + qjpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_compress_struct)) +#define qjpeg_create_decompress(cinfo) \ + qjpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct)) + +static void (*qjpeg_CreateCompress) (j_compress_ptr cinfo, int version, size_t structsize); +static void (*qjpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize); +static void (*qjpeg_destroy_compress) (j_compress_ptr cinfo); +static void (*qjpeg_destroy_decompress) (j_decompress_ptr cinfo); +static void (*qjpeg_finish_compress) (j_compress_ptr cinfo); +static jboolean (*qjpeg_finish_decompress) (j_decompress_ptr cinfo); +static jboolean (*qjpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired); +static int (*qjpeg_read_header) (j_decompress_ptr cinfo, jboolean require_image); +static JDIMENSION (*qjpeg_read_scanlines) (j_decompress_ptr cinfo, unsigned char** scanlines, JDIMENSION max_lines); +static void (*qjpeg_set_defaults) (j_compress_ptr cinfo); +static void (*qjpeg_set_quality) (j_compress_ptr cinfo, int quality, jboolean force_baseline); +static jboolean (*qjpeg_start_compress) (j_compress_ptr cinfo, jboolean write_all_tables); +static jboolean (*qjpeg_start_decompress) (j_decompress_ptr cinfo); +static struct jpeg_error_mgr* (*qjpeg_std_error) (struct jpeg_error_mgr *err); +static JDIMENSION (*qjpeg_write_scanlines) (j_compress_ptr cinfo, unsigned char** scanlines, JDIMENSION num_lines); +static void (*qjpeg_simple_progression) (j_compress_ptr cinfo); + +static dllfunction_t jpegfuncs[] = +{ + {"jpeg_CreateCompress", (void **) &qjpeg_CreateCompress}, + {"jpeg_CreateDecompress", (void **) &qjpeg_CreateDecompress}, + {"jpeg_destroy_compress", (void **) &qjpeg_destroy_compress}, + {"jpeg_destroy_decompress", (void **) &qjpeg_destroy_decompress}, + {"jpeg_finish_compress", (void **) &qjpeg_finish_compress}, + {"jpeg_finish_decompress", (void **) &qjpeg_finish_decompress}, + {"jpeg_resync_to_restart", (void **) &qjpeg_resync_to_restart}, + {"jpeg_read_header", (void **) &qjpeg_read_header}, + {"jpeg_read_scanlines", (void **) &qjpeg_read_scanlines}, + {"jpeg_set_defaults", (void **) &qjpeg_set_defaults}, + {"jpeg_set_quality", (void **) &qjpeg_set_quality}, + {"jpeg_start_compress", (void **) &qjpeg_start_compress}, + {"jpeg_start_decompress", (void **) &qjpeg_start_decompress}, + {"jpeg_std_error", (void **) &qjpeg_std_error}, + {"jpeg_write_scanlines", (void **) &qjpeg_write_scanlines}, + {"jpeg_simple_progression", (void **) &qjpeg_simple_progression}, + {NULL, NULL} +}; + +// Handle for JPEG DLL +dllhandle_t jpeg_dll = NULL; +qboolean jpeg_tried_loading = 0; +#endif + +static unsigned char jpeg_eoi_marker [2] = {0xFF, JPEG_EOI}; +static jmp_buf error_in_jpeg; +static qboolean jpeg_toolarge; + +// Our own output manager for JPEG compression +typedef struct +{ + struct jpeg_destination_mgr pub; + + qfile_t* outfile; + unsigned char* buffer; + size_t bufsize; // used if outfile is NULL +} my_destination_mgr; +typedef my_destination_mgr* my_dest_ptr; + + +/* +================================================================= + + DLL load & unload + +================================================================= +*/ + +/* +==================== +JPEG_OpenLibrary + +Try to load the JPEG DLL +==================== +*/ +qboolean JPEG_OpenLibrary (void) +{ +#ifdef LINK_TO_LIBJPEG + return true; +#else + const char* dllnames [] = + { +#if defined(WIN32) + "libjpeg.dll", +#elif defined(MACOSX) + "libjpeg.62.dylib", +#else + "libjpeg.so.62", + "libjpeg.so", +#endif + NULL + }; + + // Already loaded? + if (jpeg_dll) + return true; + + if (jpeg_tried_loading) // only try once + return false; + + jpeg_tried_loading = true; + + // Load the DLL + return Sys_LoadLibrary (dllnames, &jpeg_dll, jpegfuncs); +#endif +} + + +/* +==================== +JPEG_CloseLibrary + +Unload the JPEG DLL +==================== +*/ +void JPEG_CloseLibrary (void) +{ +#ifndef LINK_TO_LIBJPEG + Sys_UnloadLibrary (&jpeg_dll); + jpeg_tried_loading = false; // allow retry +#endif +} + + +/* +================================================================= + + JPEG decompression + +================================================================= +*/ + +static void JPEG_Noop (j_decompress_ptr cinfo) {} + +static jboolean JPEG_FillInputBuffer (j_decompress_ptr cinfo) +{ + // Insert a fake EOI marker + cinfo->src->next_input_byte = jpeg_eoi_marker; + cinfo->src->bytes_in_buffer = 2; + + return TRUE; +} + +static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes) +{ + if (cinfo->src->bytes_in_buffer <= (unsigned long)num_bytes) + { + cinfo->src->bytes_in_buffer = 0; + return; + } + + cinfo->src->next_input_byte += num_bytes; + cinfo->src->bytes_in_buffer -= num_bytes; +} + +static void JPEG_MemSrc (j_decompress_ptr cinfo, const unsigned char *buffer, size_t filesize) +{ + cinfo->src = (struct jpeg_source_mgr *)cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (struct jpeg_source_mgr)); + + cinfo->src->next_input_byte = buffer; + cinfo->src->bytes_in_buffer = filesize; + + cinfo->src->init_source = JPEG_Noop; + cinfo->src->fill_input_buffer = JPEG_FillInputBuffer; + cinfo->src->skip_input_data = JPEG_SkipInputData; + cinfo->src->resync_to_restart = qjpeg_resync_to_restart; // use the default method + cinfo->src->term_source = JPEG_Noop; +} + +static void JPEG_ErrorExit (j_common_ptr cinfo) +{ + ((struct jpeg_decompress_struct*)cinfo)->err->output_message (cinfo); + longjmp(error_in_jpeg, 1); +} + + +/* +==================== +JPEG_LoadImage + +Load a JPEG image into a BGRA buffer +==================== +*/ +unsigned char* JPEG_LoadImage_BGRA (const unsigned char *f, int filesize, int *miplevel) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + unsigned char *image_buffer = NULL, *scanline = NULL; + unsigned int line; + int submip = 0; + + // No DLL = no JPEGs + if (!jpeg_dll) + return NULL; + + if(miplevel && r_texture_jpeg_fastpicmip.integer) + submip = bound(0, *miplevel, 3); + + cinfo.err = qjpeg_std_error (&jerr); + qjpeg_create_decompress (&cinfo); + if(setjmp(error_in_jpeg)) + goto error_caught; + cinfo.err = qjpeg_std_error (&jerr); + cinfo.err->error_exit = JPEG_ErrorExit; + JPEG_MemSrc (&cinfo, f, filesize); + qjpeg_read_header (&cinfo, TRUE); + cinfo.scale_num = 1; + cinfo.scale_denom = (1 << submip); + qjpeg_start_decompress (&cinfo); + + image_width = cinfo.output_width; + image_height = cinfo.output_height; + + if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0) + { + Con_Printf("JPEG_LoadImage: invalid image size %ix%i\n", image_width, image_height); + return NULL; + } + + image_buffer = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + scanline = (unsigned char *)Mem_Alloc(tempmempool, image_width * cinfo.output_components); + if (!image_buffer || !scanline) + { + if (image_buffer) + Mem_Free (image_buffer); + if (scanline) + Mem_Free (scanline); + + Con_Printf("JPEG_LoadImage: not enough memory for %i by %i image\n", image_width, image_height); + qjpeg_finish_decompress (&cinfo); + qjpeg_destroy_decompress (&cinfo); + return NULL; + } + + // Decompress the image, line by line + line = 0; + while (cinfo.output_scanline < cinfo.output_height) + { + unsigned char *buffer_ptr; + int ind; + + qjpeg_read_scanlines (&cinfo, &scanline, 1); + + // Convert the image to BGRA + switch (cinfo.output_components) + { + // RGB images + case 3: + buffer_ptr = &image_buffer[image_width * line * 4]; + for (ind = 0; ind < image_width * 3; ind += 3, buffer_ptr += 4) + { + buffer_ptr[2] = scanline[ind]; + buffer_ptr[1] = scanline[ind + 1]; + buffer_ptr[0] = scanline[ind + 2]; + buffer_ptr[3] = 255; + } + break; + + // Greyscale images (default to it, just in case) + case 1: + default: + buffer_ptr = &image_buffer[image_width * line * 4]; + for (ind = 0; ind < image_width; ind++, buffer_ptr += 4) + { + buffer_ptr[0] = scanline[ind]; + buffer_ptr[1] = scanline[ind]; + buffer_ptr[2] = scanline[ind]; + buffer_ptr[3] = 255; + } + } + + line++; + } + Mem_Free (scanline); scanline = NULL; + + qjpeg_finish_decompress (&cinfo); + qjpeg_destroy_decompress (&cinfo); + + if(miplevel) + *miplevel -= submip; + + return image_buffer; + +error_caught: + if(scanline) + Mem_Free (scanline); + if(image_buffer) + Mem_Free (image_buffer); + qjpeg_destroy_decompress (&cinfo); + return NULL; +} + + +/* +================================================================= + + JPEG compression + +================================================================= +*/ + +#define JPEG_OUTPUT_BUF_SIZE 4096 +static void JPEG_InitDestination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + dest->buffer = (unsigned char*)cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_IMAGE, JPEG_OUTPUT_BUF_SIZE * sizeof(unsigned char)); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE; +} + +static jboolean JPEG_EmptyOutputBuffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + + if (FS_Write (dest->outfile, dest->buffer, JPEG_OUTPUT_BUF_SIZE) != (size_t) JPEG_OUTPUT_BUF_SIZE) + longjmp(error_in_jpeg, 1); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE; + return true; +} + +static void JPEG_TermDestination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + size_t datacount = JPEG_OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + // Write any data remaining in the buffer + if (datacount > 0) + if (FS_Write (dest->outfile, dest->buffer, datacount) != (fs_offset_t)datacount) + longjmp(error_in_jpeg, 1); +} + +static void JPEG_FileDest (j_compress_ptr cinfo, qfile_t* outfile) +{ + my_dest_ptr dest; + + // First time for this JPEG object? + if (cinfo->dest == NULL) + cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_destination_mgr)); + + dest = (my_dest_ptr)cinfo->dest; + dest->pub.init_destination = JPEG_InitDestination; + dest->pub.empty_output_buffer = JPEG_EmptyOutputBuffer; + dest->pub.term_destination = JPEG_TermDestination; + dest->outfile = outfile; +} + +static void JPEG_Mem_InitDestination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = dest->bufsize; +} + +static jboolean JPEG_Mem_EmptyOutputBuffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + jpeg_toolarge = true; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = dest->bufsize; + return true; +} + +static void JPEG_Mem_TermDestination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr)cinfo->dest; + dest->bufsize = dest->pub.next_output_byte - dest->buffer; +} +static void JPEG_MemDest (j_compress_ptr cinfo, void* buf, size_t bufsize) +{ + my_dest_ptr dest; + + // First time for this JPEG object? + if (cinfo->dest == NULL) + cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_destination_mgr)); + + dest = (my_dest_ptr)cinfo->dest; + dest->pub.init_destination = JPEG_Mem_InitDestination; + dest->pub.empty_output_buffer = JPEG_Mem_EmptyOutputBuffer; + dest->pub.term_destination = JPEG_Mem_TermDestination; + dest->outfile = NULL; + + dest->buffer = (unsigned char *) buf; + dest->bufsize = bufsize; +} + + +/* +==================== +JPEG_SaveImage_preflipped + +Save a preflipped JPEG image to a file +==================== +*/ +qboolean JPEG_SaveImage_preflipped (const char *filename, int width, int height, unsigned char *data) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + unsigned char *scanline; + unsigned int offset, linesize; + qfile_t* file; + + // No DLL = no JPEGs + if (!jpeg_dll) + { + Con_Print("You need the libjpeg library to save JPEG images\n"); + return false; + } + + // Open the file + file = FS_OpenRealFile(filename, "wb", true); + if (!file) + return false; + + if(setjmp(error_in_jpeg)) + goto error_caught; + cinfo.err = qjpeg_std_error (&jerr); + cinfo.err->error_exit = JPEG_ErrorExit; + + qjpeg_create_compress (&cinfo); + JPEG_FileDest (&cinfo, file); + + // Set the parameters for compression + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + qjpeg_set_defaults (&cinfo); + qjpeg_set_quality (&cinfo, (int)(scr_screenshot_jpeg_quality.value * 100), TRUE); + qjpeg_simple_progression (&cinfo); + + // turn off subsampling (to make text look better) + cinfo.optimize_coding = 1; + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + qjpeg_start_compress (&cinfo, true); + + // Compress each scanline + linesize = cinfo.image_width * 3; + offset = linesize * (cinfo.image_height - 1); + while (cinfo.next_scanline < cinfo.image_height) + { + scanline = &data[offset - cinfo.next_scanline * linesize]; + + qjpeg_write_scanlines (&cinfo, &scanline, 1); + } + + qjpeg_finish_compress (&cinfo); + qjpeg_destroy_compress (&cinfo); + + FS_Close (file); + return true; + +error_caught: + qjpeg_destroy_compress (&cinfo); + FS_Close (file); + return false; +} + +static size_t JPEG_try_SaveImage_to_Buffer (struct jpeg_compress_struct *cinfo, char *jpegbuf, size_t jpegsize, int quality, int width, int height, unsigned char *data) +{ + unsigned char *scanline; + unsigned int linesize; + + jpeg_toolarge = false; + JPEG_MemDest (cinfo, jpegbuf, jpegsize); + + // Set the parameters for compression + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + qjpeg_set_defaults (cinfo); + qjpeg_set_quality (cinfo, quality, FALSE); + + cinfo->comp_info[0].h_samp_factor = 2; + cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[1].h_samp_factor = 1; + cinfo->comp_info[1].v_samp_factor = 1; + cinfo->comp_info[2].h_samp_factor = 1; + cinfo->comp_info[2].v_samp_factor = 1; + cinfo->optimize_coding = 1; + + qjpeg_start_compress (cinfo, true); + + // Compress each scanline + linesize = width * 3; + while (cinfo->next_scanline < cinfo->image_height) + { + scanline = &data[cinfo->next_scanline * linesize]; + + qjpeg_write_scanlines (cinfo, &scanline, 1); + } + + qjpeg_finish_compress (cinfo); + + if(jpeg_toolarge) + return 0; + + return ((my_dest_ptr) cinfo->dest)->bufsize; +} + +size_t JPEG_SaveImage_to_Buffer (char *jpegbuf, size_t jpegsize, int width, int height, unsigned char *data) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + int quality; + int quality_guess; + size_t result; + + // No DLL = no JPEGs + if (!jpeg_dll) + { + Con_Print("You need the libjpeg library to save JPEG images\n"); + return false; + } + + if(setjmp(error_in_jpeg)) + goto error_caught; + cinfo.err = qjpeg_std_error (&jerr); + cinfo.err->error_exit = JPEG_ErrorExit; + + qjpeg_create_compress (&cinfo); + +#if 0 + // used to get the formula below + { + char buf[1048576]; + unsigned char *img; + int i; + + img = Mem_Alloc(tempmempool, width * height * 3); + for(i = 0; i < width * height * 3; ++i) + img[i] = rand() & 0xFF; + + for(i = 0; i <= 100; ++i) + { + Con_Printf("! %d %d %d %d\n", width, height, i, (int) JPEG_try_SaveImage_to_Buffer(&cinfo, buf, sizeof(buf), i, width, height, img)); + } + + Mem_Free(img); + } +#endif + + //quality_guess = (100 * jpegsize - 41000) / (width*height) + 2; // fits random data + quality_guess = (256 * jpegsize - 81920) / (width*height) - 8; // fits Nexuiz's/Xonotic's map pictures + + quality_guess = bound(0, quality_guess, 100); + quality = bound(0, quality_guess + sv_writepicture_quality.integer, 100); // assume it can do 10 failed attempts + + while(!(result = JPEG_try_SaveImage_to_Buffer(&cinfo, jpegbuf, jpegsize, quality, width, height, data))) + { + --quality; + if(quality < 0) + { + Con_Printf("couldn't write image at all, probably too big\n"); + return 0; + } + } + qjpeg_destroy_compress (&cinfo); + Con_DPrintf("JPEG_SaveImage_to_Buffer: guessed quality/size %d/%d, actually got %d/%d\n", quality_guess, (int)jpegsize, quality, (int)result); + + return result; + +error_caught: + qjpeg_destroy_compress (&cinfo); + return 0; +} + +typedef struct CompressedImageCacheItem +{ + char imagename[MAX_QPATH]; + size_t maxsize; + void *compressed; + size_t compressed_size; + struct CompressedImageCacheItem *next; +} +CompressedImageCacheItem; +#define COMPRESSEDIMAGECACHE_SIZE 4096 +static CompressedImageCacheItem *CompressedImageCache[COMPRESSEDIMAGECACHE_SIZE]; + +static void CompressedImageCache_Add(const char *imagename, size_t maxsize, void *compressed, size_t compressed_size) +{ + char vabuf[1024]; + const char *hashkey = va(vabuf, sizeof(vabuf), "%s:%d", imagename, (int) maxsize); + int hashindex = CRC_Block((unsigned char *) hashkey, strlen(hashkey)) % COMPRESSEDIMAGECACHE_SIZE; + CompressedImageCacheItem *i; + + if(strlen(imagename) >= MAX_QPATH) + return; // can't add this + + i = (CompressedImageCacheItem*) Z_Malloc(sizeof(CompressedImageCacheItem)); + strlcpy(i->imagename, imagename, sizeof(i->imagename)); + i->maxsize = maxsize; + i->compressed = compressed; + i->compressed_size = compressed_size; + i->next = CompressedImageCache[hashindex]; + CompressedImageCache[hashindex] = i; +} + +static CompressedImageCacheItem *CompressedImageCache_Find(const char *imagename, size_t maxsize) +{ + char vabuf[1024]; + const char *hashkey = va(vabuf, sizeof(vabuf), "%s:%d", imagename, (int) maxsize); + int hashindex = CRC_Block((unsigned char *) hashkey, strlen(hashkey)) % COMPRESSEDIMAGECACHE_SIZE; + CompressedImageCacheItem *i = CompressedImageCache[hashindex]; + + while(i) + { + if(i->maxsize == maxsize) + if(!strcmp(i->imagename, imagename)) + return i; + i = i->next; + } + return NULL; +} + +qboolean Image_Compress(const char *imagename, size_t maxsize, void **buf, size_t *size) +{ + unsigned char *imagedata, *newimagedata; + int maxPixelCount; + int components[3] = {2, 1, 0}; + CompressedImageCacheItem *i; + + JPEG_OpenLibrary (); // for now; LH had the idea of replacing this by a better format + PNG_OpenLibrary (); // for loading + + // No DLL = no JPEGs + if (!jpeg_dll) + { + Con_Print("You need the libjpeg library to save JPEG images\n"); + return false; + } + + i = CompressedImageCache_Find(imagename, maxsize); + if(i) + { + *size = i->compressed_size; + *buf = i->compressed; + } + + // load the image + imagedata = loadimagepixelsbgra(imagename, true, false, false, NULL); + if(!imagedata) + return false; + + // find an appropriate size for somewhat okay compression + if(maxsize <= 768) + maxPixelCount = 32 * 32; + else if(maxsize <= 1024) + maxPixelCount = 64 * 64; + else if(maxsize <= 4096) + maxPixelCount = 128 * 128; + else + maxPixelCount = 256 * 256; + + while(image_width * image_height > maxPixelCount) + { + int one = 1; + Image_MipReduce32(imagedata, imagedata, &image_width, &image_height, &one, image_width/2, image_height/2, 1); + } + + newimagedata = (unsigned char *) Mem_Alloc(tempmempool, image_width * image_height * 3); + + // convert the image from BGRA to RGB + Image_CopyMux(newimagedata, imagedata, image_width, image_height, false, false, false, 3, 4, components); + Mem_Free(imagedata); + + // try to compress it to JPEG + *buf = Z_Malloc(maxsize); + *size = JPEG_SaveImage_to_Buffer((char *) *buf, maxsize, image_width, image_height, newimagedata); + Mem_Free(newimagedata); + + if(!*size) + { + Z_Free(*buf); + *buf = NULL; + Con_Printf("could not compress image %s to %d bytes\n", imagename, (int)maxsize); + // return false; + // also cache failures! + } + + // store it in the cache + CompressedImageCache_Add(imagename, maxsize, *buf, *size); + return (*buf != NULL); +} diff --git a/app/jni/jpeg.h b/app/jni/jpeg.h new file mode 100644 index 0000000..ff17eb7 --- /dev/null +++ b/app/jni/jpeg.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2002 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef JPEG_H +#define JPEG_H + + +qboolean JPEG_OpenLibrary (void); +void JPEG_CloseLibrary (void); +unsigned char* JPEG_LoadImage_BGRA (const unsigned char *f, int filesize, int *miplevel); +qboolean JPEG_SaveImage_preflipped (const char *filename, int width, int height, unsigned char *data); + +/*! \returns 0 if failed, or the size actually used. + */ +size_t JPEG_SaveImage_to_Buffer (char *jpegbuf, size_t jpegsize, int width, int height, unsigned char *data); +qboolean Image_Compress(const char *imagename, size_t maxsize, void **buf, size_t *size); + + +#endif diff --git a/app/jni/keys.c b/app/jni/keys.c new file mode 100644 index 0000000..724d8c1 --- /dev/null +++ b/app/jni/keys.c @@ -0,0 +1,2003 @@ +/* + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA +*/ + +#include "quakedef.h" +#include "cl_video.h" +#include "utf8lib.h" +#include "csprogs.h" + +cvar_t con_closeontoggleconsole = {CVAR_SAVE, "con_closeontoggleconsole","1", "allows toggleconsole binds to close the console as well; when set to 2, this even works when not at the start of the line in console input; when set to 3, this works even if the toggleconsole key is the color tag"}; + +/* +key up events are sent even if in console mode +*/ + +char key_line[MAX_INPUTLINE]; +int key_linepos; +qboolean key_insert = true; // insert key toggle (for editing) +keydest_t key_dest; +int key_consoleactive; +char *keybindings[MAX_BINDMAPS][MAX_KEYS]; + +int history_line; +char history_savedline[MAX_INPUTLINE]; +char history_searchstring[MAX_INPUTLINE]; +qboolean history_matchfound = false; +conbuffer_t history; + +extern cvar_t con_textsize; + + +static void Key_History_Init(void) +{ + qfile_t *historyfile; + ConBuffer_Init(&history, HIST_TEXTSIZE, HIST_MAXLINES, zonemempool); + + historyfile = FS_OpenRealFile("darkplaces_history.txt", "rb", false); // rb to handle unix line endings on windows too + if(historyfile) + { + char buf[MAX_INPUTLINE]; + int bufpos; + int c; + + bufpos = 0; + for(;;) + { + c = FS_Getc(historyfile); + if(c < 0 || c == 0 || c == '\r' || c == '\n') + { + if(bufpos > 0) + { + buf[bufpos] = 0; + ConBuffer_AddLine(&history, buf, bufpos, 0); + bufpos = 0; + } + if(c < 0) + break; + } + else + { + if(bufpos < MAX_INPUTLINE - 1) + buf[bufpos++] = c; + } + } + + FS_Close(historyfile); + } + + history_line = -1; +} + +static void Key_History_Shutdown(void) +{ + // TODO write history to a file + + qfile_t *historyfile = FS_OpenRealFile("darkplaces_history.txt", "w", false); + if(historyfile) + { + int i; + for(i = 0; i < CONBUFFER_LINES_COUNT(&history); ++i) + FS_Printf(historyfile, "%s\n", ConBuffer_GetLine(&history, i)); + FS_Close(historyfile); + } + + ConBuffer_Shutdown(&history); +} + +static void Key_History_Push(void) +{ + if(key_line[1]) // empty? + if(strcmp(key_line, "]quit")) // putting these into the history just sucks + if(strncmp(key_line, "]quit ", 6)) // putting these into the history just sucks + if(strcmp(key_line, "]rcon_password")) // putting these into the history just sucks + if(strncmp(key_line, "]rcon_password ", 15)) // putting these into the history just sucks + ConBuffer_AddLine(&history, key_line + 1, strlen(key_line) - 1, 0); + Con_Printf("%s\n", key_line); // don't mark empty lines as history + history_line = -1; + if (history_matchfound) + history_matchfound = false; +} + +static qboolean Key_History_Get_foundCommand(void) +{ + if (!history_matchfound) + return false; + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + key_linepos = strlen(key_line); + history_matchfound = false; + return true; +} + +static void Key_History_Up(void) +{ + if(history_line == -1) // editing the "new" line + strlcpy(history_savedline, key_line + 1, sizeof(history_savedline)); + + if (Key_History_Get_foundCommand()) + return; + + if(history_line == -1) + { + history_line = CONBUFFER_LINES_COUNT(&history) - 1; + if(history_line != -1) + { + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + key_linepos = strlen(key_line); + } + } + else if(history_line > 0) + { + --history_line; // this also does -1 -> 0, so it is good + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + key_linepos = strlen(key_line); + } +} + +static void Key_History_Down(void) +{ + if(history_line == -1) // editing the "new" line + return; + + if (Key_History_Get_foundCommand()) + return; + + if(history_line < CONBUFFER_LINES_COUNT(&history) - 1) + { + ++history_line; + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + } + else + { + history_line = -1; + strlcpy(key_line + 1, history_savedline, sizeof(key_line) - 1); + } + + key_linepos = strlen(key_line); +} + +static void Key_History_First(void) +{ + if(history_line == -1) // editing the "new" line + strlcpy(history_savedline, key_line + 1, sizeof(history_savedline)); + + if (CONBUFFER_LINES_COUNT(&history) > 0) + { + history_line = 0; + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + key_linepos = strlen(key_line); + } +} + +static void Key_History_Last(void) +{ + if(history_line == -1) // editing the "new" line + strlcpy(history_savedline, key_line + 1, sizeof(history_savedline)); + + if (CONBUFFER_LINES_COUNT(&history) > 0) + { + history_line = CONBUFFER_LINES_COUNT(&history) - 1; + strlcpy(key_line + 1, ConBuffer_GetLine(&history, history_line), sizeof(key_line) - 1); + key_linepos = strlen(key_line); + } +} + +static void Key_History_Find_Backwards(void) +{ + int i; + const char *partial = key_line + 1; + char vabuf[1024]; + size_t digits = strlen(va(vabuf, sizeof(vabuf), "%i", HIST_MAXLINES)); + + if (history_line == -1) // editing the "new" line + strlcpy(history_savedline, key_line + 1, sizeof(history_savedline)); + + if (strcmp(key_line + 1, history_searchstring)) // different string? Start a new search + { + strlcpy(history_searchstring, key_line + 1, sizeof(history_searchstring)); + i = CONBUFFER_LINES_COUNT(&history) - 1; + } + else if (history_line == -1) + i = CONBUFFER_LINES_COUNT(&history) - 1; + else + i = history_line - 1; + + if (!*partial) + partial = "*"; + else if (!( strchr(partial, '*') || strchr(partial, '?') )) // no pattern? + partial = va(vabuf, sizeof(vabuf), "*%s*", partial); + + for ( ; i >= 0; i--) + if (matchpattern_with_separator(ConBuffer_GetLine(&history, i), partial, true, "", false)) + { + Con_Printf("^2%*i^7 %s\n", (int)digits, i+1, ConBuffer_GetLine(&history, i)); + history_line = i; + history_matchfound = true; + return; + } +} + +static void Key_History_Find_Forwards(void) +{ + int i; + const char *partial = key_line + 1; + char vabuf[1024]; + size_t digits = strlen(va(vabuf, sizeof(vabuf), "%i", HIST_MAXLINES)); + + if (history_line == -1) // editing the "new" line + return; + + if (strcmp(key_line + 1, history_searchstring)) // different string? Start a new search + { + strlcpy(history_searchstring, key_line + 1, sizeof(history_searchstring)); + i = 0; + } + else i = history_line + 1; + + if (!*partial) + partial = "*"; + else if (!( strchr(partial, '*') || strchr(partial, '?') )) // no pattern? + partial = va(vabuf, sizeof(vabuf), "*%s*", partial); + + for ( ; i < CONBUFFER_LINES_COUNT(&history); i++) + if (matchpattern_with_separator(ConBuffer_GetLine(&history, i), partial, true, "", false)) + { + Con_Printf("^2%*i^7 %s\n", (int)digits, i+1, ConBuffer_GetLine(&history, i)); + history_line = i; + history_matchfound = true; + return; + } +} + +static void Key_History_Find_All(void) +{ + const char *partial = key_line + 1; + int i, count = 0; + char vabuf[1024]; + size_t digits = strlen(va(vabuf, sizeof(vabuf), "%i", HIST_MAXLINES)); + Con_Printf("History commands containing \"%s\":\n", key_line + 1); + + if (!*partial) + partial = "*"; + else if (!( strchr(partial, '*') || strchr(partial, '?') )) // no pattern? + partial = va(vabuf, sizeof(vabuf), "*%s*", partial); + + for (i=0; i 1) + { + if (!strcmp(Cmd_Argv (1), "-c")) + { + ConBuffer_Clear(&history); + return; + } + i = strtol(Cmd_Argv (1), &errchar, 0); + if ((i < 0) || (i > CONBUFFER_LINES_COUNT(&history)) || (errchar && *errchar)) + i = 0; + else + i = CONBUFFER_LINES_COUNT(&history) - i; + } + + for ( ; i= MAX_INPUTLINE) + i= MAX_INPUTLINE - key_linepos - 1; + if (i > 0) + { + // terencehill: insert the clipboard text between the characters of the line + /* + char *temp = (char *) Z_Malloc(MAX_INPUTLINE); + cbd[i]=0; + temp[0]=0; + if ( key_linepos < (int)strlen(key_line) ) + strlcpy(temp, key_line + key_linepos, (int)strlen(key_line) - key_linepos +1); + key_line[key_linepos] = 0; + strlcat(key_line, cbd, sizeof(key_line)); + if (temp[0]) + strlcat(key_line, temp, sizeof(key_line)); + Z_Free(temp); + key_linepos += i; + */ + // blub: I'm changing this to use memmove() like the rest of the code does. + cbd[i] = 0; + memmove(key_line + key_linepos + i, key_line + key_linepos, sizeof(key_line) - key_linepos - i); + memcpy(key_line + key_linepos, cbd, i); + key_linepos += i; + } + Z_Free(cbd); + } + return; + } + + if (key == 'l' && keydown[K_CTRL]) + { + Cbuf_AddText ("clear\n"); + return; + } + + if (key == 'u' && keydown[K_CTRL]) // like vi/readline ^u: delete currently edited line + { + // clear line + key_line[0] = ']'; + key_line[1] = 0; + key_linepos = 1; + return; + } + + if (key == 'q' && keydown[K_CTRL]) // like zsh ^q: push line to history, don't execute, and clear + { + // clear line + Key_History_Push(); + key_line[0] = ']'; + key_line[1] = 0; + key_linepos = 1; + return; + } + + if (key == K_ENTER || key == K_KP_ENTER) + { + Cbuf_AddText (key_line+1); // skip the ] + Cbuf_AddText ("\n"); + Key_History_Push(); + key_line[0] = ']'; + key_line[1] = 0; // EvilTypeGuy: null terminate + key_linepos = 1; + // force an update, because the command may take some time + if (cls.state == ca_disconnected) + { + CL_BeginUpdateScreen(); + SCR_DrawScreen(); + CL_EndUpdateScreen(); + } + return; + } + + if (key == K_TAB) + { + if(keydown[K_CTRL]) // append to the cvar its value + { + int cvar_len, cvar_str_len, chars_to_move; + char k; + char cvar[MAX_INPUTLINE]; + const char *cvar_str; + + // go to the start of the variable + while(--key_linepos) + { + k = key_line[key_linepos]; + if(k == '\"' || k == ';' || k == ' ' || k == '\'') + break; + } + key_linepos++; + + // save the variable name in cvar + for(cvar_len=0; (k = key_line[key_linepos + cvar_len]) != 0; cvar_len++) + { + if(k == '\"' || k == ';' || k == ' ' || k == '\'') + break; + cvar[cvar_len] = k; + } + if (cvar_len==0) + return; + cvar[cvar_len] = 0; + + // go to the end of the cvar + key_linepos += cvar_len; + + // save the content of the variable in cvar_str + cvar_str = Cvar_VariableString(cvar); + cvar_str_len = strlen(cvar_str); + if (cvar_str_len==0) + return; + + // insert space and cvar_str in key_line + chars_to_move = strlen(&key_line[key_linepos]); + if (key_linepos + 1 + cvar_str_len + chars_to_move < MAX_INPUTLINE) + { + if (chars_to_move) + memmove(&key_line[key_linepos + 1 + cvar_str_len], &key_line[key_linepos], chars_to_move); + key_line[key_linepos++] = ' '; + memcpy(&key_line[key_linepos], cvar_str, cvar_str_len); + key_linepos += cvar_str_len; + key_line[key_linepos + chars_to_move] = 0; + } + else + Con_Printf("Couldn't append cvar value, edit line too long.\n"); + return; + } + // Enhanced command completion + // by EvilTypeGuy eviltypeguy@qeradiant.com + // Thanks to Fett, Taniwha + Con_CompleteCommandLine(); + return; + } + + // Advanced Console Editing by Radix radix@planetquake.com + // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com + // Enhanced by [515] + // Enhanced by terencehill + + // move cursor to the previous character + if (key == K_LEFTARROW || key == K_KP_LEFTARROW) + { + if (key_linepos < 2) + return; + if(keydown[K_CTRL]) // move cursor to the previous word + { + int pos; + char k; + pos = key_linepos-1; + + if(pos) // skip all "; ' after the word + while(--pos) + { + k = key_line[pos]; + if (!(k == '\"' || k == ';' || k == ' ' || k == '\'')) + break; + } + + if(pos) + while(--pos) + { + k = key_line[pos]; + if(k == '\"' || k == ';' || k == ' ' || k == '\'') + break; + } + key_linepos = pos + 1; + } + else if(keydown[K_SHIFT]) // move cursor to the previous character ignoring colors + { + int pos; + size_t inchar = 0; + pos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte + while (pos) + if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && isdigit(key_line[pos])) + pos-=2; + else if(pos-4 > 0 && key_line[pos-4] == STRING_COLOR_TAG && key_line[pos-3] == STRING_COLOR_RGB_TAG_CHAR + && isxdigit(key_line[pos-2]) && isxdigit(key_line[pos-1]) && isxdigit(key_line[pos])) + pos-=5; + else + { + if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && key_line[pos] == STRING_COLOR_TAG) // consider ^^ as a character + pos--; + pos--; + break; + } + // we need to move to the beginning of the character when in a wide character: + u8_charidx(key_line, pos + 1, &inchar); + key_linepos = pos + 1 - inchar; + } + else + { + key_linepos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte + } + return; + } + + // delete char before cursor + if (key == K_BACKSPACE || (key == 'h' && keydown[K_CTRL])) + { + if (key_linepos > 1) + { + int newpos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte + strlcpy(key_line + newpos, key_line + key_linepos, sizeof(key_line) + 1 - key_linepos); + key_linepos = newpos; + } + return; + } + + // delete char on cursor + if (key == K_DEL || key == K_KP_DEL) + { + size_t linelen; + linelen = strlen(key_line); + if (key_linepos < (int)linelen) + memmove(key_line + key_linepos, key_line + key_linepos + u8_bytelen(key_line + key_linepos, 1), linelen - key_linepos); + return; + } + + + // move cursor to the next character + if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW) + { + if (key_linepos >= (int)strlen(key_line)) + return; + if(keydown[K_CTRL]) // move cursor to the next word + { + int pos, len; + char k; + len = (int)strlen(key_line); + pos = key_linepos; + + while(++pos < len) + { + k = key_line[pos]; + if(k == '\"' || k == ';' || k == ' ' || k == '\'') + break; + } + + if (pos < len) // skip all "; ' after the word + while(++pos < len) + { + k = key_line[pos]; + if (!(k == '\"' || k == ';' || k == ' ' || k == '\'')) + break; + } + key_linepos = pos; + } + else if(keydown[K_SHIFT]) // move cursor to the next character ignoring colors + { + int pos, len; + len = (int)strlen(key_line); + pos = key_linepos; + + // go beyond all initial consecutive color tags, if any + if(pos < len) + while (key_line[pos] == STRING_COLOR_TAG) + { + if(isdigit(key_line[pos+1])) + pos+=2; + else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4])) + pos+=5; + else + break; + } + + // skip the char + if (key_line[pos] == STRING_COLOR_TAG && key_line[pos+1] == STRING_COLOR_TAG) // consider ^^ as a character + pos++; + pos += u8_bytelen(key_line + pos, 1); + + // now go beyond all next consecutive color tags, if any + if(pos < len) + while (key_line[pos] == STRING_COLOR_TAG) + { + if(isdigit(key_line[pos+1])) + pos+=2; + else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4])) + pos+=5; + else + break; + } + key_linepos = pos; + } + else + key_linepos += u8_bytelen(key_line + key_linepos, 1); + return; + } + + if (key == K_INS || key == K_KP_INS) // toggle insert mode + { + key_insert ^= 1; + return; + } + + // End Advanced Console Editing + + if (key == K_UPARROW || key == K_KP_UPARROW || (key == 'p' && keydown[K_CTRL])) + { + Key_History_Up(); + return; + } + + if (key == K_DOWNARROW || key == K_KP_DOWNARROW || (key == 'n' && keydown[K_CTRL])) + { + Key_History_Down(); + return; + } + // ~1.0795 = 82/76 using con_textsize 64 76 is height of the char, 6 is the distance between 2 lines + + if (keydown[K_CTRL]) + { + // prints all the matching commands + if (key == 'f') + { + Key_History_Find_All(); + return; + } + // Search forwards/backwards, pointing the history's index to the + // matching command but without fetching it to let one continue the search. + // To fetch it, it suffices to just press UP or DOWN. + if (key == 'r') + { + if (keydown[K_SHIFT]) + Key_History_Find_Forwards(); + else + Key_History_Find_Backwards(); + return; + } + // go to the last/first command of the history + if (key == ',') + { + Key_History_First(); + return; + } + if (key == '.') + { + Key_History_Last(); + return; + } + } + + if (key == K_PGUP || key == K_KP_PGUP) + { + if(keydown[K_CTRL]) + { + con_backscroll += ((vid_conheight.integer >> 2) / con_textsize.integer)-1; + } + else + con_backscroll += ((vid_conheight.integer >> 1) / con_textsize.integer)-3; + return; + } + + if (key == K_PGDN || key == K_KP_PGDN) + { + if(keydown[K_CTRL]) + { + con_backscroll -= ((vid_conheight.integer >> 2) / con_textsize.integer)-1; + } + else + con_backscroll -= ((vid_conheight.integer >> 1) / con_textsize.integer)-3; + return; + } + + if (key == K_MWHEELUP) + { + if(keydown[K_CTRL]) + con_backscroll += 1; + else if(keydown[K_SHIFT]) + con_backscroll += ((vid_conheight.integer >> 2) / con_textsize.integer)-1; + else + con_backscroll += 5; + return; + } + + if (key == K_MWHEELDOWN) + { + if(keydown[K_CTRL]) + con_backscroll -= 1; + else if(keydown[K_SHIFT]) + con_backscroll -= ((vid_conheight.integer >> 2) / con_textsize.integer)-1; + else + con_backscroll -= 5; + return; + } + + if (keydown[K_CTRL]) + { + // text zoom in + if (key == '+' || key == K_KP_PLUS) + { + if (con_textsize.integer < 128) + Cvar_SetValueQuick(&con_textsize, con_textsize.integer + 1); + return; + } + // text zoom out + if (key == '-' || key == K_KP_MINUS) + { + if (con_textsize.integer > 1) + Cvar_SetValueQuick(&con_textsize, con_textsize.integer - 1); + return; + } + // text zoom reset + if (key == '0' || key == K_KP_INS) + { + Cvar_SetValueQuick(&con_textsize, atoi(Cvar_VariableDefString("con_textsize"))); + return; + } + } + + if (key == K_HOME || key == K_KP_HOME) + { + if (keydown[K_CTRL]) + con_backscroll = CON_TEXTSIZE; + else + key_linepos = 1; + return; + } + + if (key == K_END || key == K_KP_END) + { + if (keydown[K_CTRL]) + con_backscroll = 0; + else + key_linepos = (int)strlen(key_line); + return; + } + + // non printable + if (unicode < 32) + return; + + if (key_linepos < MAX_INPUTLINE-1) + { + char buf[16]; + int len; + int blen; + blen = u8_fromchar(unicode, buf, sizeof(buf)); + if (!blen) + return; + len = (int)strlen(&key_line[key_linepos]); + // check insert mode, or always insert if at end of line + if (key_insert || len == 0) + { + // can't use strcpy to move string to right + len++; + //memmove(&key_line[key_linepos + u8_bytelen(key_line + key_linepos, 1)], &key_line[key_linepos], len); + memmove(&key_line[key_linepos + blen], &key_line[key_linepos], len); + } + memcpy(key_line + key_linepos, buf, blen); + key_linepos += blen; + //key_linepos += u8_fromchar(unicode, key_line + key_linepos, sizeof(key_line) - key_linepos - 1); + //key_line[key_linepos] = ascii; + //key_linepos++; + } +} + +//============================================================================ + +int chat_mode; +char chat_buffer[MAX_INPUTLINE]; +unsigned int chat_bufferlen = 0; + +static void +Key_Message (int key, int ascii) +{ + char vabuf[1024]; + if (key == K_ENTER || ascii == 10 || ascii == 13) + { + if(chat_mode < 0) + Cmd_ExecuteString(chat_buffer, src_command, true); // not Cbuf_AddText to allow semiclons in args; however, this allows no variables then. Use aliases! + else + Cmd_ForwardStringToServer(va(vabuf, sizeof(vabuf), "%s %s", chat_mode ? "say_team" : "say ", chat_buffer)); + + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + // TODO add support for arrow keys and simple editing + + if (key == K_ESCAPE) { + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + if (key == K_BACKSPACE) { + if (chat_bufferlen) { + chat_bufferlen = u8_prevbyte(chat_buffer, chat_bufferlen); + chat_buffer[chat_bufferlen] = 0; + } + return; + } + + if(key == K_TAB) { + chat_bufferlen = Nicks_CompleteChatLine(chat_buffer, sizeof(chat_buffer), chat_bufferlen); + return; + } + + // ctrl+key generates an ascii value < 32 and shows a char from the charmap + if (ascii > 0 && ascii < 32 && utf8_enable.integer) + ascii = 0xE000 + ascii; + + if (chat_bufferlen == sizeof (chat_buffer) - 1) + return; // all full + + if (!ascii) + return; // non printable + + chat_bufferlen += u8_fromchar(ascii, chat_buffer+chat_bufferlen, sizeof(chat_buffer) - chat_bufferlen - 1); + + //chat_buffer[chat_bufferlen++] = ascii; + //chat_buffer[chat_bufferlen] = 0; +} + +//============================================================================ + + +/* +=================== +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 (const char *str) +{ + const keyname_t *kn; + + if (!str || !str[0]) + return -1; + if (!str[1]) + return tolower(str[0]); + + for (kn = keynames; kn->name; kn++) { + if (!strcasecmp (str, kn->name)) + return kn->keynum; + } + return -1; +} + +/* +=================== +Returns a string (either a single ascii char, or a K_* name) for the +given keynum. +FIXME: handle quote special (general escape sequence?) +=================== +*/ +const char * +Key_KeynumToString (int keynum, char *tinystr, size_t tinystrlength) +{ + const keyname_t *kn; + + // -1 is an invalid code + if (keynum < 0) + return ""; + + // search overrides first, because some characters are special + for (kn = keynames; kn->name; kn++) + if (keynum == kn->keynum) + return kn->name; + + // if it is printable, output it as a single character + if (keynum > 32 && keynum < 256) + { + if (tinystrlength >= 2) + { + tinystr[0] = keynum; + tinystr[1] = 0; + } + return tinystr; + } + + // if it is not overridden and not printable, we don't know what to do with it + return ""; +} + + +qboolean +Key_SetBinding (int keynum, int bindmap, const char *binding) +{ + char *newbinding; + size_t l; + + if (keynum == -1 || keynum >= MAX_KEYS) + return false; + if ((bindmap < 0) || (bindmap >= MAX_BINDMAPS)) + return false; + +// free old bindings + if (keybindings[bindmap][keynum]) { + Z_Free (keybindings[bindmap][keynum]); + keybindings[bindmap][keynum] = NULL; + } + if(!binding[0]) // make "" binds be removed --blub + return true; +// allocate memory for new binding + l = strlen (binding); + newbinding = (char *)Z_Malloc (l + 1); + memcpy (newbinding, binding, l + 1); + newbinding[l] = 0; + keybindings[bindmap][keynum] = newbinding; + return true; +} + +void Key_GetBindMap(int *fg, int *bg) +{ + if(fg) + *fg = key_bmap; + if(bg) + *bg = key_bmap2; +} + +qboolean Key_SetBindMap(int fg, int bg) +{ + if(fg >= MAX_BINDMAPS) + return false; + if(bg >= MAX_BINDMAPS) + return false; + if(fg >= 0) + key_bmap = fg; + if(bg >= 0) + key_bmap2 = bg; + return true; +} + +static void +Key_In_Unbind_f (void) +{ + int b, m; + char *errchar = NULL; + + if (Cmd_Argc () != 3) { + Con_Print("in_unbind : remove commands from a key\n"); + return; + } + + m = strtol(Cmd_Argv (1), &errchar, 0); + if ((m < 0) || (m >= MAX_BINDMAPS) || (errchar && *errchar)) { + Con_Printf("%s isn't a valid bindmap\n", Cmd_Argv(1)); + return; + } + + b = Key_StringToKeynum (Cmd_Argv (2)); + if (b == -1) { + Con_Printf("\"%s\" isn't a valid key\n", Cmd_Argv (2)); + return; + } + + if(!Key_SetBinding (b, m, "")) + Con_Printf("Key_SetBinding failed for unknown reason\n"); +} + +static void +Key_In_Bind_f (void) +{ + int i, c, b, m; + char cmd[MAX_INPUTLINE]; + char *errchar = NULL; + + c = Cmd_Argc (); + + if (c != 3 && c != 4) { + Con_Print("in_bind [command] : attach a command to a key\n"); + return; + } + + m = strtol(Cmd_Argv (1), &errchar, 0); + if ((m < 0) || (m >= MAX_BINDMAPS) || (errchar && *errchar)) { + Con_Printf("%s isn't a valid bindmap\n", Cmd_Argv(1)); + return; + } + + b = Key_StringToKeynum (Cmd_Argv (2)); + if (b == -1 || b >= MAX_KEYS) { + Con_Printf("\"%s\" isn't a valid key\n", Cmd_Argv (2)); + return; + } + + if (c == 3) { + if (keybindings[m][b]) + Con_Printf("\"%s\" = \"%s\"\n", Cmd_Argv (2), keybindings[m][b]); + else + Con_Printf("\"%s\" is not bound\n", Cmd_Argv (2)); + return; + } +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + for (i = 3; i < c; i++) { + strlcat (cmd, Cmd_Argv (i), sizeof (cmd)); + if (i != (c - 1)) + strlcat (cmd, " ", sizeof (cmd)); + } + + if(!Key_SetBinding (b, m, cmd)) + Con_Printf("Key_SetBinding failed for unknown reason\n"); +} + +static void +Key_In_Bindmap_f (void) +{ + int m1, m2, c; + char *errchar = NULL; + + c = Cmd_Argc (); + + if (c != 3) { + Con_Print("in_bindmap : set current bindmap and fallback\n"); + return; + } + + m1 = strtol(Cmd_Argv (1), &errchar, 0); + if ((m1 < 0) || (m1 >= MAX_BINDMAPS) || (errchar && *errchar)) { + Con_Printf("%s isn't a valid bindmap\n", Cmd_Argv(1)); + return; + } + + m2 = strtol(Cmd_Argv (2), &errchar, 0); + if ((m2 < 0) || (m2 >= MAX_BINDMAPS) || (errchar && *errchar)) { + Con_Printf("%s isn't a valid bindmap\n", Cmd_Argv(2)); + return; + } + + key_bmap = m1; + key_bmap2 = m2; +} + +static void +Key_Unbind_f (void) +{ + int b; + + if (Cmd_Argc () != 2) { + Con_Print("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; + } + + if(!Key_SetBinding (b, 0, "")) + Con_Printf("Key_SetBinding failed for unknown reason\n"); +} + +static void +Key_Unbindall_f (void) +{ + int i, j; + + for (j = 0; j < MAX_BINDMAPS; j++) + for (i = 0; i < (int)(sizeof(keybindings[0])/sizeof(keybindings[0][0])); i++) + if (keybindings[j][i]) + Key_SetBinding (i, j, ""); +} + +static void +Key_PrintBindList(int j) +{ + char bindbuf[MAX_INPUTLINE]; + char tinystr[2]; + const char *p; + int i; + + for (i = 0; i < (int)(sizeof(keybindings[0])/sizeof(keybindings[0][0])); i++) + { + p = keybindings[j][i]; + if (p) + { + Cmd_QuoteString(bindbuf, sizeof(bindbuf), p, "\"\\", false); + if (j == 0) + Con_Printf("^2%s ^7= \"%s\"\n", Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf); + else + Con_Printf("^3bindmap %d: ^2%s ^7= \"%s\"\n", j, Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf); + } + } +} + +static void +Key_In_BindList_f (void) +{ + int m; + char *errchar = NULL; + + if(Cmd_Argc() >= 2) + { + m = strtol(Cmd_Argv(1), &errchar, 0); + if ((m < 0) || (m >= MAX_BINDMAPS) || (errchar && *errchar)) { + Con_Printf("%s isn't a valid bindmap\n", Cmd_Argv(1)); + return; + } + Key_PrintBindList(m); + } + else + { + for (m = 0; m < MAX_BINDMAPS; m++) + Key_PrintBindList(m); + } +} + +static void +Key_BindList_f (void) +{ + Key_PrintBindList(0); +} + +static void +Key_Bind_f (void) +{ + int i, c, b; + char cmd[MAX_INPUTLINE]; + + c = Cmd_Argc (); + + if (c != 2 && c != 3) { + Con_Print("bind [command] : attach a command to a key\n"); + return; + } + b = Key_StringToKeynum (Cmd_Argv (1)); + if (b == -1 || b >= MAX_KEYS) { + Con_Printf("\"%s\" isn't a valid key\n", Cmd_Argv (1)); + return; + } + + if (c == 2) { + if (keybindings[0][b]) + Con_Printf("\"%s\" = \"%s\"\n", Cmd_Argv (1), keybindings[0][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++) { + strlcat (cmd, Cmd_Argv (i), sizeof (cmd)); + if (i != (c - 1)) + strlcat (cmd, " ", sizeof (cmd)); + } + + if(!Key_SetBinding (b, 0, cmd)) + Con_Printf("Key_SetBinding failed for unknown reason\n"); +} + +/* +============ +Writes lines containing "bind key value" +============ +*/ +void +Key_WriteBindings (qfile_t *f) +{ + int i, j; + char bindbuf[MAX_INPUTLINE]; + char tinystr[2]; + const char *p; + + for (j = 0; j < MAX_BINDMAPS; j++) + { + for (i = 0; i < (int)(sizeof(keybindings[0])/sizeof(keybindings[0][0])); i++) + { + p = keybindings[j][i]; + if (p) + { + Cmd_QuoteString(bindbuf, sizeof(bindbuf), p, "\"\\", false); // don't need to escape $ because cvars are not expanded inside bind + if (j == 0) + FS_Printf(f, "bind %s \"%s\"\n", Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf); + else + FS_Printf(f, "in_bind %d %s \"%s\"\n", j, Key_KeynumToString (i, tinystr, sizeof(tinystr)), bindbuf); + } + } + } +} + + +void +Key_Init (void) +{ + Key_History_Init(); + key_line[0] = ']'; + key_line[1] = 0; + key_linepos = 1; + +// +// register our functions +// + Cmd_AddCommand ("in_bind", Key_In_Bind_f, "binds a command to the specified key in the selected bindmap"); + Cmd_AddCommand ("in_unbind", Key_In_Unbind_f, "removes command on the specified key in the selected bindmap"); + Cmd_AddCommand ("in_bindlist", Key_In_BindList_f, "bindlist: displays bound keys for all bindmaps, or the given bindmap"); + Cmd_AddCommand ("in_bindmap", Key_In_Bindmap_f, "selects active foreground and background (used only if a key is not bound in the foreground) bindmaps for typing"); + + Cmd_AddCommand ("bind", Key_Bind_f, "binds a command to the specified key in bindmap 0"); + Cmd_AddCommand ("unbind", Key_Unbind_f, "removes a command on the specified key in bindmap 0"); + Cmd_AddCommand ("bindlist", Key_BindList_f, "bindlist: displays bound keys for bindmap 0 bindmaps"); + Cmd_AddCommand ("unbindall", Key_Unbindall_f, "removes all commands from all keys in all bindmaps (leaving only shift-escape and escape)"); + + Cmd_AddCommand ("history", Key_History_f, "prints the history of executed commands (history X prints the last X entries, history -c clears the whole history)"); + + Cvar_RegisterVariable (&con_closeontoggleconsole); +} + +void +Key_Shutdown (void) +{ + Key_History_Shutdown(); +} + +const char *Key_GetBind (int key, int bindmap) +{ + const char *bind; + if (key < 0 || key >= MAX_KEYS) + return NULL; + if(bindmap >= MAX_BINDMAPS) + return NULL; + if(bindmap >= 0) + { + bind = keybindings[bindmap][key]; + } + else + { + bind = keybindings[key_bmap][key]; + if (!bind) + bind = keybindings[key_bmap2][key]; + } + return bind; +} + +void Key_FindKeysForCommand (const char *command, int *keys, int numkeys, int bindmap) +{ + int count; + int j; + const char *b; + + for (j = 0;j < numkeys;j++) + keys[j] = -1; + + if(bindmap >= MAX_BINDMAPS) + return; + + count = 0; + + for (j = 0; j < MAX_KEYS; ++j) + { + b = Key_GetBind(j, bindmap); + if (!b) + continue; + if (!strcmp (b, command) ) + { + keys[count++] = j; + if (count == numkeys) + break; + } + } +} + +/* +=================== +Called by the system between frames for both key up and key down events +Should NOT be called during an interrupt! +=================== +*/ +static char tbl_keyascii[MAX_KEYS]; +static keydest_t tbl_keydest[MAX_KEYS]; + +typedef struct eventqueueitem_s +{ + int key; + int ascii; + qboolean down; +} +eventqueueitem_t; +static int events_blocked = 0; +static eventqueueitem_t eventqueue[32]; +static unsigned eventqueue_idx = 0; + +static void Key_EventQueue_Add(int key, int ascii, qboolean down) +{ + if(eventqueue_idx < sizeof(eventqueue) / sizeof(*eventqueue)) + { + eventqueue[eventqueue_idx].key = key; + eventqueue[eventqueue_idx].ascii = ascii; + eventqueue[eventqueue_idx].down = down; + ++eventqueue_idx; + } +} + +void Key_EventQueue_Block(void) +{ + // block key events until call to Unblock + events_blocked = true; +} + +void Key_EventQueue_Unblock(void) +{ + // unblocks key events again + unsigned i; + events_blocked = false; + for(i = 0; i < eventqueue_idx; ++i) + Key_Event(eventqueue[i].key, eventqueue[i].ascii, eventqueue[i].down); + eventqueue_idx = 0; +} + +void +Key_Event (int key, int ascii, qboolean down) +{ + const char *bind; + qboolean q; + keydest_t keydest = key_dest; + char vabuf[1024]; + + if (key < 0 || key >= MAX_KEYS) + return; + + if(events_blocked) + { + Key_EventQueue_Add(key, ascii, down); + return; + } + + if (ascii == 0x80 && utf8_enable.integer) // pressing AltGr-5 (or AltGr-e) and for some reason we get windows-1252 encoding? + ascii = 0x20AC; // we want the Euro currency sign + // TODO find out which vid_ drivers do it and fix it there + // but catching U+0080 here is no loss as that char is not useful anyway + + // get key binding + bind = keybindings[key_bmap][key]; + if (!bind) + bind = keybindings[key_bmap2][key]; + + if (developer_insane.integer) + Con_DPrintf("Key_Event(%i, '%c', %s) keydown %i bind \"%s\"\n", key, ascii ? ascii : '?', down ? "down" : "up", keydown[key], bind ? bind : ""); + + if(key_consoleactive) + keydest = key_console; + + if (down) + { + // increment key repeat count each time a down is received so that things + // which want to ignore key repeat can ignore it + keydown[key] = min(keydown[key] + 1, 2); + if(keydown[key] == 1) { + tbl_keyascii[key] = ascii; + tbl_keydest[key] = keydest; + } else { + ascii = tbl_keyascii[key]; + keydest = tbl_keydest[key]; + } + } + else + { + // clear repeat count now that the key is released + keydown[key] = 0; + keydest = tbl_keydest[key]; + ascii = tbl_keyascii[key]; + } + + if(keydest == key_void) + return; + + // key_consoleactive is a flag not a key_dest because the console is a + // high priority overlay ontop of the normal screen (designed as a safety + // feature so that developers and users can rescue themselves from a bad + // situation). + // + // this also means that toggling the console on/off does not lose the old + // key_dest state + + // specially handle escape (togglemenu) and shift-escape (toggleconsole) + // engine bindings, these are not handled as normal binds so that the user + // can recover from a completely empty bindmap + if (key == K_ESCAPE) + { + // ignore key repeats on escape + if (keydown[key] > 1) + return; + + // escape does these things: + // key_consoleactive - close console + // key_message - abort messagemode + // key_menu - go to parent menu (or key_game) + // key_game - open menu + + // in all modes shift-escape toggles console + if (keydown[K_SHIFT]) + { + if(down) + { + Con_ToggleConsole_f (); + tbl_keydest[key] = key_void; // esc release should go nowhere (especially not to key_menu or key_game) + } + return; + } + + switch (keydest) + { + case key_console: + if(down) + { + if(key_consoleactive & KEY_CONSOLEACTIVE_FORCED) + { + key_consoleactive &= ~KEY_CONSOLEACTIVE_USER; + MR_ToggleMenu(1); + } + else + Con_ToggleConsole_f(); + } + break; + + case key_message: + if (down) + Key_Message (key, ascii); // that'll close the message input + break; + + case key_menu: + case key_menu_grabbed: + MR_KeyEvent (key, ascii, down); + break; + + case key_game: + // csqc has priority over toggle menu if it wants to (e.g. handling escape for UI stuff in-game.. :sick:) + q = CL_VM_InputEvent(down ? 0 : 1, key, ascii); + if (!q && down) + MR_ToggleMenu(1); + break; + + default: + Con_Printf ("Key_Event: Bad key_dest\n"); + } + return; + } + + // send function keydowns to interpreter no matter what mode is (unless the menu has specifically grabbed the keyboard, for rebinding keys) + // VorteX: Omnicide does bind F* keys + if (keydest != key_menu_grabbed) + if (key >= K_F1 && key <= K_F12 && gamemode != GAME_BLOODOMNICIDE) + { + if (bind) + { + if(keydown[key] == 1 && down) + { + // button commands add keynum as a parm + if (bind[0] == '+') + Cbuf_AddText (va(vabuf, sizeof(vabuf), "%s %i\n", bind, key)); + else + { + Cbuf_AddText (bind); + Cbuf_AddText ("\n"); + } + } else if(bind[0] == '+' && !down && keydown[key] == 0) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "-%s %i\n", bind + 1, key)); + } + return; + } + + // send input to console if it wants it + if (keydest == key_console) + { + if (!down) + return; + // con_closeontoggleconsole enables toggleconsole keys to close the + // console, as long as they are not the color prefix character + // (special exemption for german keyboard layouts) + if (con_closeontoggleconsole.integer && bind && !strncmp(bind, "toggleconsole", strlen("toggleconsole")) && (key_consoleactive & KEY_CONSOLEACTIVE_USER) && (con_closeontoggleconsole.integer >= ((ascii != STRING_COLOR_TAG) ? 2 : 3) || key_linepos == 1)) + { + Con_ToggleConsole_f (); + return; + } + + if (COM_CheckParm ("-noconsole")) + return; // only allow the key bind to turn off console + + Key_Console (key, ascii); + return; + } + + // handle toggleconsole in menu too + if (keydest == key_menu) + { + if (down && con_closeontoggleconsole.integer && bind && !strncmp(bind, "toggleconsole", strlen("toggleconsole")) && ascii != STRING_COLOR_TAG) + { + Con_ToggleConsole_f (); + tbl_keydest[key] = key_void; // key release should go nowhere (especially not to key_menu or key_game) + return; + } + } + + // ignore binds while a video is played, let the video system handle the key event + if (cl_videoplaying) + { + if (gamemode == GAME_BLOODOMNICIDE) // menu controls key events + MR_KeyEvent(key, ascii, down); + else + CL_Video_KeyEvent (key, ascii, keydown[key] != 0); + return; + } + + // anything else is a key press into the game, chat line, or menu + switch (keydest) + { + case key_message: + if (down) + Key_Message (key, ascii); + break; + case key_menu: + case key_menu_grabbed: + MR_KeyEvent (key, ascii, down); + break; + case key_game: + q = CL_VM_InputEvent(down ? 0 : 1, key, ascii); + // ignore key repeats on binds and only send the bind if the event hasnt been already processed by csqc + if (!q && bind) + { + if(keydown[key] == 1 && down) + { + // button commands add keynum as a parm + if (bind[0] == '+') + Cbuf_AddText (va(vabuf, sizeof(vabuf), "%s %i\n", bind, key)); + else + { + Cbuf_AddText (bind); + Cbuf_AddText ("\n"); + } + } else if(bind[0] == '+' && !down && keydown[key] == 0) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "-%s %i\n", bind + 1, key)); + } + break; + default: + Con_Printf ("Key_Event: Bad key_dest\n"); + } +} + +// a helper to simulate release of ALL keys +void +Key_ReleaseAll (void) +{ + int key; + // clear the event queue first + eventqueue_idx = 0; + // then send all down events (possibly into the event queue) + for(key = 0; key < MAX_KEYS; ++key) + if(keydown[key]) + Key_Event(key, 0, false); + // now all keys are guaranteed down (once the event queue is unblocked) + // and only future events count +} + +/* +=================== +Key_ClearStates +=================== +*/ +void +Key_ClearStates (void) +{ + memset(keydown, 0, sizeof(keydown)); +} diff --git a/app/jni/keys.h b/app/jni/keys.h new file mode 100644 index 0000000..cffaa3b --- /dev/null +++ b/app/jni/keys.h @@ -0,0 +1,392 @@ +/* + $RCSfile$ + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id: keys.h 11463 2011-10-22 23:52:58Z havoc $ +*/ + +#ifndef __KEYS_H +#define __KEYS_H + +#include "qtypes.h" + +// +// these are the key numbers that should be passed to Key_Event +// +typedef enum keynum_e +{ + K_TEXT = 1, // used only for unicode character input + K_TAB = 9, + K_ENTER = 13, + K_ESCAPE = 27, + K_SPACE = 32, + + // normal keys should be passed as lowercased ascii + + K_BACKSPACE = 127, + K_UPARROW, + K_DOWNARROW, + K_LEFTARROW, + K_RIGHTARROW, + + K_ALT, + K_CTRL, + K_SHIFT, + + K_F1, + K_F2, + K_F3, + K_F4, + K_F5, + K_F6, + K_F7, + K_F8, + K_F9, + K_F10, + K_F11, + K_F12, + + K_INS, + K_DEL, + K_PGDN, + K_PGUP, + K_HOME, + K_END, + + K_PAUSE, + + K_NUMLOCK, + K_CAPSLOCK, + K_SCROLLOCK, + + K_KP_0, + K_KP_INS = K_KP_0, + K_KP_1, + K_KP_END = K_KP_1, + K_KP_2, + K_KP_DOWNARROW = K_KP_2, + K_KP_3, + K_KP_PGDN = K_KP_3, + K_KP_4, + K_KP_LEFTARROW = K_KP_4, + K_KP_5, + K_KP_6, + K_KP_RIGHTARROW = K_KP_6, + K_KP_7, + K_KP_HOME = K_KP_7, + K_KP_8, + K_KP_UPARROW = K_KP_8, + K_KP_9, + K_KP_PGUP = K_KP_9, + K_KP_PERIOD, + K_KP_DEL = K_KP_PERIOD, + K_KP_DIVIDE, + K_KP_SLASH = K_KP_DIVIDE, + K_KP_MULTIPLY, + K_KP_MINUS, + K_KP_PLUS, + K_KP_ENTER, + K_KP_EQUALS, + + K_PRINTSCREEN, + + // mouse buttons generate virtual keys + + K_MOUSE1 = 512, + K_OTHERDEVICESBEGIN = K_MOUSE1, + K_MOUSE2, + K_MOUSE3, + K_MWHEELUP, + K_MWHEELDOWN, + K_MOUSE4, + K_MOUSE5, + K_MOUSE6, + K_MOUSE7, + K_MOUSE8, + K_MOUSE9, + K_MOUSE10, + K_MOUSE11, + K_MOUSE12, + K_MOUSE13, + K_MOUSE14, + K_MOUSE15, + K_MOUSE16, + +// +// joystick buttons +// + K_JOY1 = 768, + K_JOY2, + K_JOY3, + K_JOY4, + K_JOY5, + K_JOY6, + K_JOY7, + K_JOY8, + K_JOY9, + K_JOY10, + K_JOY11, + K_JOY12, + K_JOY13, + K_JOY14, + K_JOY15, + K_JOY16, + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// + K_AUX1, + K_AUX2, + K_AUX3, + K_AUX4, + K_AUX5, + K_AUX6, + K_AUX7, + K_AUX8, + K_AUX9, + K_AUX10, + K_AUX11, + K_AUX12, + K_AUX13, + K_AUX14, + K_AUX15, + K_AUX16, + K_AUX17, + K_AUX18, + K_AUX19, + K_AUX20, + K_AUX21, + K_AUX22, + K_AUX23, + K_AUX24, + K_AUX25, + K_AUX26, + K_AUX27, + K_AUX28, + K_AUX29, + K_AUX30, + K_AUX31, + K_AUX32, + + // Microsoft Xbox 360 Controller For Windows + K_X360_DPAD_UP, + K_X360_DPAD_DOWN, + K_X360_DPAD_LEFT, + K_X360_DPAD_RIGHT, + K_X360_START, + K_X360_BACK, + K_X360_LEFT_THUMB, + K_X360_RIGHT_THUMB, + K_X360_LEFT_SHOULDER, + K_X360_RIGHT_SHOULDER, + K_X360_A, + K_X360_B, + K_X360_X, + K_X360_Y, + K_X360_LEFT_TRIGGER, + K_X360_RIGHT_TRIGGER, + K_X360_LEFT_THUMB_UP, + K_X360_LEFT_THUMB_DOWN, + K_X360_LEFT_THUMB_LEFT, + K_X360_LEFT_THUMB_RIGHT, + K_X360_RIGHT_THUMB_UP, + K_X360_RIGHT_THUMB_DOWN, + K_X360_RIGHT_THUMB_LEFT, + K_X360_RIGHT_THUMB_RIGHT, + + // generic joystick emulation for menu + K_JOY_UP, + K_JOY_DOWN, + K_JOY_LEFT, + K_JOY_RIGHT, + + K_MIDINOTE0 = 896, // to this, the note number is added + K_MIDINOTE1, + K_MIDINOTE2, + K_MIDINOTE3, + K_MIDINOTE4, + K_MIDINOTE5, + K_MIDINOTE6, + K_MIDINOTE7, + K_MIDINOTE8, + K_MIDINOTE9, + K_MIDINOTE10, + K_MIDINOTE11, + K_MIDINOTE12, + K_MIDINOTE13, + K_MIDINOTE14, + K_MIDINOTE15, + K_MIDINOTE16, + K_MIDINOTE17, + K_MIDINOTE18, + K_MIDINOTE19, + K_MIDINOTE20, + K_MIDINOTE21, + K_MIDINOTE22, + K_MIDINOTE23, + K_MIDINOTE24, + K_MIDINOTE25, + K_MIDINOTE26, + K_MIDINOTE27, + K_MIDINOTE28, + K_MIDINOTE29, + K_MIDINOTE30, + K_MIDINOTE31, + K_MIDINOTE32, + K_MIDINOTE33, + K_MIDINOTE34, + K_MIDINOTE35, + K_MIDINOTE36, + K_MIDINOTE37, + K_MIDINOTE38, + K_MIDINOTE39, + K_MIDINOTE40, + K_MIDINOTE41, + K_MIDINOTE42, + K_MIDINOTE43, + K_MIDINOTE44, + K_MIDINOTE45, + K_MIDINOTE46, + K_MIDINOTE47, + K_MIDINOTE48, + K_MIDINOTE49, + K_MIDINOTE50, + K_MIDINOTE51, + K_MIDINOTE52, + K_MIDINOTE53, + K_MIDINOTE54, + K_MIDINOTE55, + K_MIDINOTE56, + K_MIDINOTE57, + K_MIDINOTE58, + K_MIDINOTE59, + K_MIDINOTE60, + K_MIDINOTE61, + K_MIDINOTE62, + K_MIDINOTE63, + K_MIDINOTE64, + K_MIDINOTE65, + K_MIDINOTE66, + K_MIDINOTE67, + K_MIDINOTE68, + K_MIDINOTE69, + K_MIDINOTE70, + K_MIDINOTE71, + K_MIDINOTE72, + K_MIDINOTE73, + K_MIDINOTE74, + K_MIDINOTE75, + K_MIDINOTE76, + K_MIDINOTE77, + K_MIDINOTE78, + K_MIDINOTE79, + K_MIDINOTE80, + K_MIDINOTE81, + K_MIDINOTE82, + K_MIDINOTE83, + K_MIDINOTE84, + K_MIDINOTE85, + K_MIDINOTE86, + K_MIDINOTE87, + K_MIDINOTE88, + K_MIDINOTE89, + K_MIDINOTE90, + K_MIDINOTE91, + K_MIDINOTE92, + K_MIDINOTE93, + K_MIDINOTE94, + K_MIDINOTE95, + K_MIDINOTE96, + K_MIDINOTE97, + K_MIDINOTE98, + K_MIDINOTE99, + K_MIDINOTE100, + K_MIDINOTE101, + K_MIDINOTE102, + K_MIDINOTE103, + K_MIDINOTE104, + K_MIDINOTE105, + K_MIDINOTE106, + K_MIDINOTE107, + K_MIDINOTE108, + K_MIDINOTE109, + K_MIDINOTE110, + K_MIDINOTE111, + K_MIDINOTE112, + K_MIDINOTE113, + K_MIDINOTE114, + K_MIDINOTE115, + K_MIDINOTE116, + K_MIDINOTE117, + K_MIDINOTE118, + K_MIDINOTE119, + K_MIDINOTE120, + K_MIDINOTE121, + K_MIDINOTE122, + K_MIDINOTE123, + K_MIDINOTE124, + K_MIDINOTE125, + K_MIDINOTE126, + K_MIDINOTE127, + + MAX_KEYS +} +keynum_t; + +typedef enum keydest_e { key_game, key_message, key_menu, key_menu_grabbed, key_console, key_void } keydest_t; + +extern char key_line[MAX_INPUTLINE]; +extern int key_linepos; +extern qboolean key_insert; // insert key toggle (for editing) +extern keydest_t key_dest; +// key_consoleactive bits +// user wants console (halfscreen) +#define KEY_CONSOLEACTIVE_USER 1 +// console forced because there's nothing else active (fullscreen) +#define KEY_CONSOLEACTIVE_FORCED 4 +extern int key_consoleactive; +extern char *keybindings[MAX_BINDMAPS][MAX_KEYS]; + +extern int chat_mode; // 0 for say, 1 for say_team, -1 for command +extern char chat_buffer[MAX_INPUTLINE]; +extern unsigned int chat_bufferlen; + +void Key_ClearEditLine(int edit_line); +void Key_WriteBindings(qfile_t *f); +void Key_Init(void); +void Key_Shutdown(void); +void Key_Init_Cvars(void); +void Key_Event(int key, int ascii, qboolean down); +void Key_ReleaseAll (void); +void Key_ClearStates (void); // FIXME: should this function still exist? Or should Key_ReleaseAll be used instead when shutting down a vid driver? +void Key_EventQueue_Block(void); +void Key_EventQueue_Unblock(void); + +qboolean Key_SetBinding (int keynum, int bindmap, const char *binding); +const char *Key_GetBind (int key, int bindmap); +void Key_FindKeysForCommand (const char *command, int *keys, int numkeys, int bindmap); +qboolean Key_SetBindMap(int fg, int bg); +void Key_GetBindMap(int *fg, int *bg); + +#endif // __KEYS_H + diff --git a/app/jni/lhfont.h b/app/jni/lhfont.h new file mode 100644 index 0000000..e651180 --- /dev/null +++ b/app/jni/lhfont.h @@ -0,0 +1,106 @@ +0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x08,0x08,0x99,0x00,0x83,0xFF,0xFF,0x00,0xE1,0x00,0x99,0x00,0x83,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x8B,0x00,0x85,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8B,0xFF,0x89,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x9D,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x8A,0xFF,0x89,0x00,0x86,0xFF,0x84,0x00,0x89,0xFF, +0x87,0x00,0x85,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x85,0x00,0x84,0xFF,0x88,0x00,0x8B,0xFF,0x88,0x00,0x86,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x86,0xFF,0x9B,0x00,0x84,0xFF,0x85,0x00,0x81,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x99,0x00,0x83,0xFF,0x87,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x83,0xFF, +0x93,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x84,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x8B,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x87,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x87,0xFF,0x8A,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x8A,0x00,0x82,0xFF,0x8D,0x00, +0x83,0xFF,0x8D,0x00,0x82,0xFF,0x96,0x00,0x8B,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x88,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x87,0xFF,0x89,0x00,0x85,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0x9F,0x00,0x84,0xFF,0x94,0x00,0x8B,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x89,0xFF,0x83,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x8A,0x00,0x84,0xFF,0x86,0x00,0x84,0xFF,0x9F,0x00,0x84,0xFF,0x95,0x00,0x84,0xFF,0x87,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x85,0x00,0x89,0xFF,0x8A,0x00,0x84,0xFF, +0x87,0x00,0x82,0xFF,0x8D,0x00,0x83,0xFF,0x8D,0x00,0x82,0xFF,0x98,0x00,0x83,0xFF,0x87,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x99,0x00,0x84,0xFF,0x85,0x00,0x81,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x9B,0x00,0x83,0xFF,0x85,0x00,0xFF,0x00,0xB6,0x00,0x86,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x86,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x93,0x00,0xFF,0x00,0xB7,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x86,0xFF,0x92,0x00,0xFF,0x00,0xE0,0x00,0x86,0xFF,0x81,0x00,0x83,0xFF,0x91,0x00,0xFF,0x00,0xE1,0x00,0x85,0xFF, +0x81,0x00,0x83,0xFF,0x91,0x00,0xF3,0x00,0x85,0xFF,0xFF,0x00,0x85,0x00,0xF3,0x00,0x86,0xFF,0xFF,0x00,0x84,0x00,0x93,0x00,0x89,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0x92,0x00,0x8A,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF, +0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x86,0x00,0x87,0xFF,0x88,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x82,0x00,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x86,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x8A,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x00,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x81,0x00,0x92,0x00,0x8A,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x93,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF, +0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x00,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8D,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x84,0xFF,0x90,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x87,0x00,0x8D,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x81,0x00,0x84,0x00,0x84,0xFF,0x89,0x00,0x88,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x89,0xFF,0x84,0x00,0x83,0xFF,0x8A,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0xA4,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x88,0x00,0x8B,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x82,0x00,0x85,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0xA5,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF, +0x87,0x00,0x87,0xFF,0x83,0x00,0x85,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0xA3,0x00,0x83,0xFF,0x94,0x00,0x86,0xFF,0x97,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x97,0x00,0x85,0xFF,0xB7,0x00,0x85,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0xA3,0x00,0x83,0xFF,0x95,0x00,0x85,0xFF,0x97,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x97,0x00,0x85,0xFF,0xB7,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0x97,0x00,0x85,0xFF,0xFF,0x00,0xE1,0x00,0x96,0x00,0x86,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x83,0xFF,0x8D,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x89,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x8F,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x93,0x00,0x8D,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8C,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x87,0x00,0x85,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x8E,0x00,0x84,0xFF,0x83,0x00,0x87,0xFF,0x93,0x00,0x8D,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x91,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x84,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF, +0x89,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8F,0x00,0x84,0xFF,0x8A,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x8A,0x00,0x83,0xFF,0x8E,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x88,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x85,0xFF,0x8A,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x91,0x00, +0x81,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x85,0xFF,0x89,0x00,0x85,0xFF,0x8A,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x91,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x8E,0x00,0x83,0xFF,0x84,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x92,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x8A,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF, +0x8A,0x00,0x84,0xFF,0x8F,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x93,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x83,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x84,0xFF,0x8C,0x00,0x87,0xFF,0x86,0x00,0x87,0xFF,0x94,0x00,0x81,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x87,0xFF,0x87,0x00,0x85,0xFF,0x95,0x00,0xFF,0x00,0xE4,0x00,0x83,0xFF,0x96,0x00,0xFF,0x00,0xE5,0x00,0x81,0xFF,0x97,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x87,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x8B,0xFF,0x83,0x00,0x85,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0x82,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x8A,0x00,0x89,0xFF,0x86,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x82,0x00,0x87,0xFF,0x88,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x82,0x00,0x81,0x00, +0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00, +0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF, +0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x00,0x00,0x86,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x84,0x00,0x82,0xFF,0x83,0x00,0x82,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00, +0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x81,0xFF,0x83,0x00,0x81,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x86,0xFF,0x00,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x85,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x85,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x82,0x00,0x89,0xFF,0x87,0x00,0x85,0xFF,0x86,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x82,0x00,0x89,0xFF,0x86,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x82,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x82,0x00,0x83,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF, +0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xB3,0x00,0x83,0xFF,0xC7,0x00,0xFF,0x00,0xB3,0x00,0x84,0xFF,0xC6,0x00,0x83,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x89,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00, +0x87,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x85,0x00,0x82,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x8A,0xFF,0x8A,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x86,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x95,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x8B,0xFF,0x87,0x00,0x84,0xFF,0x94,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x88,0x00,0x88,0xFF,0x89,0x00, +0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0xA5,0x00,0x84,0xFF,0x9D,0x00,0x84,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x89,0x00,0x88,0xFF,0x88,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x84,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x8A,0xFF,0xA5,0x00,0x83,0xFF,0x9F,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x84,0x00, +0x88,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0xA5,0x00,0x83,0xFF,0x9F,0x00,0x83,0xFF,0x89,0x00,0x85,0xFF,0x83,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0xA5,0x00,0x84,0xFF,0x9D,0x00,0x84,0xFF,0x89,0x00,0x86,0xFF,0x82,0x00,0x82,0x00,0x89,0xFF,0x86,0x00,0x85,0xFF,0x87,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x87,0x00, +0x86,0xFF,0x85,0x00,0x8B,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x8B,0xFF,0x87,0x00,0x84,0xFF,0x8E,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x87,0xFF,0x87,0x00,0x85,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x85,0xFF,0x85,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x86,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x8F,0x00,0x83,0xFF,0x81,0x00,0xFF,0x00,0xA5,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF, +0x97,0x00,0x84,0xFF,0x88,0x00,0x8A,0xFF,0x82,0x00,0xFF,0x00,0xA5,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0x89,0x00,0x89,0xFF,0x83,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xC5,0x00,0x83,0xFF,0xB5,0x00,0xFF,0x00,0xC5,0x00,0x84,0xFF,0xB4,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x89,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x81,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x95,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x95,0x00,0x83,0xFF, +0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x84,0x00,0x84,0xFF,0x84,0x00,0x83,0xFF,0x82,0x00,0x8C,0xFF,0x97,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x8A,0x00,0xB0,0x00,0x8D,0xFF,0x83,0x00,0x89,0xFF,0x84,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x89,0x00,0x84,0xFF,0x89,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x89,0x00,0xB0,0x00,0x8D,0xFF,0x87,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x85,0x00,0x84,0xFF, +0x82,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x97,0x00,0x84,0xFF,0x8B,0x00,0x84,0xFF,0x88,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x88,0x00,0x95,0x00,0x83,0xFF,0x96,0x00,0x8D,0xFF,0x87,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x86,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x96,0x00,0x84,0xFF,0x8D,0x00,0x84,0xFF,0x83,0x00,0x8F,0xFF,0x81,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x94,0x00,0x84,0xFF,0x87,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x88,0xFF,0x87,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x86,0xFF,0x95,0x00,0x83,0xFF, +0x8F,0x00,0x83,0xFF,0x83,0x00,0x8F,0xFF,0x81,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x95,0x00,0x84,0xFF,0x86,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x89,0x00,0x84,0xFF,0x86,0x00,0x88,0xFF,0x00,0x00,0x82,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0xBA,0x00,0x84,0xFF,0x85,0x00,0x95,0x00,0x83,0xFF,0x96,0x00,0x8D,0xFF,0x83,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x8D,0x00,0x84,0xFF,0x86,0x00,0x86,0xFF,0x82,0x00,0x81,0xFF,0x88,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0xBB,0x00,0x84,0xFF, +0x84,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x8D,0xFF,0x83,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x86,0x00,0x86,0xFF,0x8D,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xBC,0x00,0x84,0xFF,0x83,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x8D,0xFF,0x83,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x85,0x00,0x87,0xFF,0x8D,0x00,0x83,0xFF,0x85,0x00,0x84,0xFF,0x8D,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xBD,0x00,0x84,0xFF, +0x82,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x88,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x8C,0x00,0x83,0xFF,0x86,0x00,0x84,0xFF,0x8B,0x00,0x84,0xFF,0xDD,0x00,0x84,0xFF,0x81,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x89,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x8C,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x89,0x00,0x84,0xFF,0xDF,0x00,0x83,0xFF,0x81,0x00,0xA2,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0xB6,0x00, +0x87,0xFF,0x9A,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0xE6,0x00,0xA2,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0xB7,0x00,0x85,0xFF,0x9C,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xE7,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x89,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0xC3,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x84,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF, +0x83,0x00,0x8A,0xFF,0x8A,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x88,0xFF,0x99,0x00,0xA1,0xFF,0x86,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x96,0x00,0xA5,0xFF,0x84,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF, +0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x94,0x00,0xA9,0xFF,0x82,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x88,0x00,0x88,0xFF,0x89,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x89,0x00,0x88,0xFF, +0x88,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x84,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x8A,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x84,0x00,0x89,0xFF,0x86,0x00,0x85,0xFF,0x87,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x87,0x00,0x86,0xFF,0x85,0x00,0x8B,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x95,0x00,0xA9,0xFF,0x82,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x85,0x00,0x87,0xFF,0x87,0x00,0x85,0xFF,0x87,0x00,0x89,0xFF, +0x85,0x00,0x89,0xFF,0x89,0x00,0x85,0xFF,0x85,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x98,0x00,0xA5,0xFF,0x84,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xB8,0x00,0xA1,0xFF,0x86,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xE1,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xB2,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x97,0x00,0x85,0xFF,0xFF,0x00,0x94,0x00,0xB1,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x95,0x00,0x87,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x81,0xFF,0xAB,0x00,0x81,0x00,0xAB,0xFF, +0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x83,0xFF,0xA9,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x85,0xFF,0xA7,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x87,0xFF,0xA5,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00, +0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00, +0x83,0xFF,0x85,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x87,0xFF,0xA5,0x00,0x82,0x00,0xA9,0xFF,0x83,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x85,0xFF, +0xA7,0x00,0x83,0x00,0xA7,0xFF,0x84,0x00,0x8D,0xFF,0x81,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x83,0xFF,0xA9,0x00,0xB1,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x95,0x00,0x87,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x81,0xFF,0xAB,0x00,0xB2,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x97,0x00,0x85,0xFF,0xFF,0x00,0x94,0x00,0xFF,0x00,0xFF,0x00,0x99,0x00,0x83,0xFF,0xFF,0x00,0xE1,0x00,0x99,0x00,0x83,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x8B,0x00, +0x85,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8B,0xFF,0x89,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x9D,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x8A,0xFF,0x89,0x00,0x86,0xFF,0x84,0x00,0x89,0xFF,0x87,0x00,0x85,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x85,0x00,0x84,0xFF,0x88,0x00,0x8B,0xFF,0x88,0x00,0x86,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x86,0xFF,0x9B,0x00,0x84,0xFF,0x85,0x00,0x81,0x00,0x89,0xFF,0x87,0x00, +0x89,0xFF,0x83,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x99,0x00,0x83,0xFF,0x87,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x84,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x8B,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF, +0x87,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x87,0xFF,0x8A,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x8A,0x00,0x82,0xFF,0x8D,0x00,0x83,0xFF,0x8D,0x00,0x82,0xFF,0x96,0x00,0x8B,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x88,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x87,0xFF,0x89,0x00,0x85,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0x9F,0x00,0x84,0xFF,0x94,0x00,0x8B,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x8A,0x00,0x84,0xFF,0x86,0x00,0x84,0xFF,0x9F,0x00,0x84,0xFF,0x95,0x00,0x84,0xFF,0x87,0x00, +0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x8D,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x85,0x00,0x89,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x82,0xFF,0x8D,0x00,0x83,0xFF,0x8D,0x00,0x82,0xFF,0x98,0x00,0x83,0xFF,0x87,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x99,0x00,0x84,0xFF,0x85,0x00,0x81,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF, +0x8B,0x00,0x83,0xFF,0x9B,0x00,0x83,0xFF,0x85,0x00,0xFF,0x00,0xB6,0x00,0x86,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x86,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x93,0x00,0xFF,0x00,0xB7,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x86,0xFF,0x92,0x00,0xFF,0x00,0xE0,0x00,0x86,0xFF,0x81,0x00,0x83,0xFF,0x91,0x00,0xFF,0x00,0xE1,0x00,0x85,0xFF,0x81,0x00,0x83,0xFF,0x91,0x00,0xF3,0x00,0x85,0xFF,0xFF,0x00,0x85,0x00,0xF3,0x00,0x86,0xFF,0xFF,0x00,0x84,0x00,0x93,0x00,0x89,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x85,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0x92,0x00,0x8A,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x86,0x00,0x87,0xFF,0x88,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x84,0x00,0x89,0xFF,0x82,0x00,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x8A,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x00,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x92,0x00,0x8A,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x93,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x00,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8D,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x84,0xFF,0x90,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x87,0x00,0x8D,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x84,0x00,0x84,0xFF,0x89,0x00,0x88,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x89,0xFF,0x84,0x00,0x83,0xFF,0x8A,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0xA4,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x85,0x00, +0x83,0xFF,0x88,0x00,0x8B,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x82,0x00,0x85,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0xA5,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x83,0x00,0x85,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0xA3,0x00,0x83,0xFF,0x94,0x00,0x86,0xFF,0x97,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x97,0x00,0x85,0xFF,0xB7,0x00,0x85,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0xA3,0x00,0x83,0xFF, +0x95,0x00,0x85,0xFF,0x97,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x97,0x00,0x85,0xFF,0xB7,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0x97,0x00,0x85,0xFF,0xFF,0x00,0xE1,0x00,0x96,0x00,0x86,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x83,0xFF,0x8D,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x8F,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x93,0x00,0x8D,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8C,0x00,0x88,0xFF, +0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x87,0x00,0x85,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x8E,0x00,0x84,0xFF,0x83,0x00,0x87,0xFF,0x93,0x00,0x8D,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x91,0x00, +0x84,0xFF,0x88,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x84,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF,0x89,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8C,0x00,0x82,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x81,0x00, +0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0x8F,0x00,0x84,0xFF,0x8A,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x8A,0x00,0x83,0xFF,0x8E,0x00,0x84,0xFF,0x8B,0x00,0x83,0xFF,0xA3,0x00,0x81,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x83,0x00,0x8A,0xFF,0x85,0x00,0x88,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x85,0xFF,0x8A,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x91,0x00,0x81,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF, +0x86,0x00,0x85,0xFF,0x89,0x00,0x85,0xFF,0x8A,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x91,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x8E,0x00,0x83,0xFF,0x84,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x92,0x00, +0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x8A,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x8F,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x93,0x00,0x81,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x8A,0xFF,0x85,0x00,0x8A,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00, +0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x81,0x00,0x84,0xFF,0x83,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x84,0xFF,0x8C,0x00,0x87,0xFF,0x86,0x00,0x87,0xFF,0x94,0x00,0x81,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x89,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x87,0xFF, +0x87,0x00,0x85,0xFF,0x95,0x00,0xFF,0x00,0xE4,0x00,0x83,0xFF,0x96,0x00,0xFF,0x00,0xE5,0x00,0x81,0xFF,0x97,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0x83,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x87,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x85,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0x82,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x83,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x8A,0x00,0x89,0xFF,0x86,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x82,0x00,0x87,0xFF,0x88,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x82,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF, +0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x81,0x00,0x81,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x00,0x00,0x86,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00, +0x85,0xFF,0x84,0x00,0x82,0xFF,0x83,0x00,0x82,0xFF,0x84,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x85,0x00,0x81,0xFF,0x83,0x00,0x81,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8D,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF, +0x8B,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x8D,0xFF,0x83,0x00,0x86,0xFF,0x00,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x81,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x85,0xFF,0x81,0x00,0x85,0xFF,0x83,0x00,0x85,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x82,0x00,0x89,0xFF,0x87,0x00,0x85,0xFF,0x86,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x84,0x00, +0x8A,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x82,0x00,0x89,0xFF,0x86,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x83,0x00,0x84,0xFF,0x82,0x00,0x83,0xFF,0x84,0x00,0x89,0xFF,0x82,0x00,0x83,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x87,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF, +0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x83,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xB3,0x00,0x83,0xFF,0xC7,0x00,0xFF,0x00,0xB3,0x00,0x84,0xFF,0xC6,0x00,0x83,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x89,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x8D,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x85,0x00,0x82,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x8A,0xFF,0x8A,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF, +0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x88,0xFF,0x88,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x8C,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x86,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x95,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF, +0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x8B,0xFF,0x87,0x00,0x84,0xFF,0x94,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x88,0x00,0x88,0xFF,0x89,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0xA5,0x00,0x84,0xFF,0x9D,0x00,0x84,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x87,0x00,0x83,0xFF,0x89,0x00,0x88,0xFF,0x88,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x84,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x8A,0xFF,0xA5,0x00,0x83,0xFF,0x9F,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x85,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0xA5,0x00,0x83,0xFF,0x9F,0x00,0x83,0xFF,0x89,0x00,0x85,0xFF,0x83,0x00,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF, +0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0xA5,0x00,0x84,0xFF,0x9D,0x00,0x84,0xFF,0x89,0x00,0x86,0xFF,0x82,0x00,0x82,0x00,0x89,0xFF,0x86,0x00,0x85,0xFF,0x87,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x87,0x00,0x86,0xFF,0x85,0x00,0x8B,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x87,0x00,0x8B,0xFF,0x87,0x00,0x84,0xFF,0x8E,0x00,0x83,0xFF,0x81,0x00,0x83,0x00,0x87,0xFF, +0x87,0x00,0x85,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x85,0xFF,0x85,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x86,0x00,0x8B,0xFF,0x86,0x00,0x84,0xFF,0x8F,0x00,0x83,0xFF,0x81,0x00,0xFF,0x00,0xA5,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x88,0x00,0x8A,0xFF,0x82,0x00,0xFF,0x00,0xA5,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x97,0x00,0x83,0xFF,0x89,0x00,0x89,0xFF,0x83,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xC5,0x00,0x83,0xFF,0xB5,0x00,0xFF,0x00, +0xC5,0x00,0x84,0xFF,0xB4,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x89,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x85,0xFF,0x81,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8C,0x00,0x84,0xFF,0x95,0x00,0x83,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x84,0x00,0x84,0xFF,0x84,0x00,0x83,0xFF,0x82,0x00,0x8C,0xFF,0x97,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0x88,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF, +0x89,0x00,0x84,0xFF,0x8A,0x00,0xB0,0x00,0x8D,0xFF,0x83,0x00,0x89,0xFF,0x84,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x97,0x00,0x84,0xFF,0x89,0x00,0x84,0xFF,0x89,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF,0x8A,0x00,0x84,0xFF,0x89,0x00,0xB0,0x00,0x8D,0xFF,0x87,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x85,0x00,0x84,0xFF,0x82,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x97,0x00,0x84,0xFF,0x8B,0x00,0x84,0xFF,0x88,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x8D,0x00,0x83,0xFF,0x95,0x00,0x83,0xFF,0x8B,0x00,0x84,0xFF,0x88,0x00,0x95,0x00,0x83,0xFF,0x96,0x00,0x8D,0xFF,0x87,0x00, +0x81,0xFF,0x81,0x00,0x81,0xFF,0x86,0x00,0x84,0xFF,0x87,0x00,0x83,0xFF,0x81,0x00,0x85,0xFF,0x96,0x00,0x84,0xFF,0x8D,0x00,0x84,0xFF,0x83,0x00,0x8F,0xFF,0x81,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x94,0x00,0x84,0xFF,0x87,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x88,0xFF,0x87,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x81,0x00,0x86,0xFF,0x95,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x83,0x00,0x8F,0xFF,0x81,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x95,0x00,0x84,0xFF,0x86,0x00,0x95,0x00,0x83,0xFF,0x98,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x88,0xFF,0x89,0x00,0x84,0xFF,0x86,0x00,0x88,0xFF,0x00,0x00,0x82,0xFF,0x88,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0xBA,0x00,0x84,0xFF,0x85,0x00,0x95,0x00,0x83,0xFF,0x96,0x00,0x8D,0xFF,0x83,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x8D,0x00,0x84,0xFF,0x86,0x00,0x86,0xFF,0x82,0x00,0x81,0xFF,0x88,0x00,0x84,0xFF,0x86,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0xBB,0x00,0x84,0xFF,0x84,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x8D,0xFF,0x83,0x00,0x81,0xFF,0x81,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x82,0x00,0x84,0xFF,0x86,0x00,0x86,0xFF,0x8D,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x85,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xBC,0x00,0x84,0xFF,0x83,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x83,0x00,0x8D,0xFF,0x83,0x00,0x89,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x84,0xFF,0x85,0x00,0x87,0xFF,0x8D,0x00,0x83,0xFF,0x85,0x00,0x84,0xFF,0x8D,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xBD,0x00,0x84,0xFF,0x82,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x86,0x00,0x88,0xFF,0x83,0x00,0x83,0xFF,0x84,0x00,0x84,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x8C,0x00,0x83,0xFF,0x86,0x00,0x84,0xFF,0x8B,0x00, +0x84,0xFF,0xDD,0x00,0x84,0xFF,0x81,0x00,0x95,0x00,0x83,0xFF,0x88,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x89,0x00,0x81,0xFF,0x87,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x8C,0x00,0x83,0xFF,0x87,0x00,0x84,0xFF,0x89,0x00,0x84,0xFF,0xDF,0x00,0x83,0xFF,0x81,0x00,0xA2,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0xB6,0x00,0x87,0xFF,0x9A,0x00,0x84,0xFF,0x87,0x00,0x84,0xFF,0xE6,0x00,0xA2,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0xB7,0x00,0x85,0xFF,0x9C,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0xE7,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00, +0x8B,0xFF,0xFF,0x00,0xE1,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x85,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x89,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x89,0x00,0x83,0xFF,0x89,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0xC3,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x84,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x87,0x00,0x8B,0xFF,0x83,0x00,0x8A,0xFF,0x8A,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x85,0x00,0x89,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x88,0xFF,0x99,0x00,0xA1,0xFF,0x86,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x96,0x00,0xA5,0xFF,0x84,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x93,0x00,0x83,0xFF,0x83,0x00,0x8B,0xFF,0x8B,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x94,0x00,0xA9,0xFF,0x82,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00, +0x83,0xFF,0x87,0x00,0x83,0xFF,0x88,0x00,0x88,0xFF,0x89,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x88,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x89,0x00,0x88,0xFF,0x88,0x00,0x86,0xFF,0x84,0x00,0x83,0xFF,0x81,0x00,0x83,0xFF,0x85,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x84,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x8A,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00, +0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x90,0x00,0x84,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x8F,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x91,0x00,0x83,0xFF,0x85,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x83,0x00,0x83,0xFF,0x87,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF, +0x81,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x84,0x00,0x89,0xFF,0x86,0x00,0x85,0xFF,0x87,0x00,0x8A,0xFF,0x84,0x00,0x8A,0xFF,0x87,0x00,0x86,0xFF,0x85,0x00,0x8B,0xFF,0x84,0x00,0x88,0xFF,0x85,0x00,0x89,0xFF,0x86,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x95,0x00,0xA9,0xFF,0x82,0x00,0x81,0x00,0x85,0xFF,0x8F,0x00,0x85,0xFF,0x85,0x00,0x87,0xFF,0x87,0x00,0x85,0xFF,0x87,0x00,0x89,0xFF,0x85,0x00,0x89,0xFF,0x89,0x00,0x85,0xFF,0x85,0x00,0x8B,0xFF,0x85,0x00,0x87,0xFF,0x85,0x00,0x89,0xFF,0x87,0x00,0x87,0xFF,0x87,0x00,0x87,0xFF,0x98,0x00,0xA5,0xFF,0x84,0x00,0x81,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xB8,0x00,0xA1,0xFF,0x86,0x00,0x81,0x00, +0x8B,0xFF,0x83,0x00,0x8B,0xFF,0xFF,0x00,0xE1,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xC2,0x00,0x89,0xFF,0x97,0x00,0x85,0xFF,0xFF,0x00,0x94,0x00,0xC1,0x00,0x8B,0xFF,0x95,0x00,0x87,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x81,0xFF,0xAB,0x00,0x91,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x83,0xFF,0xA9,0x00,0x91,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00, +0x85,0xFF,0xA7,0x00,0x91,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x87,0xFF,0xA5,0x00,0x85,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x85,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF, +0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x85,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x87,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x85,0x00,0x83,0xFF,0x87,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x86,0x00,0x83,0xFF,0x88,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x89,0xFF,0x89,0x00,0x83,0xFF,0x8B,0x00,0x83,0xFF,0x85,0x00,0x91,0x00,0xAB,0xFF,0x82,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00, +0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x87,0xFF,0xA5,0x00,0x92,0x00,0xA9,0xFF,0x83,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x85,0xFF,0xA7,0x00,0x93,0x00,0xA7,0xFF,0x84,0x00,0x8D,0xFF,0x93,0x00,0x89,0xFF,0x84,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x83,0xFF,0xA9,0x00,0xC1,0x00,0x8B,0xFF,0x95,0x00,0x87,0xFF,0x85,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x83,0x00,0x8B,0xFF,0x93,0x00,0x8B,0xFF,0x93,0x00,0x81,0xFF,0xAB,0x00,0xC2,0x00,0x89,0xFF,0x97,0x00,0x85,0xFF,0xFF,0x00,0x94,0x00,0xFF,0x00, +0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x52,0x55,0x45,0x56,0x49,0x53,0x49,0x4F,0x4E,0x2D,0x58,0x46,0x49,0x4C,0x45,0x2E,0x00 diff --git a/app/jni/lhnet.c b/app/jni/lhnet.c new file mode 100644 index 0000000..e3bc6b7 --- /dev/null +++ b/app/jni/lhnet.c @@ -0,0 +1,1419 @@ + +// Written by Forest Hale 2003-06-15 and placed into public domain. + +#ifdef WIN32 +#ifdef _MSC_VER +#pragma comment(lib, "ws2_32.lib") +#endif +# ifdef SUPPORTIPV6 +// Windows XP or higher is required for getaddrinfo, but the inclusion of wspiapi provides fallbacks for older versions +# define _WIN32_WINNT 0x0501 +# endif +# include +# include +# ifdef USE_WSPIAPI_H +# include +# endif +#endif + +#ifndef STANDALONETEST +#include "quakedef.h" +#endif + +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SUPPORTIPV6 +#include +#endif +#endif + +#ifdef __MORPHOS__ +#include +#endif + +// for Z_Malloc/Z_Free in quake +#ifndef STANDALONETEST +#include "zone.h" +#include "sys.h" +#include "netconn.h" +#else +#define Con_Print printf +#define Con_Printf printf +#define Z_Malloc malloc +#define Z_Free free +#endif + +#include "lhnet.h" + +#if defined(WIN32) +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ECONNREFUSED WSAECONNREFUSED + +#define SOCKETERRNO WSAGetLastError() + +#define IOC_VENDOR 0x18000000 +#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) + +#define SOCKLEN_T int +#elif defined(__MORPHOS__) +#define ioctlsocket IoctlSocket +#define closesocket CloseSocket +#define SOCKETERRNO Errno() + +#define SOCKLEN_T int +#else +#define ioctlsocket ioctl +#define closesocket close +#define SOCKETERRNO errno + +#define SOCKLEN_T socklen_t +#endif + +#ifdef MSG_DONTWAIT +#define LHNET_RECVFROM_FLAGS MSG_DONTWAIT +#define LHNET_SENDTO_FLAGS 0 +#else +#define LHNET_RECVFROM_FLAGS 0 +#define LHNET_SENDTO_FLAGS 0 +#endif + +typedef struct lhnetaddressnative_s +{ + lhnetaddresstype_t addresstype; + int port; + union + { + struct sockaddr sock; + struct sockaddr_in in; +#ifdef SUPPORTIPV6 + struct sockaddr_in6 in6; +#endif + } + addr; +} +lhnetaddressnative_t; + +// to make LHNETADDRESS_FromString resolve repeated hostnames faster, cache them +#define MAX_NAMECACHE 64 +static struct namecache_s +{ + lhnetaddressnative_t address; + double expirationtime; + char name[64]; +} +namecache[MAX_NAMECACHE]; +static int namecacheposition = 0; + +int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addresstype, int port) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + if (!address) + return 0; + switch(addresstype) + { + default: + break; + case LHNETADDRESSTYPE_LOOP: + // local:port (loopback) + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_LOOP; + address->port = port; + return 1; + case LHNETADDRESSTYPE_INET4: + // 0.0.0.0:port (INADDR_ANY, binds to all interfaces) + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = AF_INET; + address->addr.in.sin_port = htons((unsigned short)port); + return 1; +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: + // [0:0:0:0:0:0:0:0]:port (IN6ADDR_ANY, binds to all interfaces) + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_INET6; + address->port = port; + address->addr.in6.sin6_family = AF_INET6; + address->addr.in6.sin6_port = htons((unsigned short)port); + return 1; +#endif + } + return 0; +} + +#ifdef SUPPORTIPV6 +static int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int port) +{ + char port_buff [16]; + struct addrinfo hints; + struct addrinfo* addrinf; + int err; + + dpsnprintf (port_buff, sizeof (port_buff), "%d", port); + port_buff[sizeof (port_buff) - 1] = '\0'; + + memset(&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + //hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(name, port_buff, &hints, &addrinf); + if (err != 0 || addrinf == NULL) + return 0; + if (addrinf->ai_addr->sa_family != AF_INET6 && addrinf->ai_addr->sa_family != AF_INET) + { + freeaddrinfo (addrinf); + return 0; + } + + // great it worked + if (addrinf->ai_addr->sa_family == AF_INET6) + { + address->addresstype = LHNETADDRESSTYPE_INET6; + memcpy(&address->addr.in6, addrinf->ai_addr, sizeof(address->addr.in6)); + } + else + { + address->addresstype = LHNETADDRESSTYPE_INET4; + memcpy(&address->addr.in, addrinf->ai_addr, sizeof(address->addr.in)); + } + address->port = port; + + freeaddrinfo (addrinf); + return 1; +} + +int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + int i, port, d1, d2, d3, d4, resolved; + size_t namelen; + unsigned char *a; + char name[128]; +#ifdef STANDALONETEST + char string2[128]; +#endif + const char* addr_start; + const char* addr_end = NULL; + const char* port_name = NULL; + int addr_family = AF_UNSPEC; + + if (!address || !string || !*string) + return 0; + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_NONE; + port = 0; + + // If it's a bracketed IPv6 address + if (string[0] == '[') + { + const char* end_bracket = strchr(string, ']'); + + if (end_bracket == NULL) + return 0; + + if (end_bracket[1] == ':') + port_name = end_bracket + 2; + else if (end_bracket[1] != '\0') + return 0; + + addr_family = AF_INET6; + addr_start = &string[1]; + addr_end = end_bracket; + } + else + { + const char* first_colon; + + addr_start = string; + + // If it's a numeric non-bracket IPv6 address (-> no port), + // or it's a numeric IPv4 address, or a name, with a port + first_colon = strchr(string, ':'); + if (first_colon != NULL) + { + const char* last_colon = strrchr(first_colon + 1, ':'); + + // If it's an numeric IPv4 address, or a name, with a port + if (last_colon == NULL) + { + addr_end = first_colon; + port_name = first_colon + 1; + } + else + addr_family = AF_INET6; + } + } + + if (addr_end != NULL) + namelen = addr_end - addr_start; + else + namelen = strlen (addr_start); + + if (namelen >= sizeof(name)) + namelen = sizeof(name) - 1; + memcpy (name, addr_start, namelen); + name[namelen] = 0; + + if (port_name) + port = atoi(port_name); + + if (port == 0) + port = defaultport; + + // handle loopback + if (!strcmp(name, "local")) + { + address->addresstype = LHNETADDRESSTYPE_LOOP; + address->port = port; + return 1; + } + // try to parse as dotted decimal ipv4 address first + // note this supports partial ip addresses + d1 = d2 = d3 = d4 = 0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + if (addr_family != AF_INET6 && + sscanf(name, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) >= 1 && (unsigned int)d1 < 256 && (unsigned int)d2 < 256 && (unsigned int)d3 < 256 && (unsigned int)d4 < 256) + { + // parsed a valid ipv4 address + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = AF_INET; + address->addr.in.sin_port = htons((unsigned short)port); + a = (unsigned char *)&address->addr.in.sin_addr; + a[0] = d1; + a[1] = d2; + a[2] = d3; + a[3] = d4; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("manual parsing of ipv4 dotted decimal address \"%s\" successful: %s\n", string, string2); +#endif + return 1; + } + for (i = 0;i < MAX_NAMECACHE;i++) + if (!strcmp(namecache[i].name, name)) + break; +#ifdef STANDALONETEST + if (i < MAX_NAMECACHE) +#else + if (i < MAX_NAMECACHE && realtime < namecache[i].expirationtime) +#endif + { + *address = namecache[i].address; + address->port = port; + if (address->addresstype == LHNETADDRESSTYPE_INET6) + { + address->addr.in6.sin6_port = htons((unsigned short)port); + return 1; + } + else if (address->addresstype == LHNETADDRESSTYPE_INET4) + { + address->addr.in.sin_port = htons((unsigned short)port); + return 1; + } + return 0; + } + + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + + // try resolving the address (handles dns and other ip formats) + resolved = LHNETADDRESS_Resolve(address, name, port); + if (resolved) + { +#ifdef STANDALONETEST + const char *protoname; + + switch (address->addresstype) + { + case LHNETADDRESSTYPE_INET6: + protoname = "ipv6"; + break; + case LHNETADDRESSTYPE_INET4: + protoname = "ipv4"; + break; + default: + protoname = "UNKNOWN"; + break; + } + LHNETADDRESS_ToString(vaddress, string2, sizeof(string2), 1); + Con_Printf("LHNETADDRESS_Resolve(\"%s\") returned %s address %s\n", string, protoname, string2); +#endif + namecache[namecacheposition].address = *address; + } + else + { +#ifdef STANDALONETEST + printf("name resolution failed on address \"%s\"\n", name); +#endif + namecache[namecacheposition].address.addresstype = LHNETADDRESSTYPE_NONE; + } + + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; + return resolved; +} +#else +int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + int i, port, namelen, d1, d2, d3, d4; + struct hostent *hostentry; + unsigned char *a; + const char *colon; + char name[128]; +#ifdef STANDALONETEST + char string2[128]; +#endif + if (!address || !string || !*string) + return 0; + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_NONE; + port = 0; + colon = strrchr(string, ':'); + if (colon && (colon == strchr(string, ':') || (string[0] == '[' && colon - string > 0 && colon[-1] == ']'))) + // EITHER: colon is the ONLY colon OR: colon comes after [...] delimited IPv6 address + // fixes misparsing of IPv6 addresses without port + { + port = atoi(colon + 1); + } + else + colon = string + strlen(string); + if (port == 0) + port = defaultport; + namelen = colon - string; + if (namelen > 127) + namelen = 127; + if (string[0] == '[' && namelen > 0 && string[namelen-1] == ']') // ipv6 + { + string++; + namelen -= 2; + } + memcpy(name, string, namelen); + name[namelen] = 0; + // handle loopback + if (!strcmp(name, "local")) + { + address->addresstype = LHNETADDRESSTYPE_LOOP; + address->port = port; + return 1; + } + // try to parse as dotted decimal ipv4 address first + // note this supports partial ip addresses + d1 = d2 = d3 = d4 = 0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + if (sscanf(name, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) >= 1 && (unsigned int)d1 < 256 && (unsigned int)d2 < 256 && (unsigned int)d3 < 256 && (unsigned int)d4 < 256) + { + // parsed a valid ipv4 address + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = AF_INET; + address->addr.in.sin_port = htons((unsigned short)port); + a = (unsigned char *)&address->addr.in.sin_addr; + a[0] = d1; + a[1] = d2; + a[2] = d3; + a[3] = d4; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("manual parsing of ipv4 dotted decimal address \"%s\" successful: %s\n", string, string2); +#endif + return 1; + } + for (i = 0;i < MAX_NAMECACHE;i++) + if (!strcmp(namecache[i].name, name)) + break; +#ifdef STANDALONETEST + if (i < MAX_NAMECACHE) +#else + if (i < MAX_NAMECACHE && realtime < namecache[i].expirationtime) +#endif + { + *address = namecache[i].address; + address->port = port; + if (address->addresstype == LHNETADDRESSTYPE_INET6) + { +#ifdef SUPPORTIPV6 + address->addr.in6.sin6_port = htons((unsigned short)port); + return 1; +#endif + } + else if (address->addresstype == LHNETADDRESSTYPE_INET4) + { + address->addr.in.sin_port = htons((unsigned short)port); + return 1; + } + return 0; + } + // try gethostbyname (handles dns and other ip formats) + hostentry = gethostbyname(name); + if (hostentry) + { + if (hostentry->h_addrtype == AF_INET6) + { +#ifdef SUPPORTIPV6 + // great it worked + address->addresstype = LHNETADDRESSTYPE_INET6; + address->port = port; + address->addr.in6.sin6_family = hostentry->h_addrtype; + address->addr.in6.sin6_port = htons((unsigned short)port); + memcpy(&address->addr.in6.sin6_addr, hostentry->h_addr_list[0], sizeof(address->addr.in6.sin6_addr)); + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address = *address; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("gethostbyname(\"%s\") returned ipv6 address %s\n", string, string2); +#endif + return 1; +#endif + } + else if (hostentry->h_addrtype == AF_INET) + { + // great it worked + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = hostentry->h_addrtype; + address->addr.in.sin_port = htons((unsigned short)port); + memcpy(&address->addr.in.sin_addr, hostentry->h_addr_list[0], sizeof(address->addr.in.sin_addr)); + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address = *address; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("gethostbyname(\"%s\") returned ipv4 address %s\n", string, string2); +#endif + return 1; + } + } +#ifdef STANDALONETEST + printf("gethostbyname failed on address \"%s\"\n", name); +#endif + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address.addresstype = LHNETADDRESSTYPE_NONE; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; + return 0; +} +#endif + +int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stringbuffersize, int includeport) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + const unsigned char *a; + *string = 0; + if (!address || !string || stringbuffersize < 1) + return 0; + switch(address->addresstype) + { + default: + break; + case LHNETADDRESSTYPE_LOOP: + if (includeport) + { + if (stringbuffersize >= 12) + { + dpsnprintf(string, stringbuffersize, "local:%d", address->port); + return 1; + } + } + else + { + if (stringbuffersize >= 6) + { + memcpy(string, "local", 6); + return 1; + } + } + break; + case LHNETADDRESSTYPE_INET4: + a = (const unsigned char *)(&address->addr.in.sin_addr); + if (includeport) + { + if (stringbuffersize >= 22) + { + dpsnprintf(string, stringbuffersize, "%d.%d.%d.%d:%d", a[0], a[1], a[2], a[3], address->port); + return 1; + } + } + else + { + if (stringbuffersize >= 16) + { + dpsnprintf(string, stringbuffersize, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + return 1; + } + } + break; +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: + a = (const unsigned char *)(&address->addr.in6.sin6_addr); + if (includeport) + { + if (stringbuffersize >= 88) + { + dpsnprintf(string, stringbuffersize, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d", a[0] * 256 + a[1], a[2] * 256 + a[3], a[4] * 256 + a[5], a[6] * 256 + a[7], a[8] * 256 + a[9], a[10] * 256 + a[11], a[12] * 256 + a[13], a[14] * 256 + a[15], address->port); + return 1; + } + } + else + { + if (stringbuffersize >= 80) + { + dpsnprintf(string, stringbuffersize, "%x:%x:%x:%x:%x:%x:%x:%x", a[0] * 256 + a[1], a[2] * 256 + a[3], a[4] * 256 + a[5], a[6] * 256 + a[7], a[8] * 256 + a[9], a[10] * 256 + a[11], a[12] * 256 + a[13], a[14] * 256 + a[15]); + return 1; + } + } + break; +#endif + } + return 0; +} + +int LHNETADDRESS_GetAddressType(const lhnetaddress_t *address) +{ + if (address) + return address->addresstype; + else + return LHNETADDRESSTYPE_NONE; +} + +const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress, char *ifname, size_t ifnamelength) +{ +#ifdef SUPPORTIPV6 + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + + if (address && address->addresstype == LHNETADDRESSTYPE_INET6) + { +#ifndef _WIN32 + + if (if_indextoname(address->addr.in6.sin6_scope_id, ifname) == ifname) + return ifname; + +#else + + // The Win32 API doesn't have if_indextoname() until Windows Vista, + // but luckily it just uses the interface ID as the interface name + + if (dpsnprintf(ifname, ifnamelength, "%lu", address->addr.in6.sin6_scope_id) > 0) + return ifname; + +#endif + } +#endif + + return NULL; +} + +int LHNETADDRESS_GetPort(const lhnetaddress_t *address) +{ + if (!address) + return -1; + return address->port; +} + +int LHNETADDRESS_SetPort(lhnetaddress_t *vaddress, int port) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + if (!address) + return 0; + address->port = port; + switch(address->addresstype) + { + case LHNETADDRESSTYPE_LOOP: + return 1; + case LHNETADDRESSTYPE_INET4: + address->addr.in.sin_port = htons((unsigned short)port); + return 1; +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: + address->addr.in6.sin6_port = htons((unsigned short)port); + return 1; +#endif + default: + return 0; + } +} + +int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t *vaddress2) +{ + lhnetaddressnative_t *address1 = (lhnetaddressnative_t *)vaddress1; + lhnetaddressnative_t *address2 = (lhnetaddressnative_t *)vaddress2; + if (!address1 || !address2) + return 1; + if (address1->addresstype != address2->addresstype) + return 1; + switch(address1->addresstype) + { + case LHNETADDRESSTYPE_LOOP: + if (address1->port != address2->port) + return -1; + return 0; + case LHNETADDRESSTYPE_INET4: + if (address1->addr.in.sin_family != address2->addr.in.sin_family) + return 1; + if (memcmp(&address1->addr.in.sin_addr, &address2->addr.in.sin_addr, sizeof(address1->addr.in.sin_addr))) + return 1; + if (address1->port != address2->port) + return -1; + return 0; +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: + if (address1->addr.in6.sin6_family != address2->addr.in6.sin6_family) + return 1; + if (memcmp(&address1->addr.in6.sin6_addr, &address2->addr.in6.sin6_addr, sizeof(address1->addr.in6.sin6_addr))) + return 1; + if (address1->port != address2->port) + return -1; + return 0; +#endif + default: + return 1; + } +} + +typedef struct lhnetpacket_s +{ + void *data; + int length; + int sourceport; + int destinationport; + time_t timeout; +#ifndef STANDALONETEST + double sentdoubletime; +#endif + struct lhnetpacket_s *next, *prev; +} +lhnetpacket_t; + +static int lhnet_active; +static lhnetsocket_t lhnet_socketlist; +static lhnetpacket_t lhnet_packetlist; +static int lhnet_default_dscp = 0; +#ifdef WIN32 +static int lhnet_didWSAStartup = 0; +static WSADATA lhnet_winsockdata; +#endif + +void LHNET_Init(void) +{ + if (lhnet_active) + return; + lhnet_socketlist.next = lhnet_socketlist.prev = &lhnet_socketlist; + lhnet_packetlist.next = lhnet_packetlist.prev = &lhnet_packetlist; + lhnet_active = 1; +#ifdef WIN32 + lhnet_didWSAStartup = !WSAStartup(MAKEWORD(1, 1), &lhnet_winsockdata); + if (!lhnet_didWSAStartup) + Con_Print("LHNET_Init: WSAStartup failed, networking disabled\n"); +#endif +} + +int LHNET_DefaultDSCP(int dscp) +{ +#ifdef IP_TOS + int prev = lhnet_default_dscp; + if(dscp >= 0) + lhnet_default_dscp = dscp; + return prev; +#else + return -1; +#endif +} + +void LHNET_Shutdown(void) +{ + lhnetpacket_t *p; + if (!lhnet_active) + return; + while (lhnet_socketlist.next != &lhnet_socketlist) + LHNET_CloseSocket(lhnet_socketlist.next); + while (lhnet_packetlist.next != &lhnet_packetlist) + { + p = lhnet_packetlist.next; + p->prev->next = p->next; + p->next->prev = p->prev; + Z_Free(p); + } +#ifdef WIN32 + if (lhnet_didWSAStartup) + { + lhnet_didWSAStartup = 0; + WSACleanup(); + } +#endif + lhnet_active = 0; +} + +static const char *LHNETPRIVATE_StrError(void) +{ +#ifdef WIN32 + int i = WSAGetLastError(); + switch (i) + { + case WSAEINTR: return "WSAEINTR"; + case WSAEBADF: return "WSAEBADF"; + case WSAEACCES: return "WSAEACCES"; + case WSAEFAULT: return "WSAEFAULT"; + case WSAEINVAL: return "WSAEINVAL"; + case WSAEMFILE: return "WSAEMFILE"; + case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK"; + case WSAEINPROGRESS: return "WSAEINPROGRESS"; + case WSAEALREADY: return "WSAEALREADY"; + case WSAENOTSOCK: return "WSAENOTSOCK"; + case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ"; + case WSAEMSGSIZE: return "WSAEMSGSIZE"; + case WSAEPROTOTYPE: return "WSAEPROTOTYPE"; + case WSAENOPROTOOPT: return "WSAENOPROTOOPT"; + case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT"; + case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT"; + case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP"; + case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT"; + case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT"; + case WSAEADDRINUSE: return "WSAEADDRINUSE"; + case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL"; + case WSAENETDOWN: return "WSAENETDOWN"; + case WSAENETUNREACH: return "WSAENETUNREACH"; + case WSAENETRESET: return "WSAENETRESET"; + case WSAECONNABORTED: return "WSAECONNABORTED"; + case WSAECONNRESET: return "WSAECONNRESET"; + case WSAENOBUFS: return "WSAENOBUFS"; + case WSAEISCONN: return "WSAEISCONN"; + case WSAENOTCONN: return "WSAENOTCONN"; + case WSAESHUTDOWN: return "WSAESHUTDOWN"; + case WSAETOOMANYREFS: return "WSAETOOMANYREFS"; + case WSAETIMEDOUT: return "WSAETIMEDOUT"; + case WSAECONNREFUSED: return "WSAECONNREFUSED"; + case WSAELOOP: return "WSAELOOP"; + case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; + case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; + case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH"; + case WSAENOTEMPTY: return "WSAENOTEMPTY"; + case WSAEPROCLIM: return "WSAEPROCLIM"; + case WSAEUSERS: return "WSAEUSERS"; + case WSAEDQUOT: return "WSAEDQUOT"; + case WSAESTALE: return "WSAESTALE"; + case WSAEREMOTE: return "WSAEREMOTE"; + case WSAEDISCON: return "WSAEDISCON"; + case 0: return "no error"; + default: return "unknown WSAE error"; + } +#else + return strerror(errno); +#endif +} + +void LHNET_SleepUntilPacket_Microseconds(int microseconds) +{ +#ifdef FD_SET + fd_set fdreadset; + struct timeval tv; + int lastfd; + lhnetsocket_t *s; + FD_ZERO(&fdreadset); + lastfd = 0; + for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) + { + if (s->address.addresstype == LHNETADDRESSTYPE_INET4 || s->address.addresstype == LHNETADDRESSTYPE_INET6) + { + if (lastfd < s->inetsocket) + lastfd = s->inetsocket; +#if defined(WIN32) && !defined(_MSC_VER) + FD_SET((int)s->inetsocket, &fdreadset); +#else + FD_SET((unsigned int)s->inetsocket, &fdreadset); +#endif + } + } + tv.tv_sec = microseconds / 1000000; + tv.tv_usec = microseconds % 1000000; + select(lastfd + 1, &fdreadset, NULL, NULL, &tv); +#else + Sys_Sleep(microseconds); +#endif +} + +lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) +{ + lhnetsocket_t *lhnetsocket, *s; + if (!address) + return NULL; + lhnetsocket = (lhnetsocket_t *)Z_Malloc(sizeof(*lhnetsocket)); + if (lhnetsocket) + { + memset(lhnetsocket, 0, sizeof(*lhnetsocket)); + lhnetsocket->address = *address; + switch(lhnetsocket->address.addresstype) + { + case LHNETADDRESSTYPE_LOOP: + if (lhnetsocket->address.port == 0) + { + // allocate a port dynamically + // this search will always terminate because there is never + // an allocated socket with port 0, so if the number wraps it + // will find the port is unused, and then refuse to use port + // 0, causing an intentional failure condition + lhnetsocket->address.port = 1024; + for (;;) + { + for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) + if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) + break; + if (s == &lhnet_socketlist) + break; + lhnetsocket->address.port++; + } + } + // check if the port is available + for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) + if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) + break; + if (s == &lhnet_socketlist && lhnetsocket->address.port != 0) + { + lhnetsocket->next = &lhnet_socketlist; + lhnetsocket->prev = lhnetsocket->next->prev; + lhnetsocket->next->prev = lhnetsocket; + lhnetsocket->prev->next = lhnetsocket; + return lhnetsocket; + } + break; + case LHNETADDRESSTYPE_INET4: +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: +#endif +#ifdef WIN32 + if (lhnet_didWSAStartup) + { +#endif +#ifdef SUPPORTIPV6 + if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) +#else + if ((lhnetsocket->inetsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) +#endif + { +#ifdef WIN32 + u_long _false = 0; +#endif +#ifdef MSG_DONTWAIT + if (1) +#else +#ifdef WIN32 + u_long _true = 1; +#else + char _true = 1; +#endif + if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) != -1) +#endif + { +#ifdef IPV6_V6ONLY + // We need to set this flag to tell the OS that we only listen on IPv6. If we don't + // most OSes will create a dual-protocol socket that also listens on IPv4. In this case + // if an IPv4 socket is already bound to the port we want, our bind() call will fail. + int ipv6_only = 1; + if (address->addresstype != LHNETADDRESSTYPE_INET6 + || setsockopt (lhnetsocket->inetsocket, IPPROTO_IPV6, IPV6_V6ONLY, + (const char *)&ipv6_only, sizeof(ipv6_only)) == 0 +#ifdef WIN32 + // The Win32 API only supports IPV6_V6ONLY since Windows Vista, but fortunately + // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true) + || SOCKETERRNO == WSAENOPROTOOPT +#endif + ) +#endif + { + lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address; + SOCKLEN_T namelen; + int bindresult; + +#if defined(SOL_RFC1149) && defined(RFC1149_1149ONLY) + // we got reports of massive lags when this protocol was chosen as transport + // so better turn it off + { + int rfc1149only = 0; + int rfc1149enabled = 0; + if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_1149ONLY, &rfc1149only)) + Con_Printf("LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_1149ONLY) returned error: %s\n", LHNETPRIVATE_StrError()); + if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_ENABLED, &rfc1149enabled)) + Con_Printf("LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_ENABLED) returned error: %s\n", LHNETPRIVATE_StrError()); + } +#endif + +#ifdef SUPPORTIPV6 + if (address->addresstype == LHNETADDRESSTYPE_INET6) + { + namelen = sizeof(localaddress->addr.in6); + bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen); + if (bindresult != -1) + getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen); + } + else +#endif + { + namelen = sizeof(localaddress->addr.in); + bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen); + if (bindresult != -1) + getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen); + } + if (bindresult != -1) + { + int i = 1; + // enable broadcast on this socket + setsockopt(lhnetsocket->inetsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)); +#ifdef IP_TOS + { + // enable DSCP for ToS support + int tos = lhnet_default_dscp << 2; + setsockopt(lhnetsocket->inetsocket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)); + } +#endif + lhnetsocket->next = &lhnet_socketlist; + lhnetsocket->prev = lhnetsocket->next->prev; + lhnetsocket->next->prev = lhnetsocket; + lhnetsocket->prev->next = lhnetsocket; +#ifdef WIN32 + if (ioctlsocket(lhnetsocket->inetsocket, SIO_UDP_CONNRESET, &_false) == -1) + Con_DPrintf("LHNET_OpenSocket_Connectionless: ioctlsocket SIO_UDP_CONNRESET returned error: %s\n", LHNETPRIVATE_StrError()); +#endif + return lhnetsocket; + } + else + Con_Printf("LHNET_OpenSocket_Connectionless: bind returned error: %s\n", LHNETPRIVATE_StrError()); + } +#ifdef IPV6_V6ONLY + else + Con_Printf("LHNET_OpenSocket_Connectionless: setsockopt(IPV6_V6ONLY) returned error: %s\n", LHNETPRIVATE_StrError()); +#endif + } + else + Con_Printf("LHNET_OpenSocket_Connectionless: ioctlsocket returned error: %s\n", LHNETPRIVATE_StrError()); + closesocket(lhnetsocket->inetsocket); + } + else + Con_Printf("LHNET_OpenSocket_Connectionless: socket returned error: %s\n", LHNETPRIVATE_StrError()); +#ifdef WIN32 + } + else + Con_Print("LHNET_OpenSocket_Connectionless: can't open a socket (WSAStartup failed during LHNET_Init)\n"); +#endif + break; + default: + break; + } + Z_Free(lhnetsocket); + } + return NULL; +} + +void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket) +{ + if (lhnetsocket) + { + // unlink from socket list + if (lhnetsocket->next == NULL) + return; // invalid! + lhnetsocket->next->prev = lhnetsocket->prev; + lhnetsocket->prev->next = lhnetsocket->next; + lhnetsocket->next = NULL; + lhnetsocket->prev = NULL; + + // no special close code for loopback, just inet + if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4 || lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) + { + closesocket(lhnetsocket->inetsocket); + } + Z_Free(lhnetsocket); + } +} + +lhnetaddress_t *LHNET_AddressFromSocket(lhnetsocket_t *sock) +{ + if (sock) + return &sock->address; + else + return NULL; +} + +int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *vaddress) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + int value = 0; + if (!lhnetsocket || !address || !content || maxcontentlength < 1) + return -1; + if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP) + { + time_t currenttime; + lhnetpacket_t *p, *pnext; + // scan for any old packets to timeout while searching for a packet + // that is waiting to be delivered to this socket + currenttime = time(NULL); + for (p = lhnet_packetlist.next;p != &lhnet_packetlist;p = pnext) + { + pnext = p->next; + if (p->timeout < currenttime) + { + // unlink and free + p->next->prev = p->prev; + p->prev->next = p->next; + Z_Free(p); + continue; + } +#ifndef STANDALONETEST + if (cl_netlocalping.value && (realtime - cl_netlocalping.value * (1.0 / 2000.0)) < p->sentdoubletime) + continue; +#endif + if (value == 0 && p->destinationport == lhnetsocket->address.port) + { + if (p->length <= maxcontentlength) + { + lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address; + *address = *localaddress; + address->port = p->sourceport; + memcpy(content, p->data, p->length); + value = p->length; + } + else + value = -1; + // unlink and free + p->next->prev = p->prev; + p->prev->next = p->next; + Z_Free(p); + } + } + } + else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4) + { + SOCKLEN_T inetaddresslength; + address->addresstype = LHNETADDRESSTYPE_NONE; + inetaddresslength = sizeof(address->addr.in); + value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); + if (value > 0) + { + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = ntohs(address->addr.in.sin_port); + return value; + } + else if (value < 0) + { + int e = SOCKETERRNO; + if (e == EWOULDBLOCK) + return 0; + switch (e) + { + case ECONNREFUSED: + Con_Print("Connection refused\n"); + return 0; + } + Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); + } + } +#ifdef SUPPORTIPV6 + else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) + { + SOCKLEN_T inetaddresslength; + address->addresstype = LHNETADDRESSTYPE_NONE; + inetaddresslength = sizeof(address->addr.in6); + value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); + if (value > 0) + { + address->addresstype = LHNETADDRESSTYPE_INET6; + address->port = ntohs(address->addr.in6.sin6_port); + return value; + } + else if (value == -1) + { + int e = SOCKETERRNO; + if (e == EWOULDBLOCK) + return 0; + switch (e) + { + case ECONNREFUSED: + Con_Print("Connection refused\n"); + return 0; + } + Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); + } + } +#endif + return value; +} + +int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentlength, const lhnetaddress_t *vaddress) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + int value = -1; + if (!lhnetsocket || !address || !content || contentlength < 1) + return -1; + if (lhnetsocket->address.addresstype != address->addresstype) + return -1; + if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP) + { + lhnetpacket_t *p; + p = (lhnetpacket_t *)Z_Malloc(sizeof(*p) + contentlength); + p->data = (void *)(p + 1); + memcpy(p->data, content, contentlength); + p->length = contentlength; + p->sourceport = lhnetsocket->address.port; + p->destinationport = address->port; + p->timeout = time(NULL) + 10; + p->next = &lhnet_packetlist; + p->prev = p->next->prev; + p->next->prev = p; + p->prev->next = p; +#ifndef STANDALONETEST + p->sentdoubletime = realtime; +#endif + value = contentlength; + } + else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4) + { + value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, LHNET_SENDTO_FLAGS, (struct sockaddr *)&address->addr.in, sizeof(struct sockaddr_in)); + if (value == -1) + { + if (SOCKETERRNO == EWOULDBLOCK) + return 0; + Con_DPrintf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError()); + } + } +#ifdef SUPPORTIPV6 + else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) + { + value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, 0, (struct sockaddr *)&address->addr.in6, sizeof(struct sockaddr_in6)); + if (value == -1) + { + if (SOCKETERRNO == EWOULDBLOCK) + return 0; + Con_DPrintf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError()); + } + } +#endif + return value; +} + +#ifdef STANDALONETEST +int main(int argc, char **argv) +{ +#if 1 + char *buffer = "test", buffer2[1024]; + int blen = strlen(buffer); + int b2len = 1024; + lhnetsocket_t *sock1; + lhnetsocket_t *sock2; + lhnetaddress_t myaddy1; + lhnetaddress_t myaddy2; + lhnetaddress_t myaddy3; + lhnetaddress_t localhostaddy1; + lhnetaddress_t localhostaddy2; + int test1; + int test2; + + printf("calling LHNET_Init\n"); + LHNET_Init(); + + printf("calling LHNET_FromPort twice to create two local addresses\n"); + LHNETADDRESS_FromPort(&myaddy1, LHNETADDRESSTYPE_INET4, 4000); + LHNETADDRESS_FromPort(&myaddy2, LHNETADDRESSTYPE_INET4, 4001); + LHNETADDRESS_FromString(&localhostaddy1, "127.0.0.1", 4000); + LHNETADDRESS_FromString(&localhostaddy2, "127.0.0.1", 4001); + + printf("calling LHNET_OpenSocket_Connectionless twice to create two local sockets\n"); + sock1 = LHNET_OpenSocket_Connectionless(&myaddy1); + sock2 = LHNET_OpenSocket_Connectionless(&myaddy2); + + printf("calling LHNET_Write to send a packet from the first socket to the second socket\n"); + test1 = LHNET_Write(sock1, buffer, blen, &localhostaddy2); + printf("sleeping briefly\n"); +#ifdef WIN32 + Sleep (100); +#else + usleep (100000); +#endif + printf("calling LHNET_Read on the second socket to read the packet sent from the first socket\n"); + test2 = LHNET_Read(sock2, buffer2, b2len - 1, &myaddy3); + if (test2 > 0) + Con_Printf("socket to socket test succeeded\n"); + else + Con_Printf("socket to socket test failed\n"); + +#ifdef WIN32 + printf("press any key to exit\n"); + getchar(); +#endif + + printf("calling LHNET_Shutdown\n"); + LHNET_Shutdown(); + printf("exiting\n"); + return 0; +#else + lhnetsocket_t *sock[16], *sendsock; + int i; + int numsockets; + int count; + int length; + int port; + time_t oldtime; + time_t newtime; + char *sendmessage; + int sendmessagelength; + lhnetaddress_t destaddress; + lhnetaddress_t receiveaddress; + lhnetaddress_t sockaddress[16]; + char buffer[1536], addressstring[128], addressstring2[128]; + if ((argc == 2 || argc == 5) && (port = atoi(argv[1])) >= 1 && port < 65535) + { + printf("calling LHNET_Init()\n"); + LHNET_Init(); + + numsockets = 0; + LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_LOOP, port); + LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET4, port); + LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET6, port+1); + + sendsock = NULL; + sendmessage = NULL; + sendmessagelength = 0; + + for (i = 0;i < numsockets;i++) + { + LHNETADDRESS_ToString(&sockaddress[i], addressstring, sizeof(addressstring), 1); + printf("calling LHNET_OpenSocket_Connectionless(<%s>)\n", addressstring); + if ((sock[i] = LHNET_OpenSocket_Connectionless(&sockaddress[i]))) + { + LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1); + printf("opened socket successfully (address \"%s\")\n", addressstring2); + } + else + { + printf("failed to open socket\n"); + if (i == 0) + { + LHNET_Shutdown(); + return -1; + } + } + } + count = 0; + if (argc == 5) + { + count = atoi(argv[2]); + if (LHNETADDRESS_FromString(&destaddress, argv[3], -1)) + { + sendmessage = argv[4]; + sendmessagelength = strlen(sendmessage); + sendsock = NULL; + for (i = 0;i < numsockets;i++) + if (sock[i] && LHNETADDRESS_GetAddressType(&destaddress) == LHNETADDRESS_GetAddressType(&sockaddress[i])) + sendsock = sock[i]; + if (sendsock == NULL) + { + printf("Could not find an open socket matching the addresstype (%i) of destination address, switching to listen only mode\n", LHNETADDRESS_GetAddressType(&destaddress)); + argc = 2; + } + } + else + { + printf("LHNETADDRESS_FromString did not like the address \"%s\", switching to listen only mode\n", argv[3]); + argc = 2; + } + } + printf("started, now listening for \"exit\" on the opened sockets\n"); + oldtime = time(NULL); + for(;;) + { +#ifdef WIN32 + Sleep(1); +#else + usleep(1); +#endif + for (i = 0;i < numsockets;i++) + { + if (sock[i]) + { + length = LHNET_Read(sock[i], buffer, sizeof(buffer), &receiveaddress); + if (length < 0) + printf("localsock read error: length < 0"); + else if (length > 0 && length < (int)sizeof(buffer)) + { + buffer[length] = 0; + LHNETADDRESS_ToString(&receiveaddress, addressstring, sizeof(addressstring), 1); + LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1); + printf("received message \"%s\" from \"%s\" on socket \"%s\"\n", buffer, addressstring, addressstring2); + if (!strcmp(buffer, "exit")) + break; + } + } + } + if (i < numsockets) + break; + if (argc == 5 && count > 0) + { + newtime = time(NULL); + if (newtime != oldtime) + { + LHNETADDRESS_ToString(&destaddress, addressstring, sizeof(addressstring), 1); + LHNETADDRESS_ToString(LHNET_AddressFromSocket(sendsock), addressstring2, sizeof(addressstring2), 1); + printf("calling LHNET_Write(<%s>, \"%s\", %i, <%s>)\n", addressstring2, sendmessage, sendmessagelength, addressstring); + length = LHNET_Write(sendsock, sendmessage, sendmessagelength, &destaddress); + if (length == sendmessagelength) + printf("sent successfully\n"); + else + printf("LH_Write failed, returned %i (length of message was %i)\n", length, strlen(argv[4])); + oldtime = newtime; + count--; + if (count <= 0) + printf("Done sending, still listening for \"exit\"\n"); + } + } + } + for (i = 0;i < numsockets;i++) + { + if (sock[i]) + { + LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1); + printf("calling LHNET_CloseSocket(<%s>)\n", addressstring2); + LHNET_CloseSocket(sock[i]); + } + } + printf("calling LHNET_Shutdown()\n"); + LHNET_Shutdown(); + return 0; + } + printf("Testing code for lhnet.c\nusage: lhnettest [ ]\n"); + return -1; +#endif +} +#endif + diff --git a/app/jni/lhnet.h b/app/jni/lhnet.h new file mode 100644 index 0000000..e66e5a5 --- /dev/null +++ b/app/jni/lhnet.h @@ -0,0 +1,52 @@ + +// Written by Forest Hale 2003-06-15 and placed into public domain. + +#ifndef LHNET_H +#define LHNET_H + +typedef enum lhnetaddresstype_e +{ + LHNETADDRESSTYPE_NONE, + LHNETADDRESSTYPE_LOOP, + LHNETADDRESSTYPE_INET4, + LHNETADDRESSTYPE_INET6 +} +lhnetaddresstype_t; + +typedef struct lhnetaddress_s +{ + lhnetaddresstype_t addresstype; + int port; // used by LHNETADDRESSTYPE_LOOP + unsigned char storage[256]; // sockaddr_in or sockaddr_in6 +} +lhnetaddress_t; + +int LHNETADDRESS_FromPort(lhnetaddress_t *address, lhnetaddresstype_t addresstype, int port); +int LHNETADDRESS_FromString(lhnetaddress_t *address, const char *string, int defaultport); +int LHNETADDRESS_ToString(const lhnetaddress_t *address, char *string, int stringbuffersize, int includeport); +int LHNETADDRESS_GetAddressType(const lhnetaddress_t *address); +const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *address, char *ifname, size_t ifnamelength); +int LHNETADDRESS_GetPort(const lhnetaddress_t *address); +int LHNETADDRESS_SetPort(lhnetaddress_t *address, int port); +int LHNETADDRESS_Compare(const lhnetaddress_t *address1, const lhnetaddress_t *address2); + +typedef struct lhnetsocket_s +{ + lhnetaddress_t address; + int inetsocket; + struct lhnetsocket_s *next, *prev; +} +lhnetsocket_t; + +void LHNET_Init(void); +void LHNET_Shutdown(void); +int LHNET_DefaultDSCP(int dscp); // < 0: query; >= 0: set (returns previous value) +void LHNET_SleepUntilPacket_Microseconds(int microseconds); +lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address); +void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket); +lhnetaddress_t *LHNET_AddressFromSocket(lhnetsocket_t *sock); +int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *address); +int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentlength, const lhnetaddress_t *address); + +#endif + diff --git a/app/jni/libcurl.c b/app/jni/libcurl.c new file mode 100644 index 0000000..2d95afb --- /dev/null +++ b/app/jni/libcurl.c @@ -0,0 +1,1828 @@ +#include "quakedef.h" +#include "fs.h" +#include "libcurl.h" +#include "thread.h" + +#include "image.h" +#include "jpeg.h" +#include "image_png.h" + +static cvar_t cl_curl_maxdownloads = {CVAR_SAVE, "cl_curl_maxdownloads","1", "maximum number of concurrent HTTP/FTP downloads"}; +static cvar_t cl_curl_maxspeed = {CVAR_SAVE, "cl_curl_maxspeed","300", "maximum download speed (KiB/s)"}; +static cvar_t sv_curl_defaulturl = {CVAR_SAVE, "sv_curl_defaulturl","", "default autodownload source URL"}; +static cvar_t sv_curl_serverpackages = {CVAR_SAVE, "sv_curl_serverpackages","", "list of required files for the clients, separated by spaces"}; +static cvar_t sv_curl_maxspeed = {CVAR_SAVE, "sv_curl_maxspeed","0", "maximum download speed for clients downloading from sv_curl_defaulturl (KiB/s)"}; +static cvar_t cl_curl_enabled = {CVAR_SAVE, "cl_curl_enabled","1", "whether client's download support is enabled"}; +static cvar_t cl_curl_useragent = {0, "cl_curl_useragent","1", "send the User-Agent string (note: turning this off may break stuff)"}; +static cvar_t cl_curl_useragent_append = {0, "cl_curl_useragent_append","", "a string to append to the User-Agent string (useful for name and version number of your mod)"}; + +/* +================================================================= + + Minimal set of definitions from libcurl + + WARNING: for a matter of simplicity, several pointer types are + casted to "void*", and most enumerated values are not included + +================================================================= +*/ + +typedef struct CURL_s CURL; +typedef struct CURLM_s CURLM; +typedef struct curl_slist curl_slist; +typedef enum +{ + CURLE_OK = 0 +} +CURLcode; +typedef enum +{ + CURLM_CALL_MULTI_PERFORM=-1, /* please call curl_multi_perform() soon */ + CURLM_OK = 0 +} +CURLMcode; +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_SSL 1 +#define CURL_GLOBAL_WIN32 2 +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 +#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number +typedef enum +{ + CINIT(WRITEDATA, OBJECTPOINT, 1), + CINIT(URL, OBJECTPOINT, 2), + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + CINIT(POSTFIELDS, OBJECTPOINT, 15), + CINIT(REFERER, OBJECTPOINT, 16), + CINIT(USERAGENT, OBJECTPOINT, 18), + CINIT(LOW_SPEED_LIMIT, LONG , 19), + CINIT(LOW_SPEED_TIME, LONG, 20), + CINIT(RESUME_FROM, LONG, 21), + CINIT(HTTPHEADER, OBJECTPOINT, 23), + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + CINIT(POSTFIELDSIZE, LONG, 60), + CINIT(PRIVATE, OBJECTPOINT, 103), + CINIT(PROTOCOLS, LONG, 181), + CINIT(REDIR_PROTOCOLS, LONG, 182) +} +CURLoption; +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +typedef enum +{ + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} +curl_infotype; +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 +typedef enum +{ + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27 +} +CURLINFO; + +typedef enum +{ + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST +} +CURLMSG; +typedef struct +{ + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union + { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } + data; +} +CURLMsg; + +static void (*qcurl_global_init) (long flags); +static void (*qcurl_global_cleanup) (void); + +static CURL * (*qcurl_easy_init) (void); +static void (*qcurl_easy_cleanup) (CURL *handle); +static CURLcode (*qcurl_easy_setopt) (CURL *handle, CURLoption option, ...); +static CURLcode (*qcurl_easy_getinfo) (CURL *handle, CURLINFO info, ...); +static const char * (*qcurl_easy_strerror) (CURLcode); + +static CURLM * (*qcurl_multi_init) (void); +static CURLMcode (*qcurl_multi_perform) (CURLM *multi_handle, int *running_handles); +static CURLMcode (*qcurl_multi_add_handle) (CURLM *multi_handle, CURL *easy_handle); +static CURLMcode (*qcurl_multi_remove_handle) (CURLM *multi_handle, CURL *easy_handle); +static CURLMsg * (*qcurl_multi_info_read) (CURLM *multi_handle, int *msgs_in_queue); +static void (*qcurl_multi_cleanup) (CURLM *); +static const char * (*qcurl_multi_strerror) (CURLcode); +static curl_slist * (*qcurl_slist_append) (curl_slist *list, const char *string); +static void (*qcurl_slist_free_all) (curl_slist *list); + +static dllfunction_t curlfuncs[] = +{ + {"curl_global_init", (void **) &qcurl_global_init}, + {"curl_global_cleanup", (void **) &qcurl_global_cleanup}, + {"curl_easy_init", (void **) &qcurl_easy_init}, + {"curl_easy_cleanup", (void **) &qcurl_easy_cleanup}, + {"curl_easy_setopt", (void **) &qcurl_easy_setopt}, + {"curl_easy_strerror", (void **) &qcurl_easy_strerror}, + {"curl_easy_getinfo", (void **) &qcurl_easy_getinfo}, + {"curl_multi_init", (void **) &qcurl_multi_init}, + {"curl_multi_perform", (void **) &qcurl_multi_perform}, + {"curl_multi_add_handle", (void **) &qcurl_multi_add_handle}, + {"curl_multi_remove_handle",(void **) &qcurl_multi_remove_handle}, + {"curl_multi_info_read", (void **) &qcurl_multi_info_read}, + {"curl_multi_cleanup", (void **) &qcurl_multi_cleanup}, + {"curl_multi_strerror", (void **) &qcurl_multi_strerror}, + {"curl_slist_append", (void **) &qcurl_slist_append}, + {"curl_slist_free_all", (void **) &qcurl_slist_free_all}, + {NULL, NULL} +}; + +// Handle for CURL DLL +static dllhandle_t curl_dll = NULL; +// will be checked at many places to find out if qcurl calls are allowed + +#define LOADTYPE_NONE 0 +#define LOADTYPE_PAK 1 +#define LOADTYPE_CACHEPIC 2 +#define LOADTYPE_SKINFRAME 3 + +void *curl_mutex = NULL; + +typedef struct downloadinfo_s +{ + char filename[MAX_OSPATH]; + char url[1024]; + char referer[256]; + qfile_t *stream; + fs_offset_t startpos; + CURL *curle; + qboolean started; + int loadtype; + unsigned long bytes_received; // for buffer + double bytes_received_curl; // for throttling + double bytes_sent_curl; // for throttling + struct downloadinfo_s *next, *prev; + qboolean forthismap; + double maxspeed; + curl_slist *slist; // http headers + + unsigned char *buffer; + size_t buffersize; + curl_callback_t callback; + void *callback_data; + + const unsigned char *postbuf; + size_t postbufsize; + const char *post_content_type; + const char *extraheaders; +} +downloadinfo; +static downloadinfo *downloads = NULL; +static int numdownloads = 0; + +static qboolean noclear = FALSE; + +static int numdownloads_fail = 0; +static int numdownloads_success = 0; +static int numdownloads_added = 0; +static char command_when_done[256] = ""; +static char command_when_error[256] = ""; + +/* +==================== +Curl_CommandWhenDone + +Sets the command which is to be executed when the last download completes AND +all downloads since last server connect ended with a successful status. +Setting the command to NULL clears it. +==================== +*/ +static void Curl_CommandWhenDone(const char *cmd) +{ + if(!curl_dll) + return; + if(cmd) + strlcpy(command_when_done, cmd, sizeof(command_when_done)); + else + *command_when_done = 0; +} + +/* +FIXME +Do not use yet. Not complete. +Problem: what counts as an error? +*/ + +static void Curl_CommandWhenError(const char *cmd) +{ + if(!curl_dll) + return; + if(cmd) + strlcpy(command_when_error, cmd, sizeof(command_when_error)); + else + *command_when_error = 0; +} + +/* +==================== +Curl_Clear_forthismap + +Clears the "will disconnect on failure" flags. +==================== +*/ +void Curl_Clear_forthismap(void) +{ + downloadinfo *di; + if(noclear) + return; + if (curl_mutex) Thread_LockMutex(curl_mutex); + for(di = downloads; di; di = di->next) + di->forthismap = false; + Curl_CommandWhenError(NULL); + Curl_CommandWhenDone(NULL); + numdownloads_fail = 0; + numdownloads_success = 0; + numdownloads_added = 0; + if (curl_mutex) Thread_UnlockMutex(curl_mutex); +} + +/* +==================== +Curl_Have_forthismap + +Returns true if a download needed for the current game is running. +==================== +*/ +qboolean Curl_Have_forthismap(void) +{ + return numdownloads_added != 0; +} + +void Curl_Register_predownload(void) +{ + if (curl_mutex) Thread_LockMutex(curl_mutex); + Curl_CommandWhenDone("cl_begindownloads"); + Curl_CommandWhenError("cl_begindownloads"); + if (curl_mutex) Thread_UnlockMutex(curl_mutex); +} + +/* +==================== +Curl_CheckCommandWhenDone + +Checks if a "done command" is to be executed. +All downloads finished, at least one success since connect, no single failure +-> execute the command. +*/ +static void Curl_CheckCommandWhenDone(void) +{ + if(!curl_dll) + return; + if(numdownloads_added && ((numdownloads_success + numdownloads_fail) == numdownloads_added)) + { + if(numdownloads_fail == 0) + { + Con_DPrintf("cURL downloads occurred, executing %s\n", command_when_done); + Cbuf_AddText("\n"); + Cbuf_AddText(command_when_done); + Cbuf_AddText("\n"); + } + else + { + Con_DPrintf("cURL downloads FAILED, executing %s\n", command_when_error); + Cbuf_AddText("\n"); + Cbuf_AddText(command_when_error); + Cbuf_AddText("\n"); + } + Curl_Clear_forthismap(); + } +} + +/* +==================== +CURL_CloseLibrary + +Load the cURL DLL +==================== +*/ +static qboolean CURL_OpenLibrary (void) +{ + const char* dllnames [] = + { +#if defined(WIN32) + "libcurl-4.dll", + "libcurl-3.dll", +#elif defined(MACOSX) + "libcurl.4.dylib", // Mac OS X Notyetreleased + "libcurl.3.dylib", // Mac OS X Tiger + "libcurl.2.dylib", // Mac OS X Panther +#else + "libcurl.so.4", + "libcurl.so.3", + "libcurl.so", // FreeBSD +#endif + NULL + }; + + // Already loaded? + if (curl_dll) + return true; + + // Load the DLL + return Sys_LoadLibrary (dllnames, &curl_dll, curlfuncs); +} + + +/* +==================== +CURL_CloseLibrary + +Unload the cURL DLL +==================== +*/ +static void CURL_CloseLibrary (void) +{ + Sys_UnloadLibrary (&curl_dll); +} + + +static CURLM *curlm = NULL; +static double bytes_received = 0; // used for bandwidth throttling +static double bytes_sent = 0; // used for bandwidth throttling +static double curltime = 0; + +/* +==================== +CURL_fwrite + +fwrite-compatible function that writes the data to a file. libcurl can call +this. +==================== +*/ +static size_t CURL_fwrite(void *data, size_t size, size_t nmemb, void *vdi) +{ + fs_offset_t ret = -1; + size_t bytes = size * nmemb; + downloadinfo *di = (downloadinfo *) vdi; + + if(di->buffer) + { + if(di->bytes_received + bytes <= di->buffersize) + { + memcpy(di->buffer + di->bytes_received, data, bytes); + ret = bytes; + } + // otherwise: buffer overrun, ret stays -1 + } + + if(di->stream) + { + ret = FS_Write(di->stream, data, bytes); + } + + di->bytes_received += bytes; + + return ret; // why not ret / nmemb? +} + +typedef enum +{ + CURL_DOWNLOAD_SUCCESS = 0, + CURL_DOWNLOAD_FAILED, + CURL_DOWNLOAD_ABORTED, + CURL_DOWNLOAD_SERVERERROR +} +CurlStatus; + +static void curl_default_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + downloadinfo *di = (downloadinfo *) cbdata; + switch(status) + { + case CURLCBSTATUS_OK: + Con_DPrintf("Download of %s: OK\n", di->filename); + break; + case CURLCBSTATUS_FAILED: + Con_DPrintf("Download of %s: FAILED\n", di->filename); + break; + case CURLCBSTATUS_ABORTED: + Con_DPrintf("Download of %s: ABORTED\n", di->filename); + break; + case CURLCBSTATUS_SERVERERROR: + Con_DPrintf("Download of %s: (unknown server error)\n", di->filename); + break; + case CURLCBSTATUS_UNKNOWN: + Con_DPrintf("Download of %s: (unknown client error)\n", di->filename); + break; + default: + Con_DPrintf("Download of %s: %d\n", di->filename, status); + break; + } +} + +static void curl_quiet_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + curl_default_callback(status, length_received, buffer, cbdata); +} + +static unsigned char *decode_image(downloadinfo *di, const char *content_type) +{ + unsigned char *pixels = NULL; + fs_offset_t filesize = 0; + unsigned char *data = FS_LoadFile(di->filename, tempmempool, true, &filesize); + if(data) + { + int mip = 0; + if(!strcmp(content_type, "image/jpeg")) + pixels = JPEG_LoadImage_BGRA(data, filesize, &mip); + else if(!strcmp(content_type, "image/png")) + pixels = PNG_LoadImage_BGRA(data, filesize, &mip); + else if(filesize >= 7 && !strncmp((char *) data, "\xFF\xD8", 7)) + pixels = JPEG_LoadImage_BGRA(data, filesize, &mip); + else if(filesize >= 7 && !strncmp((char *) data, "\x89PNG\x0D\x0A\x1A\x0A", 7)) + pixels = PNG_LoadImage_BGRA(data, filesize, &mip); + else + Con_Printf("Did not detect content type: %s\n", content_type); + Mem_Free(data); + } + // do we call Image_MakeLinearColorsFromsRGB or not? + return pixels; +} + +/* +==================== +Curl_EndDownload + +stops a download. It receives a status (CURL_DOWNLOAD_SUCCESS, +CURL_DOWNLOAD_FAILED or CURL_DOWNLOAD_ABORTED) and in the second case the error +code from libcurl, or 0, if another error has occurred. +==================== +*/ +static qboolean Curl_Begin(const char *URL, const char *extraheaders, double maxspeed, const char *name, int loadtype, qboolean forthismap, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata); +static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error, const char *content_type_) +{ + char content_type[64]; + qboolean ok = false; + if(!curl_dll) + return; + switch(status) + { + case CURL_DOWNLOAD_SUCCESS: + ok = true; + di->callback(CURLCBSTATUS_OK, di->bytes_received, di->buffer, di->callback_data); + break; + case CURL_DOWNLOAD_FAILED: + di->callback(CURLCBSTATUS_FAILED, di->bytes_received, di->buffer, di->callback_data); + break; + case CURL_DOWNLOAD_ABORTED: + di->callback(CURLCBSTATUS_ABORTED, di->bytes_received, di->buffer, di->callback_data); + break; + case CURL_DOWNLOAD_SERVERERROR: + // reopen to enforce it to have zero bytes again + if(di->stream) + { + FS_Close(di->stream); + di->stream = FS_OpenRealFile(di->filename, "wb", false); + } + + if(di->callback) + di->callback(error ? (int) error : CURLCBSTATUS_SERVERERROR, di->bytes_received, di->buffer, di->callback_data); + break; + default: + if(di->callback) + di->callback(CURLCBSTATUS_UNKNOWN, di->bytes_received, di->buffer, di->callback_data); + break; + } + if(content_type_) + strlcpy(content_type, content_type_, sizeof(content_type)); + else + *content_type = 0; + + if(di->curle) + { + qcurl_multi_remove_handle(curlm, di->curle); + qcurl_easy_cleanup(di->curle); + if(di->slist) + qcurl_slist_free_all(di->slist); + } + + if(!di->callback && ok && !di->bytes_received) + { + Con_Printf("ERROR: empty file\n"); + ok = false; + } + + if(di->stream) + FS_Close(di->stream); + +#define CLEAR_AND_RETRY() \ + do \ + { \ + di->stream = FS_OpenRealFile(di->filename, "wb", false); \ + FS_Close(di->stream); \ + if(di->startpos && !di->callback) \ + { \ + Curl_Begin(di->url, di->extraheaders, di->maxspeed, di->filename, di->loadtype, di->forthismap, di->post_content_type, di->postbuf, di->postbufsize, NULL, 0, NULL, NULL); \ + di->forthismap = false; \ + } \ + } \ + while(0) + + if(ok && di->loadtype == LOADTYPE_PAK) + { + ok = FS_AddPack(di->filename, NULL, true); + if(!ok) + CLEAR_AND_RETRY(); + } + else if(ok && di->loadtype == LOADTYPE_CACHEPIC) + { + const char *p; + unsigned char *pixels = NULL; + + p = di->filename; +#ifdef WE_ARE_EVIL + if(!strncmp(p, "dlcache/", 8)) + p += 8; +#endif + + pixels = decode_image(di, content_type); + if(pixels) + Draw_NewPic(p, image_width, image_height, true, pixels); + else + CLEAR_AND_RETRY(); + } + else if(ok && di->loadtype == LOADTYPE_SKINFRAME) + { + const char *p; + unsigned char *pixels = NULL; + + p = di->filename; +#ifdef WE_ARE_EVIL + if(!strncmp(p, "dlcache/", 8)) + p += 8; +#endif + + pixels = decode_image(di, content_type); + if(pixels) + R_SkinFrame_LoadInternalBGRA(p, TEXF_FORCE_RELOAD | TEXF_MIPMAP | TEXF_ALPHA, pixels, image_width, image_height, false); // TODO what sRGB argument to put here? + else + CLEAR_AND_RETRY(); + } + + if(di->prev) + di->prev->next = di->next; + else + downloads = di->next; + if(di->next) + di->next->prev = di->prev; + + --numdownloads; + if(di->forthismap) + { + if(ok) + ++numdownloads_success; + else + ++numdownloads_fail; + } + Z_Free(di); +} + +/* +==================== +CleanURL + +Returns a "cleaned up" URL for display (to strip login data) +==================== +*/ +static const char *CleanURL(const char *url, char *urlbuf, size_t urlbuflength) +{ + const char *p, *q, *r; + + // if URL is of form anything://foo-without-slash@rest, replace by anything://rest + p = strstr(url, "://"); + if(p) + { + q = strchr(p + 3, '@'); + if(q) + { + r = strchr(p + 3, '/'); + if(!r || q < r) + { + dpsnprintf(urlbuf, urlbuflength, "%.*s%s", (int)(p - url + 3), url, q + 1); + return urlbuf; + } + } + } + + return url; +} + +/* +==================== +CheckPendingDownloads + +checks if there are free download slots to start new downloads in. +To not start too many downloads at once, only one download is added at a time, +up to a maximum number of cl_curl_maxdownloads are running. +==================== +*/ +static void CheckPendingDownloads(void) +{ + const char *h; + char urlbuf[1024]; + char vabuf[1024]; + if(!curl_dll) + return; + if(numdownloads < cl_curl_maxdownloads.integer) + { + downloadinfo *di; + for(di = downloads; di; di = di->next) + { + if(!di->started) + { + if(!di->buffer) + { + Con_Printf("Downloading %s -> %s", CleanURL(di->url, urlbuf, sizeof(urlbuf)), di->filename); + + di->stream = FS_OpenRealFile(di->filename, "ab", false); + if(!di->stream) + { + Con_Printf("\nFAILED: Could not open output file %s\n", di->filename); + Curl_EndDownload(di, CURL_DOWNLOAD_FAILED, CURLE_OK, NULL); + return; + } + FS_Seek(di->stream, 0, SEEK_END); + di->startpos = FS_Tell(di->stream); + + if(di->startpos > 0) + Con_Printf(", resuming from position %ld", (long) di->startpos); + Con_Print("...\n"); + } + else + { + Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url, urlbuf, sizeof(urlbuf))); + di->startpos = 0; + } + + di->curle = qcurl_easy_init(); + di->slist = NULL; + qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url); + if(cl_curl_useragent.integer) + { + const char *ua +#ifdef HTTP_USER_AGENT + = HTTP_USER_AGENT; +#else + = engineversion; +#endif + if(!ua) + ua = ""; + if(*cl_curl_useragent_append.string) + ua = va(vabuf, sizeof(vabuf), "%s%s%s", + ua, + (ua[0] && ua[strlen(ua)-1] != ' ') + ? " " + : "", + cl_curl_useragent_append.string); + qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ua); + } + else + qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ""); + qcurl_easy_setopt(di->curle, CURLOPT_REFERER, di->referer); + qcurl_easy_setopt(di->curle, CURLOPT_RESUME_FROM, (long) di->startpos); + qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 1); + qcurl_easy_setopt(di->curle, CURLOPT_WRITEFUNCTION, CURL_fwrite); + qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_LIMIT, (long) 256); + qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_TIME, (long) 45); + qcurl_easy_setopt(di->curle, CURLOPT_WRITEDATA, (void *) di); + qcurl_easy_setopt(di->curle, CURLOPT_PRIVATE, (void *) di); + qcurl_easy_setopt(di->curle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP); + if(qcurl_easy_setopt(di->curle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP) != CURLE_OK) + { + Con_Printf("^1WARNING:^7 for security reasons, please upgrade to libcurl 7.19.4 or above. In a later version of DarkPlaces, HTTP redirect support will be disabled for this libcurl version.\n"); + //qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 0); + } + if(di->post_content_type) + { + qcurl_easy_setopt(di->curle, CURLOPT_POST, 1); + qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDS, di->postbuf); + qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDSIZE, di->postbufsize); + di->slist = qcurl_slist_append(di->slist, va(vabuf, sizeof(vabuf), "Content-Type: %s", di->post_content_type)); + } + + // parse extra headers into slist + // \n separated list! + h = di->extraheaders; + while(h) + { + const char *hh = strchr(h, '\n'); + if(hh) + { + char *buf = (char *) Mem_Alloc(tempmempool, hh - h + 1); + memcpy(buf, h, hh - h); + buf[hh - h] = 0; + di->slist = qcurl_slist_append(di->slist, buf); + h = hh + 1; + } + else + { + di->slist = qcurl_slist_append(di->slist, h); + h = NULL; + } + } + + qcurl_easy_setopt(di->curle, CURLOPT_HTTPHEADER, di->slist); + + qcurl_multi_add_handle(curlm, di->curle); + di->started = true; + ++numdownloads; + if(numdownloads >= cl_curl_maxdownloads.integer) + break; + } + } + } +} + +/* +==================== +Curl_Init + +this function MUST be called before using anything else in this file. +On Win32, this must be called AFTER WSAStartup has been done! +==================== +*/ +void Curl_Init(void) +{ + CURL_OpenLibrary(); + if(!curl_dll) + return; + if (Thread_HasThreads()) curl_mutex = Thread_CreateMutex(); + qcurl_global_init(CURL_GLOBAL_NOTHING); + curlm = qcurl_multi_init(); +} + +/* +==================== +Curl_Shutdown + +Surprise... closes all the stuff. Please do this BEFORE shutting down LHNET. +==================== +*/ +void Curl_ClearRequirements(void); +void Curl_Shutdown(void) +{ + if(!curl_dll) + return; + Curl_ClearRequirements(); + Curl_CancelAll(); + if (curl_mutex) Thread_DestroyMutex(curl_mutex); + CURL_CloseLibrary(); + curl_dll = NULL; +} + +/* +==================== +Curl_Find + +Finds the internal information block for a download given by file name. +==================== +*/ +static downloadinfo *Curl_Find(const char *filename) +{ + downloadinfo *di; + if(!curl_dll) + return NULL; + for(di = downloads; di; di = di->next) + if(!strcasecmp(di->filename, filename)) + return di; + return NULL; +} + +void Curl_Cancel_ToMemory(curl_callback_t callback, void *cbdata) +{ + downloadinfo *di; + if(!curl_dll) + return; + for(di = downloads; di; ) + { + if(di->callback == callback && di->callback_data == cbdata) + { + di->callback = curl_quiet_callback; // do NOT call the callback + Curl_EndDownload(di, CURL_DOWNLOAD_ABORTED, CURLE_OK, NULL); + di = downloads; + } + else + di = di->next; + } +} + +/* +==================== +Curl_Begin + +Starts a download of a given URL to the file name portion of this URL (or name +if given) in the "dlcache/" folder. +==================== +*/ +static qboolean Curl_Begin(const char *URL, const char *extraheaders, double maxspeed, const char *name, int loadtype, qboolean forthismap, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) +{ + if(buf) + if(loadtype != LOADTYPE_NONE) + Host_Error("Curl_Begin: loadtype and buffer are both set"); + + if(!curl_dll) + { + return false; + } + else + { + char fn[MAX_OSPATH]; + char urlbuf[1024]; + const char *p, *q; + size_t length; + downloadinfo *di; + + // if URL is protocol:///* or protocol://:port/*, insert the IP of the current server + p = strchr(URL, ':'); + if(p) + { + if(!strncmp(p, ":///", 4) || !strncmp(p, "://:", 4)) + { + char addressstring[128]; + *addressstring = 0; + InfoString_GetValue(cls.userinfo, "*ip", addressstring, sizeof(addressstring)); + q = strchr(addressstring, ':'); + if(!q) + q = addressstring + strlen(addressstring); + if(*addressstring) + { + dpsnprintf(urlbuf, sizeof(urlbuf), "%.*s://%.*s%s", (int) (p - URL), URL, (int) (q - addressstring), addressstring, URL + (p - URL) + 3); + URL = urlbuf; + } + } + } + + // Note: This extraction of the file name portion is NOT entirely correct. + // + // It does the following: + // + // http://host/some/script.cgi/SomeFile.pk3?uid=ABCDE -> SomeFile.pk3 + // http://host/some/script.php?uid=ABCDE&file=/SomeFile.pk3 -> SomeFile.pk3 + // http://host/some/script.php?uid=ABCDE&file=SomeFile.pk3 -> script.php + // + // However, I'd like to keep this "buggy" behavior so that PHP script + // authors can write download scripts without having to enable + // AcceptPathInfo on Apache. They just have to ensure that their script + // can be called with such a "fake" path name like + // http://host/some/script.php?uid=ABCDE&file=/SomeFile.pk3 + // + // By the way, such PHP scripts should either send the file or a + // "Location:" redirect; PHP code example: + // + // header("Location: http://www.example.com/"); + // + // By the way, this will set User-Agent to something like + // "Nexuiz build 22:27:55 Mar 17 2006" (engineversion) and Referer to + // dp://serverhost:serverport/ so you can filter on this; an example + // httpd log file line might be: + // + // 141.2.16.3 - - [17/Mar/2006:22:32:43 +0100] "GET /maps/tznex07.pk3 HTTP/1.1" 200 1077455 "dp://141.2.16.7:26000/" "Nexuiz Linux 22:07:43 Mar 17 2006" + + if (curl_mutex) Thread_LockMutex(curl_mutex); + + if(buf) + { + if(!name) + name = CleanURL(URL, urlbuf, sizeof(urlbuf)); + } + else + { + if(!name) + { + name = CleanURL(URL, urlbuf, sizeof(urlbuf)); + p = strrchr(name, '/'); + p = p ? (p+1) : name; + q = strchr(p, '?'); + length = q ? (size_t)(q - p) : strlen(p); + dpsnprintf(fn, sizeof(fn), "dlcache/%.*s", (int)length, p); + } + else + { + dpsnprintf(fn, sizeof(fn), "dlcache/%s", name); + } + + name = fn; // make it point back + + // already downloading the file? + { + downloadinfo *di = Curl_Find(fn); + if(di) + { + Con_Printf("Can't download %s, already getting it from %s!\n", fn, CleanURL(di->url, urlbuf, sizeof(urlbuf))); + + // however, if it was not for this map yet... + if(forthismap && !di->forthismap) + { + di->forthismap = true; + // this "fakes" a download attempt so the client will wait for + // the download to finish and then reconnect + ++numdownloads_added; + } + + return false; + } + } + + if(FS_FileExists(fn)) + { + if(loadtype == LOADTYPE_PAK) + { + qboolean already_loaded; + if(FS_AddPack(fn, &already_loaded, true)) + { + Con_DPrintf("%s already exists, not downloading!\n", fn); + if(already_loaded) + Con_DPrintf("(pak was already loaded)\n"); + else + { + if(forthismap) + { + ++numdownloads_added; + ++numdownloads_success; + } + } + + return false; + } + else + { + qfile_t *f = FS_OpenRealFile(fn, "rb", false); + if(f) + { + char buf[4] = {0}; + FS_Read(f, buf, sizeof(buf)); // no "-1", I will use memcmp + + if(memcmp(buf, "PK\x03\x04", 4) && memcmp(buf, "PACK", 4)) + { + Con_DPrintf("Detected non-PAK %s, clearing and NOT resuming.\n", fn); + FS_Close(f); + f = FS_OpenRealFile(fn, "wb", false); + if(f) + FS_Close(f); + } + else + { + // OK + FS_Close(f); + } + } + } + } + else + { + // never resume these + qfile_t *f = FS_OpenRealFile(fn, "wb", false); + if(f) + FS_Close(f); + } + } + } + + // if we get here, we actually want to download... so first verify the + // URL scheme (so one can't read local files using file://) + if(strncmp(URL, "http://", 7) && strncmp(URL, "ftp://", 6) && strncmp(URL, "https://", 8)) + { + Con_Printf("Curl_Begin(\"%s\"): nasty URL scheme rejected\n", URL); + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + return false; + } + + if(forthismap) + ++numdownloads_added; + di = (downloadinfo *) Z_Malloc(sizeof(*di)); + strlcpy(di->filename, name, sizeof(di->filename)); + strlcpy(di->url, URL, sizeof(di->url)); + dpsnprintf(di->referer, sizeof(di->referer), "dp://%s/", cls.netcon ? cls.netcon->address : "notconnected.invalid"); + di->forthismap = forthismap; + di->stream = NULL; + di->startpos = 0; + di->curle = NULL; + di->started = false; + di->loadtype = loadtype; + di->maxspeed = maxspeed; + di->bytes_received = 0; + di->bytes_received_curl = 0; + di->bytes_sent_curl = 0; + di->extraheaders = extraheaders; + di->next = downloads; + di->prev = NULL; + if(di->next) + di->next->prev = di; + + di->buffer = buf; + di->buffersize = bufsize; + if(callback == NULL) + { + di->callback = curl_default_callback; + di->callback_data = di; + } + else + { + di->callback = callback; + di->callback_data = cbdata; + } + + if(post_content_type) + { + di->post_content_type = post_content_type; + di->postbuf = postbuf; + di->postbufsize = postbufsize; + } + else + { + di->post_content_type = NULL; + di->postbuf = NULL; + di->postbufsize = 0; + } + + downloads = di; + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + return true; + } +} + +qboolean Curl_Begin_ToFile(const char *URL, double maxspeed, const char *name, int loadtype, qboolean forthismap) +{ + return Curl_Begin(URL, NULL, maxspeed, name, loadtype, forthismap, NULL, NULL, 0, NULL, 0, NULL, NULL); +} +qboolean Curl_Begin_ToMemory(const char *URL, double maxspeed, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) +{ + return Curl_Begin(URL, NULL, maxspeed, NULL, false, false, NULL, NULL, 0, buf, bufsize, callback, cbdata); +} +qboolean Curl_Begin_ToMemory_POST(const char *URL, const char *extraheaders, double maxspeed, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) +{ + return Curl_Begin(URL, extraheaders, maxspeed, NULL, false, false, post_content_type, postbuf, postbufsize, buf, bufsize, callback, cbdata); +} + +/* +==================== +Curl_Run + +call this regularily as this will always download as much as possible without +blocking. +==================== +*/ +void Curl_Run(void) +{ + double maxspeed; + downloadinfo *di; + + noclear = FALSE; + + if(!cl_curl_enabled.integer) + return; + + if(!curl_dll) + return; + + if (curl_mutex) Thread_LockMutex(curl_mutex); + + Curl_CheckCommandWhenDone(); + + if(!downloads) + { + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + return; + } + + if(realtime < curltime) // throttle + { + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + return; + } + + { + int remaining; + CURLMcode mc; + + do + { + mc = qcurl_multi_perform(curlm, &remaining); + } + while(mc == CURLM_CALL_MULTI_PERFORM); + + for(di = downloads; di; di = di->next) + { + double b = 0; + if(di->curle) + { + qcurl_easy_getinfo(di->curle, CURLINFO_SIZE_UPLOAD, &b); + bytes_sent += (b - di->bytes_sent_curl); + di->bytes_sent_curl = b; + qcurl_easy_getinfo(di->curle, CURLINFO_SIZE_DOWNLOAD, &b); + bytes_sent += (b - di->bytes_received_curl); + di->bytes_received_curl = b; + } + } + + for(;;) + { + CURLMsg *msg = qcurl_multi_info_read(curlm, &remaining); + if(!msg) + break; + if(msg->msg == CURLMSG_DONE) + { + const char *ct = NULL; + CurlStatus failed = CURL_DOWNLOAD_SUCCESS; + CURLcode result; + qcurl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &di); + result = msg->data.result; + if(result) + { + failed = CURL_DOWNLOAD_FAILED; + } + else + { + long code; + qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &code); + switch(code / 100) + { + case 4: // e.g. 404? + case 5: // e.g. 500? + failed = CURL_DOWNLOAD_SERVERERROR; + result = (CURLcode) code; + break; + } + qcurl_easy_getinfo(msg->easy_handle, CURLINFO_CONTENT_TYPE, &ct); + } + + Curl_EndDownload(di, failed, result, ct); + } + } + } + + CheckPendingDownloads(); + + // when will we curl the next time? + // we will wait a bit to ensure our download rate is kept. + // we now know that realtime >= curltime... so set up a new curltime + + // use the slowest allowing download to derive the maxspeed... this CAN + // be done better, but maybe later + maxspeed = cl_curl_maxspeed.value; + for(di = downloads; di; di = di->next) + if(di->maxspeed > 0) + if(di->maxspeed < maxspeed || maxspeed <= 0) + maxspeed = di->maxspeed; + + if(maxspeed > 0) + { + double bytes = bytes_sent + bytes_received; // maybe smoothen a bit? + curltime = realtime + bytes / (cl_curl_maxspeed.value * 1024.0); + bytes_sent = 0; + bytes_received = 0; + } + else + curltime = realtime; + + if (curl_mutex) Thread_UnlockMutex(curl_mutex); +} + +/* +==================== +Curl_CancelAll + +Stops ALL downloads. +==================== +*/ +void Curl_CancelAll(void) +{ + if(!curl_dll) + return; + + if (curl_mutex) Thread_LockMutex(curl_mutex); + + while(downloads) + { + Curl_EndDownload(downloads, CURL_DOWNLOAD_ABORTED, CURLE_OK, NULL); + // INVARIANT: downloads will point to the next download after that! + } + + if (curl_mutex) Thread_UnlockMutex(curl_mutex); +} + +/* +==================== +Curl_Running + +returns true iff there is a download running. +==================== +*/ +qboolean Curl_Running(void) +{ + if(!curl_dll) + return false; + + return downloads != NULL; +} + +/* +==================== +Curl_GetDownloadAmount + +returns a value from 0.0 to 1.0 which represents the downloaded amount of data +for the given download. +==================== +*/ +static double Curl_GetDownloadAmount(downloadinfo *di) +{ + if(!curl_dll) + return -2; + if(di->curle) + { + double length; + qcurl_easy_getinfo(di->curle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length); + if(length > 0) + return (di->startpos + di->bytes_received) / (di->startpos + length); + else + return 0; + } + else + return -1; +} + +/* +==================== +Curl_GetDownloadSpeed + +returns the speed of the given download in bytes per second +==================== +*/ +static double Curl_GetDownloadSpeed(downloadinfo *di) +{ + if(!curl_dll) + return -2; + if(di->curle) + { + double speed; + qcurl_easy_getinfo(di->curle, CURLINFO_SPEED_DOWNLOAD, &speed); + return speed; + } + else + return -1; +} + +/* +==================== +Curl_Info_f + +prints the download list +==================== +*/ +// TODO rewrite using Curl_GetDownloadInfo? +static void Curl_Info_f(void) +{ + downloadinfo *di; + char urlbuf[1024]; + if(!curl_dll) + return; + if(Curl_Running()) + { + if (curl_mutex) Thread_LockMutex(curl_mutex); + Con_Print("Currently running downloads:\n"); + for(di = downloads; di; di = di->next) + { + double speed, percent; + Con_Printf(" %s -> %s ", CleanURL(di->url, urlbuf, sizeof(urlbuf)), di->filename); + percent = 100.0 * Curl_GetDownloadAmount(di); + speed = Curl_GetDownloadSpeed(di); + if(percent >= 0) + Con_Printf("(%.1f%% @ %.1f KiB/s)\n", percent, speed / 1024.0); + else + Con_Print("(queued)\n"); + } + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + } + else + { + Con_Print("No downloads running.\n"); + } +} + +/* +==================== +Curl_Curl_f + +implements the "curl" console command + +curl --info +curl --cancel +curl --cancel filename +curl url + +For internal use: + +curl [--pak] [--forthismap] [--for filename filename...] url + --pak: after downloading, load the package into the virtual file system + --for filename...: only download of at least one of the named files is missing + --forthismap: don't reconnect on failure + +curl --clear_autodownload + clears the download success/failure counters + +curl --finish_autodownload + if at least one download has been started, disconnect and drop to the menu + once the last download completes successfully, reconnect to the current server +==================== +*/ +static void Curl_Curl_f(void) +{ + double maxspeed = 0; + int i; + int end; + int loadtype = LOADTYPE_NONE; + qboolean forthismap = false; + const char *url; + const char *name = 0; + + if(!curl_dll) + { + Con_Print("libcurl DLL not found, this command is inactive.\n"); + return; + } + + if(!cl_curl_enabled.integer) + { + Con_Print("curl support not enabled. Set cl_curl_enabled to 1 to enable.\n"); + return; + } + + if(Cmd_Argc() < 2) + { + Con_Print("usage:\ncurl --info, curl --cancel [filename], curl url\n"); + return; + } + + url = Cmd_Argv(Cmd_Argc() - 1); + end = Cmd_Argc(); + + for(i = 1; i != end; ++i) + { + const char *a = Cmd_Argv(i); + if(!strcmp(a, "--info")) + { + Curl_Info_f(); + return; + } + else if(!strcmp(a, "--cancel")) + { + if(i == end - 1) // last argument + Curl_CancelAll(); + else + { + downloadinfo *di = Curl_Find(url); + if(di) + Curl_EndDownload(di, CURL_DOWNLOAD_ABORTED, CURLE_OK, NULL); + else + Con_Print("download not found\n"); + } + return; + } + else if(!strcmp(a, "--pak")) + { + loadtype = LOADTYPE_PAK; + } + else if(!strcmp(a, "--cachepic")) + { + loadtype = LOADTYPE_CACHEPIC; + } + else if(!strcmp(a, "--skinframe")) + { + loadtype = LOADTYPE_SKINFRAME; + } + else if(!strcmp(a, "--for")) // must be last option + { + for(i = i + 1; i != end - 1; ++i) + { + if(!FS_FileExists(Cmd_Argv(i))) + goto needthefile; // why can't I have a "double break"? + } + // if we get here, we have all the files... + return; + } + else if(!strcmp(a, "--forthismap")) + { + forthismap = true; + } + else if(!strcmp(a, "--as")) + { + if(i < end - 1) + { + ++i; + name = Cmd_Argv(i); + } + } + else if(!strcmp(a, "--clear_autodownload")) + { + // mark all running downloads as "not for this map", so if they + // fail, it does not matter + Curl_Clear_forthismap(); + return; + } + else if(!strcmp(a, "--finish_autodownload")) + { + if(numdownloads_added) + { + char donecommand[256]; + if(cls.netcon) + { + if(cl.loadbegun) // curling won't inhibit loading the map any more when at this stage, so bail out and force a reconnect + { + dpsnprintf(donecommand, sizeof(donecommand), "connect %s", cls.netcon->address); + Curl_CommandWhenDone(donecommand); + noclear = TRUE; + CL_Disconnect(); + noclear = FALSE; + Curl_CheckCommandWhenDone(); + } + else + Curl_Register_predownload(); + } + } + return; + } + else if(!strncmp(a, "--maxspeed=", 11)) + { + maxspeed = atof(a + 11); + } + else if(*a == '-') + { + Con_Printf("curl: invalid option %s\n", a); + // but we ignore the option + } + } + +needthefile: + Curl_Begin_ToFile(url, maxspeed, name, loadtype, forthismap); +} + +/* +static void curl_curlcat_callback(int code, size_t length_received, unsigned char *buffer, void *cbdata) +{ + Con_Printf("Received %d bytes (status %d):\n%.*s\n", (int) length_received, code, (int) length_received, buffer); + Z_Free(buffer); +} + +void Curl_CurlCat_f(void) +{ + unsigned char *buf; + const char *url = Cmd_Argv(1); + buf = Z_Malloc(16384); + Curl_Begin_ToMemory(url, buf, 16384, curl_curlcat_callback, NULL); +} +*/ + +/* +==================== +Curl_Init_Commands + +loads the commands and cvars this library uses +==================== +*/ +void Curl_Init_Commands(void) +{ + Cvar_RegisterVariable (&cl_curl_enabled); + Cvar_RegisterVariable (&cl_curl_maxdownloads); + Cvar_RegisterVariable (&cl_curl_maxspeed); + Cvar_RegisterVariable (&sv_curl_defaulturl); + Cvar_RegisterVariable (&sv_curl_serverpackages); + Cvar_RegisterVariable (&sv_curl_maxspeed); + Cvar_RegisterVariable (&cl_curl_useragent); + Cvar_RegisterVariable (&cl_curl_useragent_append); + Cmd_AddCommand ("curl", Curl_Curl_f, "download data from an URL and add to search path"); + //Cmd_AddCommand ("curlcat", Curl_CurlCat_f, "display data from an URL (debugging command)"); +} + +/* +==================== +Curl_GetDownloadInfo + +returns an array of Curl_downloadinfo_t structs for usage by GUIs. +The number of elements in the array is returned in int *nDownloads. +const char **additional_info may be set to a string of additional user +information, or to NULL if no such display shall occur. The returned +array must be freed later using Z_Free. +==================== +*/ +Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **additional_info, char *addinfo, size_t addinfolength) +{ + int i; + downloadinfo *di; + Curl_downloadinfo_t *downinfo; + + if(!curl_dll) + { + *nDownloads = 0; + if(additional_info) + *additional_info = NULL; + return NULL; + } + + if (curl_mutex) Thread_LockMutex(curl_mutex); + + i = 0; + for(di = downloads; di; di = di->next) + ++i; + + downinfo = (Curl_downloadinfo_t *) Z_Malloc(sizeof(*downinfo) * i); + i = 0; + for(di = downloads; di; di = di->next) + { + // do not show infobars for background downloads + if(developer.integer <= 0) + if(di->buffer) + continue; + strlcpy(downinfo[i].filename, di->filename, sizeof(downinfo[i].filename)); + if(di->curle) + { + downinfo[i].progress = Curl_GetDownloadAmount(di); + downinfo[i].speed = Curl_GetDownloadSpeed(di); + downinfo[i].queued = false; + } + else + { + downinfo[i].queued = true; + } + ++i; + } + + if(additional_info) + { + // TODO: can I clear command_when_done as soon as the first download fails? + if(*command_when_done && !numdownloads_fail && numdownloads_added) + { + if(!strncmp(command_when_done, "connect ", 8)) + dpsnprintf(addinfo, addinfolength, "(will join %s when done)", command_when_done + 8); + else if(!strcmp(command_when_done, "cl_begindownloads")) + dpsnprintf(addinfo, addinfolength, "(will enter the game when done)"); + else + dpsnprintf(addinfo, addinfolength, "(will do '%s' when done)", command_when_done); + *additional_info = addinfo; + } + else + *additional_info = NULL; + } + + *nDownloads = i; + if (curl_mutex) Thread_UnlockMutex(curl_mutex); + return downinfo; +} + + +/* +==================== +Curl_FindPackURL + +finds the URL where to find a given package. + +For this, it reads a file "curl_urls.txt" of the following format: + + data*.pk3 - + revdm*.pk3 http://revdm/downloads/are/here/ + * http://any/other/stuff/is/here/ + +The URLs should end in /. If not, downloads will still work, but the cached files +can't be just put into the data directory with the same download configuration +(you might want to do this if you want to tag downloaded files from your +server, but you should not). "-" means "don't download". + +If no single pattern matched, the cvar sv_curl_defaulturl is used as download +location instead. + +Note: pak1.pak and data*.pk3 are excluded from autodownload at another point in +this file for obvious reasons. +==================== +*/ +static const char *Curl_FindPackURL(const char *filename) +{ + static char foundurl[1024]; // invoked only by server + fs_offset_t filesize; + char *buf = (char *) FS_LoadFile("curl_urls.txt", tempmempool, true, &filesize); + if(buf && filesize) + { + // read lines of format "pattern url" + char *p = buf; + char *pattern = NULL, *patternend = NULL, *url = NULL, *urlend = NULL; + qboolean eof = false; + + pattern = p; + while(!eof) + { + switch(*p) + { + case 0: + eof = true; + // fallthrough + case '\n': + case '\r': + if(pattern && url && patternend) + { + if(!urlend) + urlend = p; + *patternend = 0; + *urlend = 0; + if(matchpattern(filename, pattern, true)) + { + strlcpy(foundurl, url, sizeof(foundurl)); + Z_Free(buf); + return foundurl; + } + } + pattern = NULL; + patternend = NULL; + url = NULL; + urlend = NULL; + break; + case ' ': + case '\t': + if(pattern && !patternend) + patternend = p; + else if(url && !urlend) + urlend = p; + break; + default: + if(!pattern) + pattern = p; + else if(pattern && patternend && !url) + url = p; + break; + } + ++p; + } + } + if(buf) + Z_Free(buf); + return sv_curl_defaulturl.string; +} + +typedef struct requirement_s +{ + struct requirement_s *next; + char filename[MAX_OSPATH]; +} +requirement; +static requirement *requirements = NULL; + + +/* +==================== +Curl_RequireFile + +Adds the given file to the list of requirements. +==================== +*/ +void Curl_RequireFile(const char *filename) +{ + requirement *req = (requirement *) Z_Malloc(sizeof(*requirements)); + req->next = requirements; + strlcpy(req->filename, filename, sizeof(req->filename)); + requirements = req; +} + +/* +==================== +Curl_ClearRequirements + +Clears the list of required files for playing on the current map. +This should be called at every map change. +==================== +*/ +void Curl_ClearRequirements(void) +{ + while(requirements) + { + requirement *req = requirements; + requirements = requirements->next; + Z_Free(req); + } +} + +/* +==================== +Curl_SendRequirements + +Makes the current host_clients download all files he needs. +This is done by sending him the following console commands: + + curl --clear_autodownload + curl --pak --for maps/pushmoddm1.bsp --forthismap http://where/this/darn/map/is/pushmoddm1.pk3 + curl --finish_autodownload +==================== +*/ +static qboolean Curl_SendRequirement(const char *filename, qboolean foundone, char *sendbuffer, size_t sendbuffer_len) +{ + const char *p; + const char *thispack = FS_WhichPack(filename); + const char *packurl; + + if(!thispack) + return false; + + p = strrchr(thispack, '/'); + if(p) + thispack = p + 1; + + packurl = Curl_FindPackURL(thispack); + + if(packurl && *packurl && strcmp(packurl, "-")) + { + if(!foundone) + strlcat(sendbuffer, "curl --clear_autodownload\n", sendbuffer_len); + + strlcat(sendbuffer, "curl --pak --forthismap --as ", sendbuffer_len); + strlcat(sendbuffer, thispack, sendbuffer_len); + if(sv_curl_maxspeed.value > 0) + dpsnprintf(sendbuffer + strlen(sendbuffer), sendbuffer_len - strlen(sendbuffer), " --maxspeed=%.1f", sv_curl_maxspeed.value); + strlcat(sendbuffer, " --for ", sendbuffer_len); + strlcat(sendbuffer, filename, sendbuffer_len); + strlcat(sendbuffer, " ", sendbuffer_len); + strlcat(sendbuffer, packurl, sendbuffer_len); + strlcat(sendbuffer, thispack, sendbuffer_len); + strlcat(sendbuffer, "\n", sendbuffer_len); + + return true; + } + + return false; +} +void Curl_SendRequirements(void) +{ + // for each requirement, find the pack name + char sendbuffer[4096] = ""; + requirement *req; + qboolean foundone = false; + const char *p; + + for(req = requirements; req; req = req->next) + foundone = Curl_SendRequirement(req->filename, foundone, sendbuffer, sizeof(sendbuffer)) || foundone; + + p = sv_curl_serverpackages.string; + while(COM_ParseToken_Simple(&p, false, false, true)) + foundone = Curl_SendRequirement(com_token, foundone, sendbuffer, sizeof(sendbuffer)) || foundone; + + if(foundone) + strlcat(sendbuffer, "curl --finish_autodownload\n", sizeof(sendbuffer)); + + if(strlen(sendbuffer) + 1 < sizeof(sendbuffer)) + Host_ClientCommands("%s", sendbuffer); + else + Con_Printf("Could not initiate autodownload due to URL buffer overflow\n"); +} diff --git a/app/jni/libcurl.h b/app/jni/libcurl.h new file mode 100644 index 0000000..c01aed3 --- /dev/null +++ b/app/jni/libcurl.h @@ -0,0 +1,44 @@ +enum +{ + CURLCBSTATUS_OK = 0, + CURLCBSTATUS_FAILED = -1, // failed for generic reason (e.g. buffer too small) + CURLCBSTATUS_ABORTED = -2, // aborted by curl --cancel + CURLCBSTATUS_SERVERERROR = -3, // only used if no HTTP status code is available + CURLCBSTATUS_UNKNOWN = -4 // should never happen +}; +typedef void (*curl_callback_t) (int status, size_t length_received, unsigned char *buffer, void *cbdata); +// code is one of the CURLCBSTATUS constants, or the HTTP error code (when > 0). + +void Curl_Run(void); +qboolean Curl_Running(void); +qboolean Curl_Begin_ToFile(const char *URL, double maxspeed, const char *name, int loadtype, qboolean forthismap); + +qboolean Curl_Begin_ToMemory(const char *URL, double maxspeed, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata); +qboolean Curl_Begin_ToMemory_POST(const char *URL, const char *extraheaders, double maxspeed, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata); + +void Curl_Init(void); +void Curl_Init_Commands(void); +void Curl_Shutdown(void); +void Curl_CancelAll(void); +void Curl_Clear_forthismap(void); +qboolean Curl_Have_forthismap(void); +void Curl_Register_predownload(void); + +void Curl_ClearRequirements(void); +void Curl_RequireFile(const char *filename); +void Curl_SendRequirements(void); + +typedef struct Curl_downloadinfo_s +{ + char filename[MAX_QPATH]; + double progress; + double speed; + qboolean queued; +} +Curl_downloadinfo_t; +Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **additional_info, char *addinfo, size_t addinfolength); + // this may and should be Z_Free()ed + // the result is actually an array + // an additional info string may be returned in additional_info as a + // pointer to a static string (but the argument may be NULL if the caller + // does not care) diff --git a/app/jni/mathlib.c b/app/jni/mathlib.c new file mode 100644 index 0000000..60cc04b --- /dev/null +++ b/app/jni/mathlib.c @@ -0,0 +1,805 @@ +/* +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 + +#include "quakedef.h" + +#include + +vec3_t vec3_origin = {0,0,0}; +float ixtable[4096]; + +/*-----------------------------------------------------------------*/ + +float m_bytenormals[NUMVERTEXNORMALS][3] = +{ +{-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, {0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, {0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, {-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, {0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, {-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, {-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, {0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, {-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, {-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, {-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, {-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, {-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, {-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, {-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, {0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, {0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, {0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, {0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, {-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, {-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, {-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, {-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, {-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, {-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, {-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, {-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, {-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, {-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, {-0.688191, -0.587785, -0.425325}, +}; + +#if 0 +unsigned char NormalToByte(const vec3_t n) +{ + int i, best; + float bestdistance, distance; + + best = 0; + bestdistance = DotProduct (n, m_bytenormals[0]); + for (i = 1;i < NUMVERTEXNORMALS;i++) + { + distance = DotProduct (n, m_bytenormals[i]); + if (distance > bestdistance) + { + bestdistance = distance; + best = i; + } + } + return best; +} + +// note: uses byte partly to force unsigned for the validity check +void ByteToNormal(unsigned char num, vec3_t n) +{ + if (num < NUMVERTEXNORMALS) + VectorCopy(m_bytenormals[num], n); + else + VectorClear(n); // FIXME: complain? +} + +// assumes "src" is normalized +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + // LordHavoc: optimized to death and beyond + int pos; + float minelem; + + if (src[0]) + { + dst[0] = 0; + if (src[1]) + { + dst[1] = 0; + if (src[2]) + { + dst[2] = 0; + pos = 0; + minelem = fabs(src[0]); + if (fabs(src[1]) < minelem) + { + pos = 1; + minelem = fabs(src[1]); + } + if (fabs(src[2]) < minelem) + pos = 2; + + dst[pos] = 1; + dst[0] -= src[pos] * src[0]; + dst[1] -= src[pos] * src[1]; + dst[2] -= src[pos] * src[2]; + + // normalize the result + VectorNormalize(dst); + } + else + dst[2] = 1; + } + else + { + dst[1] = 1; + dst[2] = 0; + } + } + else + { + dst[0] = 1; + dst[1] = 0; + dst[2] = 0; + } +} +#endif + + +// LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful! +void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up) +{ + // NOTE: this is consistent to AngleVectors applied to AnglesFromVectors + if (forward[0] == 0 && forward[1] == 0) + { + if(forward[2] > 0) + { + VectorSet(right, 0, -1, 0); + VectorSet(up, -1, 0, 0); + } + else + { + VectorSet(right, 0, -1, 0); + VectorSet(up, 1, 0, 0); + } + } + else + { + right[0] = forward[1]; + right[1] = -forward[0]; + right[2] = 0; + VectorNormalize(right); + + up[0] = (-forward[2]*forward[0]); + up[1] = (-forward[2]*forward[1]); + up[2] = (forward[0]*forward[0] + forward[1]*forward[1]); + VectorNormalize(up); + } +} + +void VectorVectorsDouble(const double *forward, double *right, double *up) +{ + if (forward[0] == 0 && forward[1] == 0) + { + if(forward[2] > 0) + { + VectorSet(right, 0, -1, 0); + VectorSet(up, -1, 0, 0); + } + else + { + VectorSet(right, 0, -1, 0); + VectorSet(up, 1, 0, 0); + } + } + else + { + right[0] = forward[1]; + right[1] = -forward[0]; + right[2] = 0; + VectorNormalize(right); + + up[0] = (-forward[2]*forward[0]); + up[1] = (-forward[2]*forward[1]); + up[2] = (forward[0]*forward[0] + forward[1]*forward[1]); + VectorNormalize(up); + } +} + +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) +{ + float t0, t1; + float angle, c, s; + vec3_t vr, vu, vf; + + angle = DEG2RAD(degrees); + c = cos(angle); + s = sin(angle); + VectorCopy(dir, vf); + VectorVectors(vf, vr, vu); + + t0 = vr[0] * c + vu[0] * -s; + t1 = vr[0] * s + vu[0] * c; + dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2]; + + t0 = vr[1] * c + vu[1] * -s; + t1 = vr[1] * s + vu[1] * c; + dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2]; + + t0 = vr[2] * c + vu[2] * -s; + t1 = vr[2] * s + vu[2] * c; + dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0] + + (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1] + + (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2]; +} + +/*-----------------------------------------------------------------*/ + +// returns the smallest integer greater than or equal to "value", or 0 if "value" is too big +unsigned int CeilPowerOf2(unsigned int value) +{ + unsigned int ceilvalue; + + if (value > (1U << (sizeof(int) * 8 - 1))) + return 0; + + ceilvalue = 1; + while (ceilvalue < value) + ceilvalue <<= 1; + + return ceilvalue; +} + + +/*-----------------------------------------------------------------*/ + + +void PlaneClassify(mplane_t *p) +{ + // for optimized plane comparisons + if (p->normal[0] == 1) + p->type = 0; + else if (p->normal[1] == 1) + p->type = 1; + else if (p->normal[2] == 1) + p->type = 2; + else + p->type = 3; + // for BoxOnPlaneSide + p->signbits = 0; + if (p->normal[0] < 0) // 1 + p->signbits |= 1; + if (p->normal[1] < 0) // 2 + p->signbits |= 2; + if (p->normal[2] < 0) // 4 + p->signbits |= 4; +} + +int BoxOnPlaneSide(const vec3_t emins, const vec3_t emaxs, const mplane_t *p) +{ + if (p->type < 3) + return ((emaxs[p->type] >= p->dist) | ((emins[p->type] < p->dist) << 1)); + switch(p->signbits) + { + default: + case 0: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1)); + case 1: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) < p->dist) << 1)); + case 2: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1)); + case 3: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) < p->dist) << 1)); + case 4: return (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1)); + case 5: return (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]) < p->dist) << 1)); + case 6: return (((p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1)); + case 7: return (((p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]) >= p->dist) | (((p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]) < p->dist) << 1)); + } +} + +#if 0 +int BoxOnPlaneSide_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, const vec_t dist) +{ + switch((normal[0] < 0) | ((normal[1] < 0) << 1) | ((normal[2] < 0) << 2)) + { + default: + case 0: return (((normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2]) >= dist) | (((normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emins[2]) < dist) << 1)); + case 1: return (((normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2]) >= dist) | (((normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emins[2]) < dist) << 1)); + case 2: return (((normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emaxs[2]) >= dist) | (((normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emins[2]) < dist) << 1)); + case 3: return (((normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emaxs[2]) >= dist) | (((normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emins[2]) < dist) << 1)); + case 4: return (((normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emins[2]) >= dist) | (((normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emaxs[2]) < dist) << 1)); + case 5: return (((normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emins[2]) >= dist) | (((normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emaxs[2]) < dist) << 1)); + case 6: return (((normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emins[2]) >= dist) | (((normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2]) < dist) << 1)); + case 7: return (((normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emins[2]) >= dist) | (((normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2]) < dist) << 1)); + } +} +#endif + +void BoxPlaneCorners(const vec3_t emins, const vec3_t emaxs, const mplane_t *p, vec3_t outnear, vec3_t outfar) +{ + if (p->type < 3) + { + outnear[0] = outnear[1] = outnear[2] = outfar[0] = outfar[1] = outfar[2] = 0; + outnear[p->type] = emins[p->type]; + outfar[p->type] = emaxs[p->type]; + return; + } + switch(p->signbits) + { + default: + case 0: outnear[0] = emaxs[0];outnear[1] = emaxs[1];outnear[2] = emaxs[2];outfar[0] = emins[0];outfar[1] = emins[1];outfar[2] = emins[2];break; + case 1: outnear[0] = emins[0];outnear[1] = emaxs[1];outnear[2] = emaxs[2];outfar[0] = emaxs[0];outfar[1] = emins[1];outfar[2] = emins[2];break; + case 2: outnear[0] = emaxs[0];outnear[1] = emins[1];outnear[2] = emaxs[2];outfar[0] = emins[0];outfar[1] = emaxs[1];outfar[2] = emins[2];break; + case 3: outnear[0] = emins[0];outnear[1] = emins[1];outnear[2] = emaxs[2];outfar[0] = emaxs[0];outfar[1] = emaxs[1];outfar[2] = emins[2];break; + case 4: outnear[0] = emaxs[0];outnear[1] = emaxs[1];outnear[2] = emins[2];outfar[0] = emins[0];outfar[1] = emins[1];outfar[2] = emaxs[2];break; + case 5: outnear[0] = emins[0];outnear[1] = emaxs[1];outnear[2] = emins[2];outfar[0] = emaxs[0];outfar[1] = emins[1];outfar[2] = emaxs[2];break; + case 6: outnear[0] = emaxs[0];outnear[1] = emins[1];outnear[2] = emins[2];outfar[0] = emins[0];outfar[1] = emaxs[1];outfar[2] = emaxs[2];break; + case 7: outnear[0] = emins[0];outnear[1] = emins[1];outnear[2] = emins[2];outfar[0] = emaxs[0];outfar[1] = emaxs[1];outfar[2] = emaxs[2];break; + } +} + +void BoxPlaneCorners_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, vec3_t outnear, vec3_t outfar) +{ + switch((normal[0] < 0) | ((normal[1] < 0) << 1) | ((normal[2] < 0) << 2)) + { + default: + case 0: outnear[0] = emaxs[0];outnear[1] = emaxs[1];outnear[2] = emaxs[2];outfar[0] = emins[0];outfar[1] = emins[1];outfar[2] = emins[2];break; + case 1: outnear[0] = emins[0];outnear[1] = emaxs[1];outnear[2] = emaxs[2];outfar[0] = emaxs[0];outfar[1] = emins[1];outfar[2] = emins[2];break; + case 2: outnear[0] = emaxs[0];outnear[1] = emins[1];outnear[2] = emaxs[2];outfar[0] = emins[0];outfar[1] = emaxs[1];outfar[2] = emins[2];break; + case 3: outnear[0] = emins[0];outnear[1] = emins[1];outnear[2] = emaxs[2];outfar[0] = emaxs[0];outfar[1] = emaxs[1];outfar[2] = emins[2];break; + case 4: outnear[0] = emaxs[0];outnear[1] = emaxs[1];outnear[2] = emins[2];outfar[0] = emins[0];outfar[1] = emins[1];outfar[2] = emaxs[2];break; + case 5: outnear[0] = emins[0];outnear[1] = emaxs[1];outnear[2] = emins[2];outfar[0] = emaxs[0];outfar[1] = emins[1];outfar[2] = emaxs[2];break; + case 6: outnear[0] = emaxs[0];outnear[1] = emins[1];outnear[2] = emins[2];outfar[0] = emins[0];outfar[1] = emaxs[1];outfar[2] = emaxs[2];break; + case 7: outnear[0] = emins[0];outnear[1] = emins[1];outnear[2] = emins[2];outfar[0] = emaxs[0];outfar[1] = emaxs[1];outfar[2] = emaxs[2];break; + } +} + +void BoxPlaneCornerDistances(const vec3_t emins, const vec3_t emaxs, const mplane_t *p, vec_t *outneardist, vec_t *outfardist) +{ + if (p->type < 3) + { + *outneardist = emins[p->type] - p->dist; + *outfardist = emaxs[p->type] - p->dist; + return; + } + switch(p->signbits) + { + default: + case 0: *outneardist = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2] - p->dist;*outfardist = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2] - p->dist;break; + case 1: *outneardist = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2] - p->dist;*outfardist = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2] - p->dist;break; + case 2: *outneardist = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2] - p->dist;*outfardist = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2] - p->dist;break; + case 3: *outneardist = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2] - p->dist;*outfardist = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2] - p->dist;break; + case 4: *outneardist = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2] - p->dist;*outfardist = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2] - p->dist;break; + case 5: *outneardist = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2] - p->dist;*outfardist = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2] - p->dist;break; + case 6: *outneardist = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2] - p->dist;*outfardist = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2] - p->dist;break; + case 7: *outneardist = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2] - p->dist;*outfardist = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2] - p->dist;break; + } +} + +void BoxPlaneCornerDistances_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, vec_t *outneardist, vec_t *outfardist) +{ + switch((normal[0] < 0) | ((normal[1] < 0) << 1) | ((normal[2] < 0) << 2)) + { + default: + case 0: *outneardist = normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2];*outfardist = normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emins[2];break; + case 1: *outneardist = normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2];*outfardist = normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emins[2];break; + case 2: *outneardist = normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emaxs[2];*outfardist = normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emins[2];break; + case 3: *outneardist = normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emaxs[2];*outfardist = normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emins[2];break; + case 4: *outneardist = normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emins[2];*outfardist = normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emaxs[2];break; + case 5: *outneardist = normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emins[2];*outfardist = normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emaxs[2];break; + case 6: *outneardist = normal[0] * emaxs[0] + normal[1] * emins[1] + normal[2] * emins[2];*outfardist = normal[0] * emins[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2];break; + case 7: *outneardist = normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emins[2];*outfardist = normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2];break; + } +} + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + double angle, sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right || up) + { + if (angles[ROLL]) + { + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + if (right) + { + right[0] = -1*(sr*sp*cy+cr*-sy); + right[1] = -1*(sr*sp*sy+cr*cy); + right[2] = -1*(sr*cp); + } + if (up) + { + up[0] = (cr*sp*cy+-sr*-sy); + up[1] = (cr*sp*sy+-sr*cy); + up[2] = cr*cp; + } + } + else + { + if (right) + { + right[0] = sy; + right[1] = -cy; + right[2] = 0; + } + if (up) + { + up[0] = (sp*cy); + up[1] = (sp*sy); + up[2] = cp; + } + } + } +} + +void AngleVectorsFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up) +{ + double angle, sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (left || up) + { + if (angles[ROLL]) + { + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + if (left) + { + left[0] = sr*sp*cy+cr*-sy; + left[1] = sr*sp*sy+cr*cy; + left[2] = sr*cp; + } + if (up) + { + up[0] = cr*sp*cy+-sr*-sy; + up[1] = cr*sp*sy+-sr*cy; + up[2] = cr*cp; + } + } + else + { + if (left) + { + left[0] = -sy; + left[1] = cy; + left[2] = 0; + } + if (up) + { + up[0] = sp*cy; + up[1] = sp*sy; + up[2] = cp; + } + } + } +} + +// LordHavoc: calculates pitch/yaw/roll angles from forward and up vectors +void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qboolean flippitch) +{ + if (forward[0] == 0 && forward[1] == 0) + { + if(forward[2] > 0) + { + angles[PITCH] = -M_PI * 0.5; + angles[YAW] = up ? atan2(-up[1], -up[0]) : 0; + } + else + { + angles[PITCH] = M_PI * 0.5; + angles[YAW] = up ? atan2(up[1], up[0]) : 0; + } + angles[ROLL] = 0; + } + else + { + angles[YAW] = atan2(forward[1], forward[0]); + angles[PITCH] = -atan2(forward[2], sqrt(forward[0]*forward[0] + forward[1]*forward[1])); + // note: we know that angles[PITCH] is in ]-pi/2..pi/2[ due to atan2(anything, positive) + if (up) + { + vec_t cp = cos(angles[PITCH]), sp = sin(angles[PITCH]); + // note: we know cp > 0, due to the range angles[pitch] is in + vec_t cy = cos(angles[YAW]), sy = sin(angles[YAW]); + vec3_t tleft, tup; + tleft[0] = -sy; + tleft[1] = cy; + tleft[2] = 0; + tup[0] = sp*cy; + tup[1] = sp*sy; + tup[2] = cp; + angles[ROLL] = -atan2(DotProduct(up, tleft), DotProduct(up, tup)); + // for up == '0 0 1', this is + // angles[ROLL] = -atan2(0, cp); + // which is 0 + } + else + angles[ROLL] = 0; + + // so no up vector is equivalent to '1 0 0'! + } + + // now convert radians to degrees, and make all values positive + VectorScale(angles, 180.0 / M_PI, angles); + if (flippitch) + angles[PITCH] *= -1; + if (angles[PITCH] < 0) angles[PITCH] += 360; + if (angles[YAW] < 0) angles[YAW] += 360; + if (angles[ROLL] < 0) angles[ROLL] += 360; + +#if 0 +{ + // debugging code + vec3_t tforward, tleft, tup, nforward, nup; + VectorCopy(forward, nforward); + VectorNormalize(nforward); + if (up) + { + VectorCopy(up, nup); + VectorNormalize(nup); + AngleVectors(angles, tforward, tleft, tup); + if (VectorDistance(tforward, nforward) > 0.01 || VectorDistance(tup, nup) > 0.01) + { + Con_Printf("vectoangles('%f %f %f', '%f %f %f') = %f %f %f\n", nforward[0], nforward[1], nforward[2], nup[0], nup[1], nup[2], angles[0], angles[1], angles[2]); + Con_Printf("^3But that is '%f %f %f', '%f %f %f'\n", tforward[0], tforward[1], tforward[2], tup[0], tup[1], tup[2]); + } + } + else + { + AngleVectors(angles, tforward, tleft, tup); + if (VectorDistance(tforward, nforward) > 0.01) + { + Con_Printf("vectoangles('%f %f %f') = %f %f %f\n", nforward[0], nforward[1], nforward[2], angles[0], angles[1], angles[2]); + Con_Printf("^3But that is '%f %f %f'\n", tforward[0], tforward[1], tforward[2]); + } + } +} +#endif +} + +#if 0 +void AngleMatrix (const vec3_t angles, const vec3_t translate, vec_t matrix[][4]) +{ + double angle, sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + matrix[0][0] = cp*cy; + matrix[0][1] = sr*sp*cy+cr*-sy; + matrix[0][2] = cr*sp*cy+-sr*-sy; + matrix[0][3] = translate[0]; + matrix[1][0] = cp*sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[1][2] = cr*sp*sy+-sr*cy; + matrix[1][3] = translate[1]; + matrix[2][0] = -sp; + matrix[2][1] = sr*cp; + matrix[2][2] = cr*cp; + matrix[2][3] = translate[2]; +} +#endif + + +// LordHavoc: renamed this to Length, and made the normal one a #define +float VectorNormalizeLength (vec3_t v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = sqrt (length); + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + + +/* +================ +R_ConcatRotations +================ +*/ +void R_ConcatRotations (const float in1[3*3], const float in2[3*3], float out[3*3]) +{ + out[0*3+0] = in1[0*3+0] * in2[0*3+0] + in1[0*3+1] * in2[1*3+0] + in1[0*3+2] * in2[2*3+0]; + out[0*3+1] = in1[0*3+0] * in2[0*3+1] + in1[0*3+1] * in2[1*3+1] + in1[0*3+2] * in2[2*3+1]; + out[0*3+2] = in1[0*3+0] * in2[0*3+2] + in1[0*3+1] * in2[1*3+2] + in1[0*3+2] * in2[2*3+2]; + out[1*3+0] = in1[1*3+0] * in2[0*3+0] + in1[1*3+1] * in2[1*3+0] + in1[1*3+2] * in2[2*3+0]; + out[1*3+1] = in1[1*3+0] * in2[0*3+1] + in1[1*3+1] * in2[1*3+1] + in1[1*3+2] * in2[2*3+1]; + out[1*3+2] = in1[1*3+0] * in2[0*3+2] + in1[1*3+1] * in2[1*3+2] + in1[1*3+2] * in2[2*3+2]; + out[2*3+0] = in1[2*3+0] * in2[0*3+0] + in1[2*3+1] * in2[1*3+0] + in1[2*3+2] * in2[2*3+0]; + out[2*3+1] = in1[2*3+0] * in2[0*3+1] + in1[2*3+1] * in2[1*3+1] + in1[2*3+2] * in2[2*3+1]; + out[2*3+2] = in1[2*3+0] * in2[0*3+2] + in1[2*3+1] * in2[1*3+2] + in1[2*3+2] * in2[2*3+2]; +} + + +/* +================ +R_ConcatTransforms +================ +*/ +void R_ConcatTransforms (const float in1[3*4], const float in2[3*4], float out[3*4]) +{ + out[0*4+0] = in1[0*4+0] * in2[0*4+0] + in1[0*4+1] * in2[1*4+0] + in1[0*4+2] * in2[2*4+0]; + out[0*4+1] = in1[0*4+0] * in2[0*4+1] + in1[0*4+1] * in2[1*4+1] + in1[0*4+2] * in2[2*4+1]; + out[0*4+2] = in1[0*4+0] * in2[0*4+2] + in1[0*4+1] * in2[1*4+2] + in1[0*4+2] * in2[2*4+2]; + out[0*4+3] = in1[0*4+0] * in2[0*4+3] + in1[0*4+1] * in2[1*4+3] + in1[0*4+2] * in2[2*4+3] + in1[0*4+3]; + out[1*4+0] = in1[1*4+0] * in2[0*4+0] + in1[1*4+1] * in2[1*4+0] + in1[1*4+2] * in2[2*4+0]; + out[1*4+1] = in1[1*4+0] * in2[0*4+1] + in1[1*4+1] * in2[1*4+1] + in1[1*4+2] * in2[2*4+1]; + out[1*4+2] = in1[1*4+0] * in2[0*4+2] + in1[1*4+1] * in2[1*4+2] + in1[1*4+2] * in2[2*4+2]; + out[1*4+3] = in1[1*4+0] * in2[0*4+3] + in1[1*4+1] * in2[1*4+3] + in1[1*4+2] * in2[2*4+3] + in1[1*4+3]; + out[2*4+0] = in1[2*4+0] * in2[0*4+0] + in1[2*4+1] * in2[1*4+0] + in1[2*4+2] * in2[2*4+0]; + out[2*4+1] = in1[2*4+0] * in2[0*4+1] + in1[2*4+1] * in2[1*4+1] + in1[2*4+2] * in2[2*4+1]; + out[2*4+2] = in1[2*4+0] * in2[0*4+2] + in1[2*4+1] * in2[1*4+2] + in1[2*4+2] * in2[2*4+2]; + out[2*4+3] = in1[2*4+0] * in2[0*4+3] + in1[2*4+1] * in2[1*4+3] + in1[2*4+2] * in2[2*4+3] + in1[2*4+3]; +} + +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs) +{ + vec3_t m1, m2; + VectorMultiply(mins, mins, m1); + VectorMultiply(maxs, maxs, m2); + return sqrt(max(m1[0], m2[0]) + max(m1[1], m2[1]) + max(m1[2], m2[2])); +} + +float RadiusFromBoundsAndOrigin (const vec3_t mins, const vec3_t maxs, const vec3_t origin) +{ + vec3_t m1, m2; + VectorSubtract(mins, origin, m1);VectorMultiply(m1, m1, m1); + VectorSubtract(maxs, origin, m2);VectorMultiply(m2, m2, m2); + return sqrt(max(m1[0], m2[0]) + max(m1[1], m2[1]) + max(m1[2], m2[2])); +} + +void Mathlib_Init(void) +{ + int a; + + // LordHavoc: setup 1.0f / N table for quick recipricols of integers + ixtable[0] = 0; + for (a = 1;a < 4096;a++) + ixtable[a] = 1.0f / a; +} + +#include "matrixlib.h" + +void Matrix4x4_Print(const matrix4x4_t *in) +{ + Con_Printf("%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" + , in->m[0][0], in->m[0][1], in->m[0][2], in->m[0][3] + , in->m[1][0], in->m[1][1], in->m[1][2], in->m[1][3] + , in->m[2][0], in->m[2][1], in->m[2][2], in->m[2][3] + , in->m[3][0], in->m[3][1], in->m[3][2], in->m[3][3]); +} + +int Math_atov(const char *s, prvm_vec3_t out) +{ + int i; + VectorClear(out); + if (*s == '\'') + s++; + for (i = 0;i < 3;i++) + { + while (*s == ' ' || *s == '\t') + s++; + out[i] = atof (s); + if (out[i] == 0 && *s != '-' && *s != '+' && (*s < '0' || *s > '9')) + break; // not a number + while (*s && *s != ' ' && *s !='\t' && *s != '\'') + s++; + if (*s == '\'') + break; + } + return i; +} + +void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f) +{ + int i; + VectorCopy(point3f, mins); + VectorCopy(point3f, maxs); + for (i = 1, point3f += 3;i < numpoints;i++, point3f += 3) + { + mins[0] = min(mins[0], point3f[0]);maxs[0] = max(maxs[0], point3f[0]); + mins[1] = min(mins[1], point3f[1]);maxs[1] = max(maxs[1], point3f[1]); + mins[2] = min(mins[2], point3f[2]);maxs[2] = max(maxs[2], point3f[2]); + } +} + +// LordHavoc: this has to be done right or you get severe precision breakdown +int LoopingFrameNumberFromDouble(double t, int loopframes) +{ + if (loopframes) + return (int)(t - floor(t/loopframes)*loopframes); + else + return (int)t; +} + diff --git a/app/jni/mathlib.h b/app/jni/mathlib.h new file mode 100644 index 0000000..9a9cd73 --- /dev/null +++ b/app/jni/mathlib.h @@ -0,0 +1,305 @@ +/* +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 + +#include "qtypes.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +struct mplane_s; +extern vec3_t vec3_origin; + +#define float_nanmask (0x7F800000) +#define double_nanmask (0x7FF8000000000000) +#define FLOAT_IS_NAN(x) (((*(int *)&x)&float_nanmask)==float_nanmask) +#define DOUBLE_IS_NAN(x) (((*(long long *)&x)&double_nanmask)==double_nanmask) + +#ifdef VEC_64 +#define VEC_IS_NAN(x) DOUBLE_IS_NAN(x) +#else +#define VEC_IS_NAN(x) FLOAT_IS_NAN(x) +#endif + +#ifdef PRVM_64 +#define PRVM_IS_NAN(x) DOUBLE_IS_NAN(x) +#else +#define PRVM_IS_NAN(x) FLOAT_IS_NAN(x) +#endif + +#define bound(min,num,max) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min)) + +#ifndef min +#define min(A,B) ((A) < (B) ? (A) : (B)) +#define max(A,B) ((A) > (B) ? (A) : (B)) +#endif + +/// LordHavoc: this function never returns exactly MIN or exactly MAX, because +/// of a QuakeC bug in id1 where the line +/// self.nextthink = self.nexthink + random() * 0.5; +/// can result in 0 (self.nextthink is 0 at this point in the code to begin +/// with), causing "stone monsters" that never spawned properly, also MAX is +/// avoided because some people use random() as an index into arrays or for +/// loop conditions, where hitting exactly MAX may be a fatal error +#define lhrandom(MIN,MAX) (((double)(rand() + 0.5) / ((double)RAND_MAX + 1)) * ((MAX)-(MIN)) + (MIN)) + +#define invpow(base,number) (log(number) / log(base)) + +/// returns log base 2 of "n" +/// \WARNING: "n" MUST be a power of 2! +#define log2i(n) ((((n) & 0xAAAAAAAA) != 0 ? 1 : 0) | (((n) & 0xCCCCCCCC) != 0 ? 2 : 0) | (((n) & 0xF0F0F0F0) != 0 ? 4 : 0) | (((n) & 0xFF00FF00) != 0 ? 8 : 0) | (((n) & 0xFFFF0000) != 0 ? 16 : 0)) + +/// \TODO: what is this function supposed to do? +#define bit2i(n) log2i((n) << 1) + +/// boolean XOR (why doesn't C have the ^^ operator for this purpose?) +#define boolxor(a,b) (!(a) != !(b)) + +/// returns the smallest integer greater than or equal to "value", or 0 if "value" is too big +unsigned int CeilPowerOf2(unsigned int value); + +#define DEG2RAD(a) ((a) * ((float) M_PI / 180.0f)) +#define RAD2DEG(a) ((a) * (180.0f / (float) M_PI)) +#define ANGLEMOD(a) ((a) - 360.0 * floor((a) / 360.0)) + +#define DotProduct2(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]) +#define Vector2Clear(a) ((a)[0]=(a)[1]=0) +#define Vector2Compare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])) +#define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) +#define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1])) +#define Vector2Set(a,b,c) ((a)[0]=(b),(a)[1]=(c)) +#define Vector2Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale)) +#define Vector2Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct2((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;} + +#define DotProduct4(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]+(a)[3]*(b)[3]) +#define Vector4Clear(a) ((a)[0]=(a)[1]=(a)[2]=(a)[3]=0) +#define Vector4Compare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])&&((a)[2]==(b)[2])&&((a)[3]==(b)[3])) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define Vector4Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2]),(b)[3]=-((a)[3])) +#define Vector4Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d),(a)[3]=(e)) +#define Vector4Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct4((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;dest[2] = (v)[2] * ilength;dest[3] = (v)[3] * ilength;} +#define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale)) +#define Vector4Multiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2],(c)[3]=(a)[3]*(b)[3]) +#define Vector4MA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2],(c)[3] = (a)[3] + (scale) * (b)[3]) +#define Vector4Lerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]), (c)[3] = (v1)[3] + (lerp) * ((v2)[3] - (v1)[3])) + +#define VectorNegate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1]),(b)[2]=-((a)[2])) +#define VectorSet(a,b,c,d) ((a)[0]=(b),(a)[1]=(c),(a)[2]=(d)) +#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[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]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +#define VectorMultiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2]) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) +#define VectorNormalize(v) {float ilength = (float) sqrt(DotProduct((v),(v)));if (ilength) ilength = 1.0f / ilength;(v)[0] *= ilength;(v)[1] *= ilength;(v)[2] *= ilength;} +#define VectorNormalize2(v,dest) {float ilength = (float) sqrt(DotProduct((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;dest[2] = (v)[2] * ilength;} +#define VectorNormalizeDouble(v) {double ilength = sqrt(DotProduct((v),(v)));if (ilength) ilength = 1.0 / ilength;(v)[0] *= ilength;(v)[1] *= ilength;(v)[2] *= ilength;} +#define VectorDistance2(a, b) (((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) + ((a)[2] - (b)[2]) * ((a)[2] - (b)[2])) +#define VectorDistance(a, b) (sqrt(VectorDistance2(a,b))) +#define VectorLength(a) (sqrt((double)DotProduct(a, a))) +#define VectorLength2(a) (DotProduct(a, a)) +#define VectorScale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale)) +#define VectorScaleCast(in, scale, outtype, out) ((out)[0] = (outtype) ((in)[0] * (scale)),(out)[1] = (outtype) ((in)[1] * (scale)),(out)[2] = (outtype) ((in)[2] * (scale))) +#define VectorCompare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])&&((a)[2]==(b)[2])) +#define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2]) +#define VectorM(scale1, b1, c) ((c)[0] = (scale1) * (b1)[0],(c)[1] = (scale1) * (b1)[1],(c)[2] = (scale1) * (b1)[2]) +#define VectorMAM(scale1, b1, scale2, b2, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2]) +#define VectorMAMAM(scale1, b1, scale2, b2, scale3, b3, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2]) +#define VectorMAMAMAM(scale1, b1, scale2, b2, scale3, b3, scale4, b4, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0] + (scale4) * (b4)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1] + (scale4) * (b4)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2] + (scale4) * (b4)[2]) +#define VectorRandom(v) do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1) +#define VectorLerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2])) +#define VectorReflect(a,r,b,c) do{double d;d = DotProduct((a), (b)) * -(1.0 + (r));VectorMA((a), (d), (b), (c));}while(0) +#define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2]) +#define BoxInsideBox(a,b,c,d) ((a)[0] >= (c)[0] && (b)[0] <= (d)[0] && (a)[1] >= (c)[1] && (b)[1] <= (d)[1] && (a)[2] >= (c)[2] && (b)[2] <= (d)[2]) +#define TriangleBBoxOverlapsBox(a,b,c,d,e) (min((a)[0], min((b)[0], (c)[0])) < (e)[0] && max((a)[0], max((b)[0], (c)[0])) > (d)[0] && min((a)[1], min((b)[1], (c)[1])) < (e)[1] && max((a)[1], max((b)[1], (c)[1])) > (d)[1] && min((a)[2], min((b)[2], (c)[2])) < (e)[2] && max((a)[2], max((b)[2], (c)[2])) > (d)[2]) + +#define TriangleNormal(a,b,c,n) ( \ + (n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), \ + (n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), \ + (n)[2] = ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0]) \ + ) + +/*! Fast PointInfrontOfTriangle. + * subtracts v1 from v0 and v2, combined into a crossproduct, combined with a + * dotproduct of the light location relative to the first point of the + * triangle (any point works, since any triangle is obviously flat), and + * finally a comparison to determine if the light is infront of the triangle + * (the goal of this statement) we do not need to normalize the surface + * normal because both sides of the comparison use it, therefore they are + * both multiplied the same amount... furthermore a subtract can be done on + * the point to eliminate one dotproduct + * this is ((p - a) * cross(a-b,c-b)) + */ +#define PointInfrontOfTriangle(p,a,b,c) \ +( ((p)[0] - (a)[0]) * (((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1])) \ ++ ((p)[1] - (a)[1]) * (((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2])) \ ++ ((p)[2] - (a)[2]) * (((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0])) > 0) + +#if 0 +// readable version, kept only for explanatory reasons +int PointInfrontOfTriangle(const float *p, const float *a, const float *b, const float *c) +{ + float dir0[3], dir1[3], normal[3]; + + // calculate two mostly perpendicular edge directions + VectorSubtract(a, b, dir0); + VectorSubtract(c, b, dir1); + + // we have two edge directions, we can calculate a third vector from + // them, which is the direction of the surface normal (its magnitude + // is not 1 however) + CrossProduct(dir0, dir1, normal); + + // compare distance of light along normal, with distance of any point + // of the triangle along the same normal (the triangle is planar, + // I.E. flat, so all points give the same answer) + return DotProduct(p, normal) > DotProduct(a, normal); +} +#endif + +#define lhcheeserand() (seed = (seed * 987211u) ^ (seed >> 13u) ^ 914867) +#define lhcheeserandom(MIN,MAX) ((double)(lhcheeserand() + 0.5) / ((double)4096.0*1024.0*1024.0) * ((MAX)-(MIN)) + (MIN)) +#define VectorCheeseRandom(v) do{(v)[0] = lhcheeserandom(-1, 1);(v)[1] = lhcheeserandom(-1, 1);(v)[2] = lhcheeserandom(-1, 1);}while(DotProduct(v, v) > 1) + +/* +// LordHavoc: quaternion math, untested, don't know if these are correct, +// need to add conversion to/from matrices +// LordHavoc: later note: the matrix faq is useful: http://skal.planet-d.net/demo/matrixfaq.htm +// LordHavoc: these are probably very wrong and I'm not sure I care, not used by anything + +// returns length of quaternion +#define qlen(a) ((float) sqrt((a)[0]*(a)[0]+(a)[1]*(a)[1]+(a)[2]*(a)[2]+(a)[3]*(a)[3])) +// returns squared length of quaternion +#define qlen2(a) ((a)[0]*(a)[0]+(a)[1]*(a)[1]+(a)[2]*(a)[2]+(a)[3]*(a)[3]) +// makes a quaternion from x, y, z, and a rotation angle (in degrees) +#define QuatMake(x,y,z,r,c)\ +{\ +if (r == 0)\ +{\ +(c)[0]=(float) ((x) * (1.0f / 0.0f));\ +(c)[1]=(float) ((y) * (1.0f / 0.0f));\ +(c)[2]=(float) ((z) * (1.0f / 0.0f));\ +(c)[3]=(float) 1.0f;\ +}\ +else\ +{\ +float r2 = (r) * 0.5 * (M_PI / 180);\ +float r2is = 1.0f / sin(r2);\ +(c)[0]=(float) ((x)/r2is);\ +(c)[1]=(float) ((y)/r2is);\ +(c)[2]=(float) ((z)/r2is);\ +(c)[3]=(float) (cos(r2));\ +}\ +} +// makes a quaternion from a vector and a rotation angle (in degrees) +#define QuatFromVec(a,r,c) QuatMake((a)[0],(a)[1],(a)[2],(r)) +// copies a quaternion +#define QuatCopy(a,c) {(c)[0]=(a)[0];(c)[1]=(a)[1];(c)[2]=(a)[2];(c)[3]=(a)[3];} +#define QuatSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];(c)[3]=(a)[3]-(b)[3];} +#define QuatAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];(c)[3]=(a)[3]+(b)[3];} +#define QuatScale(a,b,c) {(c)[0]=(a)[0]*b;(c)[1]=(a)[1]*b;(c)[2]=(a)[2]*b;(c)[3]=(a)[3]*b;} +// FIXME: this is wrong, do some more research on quaternions +//#define QuatMultiply(a,b,c) {(c)[0]=(a)[0]*(b)[0];(c)[1]=(a)[1]*(b)[1];(c)[2]=(a)[2]*(b)[2];(c)[3]=(a)[3]*(b)[3];} +// FIXME: this is wrong, do some more research on quaternions +//#define QuatMultiplyAdd(a,b,d,c) {(c)[0]=(a)[0]*(b)[0]+d[0];(c)[1]=(a)[1]*(b)[1]+d[1];(c)[2]=(a)[2]*(b)[2]+d[2];(c)[3]=(a)[3]*(b)[3]+d[3];} +#define qdist(a,b) ((float) sqrt(((b)[0]-(a)[0])*((b)[0]-(a)[0])+((b)[1]-(a)[1])*((b)[1]-(a)[1])+((b)[2]-(a)[2])*((b)[2]-(a)[2])+((b)[3]-(a)[3])*((b)[3]-(a)[3]))) +#define qdist2(a,b) (((b)[0]-(a)[0])*((b)[0]-(a)[0])+((b)[1]-(a)[1])*((b)[1]-(a)[1])+((b)[2]-(a)[2])*((b)[2]-(a)[2])+((b)[3]-(a)[3])*((b)[3]-(a)[3])) +*/ + +#define VectorCopy4(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];(b)[3]=(a)[3];} + +vec_t Length (vec3_t v); + +/// returns vector length +float VectorNormalizeLength (vec3_t v); + +/// returns vector length +float VectorNormalizeLength2 (vec3_t v, vec3_t dest); + +#define NUMVERTEXNORMALS 162 +extern float m_bytenormals[NUMVERTEXNORMALS][3]; + +unsigned char NormalToByte(const vec3_t n); +void ByteToNormal(unsigned char num, vec3_t n); + +void R_ConcatRotations (const float in1[3*3], const float in2[3*3], float out[3*3]); +void R_ConcatTransforms (const float in1[3*4], const float in2[3*4], float out[3*4]); + +void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +/// LordHavoc: proper matrix version of AngleVectors +void AngleVectorsFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up); +/// LordHavoc: builds a [3][4] matrix +void AngleMatrix (const vec3_t angles, const vec3_t translate, vec_t matrix[][4]); +/// LordHavoc: calculates pitch/yaw/roll angles from forward and up vectors +void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qboolean flippitch); + +/// LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful! +void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up); +void VectorVectorsDouble(const double *forward, double *right, double *up); + +void PlaneClassify(struct mplane_s *p); +int BoxOnPlaneSide(const vec3_t emins, const vec3_t emaxs, const struct mplane_s *p); +int BoxOnPlaneSide_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, const vec_t dist); +void BoxPlaneCorners(const vec3_t emins, const vec3_t emaxs, const struct mplane_s *p, vec3_t outnear, vec3_t outfar); +void BoxPlaneCorners_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, vec3_t outnear, vec3_t outfar); +void BoxPlaneCornerDistances(const vec3_t emins, const vec3_t emaxs, const struct mplane_s *p, vec_t *outnear, vec_t *outfar); +void BoxPlaneCornerDistances_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, vec_t *outnear, vec_t *outfar); + +#define PlaneDist(point,plane) ((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) +#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) + +/// LordHavoc: minimal plane structure +typedef struct tinyplane_s +{ + float normal[3], dist; +} +tinyplane_t; + +typedef struct tinydoubleplane_s +{ + double normal[3], dist; +} +tinydoubleplane_t; + +void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); + +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs); +float RadiusFromBoundsAndOrigin (const vec3_t mins, const vec3_t maxs, const vec3_t origin); + +struct matrix4x4_s; +/// print a matrix to the console +void Matrix4x4_Print(const struct matrix4x4_s *in); +int Math_atov(const char *s, prvm_vec3_t out); + +void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f); + +int LoopingFrameNumberFromDouble(double t, int loopframes); + +void Mathlib_Init(void); + +#endif + diff --git a/app/jni/matrixlib.c b/app/jni/matrixlib.c new file mode 100644 index 0000000..78c859c --- /dev/null +++ b/app/jni/matrixlib.c @@ -0,0 +1,1825 @@ +#include "quakedef.h" + +#include +#include "matrixlib.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4244) // LordHavoc: MSVC++ 4 x86, double/float +#pragma warning(disable : 4305) // LordHavoc: MSVC++ 6 x86, double/float +#endif + +const matrix4x4_t identitymatrix = +{ + { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1} + } +}; + +void Matrix4x4_Copy (matrix4x4_t *out, const matrix4x4_t *in) +{ + *out = *in; +} + +void Matrix4x4_CopyRotateOnly (matrix4x4_t *out, const matrix4x4_t *in) +{ + out->m[0][0] = in->m[0][0]; + out->m[0][1] = in->m[0][1]; + out->m[0][2] = in->m[0][2]; + out->m[0][3] = 0.0f; + out->m[1][0] = in->m[1][0]; + out->m[1][1] = in->m[1][1]; + out->m[1][2] = in->m[1][2]; + out->m[1][3] = 0.0f; + out->m[2][0] = in->m[2][0]; + out->m[2][1] = in->m[2][1]; + out->m[2][2] = in->m[2][2]; + out->m[2][3] = 0.0f; + out->m[3][0] = 0.0f; + out->m[3][1] = 0.0f; + out->m[3][2] = 0.0f; + out->m[3][3] = 1.0f; +} + +void Matrix4x4_CopyTranslateOnly (matrix4x4_t *out, const matrix4x4_t *in) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = 1.0f; + out->m[1][0] = 0.0f; + out->m[2][0] = 0.0f; + out->m[3][0] = in->m[0][3]; + out->m[0][1] = 0.0f; + out->m[1][1] = 1.0f; + out->m[2][1] = 0.0f; + out->m[3][1] = in->m[1][3]; + out->m[0][2] = 0.0f; + out->m[1][2] = 0.0f; + out->m[2][2] = 1.0f; + out->m[3][2] = in->m[2][3]; + out->m[0][3] = 0.0f; + out->m[1][3] = 0.0f; + out->m[2][3] = 0.0f; + out->m[3][3] = 1.0f; +#else + out->m[0][0] = 1.0f; + out->m[0][1] = 0.0f; + out->m[0][2] = 0.0f; + out->m[0][3] = in->m[0][3]; + out->m[1][0] = 0.0f; + out->m[1][1] = 1.0f; + out->m[1][2] = 0.0f; + out->m[1][3] = in->m[1][3]; + out->m[2][0] = 0.0f; + out->m[2][1] = 0.0f; + out->m[2][2] = 1.0f; + out->m[2][3] = in->m[2][3]; + out->m[3][0] = 0.0f; + out->m[3][1] = 0.0f; + out->m[3][2] = 0.0f; + out->m[3][3] = 1.0f; +#endif +} + +void Matrix4x4_Concat (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in1->m[0][0] * in2->m[0][0] + in1->m[1][0] * in2->m[0][1] + in1->m[2][0] * in2->m[0][2] + in1->m[3][0] * in2->m[0][3]; + out->m[1][0] = in1->m[0][0] * in2->m[1][0] + in1->m[1][0] * in2->m[1][1] + in1->m[2][0] * in2->m[1][2] + in1->m[3][0] * in2->m[1][3]; + out->m[2][0] = in1->m[0][0] * in2->m[2][0] + in1->m[1][0] * in2->m[2][1] + in1->m[2][0] * in2->m[2][2] + in1->m[3][0] * in2->m[2][3]; + out->m[3][0] = in1->m[0][0] * in2->m[3][0] + in1->m[1][0] * in2->m[3][1] + in1->m[2][0] * in2->m[3][2] + in1->m[3][0] * in2->m[3][3]; + out->m[0][1] = in1->m[0][1] * in2->m[0][0] + in1->m[1][1] * in2->m[0][1] + in1->m[2][1] * in2->m[0][2] + in1->m[3][1] * in2->m[0][3]; + out->m[1][1] = in1->m[0][1] * in2->m[1][0] + in1->m[1][1] * in2->m[1][1] + in1->m[2][1] * in2->m[1][2] + in1->m[3][1] * in2->m[1][3]; + out->m[2][1] = in1->m[0][1] * in2->m[2][0] + in1->m[1][1] * in2->m[2][1] + in1->m[2][1] * in2->m[2][2] + in1->m[3][1] * in2->m[2][3]; + out->m[3][1] = in1->m[0][1] * in2->m[3][0] + in1->m[1][1] * in2->m[3][1] + in1->m[2][1] * in2->m[3][2] + in1->m[3][1] * in2->m[3][3]; + out->m[0][2] = in1->m[0][2] * in2->m[0][0] + in1->m[1][2] * in2->m[0][1] + in1->m[2][2] * in2->m[0][2] + in1->m[3][2] * in2->m[0][3]; + out->m[1][2] = in1->m[0][2] * in2->m[1][0] + in1->m[1][2] * in2->m[1][1] + in1->m[2][2] * in2->m[1][2] + in1->m[3][2] * in2->m[1][3]; + out->m[2][2] = in1->m[0][2] * in2->m[2][0] + in1->m[1][2] * in2->m[2][1] + in1->m[2][2] * in2->m[2][2] + in1->m[3][2] * in2->m[2][3]; + out->m[3][2] = in1->m[0][2] * in2->m[3][0] + in1->m[1][2] * in2->m[3][1] + in1->m[2][2] * in2->m[3][2] + in1->m[3][2] * in2->m[3][3]; + out->m[0][3] = in1->m[0][3] * in2->m[0][0] + in1->m[1][3] * in2->m[0][1] + in1->m[2][3] * in2->m[0][2] + in1->m[3][3] * in2->m[0][3]; + out->m[1][3] = in1->m[0][3] * in2->m[1][0] + in1->m[1][3] * in2->m[1][1] + in1->m[2][3] * in2->m[1][2] + in1->m[3][3] * in2->m[1][3]; + out->m[2][3] = in1->m[0][3] * in2->m[2][0] + in1->m[1][3] * in2->m[2][1] + in1->m[2][3] * in2->m[2][2] + in1->m[3][3] * in2->m[2][3]; + out->m[3][3] = in1->m[0][3] * in2->m[3][0] + in1->m[1][3] * in2->m[3][1] + in1->m[2][3] * in2->m[3][2] + in1->m[3][3] * in2->m[3][3]; +#else + out->m[0][0] = in1->m[0][0] * in2->m[0][0] + in1->m[0][1] * in2->m[1][0] + in1->m[0][2] * in2->m[2][0] + in1->m[0][3] * in2->m[3][0]; + out->m[0][1] = in1->m[0][0] * in2->m[0][1] + in1->m[0][1] * in2->m[1][1] + in1->m[0][2] * in2->m[2][1] + in1->m[0][3] * in2->m[3][1]; + out->m[0][2] = in1->m[0][0] * in2->m[0][2] + in1->m[0][1] * in2->m[1][2] + in1->m[0][2] * in2->m[2][2] + in1->m[0][3] * in2->m[3][2]; + out->m[0][3] = in1->m[0][0] * in2->m[0][3] + in1->m[0][1] * in2->m[1][3] + in1->m[0][2] * in2->m[2][3] + in1->m[0][3] * in2->m[3][3]; + out->m[1][0] = in1->m[1][0] * in2->m[0][0] + in1->m[1][1] * in2->m[1][0] + in1->m[1][2] * in2->m[2][0] + in1->m[1][3] * in2->m[3][0]; + out->m[1][1] = in1->m[1][0] * in2->m[0][1] + in1->m[1][1] * in2->m[1][1] + in1->m[1][2] * in2->m[2][1] + in1->m[1][3] * in2->m[3][1]; + out->m[1][2] = in1->m[1][0] * in2->m[0][2] + in1->m[1][1] * in2->m[1][2] + in1->m[1][2] * in2->m[2][2] + in1->m[1][3] * in2->m[3][2]; + out->m[1][3] = in1->m[1][0] * in2->m[0][3] + in1->m[1][1] * in2->m[1][3] + in1->m[1][2] * in2->m[2][3] + in1->m[1][3] * in2->m[3][3]; + out->m[2][0] = in1->m[2][0] * in2->m[0][0] + in1->m[2][1] * in2->m[1][0] + in1->m[2][2] * in2->m[2][0] + in1->m[2][3] * in2->m[3][0]; + out->m[2][1] = in1->m[2][0] * in2->m[0][1] + in1->m[2][1] * in2->m[1][1] + in1->m[2][2] * in2->m[2][1] + in1->m[2][3] * in2->m[3][1]; + out->m[2][2] = in1->m[2][0] * in2->m[0][2] + in1->m[2][1] * in2->m[1][2] + in1->m[2][2] * in2->m[2][2] + in1->m[2][3] * in2->m[3][2]; + out->m[2][3] = in1->m[2][0] * in2->m[0][3] + in1->m[2][1] * in2->m[1][3] + in1->m[2][2] * in2->m[2][3] + in1->m[2][3] * in2->m[3][3]; + out->m[3][0] = in1->m[3][0] * in2->m[0][0] + in1->m[3][1] * in2->m[1][0] + in1->m[3][2] * in2->m[2][0] + in1->m[3][3] * in2->m[3][0]; + out->m[3][1] = in1->m[3][0] * in2->m[0][1] + in1->m[3][1] * in2->m[1][1] + in1->m[3][2] * in2->m[2][1] + in1->m[3][3] * in2->m[3][1]; + out->m[3][2] = in1->m[3][0] * in2->m[0][2] + in1->m[3][1] * in2->m[1][2] + in1->m[3][2] * in2->m[2][2] + in1->m[3][3] * in2->m[3][2]; + out->m[3][3] = in1->m[3][0] * in2->m[0][3] + in1->m[3][1] * in2->m[1][3] + in1->m[3][2] * in2->m[2][3] + in1->m[3][3] * in2->m[3][3]; +#endif +} + +void Matrix4x4_Transpose (matrix4x4_t *out, const matrix4x4_t *in1) +{ + out->m[0][0] = in1->m[0][0]; + out->m[0][1] = in1->m[1][0]; + out->m[0][2] = in1->m[2][0]; + out->m[0][3] = in1->m[3][0]; + out->m[1][0] = in1->m[0][1]; + out->m[1][1] = in1->m[1][1]; + out->m[1][2] = in1->m[2][1]; + out->m[1][3] = in1->m[3][1]; + out->m[2][0] = in1->m[0][2]; + out->m[2][1] = in1->m[1][2]; + out->m[2][2] = in1->m[2][2]; + out->m[2][3] = in1->m[3][2]; + out->m[3][0] = in1->m[0][3]; + out->m[3][1] = in1->m[1][3]; + out->m[3][2] = in1->m[2][3]; + out->m[3][3] = in1->m[3][3]; +} + +#if 1 +// Adapted from code contributed to Mesa by David Moore (Mesa 7.6 under SGI Free License B - which is MIT/X11-type) +// added helper for common subexpression elimination by eihrul, and other optimizations by div0 +int Matrix4x4_Invert_Full (matrix4x4_t *out, const matrix4x4_t *in1) +{ + float det; + + // note: orientation does not matter, as transpose(invert(transpose(m))) == invert(m), proof: + // transpose(invert(transpose(m))) * m + // = transpose(invert(transpose(m))) * transpose(transpose(m)) + // = transpose(transpose(m) * invert(transpose(m))) + // = transpose(identity) + // = identity + + // this seems to help gcc's common subexpression elimination, and also makes the code look nicer + float m00 = in1->m[0][0], m01 = in1->m[0][1], m02 = in1->m[0][2], m03 = in1->m[0][3], + m10 = in1->m[1][0], m11 = in1->m[1][1], m12 = in1->m[1][2], m13 = in1->m[1][3], + m20 = in1->m[2][0], m21 = in1->m[2][1], m22 = in1->m[2][2], m23 = in1->m[2][3], + m30 = in1->m[3][0], m31 = in1->m[3][1], m32 = in1->m[3][2], m33 = in1->m[3][3]; + + // calculate the adjoint + out->m[0][0] = (m11*(m22*m33 - m23*m32) - m21*(m12*m33 - m13*m32) + m31*(m12*m23 - m13*m22)); + out->m[0][1] = -(m01*(m22*m33 - m23*m32) - m21*(m02*m33 - m03*m32) + m31*(m02*m23 - m03*m22)); + out->m[0][2] = (m01*(m12*m33 - m13*m32) - m11*(m02*m33 - m03*m32) + m31*(m02*m13 - m03*m12)); + out->m[0][3] = -(m01*(m12*m23 - m13*m22) - m11*(m02*m23 - m03*m22) + m21*(m02*m13 - m03*m12)); + out->m[1][0] = -(m10*(m22*m33 - m23*m32) - m20*(m12*m33 - m13*m32) + m30*(m12*m23 - m13*m22)); + out->m[1][1] = (m00*(m22*m33 - m23*m32) - m20*(m02*m33 - m03*m32) + m30*(m02*m23 - m03*m22)); + out->m[1][2] = -(m00*(m12*m33 - m13*m32) - m10*(m02*m33 - m03*m32) + m30*(m02*m13 - m03*m12)); + out->m[1][3] = (m00*(m12*m23 - m13*m22) - m10*(m02*m23 - m03*m22) + m20*(m02*m13 - m03*m12)); + out->m[2][0] = (m10*(m21*m33 - m23*m31) - m20*(m11*m33 - m13*m31) + m30*(m11*m23 - m13*m21)); + out->m[2][1] = -(m00*(m21*m33 - m23*m31) - m20*(m01*m33 - m03*m31) + m30*(m01*m23 - m03*m21)); + out->m[2][2] = (m00*(m11*m33 - m13*m31) - m10*(m01*m33 - m03*m31) + m30*(m01*m13 - m03*m11)); + out->m[2][3] = -(m00*(m11*m23 - m13*m21) - m10*(m01*m23 - m03*m21) + m20*(m01*m13 - m03*m11)); + out->m[3][0] = -(m10*(m21*m32 - m22*m31) - m20*(m11*m32 - m12*m31) + m30*(m11*m22 - m12*m21)); + out->m[3][1] = (m00*(m21*m32 - m22*m31) - m20*(m01*m32 - m02*m31) + m30*(m01*m22 - m02*m21)); + out->m[3][2] = -(m00*(m11*m32 - m12*m31) - m10*(m01*m32 - m02*m31) + m30*(m01*m12 - m02*m11)); + out->m[3][3] = (m00*(m11*m22 - m12*m21) - m10*(m01*m22 - m02*m21) + m20*(m01*m12 - m02*m11)); + + // calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det) + det = m00*out->m[0][0] + m10*out->m[0][1] + m20*out->m[0][2] + m30*out->m[0][3]; + if (det == 0.0f) + return 0; + + // multiplications are faster than divisions, usually + det = 1.0f / det; + + // manually unrolled loop to multiply all matrix elements by 1/det + out->m[0][0] *= det; out->m[0][1] *= det; out->m[0][2] *= det; out->m[0][3] *= det; + out->m[1][0] *= det; out->m[1][1] *= det; out->m[1][2] *= det; out->m[1][3] *= det; + out->m[2][0] *= det; out->m[2][1] *= det; out->m[2][2] *= det; out->m[2][3] *= det; + out->m[3][0] *= det; out->m[3][1] *= det; out->m[3][2] *= det; out->m[3][3] *= det; + + return 1; +} +#elif 1 +// Adapted from code contributed to Mesa by David Moore (Mesa 7.6 under SGI Free License B - which is MIT/X11-type) +int Matrix4x4_Invert_Full (matrix4x4_t *out, const matrix4x4_t *in1) +{ + matrix4x4_t temp; + double det; + int i, j; + +#ifdef MATRIX4x4_OPENGLORIENTATION + temp.m[0][0] = in1->m[1][1]*in1->m[2][2]*in1->m[3][3] - in1->m[1][1]*in1->m[2][3]*in1->m[3][2] - in1->m[2][1]*in1->m[1][2]*in1->m[3][3] + in1->m[2][1]*in1->m[1][3]*in1->m[3][2] + in1->m[3][1]*in1->m[1][2]*in1->m[2][3] - in1->m[3][1]*in1->m[1][3]*in1->m[2][2]; + temp.m[1][0] = -in1->m[1][0]*in1->m[2][2]*in1->m[3][3] + in1->m[1][0]*in1->m[2][3]*in1->m[3][2] + in1->m[2][0]*in1->m[1][2]*in1->m[3][3] - in1->m[2][0]*in1->m[1][3]*in1->m[3][2] - in1->m[3][0]*in1->m[1][2]*in1->m[2][3] + in1->m[3][0]*in1->m[1][3]*in1->m[2][2]; + temp.m[2][0] = in1->m[1][0]*in1->m[2][1]*in1->m[3][3] - in1->m[1][0]*in1->m[2][3]*in1->m[3][1] - in1->m[2][0]*in1->m[1][1]*in1->m[3][3] + in1->m[2][0]*in1->m[1][3]*in1->m[3][1] + in1->m[3][0]*in1->m[1][1]*in1->m[2][3] - in1->m[3][0]*in1->m[1][3]*in1->m[2][1]; + temp.m[3][0] = -in1->m[1][0]*in1->m[2][1]*in1->m[3][2] + in1->m[1][0]*in1->m[2][2]*in1->m[3][1] + in1->m[2][0]*in1->m[1][1]*in1->m[3][2] - in1->m[2][0]*in1->m[1][2]*in1->m[3][1] - in1->m[3][0]*in1->m[1][1]*in1->m[2][2] + in1->m[3][0]*in1->m[1][2]*in1->m[2][1]; + temp.m[0][1] = -in1->m[0][1]*in1->m[2][2]*in1->m[3][3] + in1->m[0][1]*in1->m[2][3]*in1->m[3][2] + in1->m[2][1]*in1->m[0][2]*in1->m[3][3] - in1->m[2][1]*in1->m[0][3]*in1->m[3][2] - in1->m[3][1]*in1->m[0][2]*in1->m[2][3] + in1->m[3][1]*in1->m[0][3]*in1->m[2][2]; + temp.m[1][1] = in1->m[0][0]*in1->m[2][2]*in1->m[3][3] - in1->m[0][0]*in1->m[2][3]*in1->m[3][2] - in1->m[2][0]*in1->m[0][2]*in1->m[3][3] + in1->m[2][0]*in1->m[0][3]*in1->m[3][2] + in1->m[3][0]*in1->m[0][2]*in1->m[2][3] - in1->m[3][0]*in1->m[0][3]*in1->m[2][2]; + temp.m[2][1] = -in1->m[0][0]*in1->m[2][1]*in1->m[3][3] + in1->m[0][0]*in1->m[2][3]*in1->m[3][1] + in1->m[2][0]*in1->m[0][1]*in1->m[3][3] - in1->m[2][0]*in1->m[0][3]*in1->m[3][1] - in1->m[3][0]*in1->m[0][1]*in1->m[2][3] + in1->m[3][0]*in1->m[0][3]*in1->m[2][1]; + temp.m[3][1] = in1->m[0][0]*in1->m[2][1]*in1->m[3][2] - in1->m[0][0]*in1->m[2][2]*in1->m[3][1] - in1->m[2][0]*in1->m[0][1]*in1->m[3][2] + in1->m[2][0]*in1->m[0][2]*in1->m[3][1] + in1->m[3][0]*in1->m[0][1]*in1->m[2][2] - in1->m[3][0]*in1->m[0][2]*in1->m[2][1]; + temp.m[0][2] = in1->m[0][1]*in1->m[1][2]*in1->m[3][3] - in1->m[0][1]*in1->m[1][3]*in1->m[3][2] - in1->m[1][1]*in1->m[0][2]*in1->m[3][3] + in1->m[1][1]*in1->m[0][3]*in1->m[3][2] + in1->m[3][1]*in1->m[0][2]*in1->m[1][3] - in1->m[3][1]*in1->m[0][3]*in1->m[1][2]; + temp.m[1][2] = -in1->m[0][0]*in1->m[1][2]*in1->m[3][3] + in1->m[0][0]*in1->m[1][3]*in1->m[3][2] + in1->m[1][0]*in1->m[0][2]*in1->m[3][3] - in1->m[1][0]*in1->m[0][3]*in1->m[3][2] - in1->m[3][0]*in1->m[0][2]*in1->m[1][3] + in1->m[3][0]*in1->m[0][3]*in1->m[1][2]; + temp.m[2][2] = in1->m[0][0]*in1->m[1][1]*in1->m[3][3] - in1->m[0][0]*in1->m[1][3]*in1->m[3][1] - in1->m[1][0]*in1->m[0][1]*in1->m[3][3] + in1->m[1][0]*in1->m[0][3]*in1->m[3][1] + in1->m[3][0]*in1->m[0][1]*in1->m[1][3] - in1->m[3][0]*in1->m[0][3]*in1->m[1][1]; + temp.m[3][2] = -in1->m[0][0]*in1->m[1][1]*in1->m[3][2] + in1->m[0][0]*in1->m[1][2]*in1->m[3][1] + in1->m[1][0]*in1->m[0][1]*in1->m[3][2] - in1->m[1][0]*in1->m[0][2]*in1->m[3][1] - in1->m[3][0]*in1->m[0][1]*in1->m[1][2] + in1->m[3][0]*in1->m[0][2]*in1->m[1][1]; + temp.m[0][3] = -in1->m[0][1]*in1->m[1][2]*in1->m[2][3] + in1->m[0][1]*in1->m[1][3]*in1->m[2][2] + in1->m[1][1]*in1->m[0][2]*in1->m[2][3] - in1->m[1][1]*in1->m[0][3]*in1->m[2][2] - in1->m[2][1]*in1->m[0][2]*in1->m[1][3] + in1->m[2][1]*in1->m[0][3]*in1->m[1][2]; + temp.m[1][3] = in1->m[0][0]*in1->m[1][2]*in1->m[2][3] - in1->m[0][0]*in1->m[1][3]*in1->m[2][2] - in1->m[1][0]*in1->m[0][2]*in1->m[2][3] + in1->m[1][0]*in1->m[0][3]*in1->m[2][2] + in1->m[2][0]*in1->m[0][2]*in1->m[1][3] - in1->m[2][0]*in1->m[0][3]*in1->m[1][2]; + temp.m[2][3] = -in1->m[0][0]*in1->m[1][1]*in1->m[2][3] + in1->m[0][0]*in1->m[1][3]*in1->m[2][1] + in1->m[1][0]*in1->m[0][1]*in1->m[2][3] - in1->m[1][0]*in1->m[0][3]*in1->m[2][1] - in1->m[2][0]*in1->m[0][1]*in1->m[1][3] + in1->m[2][0]*in1->m[0][3]*in1->m[1][1]; + temp.m[3][3] = in1->m[0][0]*in1->m[1][1]*in1->m[2][2] - in1->m[0][0]*in1->m[1][2]*in1->m[2][1] - in1->m[1][0]*in1->m[0][1]*in1->m[2][2] + in1->m[1][0]*in1->m[0][2]*in1->m[2][1] + in1->m[2][0]*in1->m[0][1]*in1->m[1][2] - in1->m[2][0]*in1->m[0][2]*in1->m[1][1]; +#else + temp.m[0][0] = in1->m[1][1]*in1->m[2][2]*in1->m[3][3] - in1->m[1][1]*in1->m[3][2]*in1->m[2][3] - in1->m[1][2]*in1->m[2][1]*in1->m[3][3] + in1->m[1][2]*in1->m[3][1]*in1->m[2][3] + in1->m[1][3]*in1->m[2][1]*in1->m[3][2] - in1->m[1][3]*in1->m[3][1]*in1->m[2][2]; + temp.m[0][1] = -in1->m[0][1]*in1->m[2][2]*in1->m[3][3] + in1->m[0][1]*in1->m[3][2]*in1->m[2][3] + in1->m[0][2]*in1->m[2][1]*in1->m[3][3] - in1->m[0][2]*in1->m[3][1]*in1->m[2][3] - in1->m[0][3]*in1->m[2][1]*in1->m[3][2] + in1->m[0][3]*in1->m[3][1]*in1->m[2][2]; + temp.m[0][2] = in1->m[0][1]*in1->m[1][2]*in1->m[3][3] - in1->m[0][1]*in1->m[3][2]*in1->m[1][3] - in1->m[0][2]*in1->m[1][1]*in1->m[3][3] + in1->m[0][2]*in1->m[3][1]*in1->m[1][3] + in1->m[0][3]*in1->m[1][1]*in1->m[3][2] - in1->m[0][3]*in1->m[3][1]*in1->m[1][2]; + temp.m[0][3] = -in1->m[0][1]*in1->m[1][2]*in1->m[2][3] + in1->m[0][1]*in1->m[2][2]*in1->m[1][3] + in1->m[0][2]*in1->m[1][1]*in1->m[2][3] - in1->m[0][2]*in1->m[2][1]*in1->m[1][3] - in1->m[0][3]*in1->m[1][1]*in1->m[2][2] + in1->m[0][3]*in1->m[2][1]*in1->m[1][2]; + temp.m[1][0] = -in1->m[1][0]*in1->m[2][2]*in1->m[3][3] + in1->m[1][0]*in1->m[3][2]*in1->m[2][3] + in1->m[1][2]*in1->m[2][0]*in1->m[3][3] - in1->m[1][2]*in1->m[3][0]*in1->m[2][3] - in1->m[1][3]*in1->m[2][0]*in1->m[3][2] + in1->m[1][3]*in1->m[3][0]*in1->m[2][2]; + temp.m[1][1] = in1->m[0][0]*in1->m[2][2]*in1->m[3][3] - in1->m[0][0]*in1->m[3][2]*in1->m[2][3] - in1->m[0][2]*in1->m[2][0]*in1->m[3][3] + in1->m[0][2]*in1->m[3][0]*in1->m[2][3] + in1->m[0][3]*in1->m[2][0]*in1->m[3][2] - in1->m[0][3]*in1->m[3][0]*in1->m[2][2]; + temp.m[1][2] = -in1->m[0][0]*in1->m[1][2]*in1->m[3][3] + in1->m[0][0]*in1->m[3][2]*in1->m[1][3] + in1->m[0][2]*in1->m[1][0]*in1->m[3][3] - in1->m[0][2]*in1->m[3][0]*in1->m[1][3] - in1->m[0][3]*in1->m[1][0]*in1->m[3][2] + in1->m[0][3]*in1->m[3][0]*in1->m[1][2]; + temp.m[1][3] = in1->m[0][0]*in1->m[1][2]*in1->m[2][3] - in1->m[0][0]*in1->m[2][2]*in1->m[1][3] - in1->m[0][2]*in1->m[1][0]*in1->m[2][3] + in1->m[0][2]*in1->m[2][0]*in1->m[1][3] + in1->m[0][3]*in1->m[1][0]*in1->m[2][2] - in1->m[0][3]*in1->m[2][0]*in1->m[1][2]; + temp.m[2][0] = in1->m[1][0]*in1->m[2][1]*in1->m[3][3] - in1->m[1][0]*in1->m[3][1]*in1->m[2][3] - in1->m[1][1]*in1->m[2][0]*in1->m[3][3] + in1->m[1][1]*in1->m[3][0]*in1->m[2][3] + in1->m[1][3]*in1->m[2][0]*in1->m[3][1] - in1->m[1][3]*in1->m[3][0]*in1->m[2][1]; + temp.m[2][1] = -in1->m[0][0]*in1->m[2][1]*in1->m[3][3] + in1->m[0][0]*in1->m[3][1]*in1->m[2][3] + in1->m[0][1]*in1->m[2][0]*in1->m[3][3] - in1->m[0][1]*in1->m[3][0]*in1->m[2][3] - in1->m[0][3]*in1->m[2][0]*in1->m[3][1] + in1->m[0][3]*in1->m[3][0]*in1->m[2][1]; + temp.m[2][2] = in1->m[0][0]*in1->m[1][1]*in1->m[3][3] - in1->m[0][0]*in1->m[3][1]*in1->m[1][3] - in1->m[0][1]*in1->m[1][0]*in1->m[3][3] + in1->m[0][1]*in1->m[3][0]*in1->m[1][3] + in1->m[0][3]*in1->m[1][0]*in1->m[3][1] - in1->m[0][3]*in1->m[3][0]*in1->m[1][1]; + temp.m[2][3] = -in1->m[0][0]*in1->m[1][1]*in1->m[2][3] + in1->m[0][0]*in1->m[2][1]*in1->m[1][3] + in1->m[0][1]*in1->m[1][0]*in1->m[2][3] - in1->m[0][1]*in1->m[2][0]*in1->m[1][3] - in1->m[0][3]*in1->m[1][0]*in1->m[2][1] + in1->m[0][3]*in1->m[2][0]*in1->m[1][1]; + temp.m[3][0] = -in1->m[1][0]*in1->m[2][1]*in1->m[3][2] + in1->m[1][0]*in1->m[3][1]*in1->m[2][2] + in1->m[1][1]*in1->m[2][0]*in1->m[3][2] - in1->m[1][1]*in1->m[3][0]*in1->m[2][2] - in1->m[1][2]*in1->m[2][0]*in1->m[3][1] + in1->m[1][2]*in1->m[3][0]*in1->m[2][1]; + temp.m[3][1] = in1->m[0][0]*in1->m[2][1]*in1->m[3][2] - in1->m[0][0]*in1->m[3][1]*in1->m[2][2] - in1->m[0][1]*in1->m[2][0]*in1->m[3][2] + in1->m[0][1]*in1->m[3][0]*in1->m[2][2] + in1->m[0][2]*in1->m[2][0]*in1->m[3][1] - in1->m[0][2]*in1->m[3][0]*in1->m[2][1]; + temp.m[3][2] = -in1->m[0][0]*in1->m[1][1]*in1->m[3][2] + in1->m[0][0]*in1->m[3][1]*in1->m[1][2] + in1->m[0][1]*in1->m[1][0]*in1->m[3][2] - in1->m[0][1]*in1->m[3][0]*in1->m[1][2] - in1->m[0][2]*in1->m[1][0]*in1->m[3][1] + in1->m[0][2]*in1->m[3][0]*in1->m[1][1]; + temp.m[3][3] = in1->m[0][0]*in1->m[1][1]*in1->m[2][2] - in1->m[0][0]*in1->m[2][1]*in1->m[1][2] - in1->m[0][1]*in1->m[1][0]*in1->m[2][2] + in1->m[0][1]*in1->m[2][0]*in1->m[1][2] + in1->m[0][2]*in1->m[1][0]*in1->m[2][1] - in1->m[0][2]*in1->m[2][0]*in1->m[1][1]; +#endif + + det = in1->m[0][0]*temp.m[0][0] + in1->m[1][0]*temp.m[0][1] + in1->m[2][0]*temp.m[0][2] + in1->m[3][0]*temp.m[0][3]; + if (det == 0.0f) + return 0; + + det = 1.0f / det; + + for (i = 0;i < 4;i++) + for (j = 0;j < 4;j++) + out->m[i][j] = temp.m[i][j] * det; + + return 1; +} +#else +int Matrix4x4_Invert_Full (matrix4x4_t *out, const matrix4x4_t *in1) +{ + double *temp; + double *r[4]; + double rtemp[4][8]; + double m[4]; + double s; + + r[0] = rtemp[0]; + r[1] = rtemp[1]; + r[2] = rtemp[2]; + r[3] = rtemp[3]; + +#ifdef MATRIX4x4_OPENGLORIENTATION + r[0][0] = in1->m[0][0]; r[0][1] = in1->m[1][0]; r[0][2] = in1->m[2][0]; r[0][3] = in1->m[3][0]; + r[0][4] = 1.0; r[0][5] = r[0][6] = r[0][7] = 0.0; + + r[1][0] = in1->m[0][1]; r[1][1] = in1->m[1][1]; r[1][2] = in1->m[2][1]; r[1][3] = in1->m[3][1]; + r[1][5] = 1.0; r[1][4] = r[1][6] = r[1][7] = 0.0; + + r[2][0] = in1->m[0][2]; r[2][1] = in1->m[1][2]; r[2][2] = in1->m[2][2]; r[2][3] = in1->m[3][2]; + r[2][6] = 1.0; r[2][4] = r[2][5] = r[2][7] = 0.0; + + r[3][0] = in1->m[0][3]; r[3][1] = in1->m[1][3]; r[3][2] = in1->m[2][3]; r[3][3] = in1->m[3][3]; + r[3][7] = 1.0; r[3][4] = r[3][5] = r[3][6] = 0.0; +#else + r[0][0] = in1->m[0][0]; r[0][1] = in1->m[0][1]; r[0][2] = in1->m[0][2]; r[0][3] = in1->m[0][3]; + r[0][4] = 1.0; r[0][5] = r[0][6] = r[0][7] = 0.0; + + r[1][0] = in1->m[1][0]; r[1][1] = in1->m[1][1]; r[1][2] = in1->m[1][2]; r[1][3] = in1->m[1][3]; + r[1][5] = 1.0; r[1][4] = r[1][6] = r[1][7] = 0.0; + + r[2][0] = in1->m[2][0]; r[2][1] = in1->m[2][1]; r[2][2] = in1->m[2][2]; r[2][3] = in1->m[2][3]; + r[2][6] = 1.0; r[2][4] = r[2][5] = r[2][7] = 0.0; + + r[3][0] = in1->m[3][0]; r[3][1] = in1->m[3][1]; r[3][2] = in1->m[3][2]; r[3][3] = in1->m[3][3]; + r[3][7] = 1.0; r[3][4] = r[3][5] = r[3][6] = 0.0; +#endif + + if (fabs (r[3][0]) > fabs (r[2][0])) { temp = r[3]; r[3] = r[2]; r[2] = temp; } + if (fabs (r[2][0]) > fabs (r[1][0])) { temp = r[2]; r[2] = r[1]; r[1] = temp; } + if (fabs (r[1][0]) > fabs (r[0][0])) { temp = r[1]; r[1] = r[0]; r[0] = temp; } + + if (r[0][0]) + { + m[1] = r[1][0] / r[0][0]; + m[2] = r[2][0] / r[0][0]; + m[3] = r[3][0] / r[0][0]; + + s = r[0][1]; r[1][1] -= m[1] * s; r[2][1] -= m[2] * s; r[3][1] -= m[3] * s; + s = r[0][2]; r[1][2] -= m[1] * s; r[2][2] -= m[2] * s; r[3][2] -= m[3] * s; + s = r[0][3]; r[1][3] -= m[1] * s; r[2][3] -= m[2] * s; r[3][3] -= m[3] * s; + + s = r[0][4]; if (s) { r[1][4] -= m[1] * s; r[2][4] -= m[2] * s; r[3][4] -= m[3] * s; } + s = r[0][5]; if (s) { r[1][5] -= m[1] * s; r[2][5] -= m[2] * s; r[3][5] -= m[3] * s; } + s = r[0][6]; if (s) { r[1][6] -= m[1] * s; r[2][6] -= m[2] * s; r[3][6] -= m[3] * s; } + s = r[0][7]; if (s) { r[1][7] -= m[1] * s; r[2][7] -= m[2] * s; r[3][7] -= m[3] * s; } + + if (fabs (r[3][1]) > fabs (r[2][1])) { temp = r[3]; r[3] = r[2]; r[2] = temp; } + if (fabs (r[2][1]) > fabs (r[1][1])) { temp = r[2]; r[2] = r[1]; r[1] = temp; } + + if (r[1][1]) + { + m[2] = r[2][1] / r[1][1]; + m[3] = r[3][1] / r[1][1]; + r[2][2] -= m[2] * r[1][2]; + r[3][2] -= m[3] * r[1][2]; + r[2][3] -= m[2] * r[1][3]; + r[3][3] -= m[3] * r[1][3]; + + s = r[1][4]; if (s) { r[2][4] -= m[2] * s; r[3][4] -= m[3] * s; } + s = r[1][5]; if (s) { r[2][5] -= m[2] * s; r[3][5] -= m[3] * s; } + s = r[1][6]; if (s) { r[2][6] -= m[2] * s; r[3][6] -= m[3] * s; } + s = r[1][7]; if (s) { r[2][7] -= m[2] * s; r[3][7] -= m[3] * s; } + + if (fabs (r[3][2]) > fabs (r[2][2])) { temp = r[3]; r[3] = r[2]; r[2] = temp; } + + if (r[2][2]) + { + m[3] = r[3][2] / r[2][2]; + r[3][3] -= m[3] * r[2][3]; + r[3][4] -= m[3] * r[2][4]; + r[3][5] -= m[3] * r[2][5]; + r[3][6] -= m[3] * r[2][6]; + r[3][7] -= m[3] * r[2][7]; + + if (r[3][3]) + { + s = 1.0 / r[3][3]; + r[3][4] *= s; + r[3][5] *= s; + r[3][6] *= s; + r[3][7] *= s; + + m[2] = r[2][3]; + s = 1.0 / r[2][2]; + r[2][4] = s * (r[2][4] - r[3][4] * m[2]); + r[2][5] = s * (r[2][5] - r[3][5] * m[2]); + r[2][6] = s * (r[2][6] - r[3][6] * m[2]); + r[2][7] = s * (r[2][7] - r[3][7] * m[2]); + + m[1] = r[1][3]; + r[1][4] -= r[3][4] * m[1], r[1][5] -= r[3][5] * m[1]; + r[1][6] -= r[3][6] * m[1], r[1][7] -= r[3][7] * m[1]; + + m[0] = r[0][3]; + r[0][4] -= r[3][4] * m[0], r[0][5] -= r[3][5] * m[0]; + r[0][6] -= r[3][6] * m[0], r[0][7] -= r[3][7] * m[0]; + + m[1] = r[1][2]; + s = 1.0 / r[1][1]; + r[1][4] = s * (r[1][4] - r[2][4] * m[1]), r[1][5] = s * (r[1][5] - r[2][5] * m[1]); + r[1][6] = s * (r[1][6] - r[2][6] * m[1]), r[1][7] = s * (r[1][7] - r[2][7] * m[1]); + + m[0] = r[0][2]; + r[0][4] -= r[2][4] * m[0], r[0][5] -= r[2][5] * m[0]; + r[0][6] -= r[2][6] * m[0], r[0][7] -= r[2][7] * m[0]; + + m[0] = r[0][1]; + s = 1.0 / r[0][0]; + r[0][4] = s * (r[0][4] - r[1][4] * m[0]), r[0][5] = s * (r[0][5] - r[1][5] * m[0]); + r[0][6] = s * (r[0][6] - r[1][6] * m[0]), r[0][7] = s * (r[0][7] - r[1][7] * m[0]); + +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = r[0][4]; + out->m[0][1] = r[1][4]; + out->m[0][2] = r[2][4]; + out->m[0][3] = r[3][4]; + out->m[1][0] = r[0][5]; + out->m[1][1] = r[1][5]; + out->m[1][2] = r[2][5]; + out->m[1][3] = r[3][5]; + out->m[2][0] = r[0][6]; + out->m[2][1] = r[1][6]; + out->m[2][2] = r[2][6]; + out->m[2][3] = r[3][6]; + out->m[3][0] = r[0][7]; + out->m[3][1] = r[1][7]; + out->m[3][2] = r[2][7]; + out->m[3][3] = r[3][7]; +#else + out->m[0][0] = r[0][4]; + out->m[0][1] = r[0][5]; + out->m[0][2] = r[0][6]; + out->m[0][3] = r[0][7]; + out->m[1][0] = r[1][4]; + out->m[1][1] = r[1][5]; + out->m[1][2] = r[1][6]; + out->m[1][3] = r[1][7]; + out->m[2][0] = r[2][4]; + out->m[2][1] = r[2][5]; + out->m[2][2] = r[2][6]; + out->m[2][3] = r[2][7]; + out->m[3][0] = r[3][4]; + out->m[3][1] = r[3][5]; + out->m[3][2] = r[3][6]; + out->m[3][3] = r[3][7]; +#endif + + return 1; + } + } + } + } + + return 0; +} +#endif + +void Matrix4x4_Invert_Simple (matrix4x4_t *out, const matrix4x4_t *in1) +{ + // we only support uniform scaling, so assume the first row is enough + // (note the lack of sqrt here, because we're trying to undo the scaling, + // this means multiplying by the inverse scale twice - squaring it, which + // makes the sqrt a waste of time) +#if 1 + double scale = 1.0 / (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]); +#else + double scale = 3.0 / sqrt + (in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2] + + in1->m[1][0] * in1->m[1][0] + in1->m[1][1] * in1->m[1][1] + in1->m[1][2] * in1->m[1][2] + + in1->m[2][0] * in1->m[2][0] + in1->m[2][1] * in1->m[2][1] + in1->m[2][2] * in1->m[2][2]); + scale *= scale; +#endif + + // invert the rotation by transposing and multiplying by the squared + // recipricol of the input matrix scale as described above + out->m[0][0] = in1->m[0][0] * scale; + out->m[0][1] = in1->m[1][0] * scale; + out->m[0][2] = in1->m[2][0] * scale; + out->m[1][0] = in1->m[0][1] * scale; + out->m[1][1] = in1->m[1][1] * scale; + out->m[1][2] = in1->m[2][1] * scale; + out->m[2][0] = in1->m[0][2] * scale; + out->m[2][1] = in1->m[1][2] * scale; + out->m[2][2] = in1->m[2][2] * scale; + +#ifdef MATRIX4x4_OPENGLORIENTATION + // invert the translate + out->m[3][0] = -(in1->m[3][0] * out->m[0][0] + in1->m[3][1] * out->m[1][0] + in1->m[3][2] * out->m[2][0]); + out->m[3][1] = -(in1->m[3][0] * out->m[0][1] + in1->m[3][1] * out->m[1][1] + in1->m[3][2] * out->m[2][1]); + out->m[3][2] = -(in1->m[3][0] * out->m[0][2] + in1->m[3][1] * out->m[1][2] + in1->m[3][2] * out->m[2][2]); + + // don't know if there's anything worth doing here + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + // invert the translate + out->m[0][3] = -(in1->m[0][3] * out->m[0][0] + in1->m[1][3] * out->m[0][1] + in1->m[2][3] * out->m[0][2]); + out->m[1][3] = -(in1->m[0][3] * out->m[1][0] + in1->m[1][3] * out->m[1][1] + in1->m[2][3] * out->m[1][2]); + out->m[2][3] = -(in1->m[0][3] * out->m[2][0] + in1->m[1][3] * out->m[2][1] + in1->m[2][3] * out->m[2][2]); + + // don't know if there's anything worth doing here + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif +} + +void Matrix4x4_Interpolate (matrix4x4_t *out, matrix4x4_t *in1, matrix4x4_t *in2, double frac) +{ + int i, j; + for (i = 0;i < 4;i++) + for (j = 0;j < 4;j++) + out->m[i][j] = in1->m[i][j] + frac * (in2->m[i][j] - in1->m[i][j]); +} + +void Matrix4x4_Clear (matrix4x4_t *out) +{ + int i, j; + for (i = 0;i < 4;i++) + for (j = 0;j < 4;j++) + out->m[i][j] = 0; +} + +void Matrix4x4_Accumulate (matrix4x4_t *out, matrix4x4_t *in, double weight) +{ + int i, j; + for (i = 0;i < 4;i++) + for (j = 0;j < 4;j++) + out->m[i][j] += in->m[i][j] * weight; +} + +void Matrix4x4_Normalize (matrix4x4_t *out, matrix4x4_t *in1) +{ + // scale rotation matrix vectors to a length of 1 + // note: this is only designed to undo uniform scaling + double scale = 1.0 / sqrt(in1->m[0][0] * in1->m[0][0] + in1->m[0][1] * in1->m[0][1] + in1->m[0][2] * in1->m[0][2]); + *out = *in1; + Matrix4x4_Scale(out, scale, 1); +} + +void Matrix4x4_Normalize3 (matrix4x4_t *out, matrix4x4_t *in1) +{ + int i; + double scale; + // scale each rotation matrix vector to a length of 1 + // intended for use after Matrix4x4_Interpolate or Matrix4x4_Accumulate + *out = *in1; + for (i = 0;i < 3;i++) + { +#ifdef MATRIX4x4_OPENGLORIENTATION + scale = sqrt(in1->m[i][0] * in1->m[i][0] + in1->m[i][1] * in1->m[i][1] + in1->m[i][2] * in1->m[i][2]); + if (scale) + scale = 1.0 / scale; + out->m[i][0] *= scale; + out->m[i][1] *= scale; + out->m[i][2] *= scale; +#else + scale = sqrt(in1->m[0][i] * in1->m[0][i] + in1->m[1][i] * in1->m[1][i] + in1->m[2][i] * in1->m[2][i]); + if (scale) + scale = 1.0 / scale; + out->m[0][i] *= scale; + out->m[1][i] *= scale; + out->m[2][i] *= scale; +#endif + } +} + +void Matrix4x4_Reflect (matrix4x4_t *out, double normalx, double normaly, double normalz, double dist, double axisscale) +{ + int i; + double d; + double p[4], p2[4]; + p[0] = normalx; + p[1] = normaly; + p[2] = normalz; + p[3] = -dist; + p2[0] = p[0] * axisscale; + p2[1] = p[1] * axisscale; + p2[2] = p[2] * axisscale; + p2[3] = 0; + for (i = 0;i < 4;i++) + { +#ifdef MATRIX4x4_OPENGLORIENTATION + d = out->m[i][0] * p[0] + out->m[i][1] * p[1] + out->m[i][2] * p[2] + out->m[i][3] * p[3]; + out->m[i][0] += p2[0] * d; + out->m[i][1] += p2[1] * d; + out->m[i][2] += p2[2] * d; +#else + d = out->m[0][i] * p[0] + out->m[1][i] * p[1] + out->m[2][i] * p[2] + out->m[3][i] * p[3]; + out->m[0][i] += p2[0] * d; + out->m[1][i] += p2[1] * d; + out->m[2][i] += p2[2] * d; +#endif + } +} + +void Matrix4x4_CreateIdentity (matrix4x4_t *out) +{ + out->m[0][0]=1.0f; + out->m[0][1]=0.0f; + out->m[0][2]=0.0f; + out->m[0][3]=0.0f; + out->m[1][0]=0.0f; + out->m[1][1]=1.0f; + out->m[1][2]=0.0f; + out->m[1][3]=0.0f; + out->m[2][0]=0.0f; + out->m[2][1]=0.0f; + out->m[2][2]=1.0f; + out->m[2][3]=0.0f; + out->m[3][0]=0.0f; + out->m[3][1]=0.0f; + out->m[3][2]=0.0f; + out->m[3][3]=1.0f; +} + +void Matrix4x4_CreateTranslate (matrix4x4_t *out, double x, double y, double z) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0]=1.0f; + out->m[1][0]=0.0f; + out->m[2][0]=0.0f; + out->m[3][0]=x; + out->m[0][1]=0.0f; + out->m[1][1]=1.0f; + out->m[2][1]=0.0f; + out->m[3][1]=y; + out->m[0][2]=0.0f; + out->m[1][2]=0.0f; + out->m[2][2]=1.0f; + out->m[3][2]=z; + out->m[0][3]=0.0f; + out->m[1][3]=0.0f; + out->m[2][3]=0.0f; + out->m[3][3]=1.0f; +#else + out->m[0][0]=1.0f; + out->m[0][1]=0.0f; + out->m[0][2]=0.0f; + out->m[0][3]=x; + out->m[1][0]=0.0f; + out->m[1][1]=1.0f; + out->m[1][2]=0.0f; + out->m[1][3]=y; + out->m[2][0]=0.0f; + out->m[2][1]=0.0f; + out->m[2][2]=1.0f; + out->m[2][3]=z; + out->m[3][0]=0.0f; + out->m[3][1]=0.0f; + out->m[3][2]=0.0f; + out->m[3][3]=1.0f; +#endif +} + +void Matrix4x4_CreateRotate (matrix4x4_t *out, double angle, double x, double y, double z) +{ + double len, c, s; + + len = x*x+y*y+z*z; + if (len != 0.0f) + len = 1.0f / sqrt(len); + x *= len; + y *= len; + z *= len; + + angle *= (-M_PI / 180.0); + c = cos(angle); + s = sin(angle); + +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0]=x * x + c * (1 - x * x); + out->m[1][0]=x * y * (1 - c) + z * s; + out->m[2][0]=z * x * (1 - c) - y * s; + out->m[3][0]=0.0f; + out->m[0][1]=x * y * (1 - c) - z * s; + out->m[1][1]=y * y + c * (1 - y * y); + out->m[2][1]=y * z * (1 - c) + x * s; + out->m[3][1]=0.0f; + out->m[0][2]=z * x * (1 - c) + y * s; + out->m[1][2]=y * z * (1 - c) - x * s; + out->m[2][2]=z * z + c * (1 - z * z); + out->m[3][2]=0.0f; + out->m[0][3]=0.0f; + out->m[1][3]=0.0f; + out->m[2][3]=0.0f; + out->m[3][3]=1.0f; +#else + out->m[0][0]=x * x + c * (1 - x * x); + out->m[0][1]=x * y * (1 - c) + z * s; + out->m[0][2]=z * x * (1 - c) - y * s; + out->m[0][3]=0.0f; + out->m[1][0]=x * y * (1 - c) - z * s; + out->m[1][1]=y * y + c * (1 - y * y); + out->m[1][2]=y * z * (1 - c) + x * s; + out->m[1][3]=0.0f; + out->m[2][0]=z * x * (1 - c) + y * s; + out->m[2][1]=y * z * (1 - c) - x * s; + out->m[2][2]=z * z + c * (1 - z * z); + out->m[2][3]=0.0f; + out->m[3][0]=0.0f; + out->m[3][1]=0.0f; + out->m[3][2]=0.0f; + out->m[3][3]=1.0f; +#endif +} + +void Matrix4x4_CreateScale (matrix4x4_t *out, double x) +{ + out->m[0][0]=x; + out->m[0][1]=0.0f; + out->m[0][2]=0.0f; + out->m[0][3]=0.0f; + out->m[1][0]=0.0f; + out->m[1][1]=x; + out->m[1][2]=0.0f; + out->m[1][3]=0.0f; + out->m[2][0]=0.0f; + out->m[2][1]=0.0f; + out->m[2][2]=x; + out->m[2][3]=0.0f; + out->m[3][0]=0.0f; + out->m[3][1]=0.0f; + out->m[3][2]=0.0f; + out->m[3][3]=1.0f; +} + +void Matrix4x4_CreateScale3 (matrix4x4_t *out, double x, double y, double z) +{ + out->m[0][0]=x; + out->m[0][1]=0.0f; + out->m[0][2]=0.0f; + out->m[0][3]=0.0f; + out->m[1][0]=0.0f; + out->m[1][1]=y; + out->m[1][2]=0.0f; + out->m[1][3]=0.0f; + out->m[2][0]=0.0f; + out->m[2][1]=0.0f; + out->m[2][2]=z; + out->m[2][3]=0.0f; + out->m[3][0]=0.0f; + out->m[3][1]=0.0f; + out->m[3][2]=0.0f; + out->m[3][3]=1.0f; +} + +void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, double x, double y, double z, double pitch, double yaw, double roll, double scale) +{ + double angle, sr, sp, sy, cr, cp, cy; + + if (roll) + { + angle = yaw * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = pitch * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = roll * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = (cp*cy) * scale; + out->m[1][0] = (sr*sp*cy+cr*-sy) * scale; + out->m[2][0] = (cr*sp*cy+-sr*-sy) * scale; + out->m[3][0] = x; + out->m[0][1] = (cp*sy) * scale; + out->m[1][1] = (sr*sp*sy+cr*cy) * scale; + out->m[2][1] = (cr*sp*sy+-sr*cy) * scale; + out->m[3][1] = y; + out->m[0][2] = (-sp) * scale; + out->m[1][2] = (sr*cp) * scale; + out->m[2][2] = (cr*cp) * scale; + out->m[3][2] = z; + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + out->m[0][0] = (cp*cy) * scale; + out->m[0][1] = (sr*sp*cy+cr*-sy) * scale; + out->m[0][2] = (cr*sp*cy+-sr*-sy) * scale; + out->m[0][3] = x; + out->m[1][0] = (cp*sy) * scale; + out->m[1][1] = (sr*sp*sy+cr*cy) * scale; + out->m[1][2] = (cr*sp*sy+-sr*cy) * scale; + out->m[1][3] = y; + out->m[2][0] = (-sp) * scale; + out->m[2][1] = (sr*cp) * scale; + out->m[2][2] = (cr*cp) * scale; + out->m[2][3] = z; + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif + } + else if (pitch) + { + angle = yaw * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = pitch * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = (cp*cy) * scale; + out->m[1][0] = (-sy) * scale; + out->m[2][0] = (sp*cy) * scale; + out->m[3][0] = x; + out->m[0][1] = (cp*sy) * scale; + out->m[1][1] = (cy) * scale; + out->m[2][1] = (sp*sy) * scale; + out->m[3][1] = y; + out->m[0][2] = (-sp) * scale; + out->m[1][2] = 0; + out->m[2][2] = (cp) * scale; + out->m[3][2] = z; + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + out->m[0][0] = (cp*cy) * scale; + out->m[0][1] = (-sy) * scale; + out->m[0][2] = (sp*cy) * scale; + out->m[0][3] = x; + out->m[1][0] = (cp*sy) * scale; + out->m[1][1] = (cy) * scale; + out->m[1][2] = (sp*sy) * scale; + out->m[1][3] = y; + out->m[2][0] = (-sp) * scale; + out->m[2][1] = 0; + out->m[2][2] = (cp) * scale; + out->m[2][3] = z; + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif + } + else if (yaw) + { + angle = yaw * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = (cy) * scale; + out->m[1][0] = (-sy) * scale; + out->m[2][0] = 0; + out->m[3][0] = x; + out->m[0][1] = (sy) * scale; + out->m[1][1] = (cy) * scale; + out->m[2][1] = 0; + out->m[3][1] = y; + out->m[0][2] = 0; + out->m[1][2] = 0; + out->m[2][2] = scale; + out->m[3][2] = z; + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + out->m[0][0] = (cy) * scale; + out->m[0][1] = (-sy) * scale; + out->m[0][2] = 0; + out->m[0][3] = x; + out->m[1][0] = (sy) * scale; + out->m[1][1] = (cy) * scale; + out->m[1][2] = 0; + out->m[1][3] = y; + out->m[2][0] = 0; + out->m[2][1] = 0; + out->m[2][2] = scale; + out->m[2][3] = z; + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif + } + else + { +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = scale; + out->m[1][0] = 0; + out->m[2][0] = 0; + out->m[3][0] = x; + out->m[0][1] = 0; + out->m[1][1] = scale; + out->m[2][1] = 0; + out->m[3][1] = y; + out->m[0][2] = 0; + out->m[1][2] = 0; + out->m[2][2] = scale; + out->m[3][2] = z; + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + out->m[0][0] = scale; + out->m[0][1] = 0; + out->m[0][2] = 0; + out->m[0][3] = x; + out->m[1][0] = 0; + out->m[1][1] = scale; + out->m[1][2] = 0; + out->m[1][3] = y; + out->m[2][0] = 0; + out->m[2][1] = 0; + out->m[2][2] = scale; + out->m[2][3] = z; + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif + } +} + +void Matrix4x4_ToVectors(const matrix4x4_t *in, float vx[3], float vy[3], float vz[3], float t[3]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + vx[0] = in->m[0][0]; + vx[1] = in->m[0][1]; + vx[2] = in->m[0][2]; + vy[0] = in->m[1][0]; + vy[1] = in->m[1][1]; + vy[2] = in->m[1][2]; + vz[0] = in->m[2][0]; + vz[1] = in->m[2][1]; + vz[2] = in->m[2][2]; + t [0] = in->m[3][0]; + t [1] = in->m[3][1]; + t [2] = in->m[3][2]; +#else + vx[0] = in->m[0][0]; + vx[1] = in->m[1][0]; + vx[2] = in->m[2][0]; + vy[0] = in->m[0][1]; + vy[1] = in->m[1][1]; + vy[2] = in->m[2][1]; + vz[0] = in->m[0][2]; + vz[1] = in->m[1][2]; + vz[2] = in->m[2][2]; + t [0] = in->m[0][3]; + t [1] = in->m[1][3]; + t [2] = in->m[2][3]; +#endif +} + +void Matrix4x4_FromVectors(matrix4x4_t *out, const float vx[3], const float vy[3], const float vz[3], const float t[3]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = vx[0]; + out->m[1][0] = vy[0]; + out->m[2][0] = vz[0]; + out->m[3][0] = t[0]; + out->m[0][1] = vx[1]; + out->m[1][1] = vy[1]; + out->m[2][1] = vz[1]; + out->m[3][1] = t[1]; + out->m[0][2] = vx[2]; + out->m[1][2] = vy[2]; + out->m[2][2] = vz[2]; + out->m[3][2] = t[2]; + out->m[0][3] = 0.0f; + out->m[1][3] = 0.0f; + out->m[2][3] = 0.0f; + out->m[3][3] = 1.0f; +#else + out->m[0][0] = vx[0]; + out->m[0][1] = vy[0]; + out->m[0][2] = vz[0]; + out->m[0][3] = t[0]; + out->m[1][0] = vx[1]; + out->m[1][1] = vy[1]; + out->m[1][2] = vz[1]; + out->m[1][3] = t[1]; + out->m[2][0] = vx[2]; + out->m[2][1] = vy[2]; + out->m[2][2] = vz[2]; + out->m[2][3] = t[2]; + out->m[3][0] = 0.0f; + out->m[3][1] = 0.0f; + out->m[3][2] = 0.0f; + out->m[3][3] = 1.0f; +#endif +} + +void Matrix4x4_ToArrayDoubleGL(const matrix4x4_t *in, double out[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[0][3]; + out[ 4] = in->m[1][0]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[1][2]; + out[ 7] = in->m[1][3]; + out[ 8] = in->m[2][0]; + out[ 9] = in->m[2][1]; + out[10] = in->m[2][2]; + out[11] = in->m[2][3]; + out[12] = in->m[3][0]; + out[13] = in->m[3][1]; + out[14] = in->m[3][2]; + out[15] = in->m[3][3]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[3][0]; + out[ 4] = in->m[0][1]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[2][1]; + out[ 7] = in->m[3][1]; + out[ 8] = in->m[0][2]; + out[ 9] = in->m[1][2]; + out[10] = in->m[2][2]; + out[11] = in->m[3][2]; + out[12] = in->m[0][3]; + out[13] = in->m[1][3]; + out[14] = in->m[2][3]; + out[15] = in->m[3][3]; +#endif +} + +void Matrix4x4_FromArrayDoubleGL (matrix4x4_t *out, const double in[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = in[3]; + out->m[1][0] = in[4]; + out->m[1][1] = in[5]; + out->m[1][2] = in[6]; + out->m[1][3] = in[7]; + out->m[2][0] = in[8]; + out->m[2][1] = in[9]; + out->m[2][2] = in[10]; + out->m[2][3] = in[11]; + out->m[3][0] = in[12]; + out->m[3][1] = in[13]; + out->m[3][2] = in[14]; + out->m[3][3] = in[15]; +#else + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = in[3]; + out->m[0][1] = in[4]; + out->m[1][1] = in[5]; + out->m[2][1] = in[6]; + out->m[3][1] = in[7]; + out->m[0][2] = in[8]; + out->m[1][2] = in[9]; + out->m[2][2] = in[10]; + out->m[3][2] = in[11]; + out->m[0][3] = in[12]; + out->m[1][3] = in[13]; + out->m[2][3] = in[14]; + out->m[3][3] = in[15]; +#endif +} + +void Matrix4x4_ToArrayDoubleD3D(const matrix4x4_t *in, double out[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[3][0]; + out[ 4] = in->m[0][1]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[2][1]; + out[ 7] = in->m[3][1]; + out[ 8] = in->m[0][2]; + out[ 9] = in->m[1][2]; + out[10] = in->m[2][2]; + out[11] = in->m[3][2]; + out[12] = in->m[0][3]; + out[13] = in->m[1][3]; + out[14] = in->m[2][3]; + out[15] = in->m[3][3]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[0][3]; + out[ 4] = in->m[1][0]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[1][2]; + out[ 7] = in->m[1][3]; + out[ 8] = in->m[2][0]; + out[ 9] = in->m[2][1]; + out[10] = in->m[2][2]; + out[11] = in->m[2][3]; + out[12] = in->m[3][0]; + out[13] = in->m[3][1]; + out[14] = in->m[3][2]; + out[15] = in->m[3][3]; +#endif +} + +void Matrix4x4_FromArrayDoubleD3D (matrix4x4_t *out, const double in[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = in[3]; + out->m[0][1] = in[4]; + out->m[1][1] = in[5]; + out->m[2][1] = in[6]; + out->m[3][1] = in[7]; + out->m[0][2] = in[8]; + out->m[1][2] = in[9]; + out->m[2][2] = in[10]; + out->m[3][2] = in[11]; + out->m[0][3] = in[12]; + out->m[1][3] = in[13]; + out->m[2][3] = in[14]; + out->m[3][3] = in[15]; +#else + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = in[3]; + out->m[1][0] = in[4]; + out->m[1][1] = in[5]; + out->m[1][2] = in[6]; + out->m[1][3] = in[7]; + out->m[2][0] = in[8]; + out->m[2][1] = in[9]; + out->m[2][2] = in[10]; + out->m[2][3] = in[11]; + out->m[3][0] = in[12]; + out->m[3][1] = in[13]; + out->m[3][2] = in[14]; + out->m[3][3] = in[15]; +#endif +} + +void Matrix4x4_ToArrayFloatGL(const matrix4x4_t *in, float out[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[0][3]; + out[ 4] = in->m[1][0]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[1][2]; + out[ 7] = in->m[1][3]; + out[ 8] = in->m[2][0]; + out[ 9] = in->m[2][1]; + out[10] = in->m[2][2]; + out[11] = in->m[2][3]; + out[12] = in->m[3][0]; + out[13] = in->m[3][1]; + out[14] = in->m[3][2]; + out[15] = in->m[3][3]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[3][0]; + out[ 4] = in->m[0][1]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[2][1]; + out[ 7] = in->m[3][1]; + out[ 8] = in->m[0][2]; + out[ 9] = in->m[1][2]; + out[10] = in->m[2][2]; + out[11] = in->m[3][2]; + out[12] = in->m[0][3]; + out[13] = in->m[1][3]; + out[14] = in->m[2][3]; + out[15] = in->m[3][3]; +#endif +} + +void Matrix4x4_FromArrayFloatGL (matrix4x4_t *out, const float in[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = in[3]; + out->m[1][0] = in[4]; + out->m[1][1] = in[5]; + out->m[1][2] = in[6]; + out->m[1][3] = in[7]; + out->m[2][0] = in[8]; + out->m[2][1] = in[9]; + out->m[2][2] = in[10]; + out->m[2][3] = in[11]; + out->m[3][0] = in[12]; + out->m[3][1] = in[13]; + out->m[3][2] = in[14]; + out->m[3][3] = in[15]; +#else + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = in[3]; + out->m[0][1] = in[4]; + out->m[1][1] = in[5]; + out->m[2][1] = in[6]; + out->m[3][1] = in[7]; + out->m[0][2] = in[8]; + out->m[1][2] = in[9]; + out->m[2][2] = in[10]; + out->m[3][2] = in[11]; + out->m[0][3] = in[12]; + out->m[1][3] = in[13]; + out->m[2][3] = in[14]; + out->m[3][3] = in[15]; +#endif +} + +void Matrix4x4_ToArrayFloatD3D(const matrix4x4_t *in, float out[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[3][0]; + out[ 4] = in->m[0][1]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[2][1]; + out[ 7] = in->m[3][1]; + out[ 8] = in->m[0][2]; + out[ 9] = in->m[1][2]; + out[10] = in->m[2][2]; + out[11] = in->m[3][2]; + out[12] = in->m[0][3]; + out[13] = in->m[1][3]; + out[14] = in->m[2][3]; + out[15] = in->m[3][3]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[0][3]; + out[ 4] = in->m[1][0]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[1][2]; + out[ 7] = in->m[1][3]; + out[ 8] = in->m[2][0]; + out[ 9] = in->m[2][1]; + out[10] = in->m[2][2]; + out[11] = in->m[2][3]; + out[12] = in->m[3][0]; + out[13] = in->m[3][1]; + out[14] = in->m[3][2]; + out[15] = in->m[3][3]; +#endif +} + +void Matrix4x4_FromArrayFloatD3D (matrix4x4_t *out, const float in[16]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = in[3]; + out->m[0][1] = in[4]; + out->m[1][1] = in[5]; + out->m[2][1] = in[6]; + out->m[3][1] = in[7]; + out->m[0][2] = in[8]; + out->m[1][2] = in[9]; + out->m[2][2] = in[10]; + out->m[3][2] = in[11]; + out->m[0][3] = in[12]; + out->m[1][3] = in[13]; + out->m[2][3] = in[14]; + out->m[3][3] = in[15]; +#else + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = in[3]; + out->m[1][0] = in[4]; + out->m[1][1] = in[5]; + out->m[1][2] = in[6]; + out->m[1][3] = in[7]; + out->m[2][0] = in[8]; + out->m[2][1] = in[9]; + out->m[2][2] = in[10]; + out->m[2][3] = in[11]; + out->m[3][0] = in[12]; + out->m[3][1] = in[13]; + out->m[3][2] = in[14]; + out->m[3][3] = in[15]; +#endif +} + +void Matrix4x4_ToArray12FloatGL(const matrix4x4_t *in, float out[12]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[1][0]; + out[ 4] = in->m[1][1]; + out[ 5] = in->m[1][2]; + out[ 6] = in->m[2][0]; + out[ 7] = in->m[2][1]; + out[ 8] = in->m[2][2]; + out[ 9] = in->m[3][0]; + out[10] = in->m[3][1]; + out[11] = in->m[3][2]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[0][1]; + out[ 4] = in->m[1][1]; + out[ 5] = in->m[2][1]; + out[ 6] = in->m[0][2]; + out[ 7] = in->m[1][2]; + out[ 8] = in->m[2][2]; + out[ 9] = in->m[0][3]; + out[10] = in->m[1][3]; + out[11] = in->m[2][3]; +#endif +} + +void Matrix4x4_FromArray12FloatGL(matrix4x4_t *out, const float in[12]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = 0; + out->m[1][0] = in[3]; + out->m[1][1] = in[4]; + out->m[1][2] = in[5]; + out->m[1][3] = 0; + out->m[2][0] = in[6]; + out->m[2][1] = in[7]; + out->m[2][2] = in[8]; + out->m[2][3] = 0; + out->m[3][0] = in[9]; + out->m[3][1] = in[10]; + out->m[3][2] = in[11]; + out->m[3][3] = 1; +#else + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = 0; + out->m[0][1] = in[3]; + out->m[1][1] = in[4]; + out->m[2][1] = in[5]; + out->m[3][1] = 0; + out->m[0][2] = in[6]; + out->m[1][2] = in[7]; + out->m[2][2] = in[8]; + out->m[3][2] = 0; + out->m[0][3] = in[9]; + out->m[1][3] = in[10]; + out->m[2][3] = in[11]; + out->m[3][3] = 1; +#endif +} + +void Matrix4x4_ToArray12FloatD3D(const matrix4x4_t *in, float out[12]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[ 0] = in->m[0][0]; + out[ 1] = in->m[1][0]; + out[ 2] = in->m[2][0]; + out[ 3] = in->m[3][0]; + out[ 4] = in->m[0][1]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[2][1]; + out[ 7] = in->m[3][1]; + out[ 8] = in->m[0][2]; + out[ 9] = in->m[1][2]; + out[10] = in->m[2][2]; + out[11] = in->m[3][2]; +#else + out[ 0] = in->m[0][0]; + out[ 1] = in->m[0][1]; + out[ 2] = in->m[0][2]; + out[ 3] = in->m[0][3]; + out[ 4] = in->m[1][0]; + out[ 5] = in->m[1][1]; + out[ 6] = in->m[1][2]; + out[ 7] = in->m[1][3]; + out[ 8] = in->m[2][0]; + out[ 9] = in->m[2][1]; + out[10] = in->m[2][2]; + out[11] = in->m[2][3]; +#endif +} + +void Matrix4x4_FromArray12FloatD3D(matrix4x4_t *out, const float in[12]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[0][0] = in[0]; + out->m[1][0] = in[1]; + out->m[2][0] = in[2]; + out->m[3][0] = in[3]; + out->m[0][1] = in[4]; + out->m[1][1] = in[5]; + out->m[2][1] = in[6]; + out->m[3][1] = in[7]; + out->m[0][2] = in[8]; + out->m[1][2] = in[9]; + out->m[2][2] = in[10]; + out->m[3][2] = in[11]; + out->m[0][3] = 0; + out->m[1][3] = 0; + out->m[2][3] = 0; + out->m[3][3] = 1; +#else + out->m[0][0] = in[0]; + out->m[0][1] = in[1]; + out->m[0][2] = in[2]; + out->m[0][3] = in[3]; + out->m[1][0] = in[4]; + out->m[1][1] = in[5]; + out->m[1][2] = in[6]; + out->m[1][3] = in[7]; + out->m[2][0] = in[8]; + out->m[2][1] = in[9]; + out->m[2][2] = in[10]; + out->m[2][3] = in[11]; + out->m[3][0] = 0; + out->m[3][1] = 0; + out->m[3][2] = 0; + out->m[3][3] = 1; +#endif +} + +void Matrix4x4_FromOriginQuat(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z, double w) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + m->m[0][0]=1-2*(y*y+z*z);m->m[1][0]= 2*(x*y-z*w);m->m[2][0]= 2*(x*z+y*w);m->m[3][0]=ox; + m->m[0][1]= 2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[2][1]= 2*(y*z-x*w);m->m[3][1]=oy; + m->m[0][2]= 2*(x*z-y*w);m->m[1][2]= 2*(y*z+x*w);m->m[2][2]=1-2*(x*x+y*y);m->m[3][2]=oz; + m->m[0][3]= 0 ;m->m[1][3]= 0 ;m->m[2][3]= 0 ;m->m[3][3]=1; +#else + m->m[0][0]=1-2*(y*y+z*z);m->m[0][1]= 2*(x*y-z*w);m->m[0][2]= 2*(x*z+y*w);m->m[0][3]=ox; + m->m[1][0]= 2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[1][2]= 2*(y*z-x*w);m->m[1][3]=oy; + m->m[2][0]= 2*(x*z-y*w);m->m[2][1]= 2*(y*z+x*w);m->m[2][2]=1-2*(x*x+y*y);m->m[2][3]=oz; + m->m[3][0]= 0 ;m->m[3][1]= 0 ;m->m[3][2]= 0 ;m->m[3][3]=1; +#endif +} + +// see http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm +void Matrix4x4_ToOrigin3Quat4Float(const matrix4x4_t *m, float *origin, float *quat) +{ +#if 0 + float s; + quat[3] = sqrt(1.0f + m->m[0][0] + m->m[1][1] + m->m[2][2]) * 0.5f; + s = 0.25f / quat[3]; +#ifdef MATRIX4x4_OPENGLORIENTATION + origin[0] = m->m[3][0]; + origin[1] = m->m[3][1]; + origin[2] = m->m[3][2]; + quat[0] = (m->m[1][2] - m->m[2][1]) * s; + quat[1] = (m->m[2][0] - m->m[0][2]) * s; + quat[2] = (m->m[0][1] - m->m[1][0]) * s; +#else + origin[0] = m->m[0][3]; + origin[1] = m->m[1][3]; + origin[2] = m->m[2][3]; + quat[0] = (m->m[2][1] - m->m[1][2]) * s; + quat[1] = (m->m[0][2] - m->m[2][0]) * s; + quat[2] = (m->m[1][0] - m->m[0][1]) * s; +#endif + +#else + +#ifdef MATRIX4x4_OPENGLORIENTATION + float trace = m->m[0][0] + m->m[1][1] + m->m[2][2]; + origin[0] = m->m[3][0]; + origin[1] = m->m[3][1]; + origin[2] = m->m[3][2]; + if(trace > 0) + { + float r = sqrt(1.0f + trace), inv = 0.5f / r; + quat[0] = (m->m[1][2] - m->m[2][1]) * inv; + quat[1] = (m->m[2][0] - m->m[0][2]) * inv; + quat[2] = (m->m[0][1] - m->m[1][0]) * inv; + quat[3] = 0.5f * r; + } + else if(m->m[0][0] > m->m[1][1] && m->m[0][0] > m->m[2][2]) + { + float r = sqrt(1.0f + m->m[0][0] - m->m[1][1] - m->m[2][2]), inv = 0.5f / r; + quat[0] = 0.5f * r; + quat[1] = (m->m[0][1] + m->m[1][0]) * inv; + quat[2] = (m->m[2][0] + m->m[0][2]) * inv; + quat[3] = (m->m[1][2] - m->m[2][1]) * inv; + } + else if(m->m[1][1] > m->m[2][2]) + { + float r = sqrt(1.0f + m->m[1][1] - m->m[0][0] - m->m[2][2]), inv = 0.5f / r; + quat[0] = (m->m[0][1] + m->m[1][0]) * inv; + quat[1] = 0.5f * r; + quat[2] = (m->m[1][2] + m->m[2][1]) * inv; + quat[3] = (m->m[2][0] - m->m[0][2]) * inv; + } + else + { + float r = sqrt(1.0f + m->m[2][2] - m->m[0][0] - m->m[1][1]), inv = 0.5f / r; + quat[0] = (m->m[2][0] + m->m[0][2]) * inv; + quat[1] = (m->m[1][2] + m->m[2][1]) * inv; + quat[2] = 0.5f * r; + quat[3] = (m->m[0][1] - m->m[1][0]) * inv; + } +#else + float trace = m->m[0][0] + m->m[1][1] + m->m[2][2]; + origin[0] = m->m[0][3]; + origin[1] = m->m[1][3]; + origin[2] = m->m[2][3]; + if(trace > 0) + { + float r = sqrt(1.0f + trace), inv = 0.5f / r; + quat[0] = (m->m[2][1] - m->m[1][2]) * inv; + quat[1] = (m->m[0][2] - m->m[2][0]) * inv; + quat[2] = (m->m[1][0] - m->m[0][1]) * inv; + quat[3] = 0.5f * r; + } + else if(m->m[0][0] > m->m[1][1] && m->m[0][0] > m->m[2][2]) + { + float r = sqrt(1.0f + m->m[0][0] - m->m[1][1] - m->m[2][2]), inv = 0.5f / r; + quat[0] = 0.5f * r; + quat[1] = (m->m[1][0] + m->m[0][1]) * inv; + quat[2] = (m->m[0][2] + m->m[2][0]) * inv; + quat[3] = (m->m[2][1] - m->m[1][2]) * inv; + } + else if(m->m[1][1] > m->m[2][2]) + { + float r = sqrt(1.0f + m->m[1][1] - m->m[0][0] - m->m[2][2]), inv = 0.5f / r; + quat[0] = (m->m[1][0] + m->m[0][1]) * inv; + quat[1] = 0.5f * r; + quat[2] = (m->m[2][1] + m->m[1][2]) * inv; + quat[3] = (m->m[0][2] - m->m[2][0]) * inv; + } + else + { + float r = sqrt(1.0f + m->m[2][2] - m->m[0][0] - m->m[1][1]), inv = 0.5f / r; + quat[0] = (m->m[0][2] + m->m[2][0]) * inv; + quat[1] = (m->m[2][1] + m->m[1][2]) * inv; + quat[2] = 0.5f * r; + quat[3] = (m->m[1][0] - m->m[0][1]) * inv; + } +#endif + +#endif +} + +// LordHavoc: I got this code from: +//http://www.doom3world.org/phpbb2/viewtopic.php?t=2884 +void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z) +{ + double w = 1.0f - (x*x+y*y+z*z); + w = w > 0.0f ? -sqrt(w) : 0.0f; +#ifdef MATRIX4x4_OPENGLORIENTATION + m->m[0][0]=1-2*(y*y+z*z);m->m[1][0]= 2*(x*y-z*w);m->m[2][0]= 2*(x*z+y*w);m->m[3][0]=ox; + m->m[0][1]= 2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[2][1]= 2*(y*z-x*w);m->m[3][1]=oy; + m->m[0][2]= 2*(x*z-y*w);m->m[1][2]= 2*(y*z+x*w);m->m[2][2]=1-2*(x*x+y*y);m->m[3][2]=oz; + m->m[0][3]= 0 ;m->m[1][3]= 0 ;m->m[2][3]= 0 ;m->m[3][3]=1; +#else + m->m[0][0]=1-2*(y*y+z*z);m->m[0][1]= 2*(x*y-z*w);m->m[0][2]= 2*(x*z+y*w);m->m[0][3]=ox; + m->m[1][0]= 2*(x*y+z*w);m->m[1][1]=1-2*(x*x+z*z);m->m[1][2]= 2*(y*z-x*w);m->m[1][3]=oy; + m->m[2][0]= 2*(x*z-y*w);m->m[2][1]= 2*(y*z+x*w);m->m[2][2]=1-2*(x*x+y*y);m->m[2][3]=oz; + m->m[3][0]= 0 ;m->m[3][1]= 0 ;m->m[3][2]= 0 ;m->m[3][3]=1; +#endif +} + +void Matrix4x4_FromBonePose7s(matrix4x4_t *m, float originscale, const short *pose7s) +{ + float origin[3]; + float quat[4]; + float quatscale = pose7s[6] > 0 ? -1.0f / 32767.0f : 1.0f / 32767.0f; + origin[0] = pose7s[0] * originscale; + origin[1] = pose7s[1] * originscale; + origin[2] = pose7s[2] * originscale; + quat[0] = pose7s[3] * quatscale; + quat[1] = pose7s[4] * quatscale; + quat[2] = pose7s[5] * quatscale; + quat[3] = pose7s[6] * quatscale; + Matrix4x4_FromOriginQuat(m, origin[0], origin[1], origin[2], quat[0], quat[1], quat[2], quat[3]); +} + +void Matrix4x4_ToBonePose7s(const matrix4x4_t *m, float origininvscale, short *pose7s) +{ + float origin[3]; + float quat[4]; + float quatscale; + Matrix4x4_ToOrigin3Quat4Float(m, origin, quat); + // normalize quaternion so that it is unit length + quatscale = quat[0]*quat[0]+quat[1]*quat[1]+quat[2]*quat[2]+quat[3]*quat[3]; + if (quatscale) + quatscale = (quat[3] >= 0 ? -32767.0f : 32767.0f) / sqrt(quatscale); + // use a negative scale on the quat because the above function produces a + // positive quat[3] and canonical quaternions have negative quat[3] + pose7s[0] = origin[0] * origininvscale; + pose7s[1] = origin[1] * origininvscale; + pose7s[2] = origin[2] * origininvscale; + pose7s[3] = quat[0] * quatscale; + pose7s[4] = quat[1] * quatscale; + pose7s[5] = quat[2] * quatscale; + pose7s[6] = quat[3] * quatscale; +} + +void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend) +{ + double iblend = 1 - blend; + out->m[0][0] = in1->m[0][0] * iblend + in2->m[0][0] * blend; + out->m[0][1] = in1->m[0][1] * iblend + in2->m[0][1] * blend; + out->m[0][2] = in1->m[0][2] * iblend + in2->m[0][2] * blend; + out->m[0][3] = in1->m[0][3] * iblend + in2->m[0][3] * blend; + out->m[1][0] = in1->m[1][0] * iblend + in2->m[1][0] * blend; + out->m[1][1] = in1->m[1][1] * iblend + in2->m[1][1] * blend; + out->m[1][2] = in1->m[1][2] * iblend + in2->m[1][2] * blend; + out->m[1][3] = in1->m[1][3] * iblend + in2->m[1][3] * blend; + out->m[2][0] = in1->m[2][0] * iblend + in2->m[2][0] * blend; + out->m[2][1] = in1->m[2][1] * iblend + in2->m[2][1] * blend; + out->m[2][2] = in1->m[2][2] * iblend + in2->m[2][2] * blend; + out->m[2][3] = in1->m[2][3] * iblend + in2->m[2][3] * blend; + out->m[3][0] = in1->m[3][0] * iblend + in2->m[3][0] * blend; + out->m[3][1] = in1->m[3][1] * iblend + in2->m[3][1] * blend; + out->m[3][2] = in1->m[3][2] * iblend + in2->m[3][2] * blend; + out->m[3][3] = in1->m[3][3] * iblend + in2->m[3][3] * blend; +} + + +void Matrix4x4_Transform (const matrix4x4_t *in, const float v[3], float out[3]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[0] = v[0] * in->m[0][0] + v[1] * in->m[1][0] + v[2] * in->m[2][0] + in->m[3][0]; + out[1] = v[0] * in->m[0][1] + v[1] * in->m[1][1] + v[2] * in->m[2][1] + in->m[3][1]; + out[2] = v[0] * in->m[0][2] + v[1] * in->m[1][2] + v[2] * in->m[2][2] + in->m[3][2]; +#else + out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2] + in->m[0][3]; + out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2] + in->m[1][3]; + out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2] + in->m[2][3]; +#endif +} + +void Matrix4x4_Transform4 (const matrix4x4_t *in, const float v[4], float out[4]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[0] = v[0] * in->m[0][0] + v[1] * in->m[1][0] + v[2] * in->m[2][0] + v[3] * in->m[3][0]; + out[1] = v[0] * in->m[0][1] + v[1] * in->m[1][1] + v[2] * in->m[2][1] + v[3] * in->m[3][1]; + out[2] = v[0] * in->m[0][2] + v[1] * in->m[1][2] + v[2] * in->m[2][2] + v[3] * in->m[3][2]; + out[3] = v[0] * in->m[0][3] + v[1] * in->m[1][3] + v[2] * in->m[2][3] + v[3] * in->m[3][3]; +#else + out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2] + v[3] * in->m[0][3]; + out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2] + v[3] * in->m[1][3]; + out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2] + v[3] * in->m[2][3]; + out[3] = v[0] * in->m[3][0] + v[1] * in->m[3][1] + v[2] * in->m[3][2] + v[3] * in->m[3][3]; +#endif +} + +void Matrix4x4_Transform3x3 (const matrix4x4_t *in, const float v[3], float out[3]) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[0] = v[0] * in->m[0][0] + v[1] * in->m[1][0] + v[2] * in->m[2][0]; + out[1] = v[0] * in->m[0][1] + v[1] * in->m[1][1] + v[2] * in->m[2][1]; + out[2] = v[0] * in->m[0][2] + v[1] * in->m[1][2] + v[2] * in->m[2][2]; +#else + out[0] = v[0] * in->m[0][0] + v[1] * in->m[0][1] + v[2] * in->m[0][2]; + out[1] = v[0] * in->m[1][0] + v[1] * in->m[1][1] + v[2] * in->m[1][2]; + out[2] = v[0] * in->m[2][0] + v[1] * in->m[2][1] + v[2] * in->m[2][2]; +#endif +} + +// transforms a positive distance plane (A*x+B*y+C*z-D=0) through a rotation or translation matrix +void Matrix4x4_TransformPositivePlane(const matrix4x4_t *in, float x, float y, float z, float d, float *o) +{ + float scale = sqrt(in->m[0][0] * in->m[0][0] + in->m[0][1] * in->m[0][1] + in->m[0][2] * in->m[0][2]); + float iscale = 1.0f / scale; +#ifdef MATRIX4x4_OPENGLORIENTATION + o[0] = (x * in->m[0][0] + y * in->m[1][0] + z * in->m[2][0]) * iscale; + o[1] = (x * in->m[0][1] + y * in->m[1][1] + z * in->m[2][1]) * iscale; + o[2] = (x * in->m[0][2] + y * in->m[1][2] + z * in->m[2][2]) * iscale; + o[3] = d * scale + (o[0] * in->m[3][0] + o[1] * in->m[3][1] + o[2] * in->m[3][2]); +#else + o[0] = (x * in->m[0][0] + y * in->m[0][1] + z * in->m[0][2]) * iscale; + o[1] = (x * in->m[1][0] + y * in->m[1][1] + z * in->m[1][2]) * iscale; + o[2] = (x * in->m[2][0] + y * in->m[2][1] + z * in->m[2][2]) * iscale; + o[3] = d * scale + (o[0] * in->m[0][3] + o[1] * in->m[1][3] + o[2] * in->m[2][3]); +#endif +} + +// transforms a standard plane (A*x+B*y+C*z+D=0) through a rotation or translation matrix +void Matrix4x4_TransformStandardPlane(const matrix4x4_t *in, float x, float y, float z, float d, float *o) +{ + float scale = sqrt(in->m[0][0] * in->m[0][0] + in->m[0][1] * in->m[0][1] + in->m[0][2] * in->m[0][2]); + float iscale = 1.0f / scale; +#ifdef MATRIX4x4_OPENGLORIENTATION + o[0] = (x * in->m[0][0] + y * in->m[1][0] + z * in->m[2][0]) * iscale; + o[1] = (x * in->m[0][1] + y * in->m[1][1] + z * in->m[2][1]) * iscale; + o[2] = (x * in->m[0][2] + y * in->m[1][2] + z * in->m[2][2]) * iscale; + o[3] = d * scale - (o[0] * in->m[3][0] + o[1] * in->m[3][1] + o[2] * in->m[3][2]); +#else + o[0] = (x * in->m[0][0] + y * in->m[0][1] + z * in->m[0][2]) * iscale; + o[1] = (x * in->m[1][0] + y * in->m[1][1] + z * in->m[1][2]) * iscale; + o[2] = (x * in->m[2][0] + y * in->m[2][1] + z * in->m[2][2]) * iscale; + o[3] = d * scale - (o[0] * in->m[0][3] + o[1] * in->m[1][3] + o[2] * in->m[2][3]); +#endif +} + +/* +void Matrix4x4_SimpleUntransform (const matrix4x4_t *in, const float v[3], float out[3]) +{ + double t[3]; +#ifdef MATRIX4x4_OPENGLORIENTATION + t[0] = v[0] - in->m[3][0]; + t[1] = v[1] - in->m[3][1]; + t[2] = v[2] - in->m[3][2]; + out[0] = t[0] * in->m[0][0] + t[1] * in->m[0][1] + t[2] * in->m[0][2]; + out[1] = t[0] * in->m[1][0] + t[1] * in->m[1][1] + t[2] * in->m[1][2]; + out[2] = t[0] * in->m[2][0] + t[1] * in->m[2][1] + t[2] * in->m[2][2]; +#else + t[0] = v[0] - in->m[0][3]; + t[1] = v[1] - in->m[1][3]; + t[2] = v[2] - in->m[2][3]; + out[0] = t[0] * in->m[0][0] + t[1] * in->m[1][0] + t[2] * in->m[2][0]; + out[1] = t[0] * in->m[0][1] + t[1] * in->m[1][1] + t[2] * in->m[2][1]; + out[2] = t[0] * in->m[0][2] + t[1] * in->m[1][2] + t[2] * in->m[2][2]; +#endif +} +*/ + +// FIXME: optimize +void Matrix4x4_ConcatTranslate (matrix4x4_t *out, double x, double y, double z) +{ + matrix4x4_t base, temp; + base = *out; + Matrix4x4_CreateTranslate(&temp, x, y, z); + Matrix4x4_Concat(out, &base, &temp); +} + +// FIXME: optimize +void Matrix4x4_ConcatRotate (matrix4x4_t *out, double angle, double x, double y, double z) +{ + matrix4x4_t base, temp; + base = *out; + Matrix4x4_CreateRotate(&temp, angle, x, y, z); + Matrix4x4_Concat(out, &base, &temp); +} + +// FIXME: optimize +void Matrix4x4_ConcatScale (matrix4x4_t *out, double x) +{ + matrix4x4_t base, temp; + base = *out; + Matrix4x4_CreateScale(&temp, x); + Matrix4x4_Concat(out, &base, &temp); +} + +// FIXME: optimize +void Matrix4x4_ConcatScale3 (matrix4x4_t *out, double x, double y, double z) +{ + matrix4x4_t base, temp; + base = *out; + Matrix4x4_CreateScale3(&temp, x, y, z); + Matrix4x4_Concat(out, &base, &temp); +} + +void Matrix4x4_OriginFromMatrix (const matrix4x4_t *in, float *out) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out[0] = in->m[3][0]; + out[1] = in->m[3][1]; + out[2] = in->m[3][2]; +#else + out[0] = in->m[0][3]; + out[1] = in->m[1][3]; + out[2] = in->m[2][3]; +#endif +} + +double Matrix4x4_ScaleFromMatrix (const matrix4x4_t *in) +{ + // we only support uniform scaling, so assume the first row is enough + return sqrt(in->m[0][0] * in->m[0][0] + in->m[0][1] * in->m[0][1] + in->m[0][2] * in->m[0][2]); +} + +void Matrix4x4_SetOrigin (matrix4x4_t *out, double x, double y, double z) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[3][0] = x; + out->m[3][1] = y; + out->m[3][2] = z; +#else + out->m[0][3] = x; + out->m[1][3] = y; + out->m[2][3] = z; +#endif +} + +void Matrix4x4_AdjustOrigin (matrix4x4_t *out, double x, double y, double z) +{ +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[3][0] += x; + out->m[3][1] += y; + out->m[3][2] += z; +#else + out->m[0][3] += x; + out->m[1][3] += y; + out->m[2][3] += z; +#endif +} + +void Matrix4x4_Scale (matrix4x4_t *out, double rotatescale, double originscale) +{ + out->m[0][0] *= rotatescale; + out->m[0][1] *= rotatescale; + out->m[0][2] *= rotatescale; + out->m[1][0] *= rotatescale; + out->m[1][1] *= rotatescale; + out->m[1][2] *= rotatescale; + out->m[2][0] *= rotatescale; + out->m[2][1] *= rotatescale; + out->m[2][2] *= rotatescale; +#ifdef MATRIX4x4_OPENGLORIENTATION + out->m[3][0] *= originscale; + out->m[3][1] *= originscale; + out->m[3][2] *= originscale; +#else + out->m[0][3] *= originscale; + out->m[1][3] *= originscale; + out->m[2][3] *= originscale; +#endif +} + +void Matrix4x4_Abs (matrix4x4_t *out) +{ + out->m[0][0] = fabs(out->m[0][0]); + out->m[0][1] = fabs(out->m[0][1]); + out->m[0][2] = fabs(out->m[0][2]); + out->m[1][0] = fabs(out->m[1][0]); + out->m[1][1] = fabs(out->m[1][1]); + out->m[1][2] = fabs(out->m[1][2]); + out->m[2][0] = fabs(out->m[2][0]); + out->m[2][1] = fabs(out->m[2][1]); + out->m[2][2] = fabs(out->m[2][2]); +} + diff --git a/app/jni/matrixlib.h b/app/jni/matrixlib.h new file mode 100644 index 0000000..232f1ad --- /dev/null +++ b/app/jni/matrixlib.h @@ -0,0 +1,172 @@ + +#ifndef MATRIXLIB_H +#define MATRIXLIB_H + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +//#define MATRIX4x4_OPENGLORIENTATION + +typedef struct matrix4x4_s +{ + vec_t m[4][4]; +} +matrix4x4_t; + +extern const matrix4x4_t identitymatrix; + +// functions for manipulating 4x4 matrices + +// copy a matrix4x4 +void Matrix4x4_Copy (matrix4x4_t *out, const matrix4x4_t *in); +// copy only the rotation portion of a matrix4x4 +void Matrix4x4_CopyRotateOnly (matrix4x4_t *out, const matrix4x4_t *in); +// copy only the translate portion of a matrix4x4 +void Matrix4x4_CopyTranslateOnly (matrix4x4_t *out, const matrix4x4_t *in); +// multiply two matrix4x4 together, combining their transformations +// (warning: order matters - Concat(a, b, c) != Concat(a, c, b)) +void Matrix4x4_Concat (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2); +// swaps the rows and columns of the matrix +// (is this useful for anything?) +void Matrix4x4_Transpose (matrix4x4_t *out, const matrix4x4_t *in1); +// creates a matrix that does the opposite of the matrix provided +// this is a full matrix inverter, it should be able to invert any matrix that +// is possible to invert +// (non-uniform scaling, rotation, shearing, and translation, possibly others) +// warning: this function is SLOW +int Matrix4x4_Invert_Full (matrix4x4_t *out, const matrix4x4_t *in1); +// creates a matrix that does the opposite of the matrix provided +// only supports translate, rotate, scale (not scale3) matrices +void Matrix4x4_Invert_Simple (matrix4x4_t *out, const matrix4x4_t *in1); +// blends between two matrices, used primarily for animation interpolation +// (note: it is recommended to follow this with Matrix4x4_Normalize, a method +// known as nlerp rotation, often better for animation purposes than slerp) +void Matrix4x4_Interpolate (matrix4x4_t *out, matrix4x4_t *in1, matrix4x4_t *in2, double frac); +// zeros all matrix components, used with Matrix4x4_Accumulate +void Matrix4x4_Clear (matrix4x4_t *out); +// adds a weighted contribution from the supplied matrix, used to blend 3 or +// more matrices with weighting, it is recommended that Matrix4x4_Normalize be +// called afterward (a method known as nlerp rotation, often better for +// animation purposes than slerp) +void Matrix4x4_Accumulate (matrix4x4_t *out, matrix4x4_t *in, double weight); +// creates a matrix that does the same rotation and translation as the matrix +// provided, but no uniform scaling, does not support scale3 matrices +void Matrix4x4_Normalize (matrix4x4_t *out, matrix4x4_t *in1); +// creates a matrix with vectors normalized individually (use after +// Matrix4x4_Accumulate) +void Matrix4x4_Normalize3 (matrix4x4_t *out, matrix4x4_t *in1); +// modifies a matrix to have all vectors and origin reflected across the plane +// to the opposite side (at least if axisscale is -2) +void Matrix4x4_Reflect (matrix4x4_t *out, double normalx, double normaly, double normalz, double dist, double axisscale); + +// creates an identity matrix +// (a matrix which does nothing) +void Matrix4x4_CreateIdentity (matrix4x4_t *out); +// creates a translate matrix +// (moves vectors) +void Matrix4x4_CreateTranslate (matrix4x4_t *out, double x, double y, double z); +// creates a rotate matrix +// (rotates vectors) +void Matrix4x4_CreateRotate (matrix4x4_t *out, double angle, double x, double y, double z); +// creates a scaling matrix +// (expands or contracts vectors) +// (warning: do not apply this kind of matrix to direction vectors) +void Matrix4x4_CreateScale (matrix4x4_t *out, double x); +// creates a squishing matrix +// (expands or contracts vectors differently in different axis) +// (warning: this is not reversed by Invert_Simple) +// (warning: do not apply this kind of matrix to direction vectors) +void Matrix4x4_CreateScale3 (matrix4x4_t *out, double x, double y, double z); +// creates a matrix for a quake entity +void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, double x, double y, double z, double pitch, double yaw, double roll, double scale); + +// converts a matrix4x4 to a set of 3D vectors for the 3 axial directions, and the translate +void Matrix4x4_ToVectors(const matrix4x4_t *in, vec_t vx[3], vec_t vy[3], vec_t vz[3], vec_t t[3]); +// creates a matrix4x4 from a set of 3D vectors for axial directions, and translate +void Matrix4x4_FromVectors(matrix4x4_t *out, const vec_t vx[3], const vec_t vy[3], const vec_t vz[3], const vec_t t[3]); + +// converts a matrix4x4 to a double[16] array in the OpenGL orientation +void Matrix4x4_ToArrayDoubleGL(const matrix4x4_t *in, double out[16]); +// creates a matrix4x4 from a double[16] array in the OpenGL orientation +void Matrix4x4_FromArrayDoubleGL(matrix4x4_t *out, const double in[16]); +// converts a matrix4x4 to a double[16] array in the Direct3D orientation +void Matrix4x4_ToArrayDoubleD3D(const matrix4x4_t *in, double out[16]); +// creates a matrix4x4 from a double[16] array in the Direct3D orientation +void Matrix4x4_FromArrayDoubleD3D(matrix4x4_t *out, const double in[16]); + +// converts a matrix4x4 to a float[16] array in the OpenGL orientation +void Matrix4x4_ToArrayFloatGL(const matrix4x4_t *in, float out[16]); +// creates a matrix4x4 from a float[16] array in the OpenGL orientation +void Matrix4x4_FromArrayFloatGL(matrix4x4_t *out, const float in[16]); +// converts a matrix4x4 to a float[16] array in the Direct3D orientation +void Matrix4x4_ToArrayFloatD3D(const matrix4x4_t *in, float out[16]); +// creates a matrix4x4 from a float[16] array in the Direct3D orientation +void Matrix4x4_FromArrayFloatD3D(matrix4x4_t *out, const float in[16]); + +// converts a matrix4x4 to a float[12] array in the OpenGL orientation +void Matrix4x4_ToArray12FloatGL(const matrix4x4_t *in, float out[12]); +// creates a matrix4x4 from a float[12] array in the OpenGL orientation +void Matrix4x4_FromArray12FloatGL(matrix4x4_t *out, const float in[12]); +// converts a matrix4x4 to a float[12] array in the Direct3D orientation +void Matrix4x4_ToArray12FloatD3D(const matrix4x4_t *in, float out[12]); +// creates a matrix4x4 from a float[12] array in the Direct3D orientation +void Matrix4x4_FromArray12FloatD3D(matrix4x4_t *out, const float in[12]); + +// creates a matrix4x4 from an origin and quaternion (used mostly with skeletal model formats such as PSK) +void Matrix4x4_FromOriginQuat(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z, double w); +// creates an origin and quaternion from a matrix4x4_t, quat[3] is always positive +void Matrix4x4_ToOrigin3Quat4Float(const matrix4x4_t *m, float *origin, float *quat); +// creates a matrix4x4 from an origin and canonical unit-length quaternion (used mostly with skeletal model formats such as MD5) +void Matrix4x4_FromDoom3Joint(matrix4x4_t *m, double ox, double oy, double oz, double x, double y, double z); + +// creates a matrix4x4_t from an origin and canonical unit-length quaternion in short[7] normalized format +void Matrix4x4_FromBonePose7s(matrix4x4_t *m, float originscale, const short *pose7s); +// creates a short[7] representation from normalized matrix4x4_t +void Matrix4x4_ToBonePose7s(const matrix4x4_t *m, float origininvscale, short *pose7s); + +// blends two matrices together, at a given percentage (blend controls percentage of in2) +void Matrix4x4_Blend (matrix4x4_t *out, const matrix4x4_t *in1, const matrix4x4_t *in2, double blend); + +// transforms a 3D vector through a matrix4x4 +void Matrix4x4_Transform (const matrix4x4_t *in, const vec_t v[3], vec_t out[3]); +// transforms a 4D vector through a matrix4x4 +// (warning: if you don't know why you would need this, you don't need it) +// (warning: the 4th component of the vector should be 1.0) +void Matrix4x4_Transform4 (const matrix4x4_t *in, const vec_t v[4], vec_t out[4]); +// reverse transforms a 3D vector through a matrix4x4, at least for *simple* +// cases (rotation and translation *ONLY*), this attempts to undo the results +// of Transform +//void Matrix4x4_SimpleUntransform (const matrix4x4_t *in, const vec_t v[3], vec_t out[3]); +// transforms a direction vector through the rotation part of a matrix +void Matrix4x4_Transform3x3 (const matrix4x4_t *in, const vec_t v[3], vec_t out[3]); +// transforms a positive distance plane (A*x+B*y+C*z-D=0) through a rotation or translation matrix +void Matrix4x4_TransformPositivePlane (const matrix4x4_t *in, vec_t x, vec_t y, vec_t z, vec_t d, vec_t *o); +// transforms a standard plane (A*x+B*y+C*z+D=0) through a rotation or translation matrix +void Matrix4x4_TransformStandardPlane (const matrix4x4_t *in, vec_t x, vec_t y, vec_t z, vec_t d, vec_t *o); + +// ease of use functions +// immediately applies a Translate to the matrix +void Matrix4x4_ConcatTranslate (matrix4x4_t *out, double x, double y, double z); +// immediately applies a Rotate to the matrix +void Matrix4x4_ConcatRotate (matrix4x4_t *out, double angle, double x, double y, double z); +// immediately applies a Scale to the matrix +void Matrix4x4_ConcatScale (matrix4x4_t *out, double x); +// immediately applies a Scale3 to the matrix +void Matrix4x4_ConcatScale3 (matrix4x4_t *out, double x, double y, double z); + +// extracts origin vector (translate) from matrix +void Matrix4x4_OriginFromMatrix (const matrix4x4_t *in, vec_t *out); +// extracts scaling factor from matrix (only works for uniform scaling) +double Matrix4x4_ScaleFromMatrix (const matrix4x4_t *in); + +// replaces origin vector (translate) in matrix +void Matrix4x4_SetOrigin (matrix4x4_t *out, double x, double y, double z); +// moves origin vector (translate) in matrix by a simple translate +void Matrix4x4_AdjustOrigin (matrix4x4_t *out, double x, double y, double z); +// scales vectors of a matrix in place and allows you to scale origin as well +void Matrix4x4_Scale (matrix4x4_t *out, double rotatescale, double originscale); +// ensures each element of the 3x3 rotation matrix is facing in the + direction +void Matrix4x4_Abs (matrix4x4_t *out); + +#endif diff --git a/app/jni/mdfour.c b/app/jni/mdfour.c new file mode 100644 index 0000000..ddb4f26 --- /dev/null +++ b/app/jni/mdfour.c @@ -0,0 +1,229 @@ +/* + mdfour.c + + An implementation of MD4 designed for use in the samba SMB + authentication protocol + + Copyright (C) 1997-1998 Andrew Tridgell + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id: mdfour.c 10534 2010-10-15 13:47:19Z divverent $ +*/ + +#include "quakedef.h" + +#include /* XoXus: needed for memset call */ +#include "mdfour.h" + +/* NOTE: This code makes no attempt to be fast! + + It assumes that a int is at least 32 bits long +*/ + +static struct mdfour *m; + +#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z))) +#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) +#define H(X,Y,Z) ((X)^(Y)^(Z)) +#ifdef LARGE_INT32 +#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF)) +#else +#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s)))) +#endif + +#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void mdfour64(uint32 *M) +{ + int j; + uint32 AA, BB, CC, DD; + uint32 X[16]; + uint32 A,B,C,D; + + for (j=0;j<16;j++) + X[j] = M[j]; + + A = m->A; B = m->B; C = m->C; D = m->D; + AA = A; BB = B; CC = C; DD = D; + + ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); + ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); + ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); + ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); + ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); + ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); + ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); + ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); + + ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); + ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); + ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); + ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); + ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); + ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); + ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); + ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); + + ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); + ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); + ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); + ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); + ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); + ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); + ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); + ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); + + A += AA; B += BB; C += CC; D += DD; + +#ifdef LARGE_INT32 + A &= 0xFFFFFFFF; B &= 0xFFFFFFFF; + C &= 0xFFFFFFFF; D &= 0xFFFFFFFF; +#endif + + for (j=0;j<16;j++) + X[j] = 0; + + m->A = A; m->B = B; m->C = C; m->D = D; +} + +static void copy64(uint32 *M, const unsigned char *in) +{ + int i; + + for (i=0;i<16;i++) + M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | + (in[i*4+1]<<8) | (in[i*4+0]<<0); +} + +static void copy4(unsigned char *out,uint32 x) +{ + out[0] = x&0xFF; + out[1] = (x>>8)&0xFF; + out[2] = (x>>16)&0xFF; + out[3] = (x>>24)&0xFF; +} + +void mdfour_begin(struct mdfour *md) +{ + md->A = 0x67452301; + md->B = 0xefcdab89; + md->C = 0x98badcfe; + md->D = 0x10325476; + md->totalN = 0; +} + + +static void mdfour_tail(const unsigned char *in, int n) +{ + unsigned char buf[128]; + uint32 M[16]; + uint32 b; + + m->totalN += n; + + b = m->totalN * 8; + + memset(buf, 0, 128); + if (n) memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf+56, b); + copy64(M, buf); + mdfour64(M); + } else { + copy4(buf+120, b); + copy64(M, buf); + mdfour64(M); + copy64(M, buf+64); + mdfour64(M); + } +} + +void mdfour_update(struct mdfour *md, const unsigned char *in, int n) +{ + uint32 M[16]; + +// start of edit by Forest 'LordHavoc' Hale +// commented out to prevent crashing when length is 0 +// if (n == 0) mdfour_tail(in, n); +// end of edit by Forest 'LordHavoc' Hale + + m = md; + + while (n >= 64) { + copy64(M, in); + mdfour64(M); + in += 64; + n -= 64; + m->totalN += 64; + } + + mdfour_tail(in, n); +} + + +void mdfour_result(struct mdfour *md, unsigned char *out) +{ + m = md; + + copy4(out, m->A); + copy4(out+4, m->B); + copy4(out+8, m->C); + copy4(out+12, m->D); +} + + +void mdfour(unsigned char *out, const unsigned char *in, int n) +{ + struct mdfour md; + mdfour_begin(&md); + mdfour_update(&md, in, n); + mdfour_result(&md, out); +} + +/////////////////////////////////////////////////////////////// +// MD4-based checksum utility functions +// +// Copyright (C) 2000 Jeff Teunissen +// +// Author: Jeff Teunissen +// Date: 01 Jan 2000 + +unsigned Com_BlockChecksum (void *buffer, int length) +{ + int digest[4]; + unsigned val; + + mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length ); + + val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; + + return val; +} + +void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf) +{ + mdfour ( outbuf, (unsigned char *) buffer, len ); +} + diff --git a/app/jni/mdfour.h b/app/jni/mdfour.h new file mode 100644 index 0000000..3ef654c --- /dev/null +++ b/app/jni/mdfour.h @@ -0,0 +1,54 @@ +/* + mdfour.h + + an implementation of MD4 designed for use in the SMB authentication + protocol + + Copyright (C) Andrew Tridgell 1997-1998 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA +*/ + +#ifndef _MDFOUR_H +#define _MDFOUR_H + +#ifndef int32 +#define int32 int +#endif + +#if SIZEOF_INT > 4 +#define LARGE_INT32 +#endif + +#ifndef uint32 +#define uint32 unsigned int32 +#endif + +struct mdfour { + uint32 A, B, C, D; + uint32 totalN; +}; + +void mdfour_begin(struct mdfour *md); // old: MD4Init +void mdfour_update(struct mdfour *md, const unsigned char *in, int n); //old: MD4Update +void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final +void mdfour(unsigned char *out, const unsigned char *in, int n); + +#endif // _MDFOUR_H + diff --git a/app/jni/menu.c b/app/jni/menu.c new file mode 100644 index 0000000..bb74e71 --- /dev/null +++ b/app/jni/menu.c @@ -0,0 +1,6055 @@ +/* +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 "cdaudio.h" +#include "image.h" +#include "progsvm.h" + +#include "mprogdefs.h" + +#define QVR_VERSION "1.0.0" + +#define TYPE_DEMO 1 +#define TYPE_GAME 2 +#define TYPE_BOTH 3 + +static cvar_t forceqmenu = { 0, "forceqmenu", "0", "enables the quake menu instead of the quakec menu.dat (if present)" }; +static cvar_t menu_progs = { 0, "menu_progs", "menu.dat", "name of quakec menu.dat file" }; + +static int NehGameType; + +static const char* sNo = "No"; +static const char* sYes = "Yes"; + +//Game always starts in vr mode, showing the menu on the big screen in stereo +int vrMode = 2; +int bigScreen = 1; +int stereoMode = 1; + +extern int andrw; + +enum m_state_e m_state = m_main; +char m_return_reason[128]; + +extern vec3_t hmdorientation; +extern char *strGameFolder; + +extern cvar_t r_worldscale; +extern cvar_t v_eyebufferresolution; + +extern void jni_SwitchVRMode(int mode); +extern void jni_BigScreenMode(int mode); +extern void jni_SwitchStereoMode(int mode); + +//Record yaw at the moment the menu is invoked +static float hmdYaw = 0; + +void M_Menu_Main_f (void); + void M_Menu_SinglePlayer_f (void); + void M_Menu_Transfusion_Episode_f (void); + void M_Menu_Transfusion_Skill_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_Options_f (void); + void M_Menu_Options_Effects_f (void); + void M_Menu_Options_Graphics_f (void); + void M_Menu_Options_ColorControl_f (void); + void M_Menu_Keys_f (void); + void M_Menu_Reset_f (void); + void M_Menu_Video_f (void); + void M_Menu_YawPitchControl_f (void); + void M_Menu_Help_f (void); + void M_Menu_Credits_f (void); + void M_Menu_Quit_f (void); +void M_Menu_LanConfig_f (void); +void M_Menu_GameOptions_f (void); +void M_Menu_ServerList_f (void); +void M_Menu_ModList_f (void); + +static void M_Main_Draw (void); + static void M_SinglePlayer_Draw (void); + static void M_Transfusion_Episode_Draw (void); + static void M_Transfusion_Skill_Draw (void); + static void M_Load_Draw (void); + static void M_Save_Draw (void); + static void M_MultiPlayer_Draw (void); + static void M_Setup_Draw (void); + static void M_Options_Draw (void); + static void M_Options_Effects_Draw (void); + static void M_Options_Graphics_Draw (void); + static void M_Options_ColorControl_Draw (void); + static void M_Keys_Draw (void); + static void M_Reset_Draw (void); + static void M_Video_Draw (void); + static void M_Menu_YawPitchControl_Draw (void); + static void M_Help_Draw (void); + static void M_Credits_Draw (void); + static void M_Quit_Draw (void); +static void M_LanConfig_Draw (void); +static void M_GameOptions_Draw (void); +static void M_ServerList_Draw (void); +static void M_ModList_Draw (void); + + +static void M_Main_Key (int key, int ascii); + static void M_SinglePlayer_Key (int key, int ascii); + static void M_Transfusion_Episode_Key (int key, int ascii); + static void M_Transfusion_Skill_Key (int key, int ascii); + static void M_Load_Key (int key, int ascii); + static void M_Save_Key (int key, int ascii); + static void M_MultiPlayer_Key (int key, int ascii); + static void M_Setup_Key (int key, int ascii); + static void M_Options_Key (int key, int ascii); + static void M_Options_Effects_Key (int key, int ascii); + static void M_Options_Graphics_Key (int key, int ascii); + static void M_Options_ColorControl_Key (int key, int ascii); + static void M_Keys_Key (int key, int ascii); + static void M_Reset_Key (int key, int ascii); + static void M_Video_Key (int key, int ascii); + static void M_Menu_YawPitchControl_Key (int key, int ascii); + static void M_Help_Key (int key, int ascii); + static void M_Credits_Key (int key, int ascii); + static void M_Quit_Key (int key, int ascii); +static void M_LanConfig_Key (int key, int ascii); +static void M_GameOptions_Key (int key, int ascii); +static void M_ServerList_Key (int key, int ascii); +static void M_ModList_Key (int key, int ascii); + +static qboolean m_entersound; ///< play after drawing a frame, so caching won't disrupt the sound + +void M_Update_Return_Reason(const char *s) +{ + strlcpy(m_return_reason, s, sizeof(m_return_reason)); + if (s) + Con_DPrintf("%s\n", s); +} + +#define StartingGame (m_multiplayer_cursor == 1) +#define JoiningGame (m_multiplayer_cursor == 0) + +// Nehahra +#define NumberOfNehahraDemos 34 +typedef struct nehahrademonames_s +{ + const char *name; + const char *desc; +} nehahrademonames_t; + +static nehahrademonames_t NehahraDemos[NumberOfNehahraDemos] = +{ + {"intro", "Prologue"}, + {"genf", "The Beginning"}, + {"genlab", "A Doomed Project"}, + {"nehcre", "The New Recruits"}, + {"maxneh", "Breakthrough"}, + {"maxchar", "Renewal and Duty"}, + {"crisis", "Worlds Collide"}, + {"postcris", "Darkening Skies"}, + {"hearing", "The Hearing"}, + {"getjack", "On a Mexican Radio"}, + {"prelude", "Honor and Justice"}, + {"abase", "A Message Sent"}, + {"effect", "The Other Side"}, + {"uhoh", "Missing in Action"}, + {"prepare", "The Response"}, + {"vision", "Farsighted Eyes"}, + {"maxturns", "Enter the Immortal"}, + {"backlot", "Separate Ways"}, + {"maxside", "The Ancient Runes"}, + {"counter", "The New Initiative"}, + {"warprep", "Ghosts to the World"}, + {"counter1", "A Fate Worse Than Death"}, + {"counter2", "Friendly Fire"}, + {"counter3", "Minor Setback"}, + {"madmax", "Scores to Settle"}, + {"quake", "One Man"}, + {"cthmm", "Shattered Masks"}, + {"shades", "Deal with the Dead"}, + {"gophil", "An Unlikely Hero"}, + {"cstrike", "War in Hell"}, + {"shubset", "The Conspiracy"}, + {"shubdie", "Even Death May Die"}, + {"newranks", "An Empty Throne"}, + {"seal", "The Seal is Broken"} +}; + +static float menu_x, menu_y, menu_width, menu_height; + +static void M_Background(int width, int height) +{ + menu_width = bound(1.0f, (float)width, vid_conwidth.value); + menu_height = bound(1.0f, (float)height, vid_conheight.value); + menu_x = (vid_conwidth.integer - menu_width) * 0.5; + menu_y = (vid_conheight.integer - menu_height) * 0.5; + + //Make the background barely visible when menu active.. this should avoid people + //throwing up while the demo is running! + DrawQ_Fill(0, 0, vid_conwidth.integer, vid_conheight.integer, 0, 0, 0, 0.75, 0); +} + +/* +================ +M_DrawCharacter + +Draws one solid graphics character +================ +*/ +static void M_DrawCharacter (float cx, float cy, int num) +{ + char temp[2]; + temp[0] = num; + temp[1] = 0; + DrawQ_String(menu_x + cx, menu_y + cy, temp, 1, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_MENU); +} + +static void M_PrintColored(float cx, float cy, const char *str) +{ + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_MENU); +} + +static void M_Print(float cx, float cy, const char *str) +{ + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_MENU); +} + +static void M_Print_Big(float cx, float cy, const char *str) +{ + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 12, 12, 1, 1, 1, 1, 0, NULL, true, FONT_MENU); +} + +static void M_PrintRed(float cx, float cy, const char *str) +{ + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 8, 8, 1, 0, 0, 1, 0, NULL, true, FONT_MENU); +} + +static void M_PrintRed_Big(float cx, float cy, const char *str) +{ + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 12, 12, 1, 0, 0, 1, 0, NULL, true, FONT_MENU); +} + +static void M_ItemPrint(float cx, float cy, const char *str, int unghosted) +{ + if (unghosted) + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_MENU); + else + DrawQ_String(menu_x + cx, menu_y + cy, str, 0, 8, 8, 0.4, 0.4, 0.4, 1, 0, NULL, true, FONT_MENU); +} + +static void M_DrawPic(float cx, float cy, const char *picname) +{ + DrawQ_Pic(menu_x + cx, menu_y + cy, Draw_CachePic (picname), 0, 0, 1, 1, 1, 1, 0); +} + +static void M_DrawTextBox(float x, float y, float width, float height) +{ + int n; + float cx, cy; + + // draw left side + cx = x; + cy = y; + M_DrawPic (cx, cy, "gfx/box_tl"); + for (n = 0; n < height; n++) + { + cy += 8; + M_DrawPic (cx, cy, "gfx/box_ml"); + } + M_DrawPic (cx, cy+8, "gfx/box_bl"); + + // draw middle + cx += 8; + while (width > 0) + { + cy = y; + M_DrawPic (cx, cy, "gfx/box_tm"); + for (n = 0; n < height; n++) + { + cy += 8; + if (n >= 1) + M_DrawPic (cx, cy, "gfx/box_mm2"); + else + M_DrawPic (cx, cy, "gfx/box_mm"); + } + M_DrawPic (cx, cy+8, "gfx/box_bm"); + width -= 2; + cx += 16; + } + + // draw right side + cy = y; + M_DrawPic (cx, cy, "gfx/box_tr"); + for (n = 0; n < height; n++) + { + cy += 8; + M_DrawPic (cx, cy, "gfx/box_mr"); + } + M_DrawPic (cx, cy+8, "gfx/box_br"); +} + +//============================================================================= + +//int m_save_demonum; + +extern cvar_t cl_nosplashscreen; +extern cvar_t cl_autocentreoffset; + +/* +================ +M_ToggleMenu +================ +*/ +static void M_ToggleMenu(int mode) +{ + m_entersound = true; + + if ((key_dest != key_menu && key_dest != key_menu_grabbed) || m_state != m_main) + { + if(mode == 0) + return; // the menu is off, and we want it off + + hmdYaw = hmdorientation[YAW]; + + if (mode == 1 || cl_nosplashscreen.integer == 1) + M_Menu_Main_f(); + else + //These are only shown at the start of the game + M_Menu_Credits_f(); + + jni_BigScreenMode(1); + } + else + { + if(mode == 1) + return; // the menu is on, and we want it on + key_dest = key_game; + m_state = m_none; + jni_BigScreenMode(0); + } +} + + +static int demo_cursor; +static void M_Demo_Draw (void) +{ + int i; + + M_Background(320, 200); + + for (i = 0;i < NumberOfNehahraDemos;i++) + M_Print(16, 16 + 8*i, NehahraDemos[i].desc); + + // line cursor + M_DrawCharacter (8, 16 + demo_cursor*8, 12+((int)(realtime*4)&1)); +} + + +static void M_Menu_Demos_f (void) +{ + key_dest = key_menu; + m_state = m_demo; + m_entersound = true; +} + + +static void M_Demo_Key (int k, int ascii) +{ + char vabuf[1024]; + switch (k) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + case K_MOUSE1: + case K_ENTER: + S_LocalSound ("sound/misc/menu2.wav"); + m_state = m_none; + key_dest = key_game; + Cbuf_AddText (va(vabuf, sizeof(vabuf), "playdemo %s\n", NehahraDemos[demo_cursor].name)); + return; + + case K_UPARROW: + case K_LEFTARROW: + case 'a': + S_LocalSound ("sound/misc/menu1.wav"); + demo_cursor--; + if (demo_cursor < 0) + demo_cursor = NumberOfNehahraDemos-1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + case 'd': + S_LocalSound ("sound/misc/menu1.wav"); + demo_cursor++; + if (demo_cursor >= NumberOfNehahraDemos) + demo_cursor = 0; + break; + } +} + +//============================================================================= +/* MAIN MENU */ + +static int m_main_cursor; +static qboolean m_missingdata = false; +int gameAssetsDownloadStatus = -1; + +static int MAIN_ITEMS = 5; // Nehahra: Menu Disable + + +void M_Menu_Main_f (void) +{ + const char *s; + s = "gfx/mainmenu"; + + if (gamemode == GAME_NEHAHRA) + { + if (FS_FileExists("maps/neh1m4.bsp")) + { + if (FS_FileExists("hearing.dem")) + { + Con_DPrint("Main menu: Nehahra movie and game detected.\n"); + NehGameType = TYPE_BOTH; + } + else + { + Con_DPrint("Nehahra game detected.\n"); + NehGameType = TYPE_GAME; + } + } + else + { + if (FS_FileExists("hearing.dem")) + { + Con_DPrint("Nehahra movie detected.\n"); + NehGameType = TYPE_DEMO; + } + else + { + Con_DPrint("Nehahra not found.\n"); + NehGameType = TYPE_GAME; // could just complain, but... + } + } + if (NehGameType == TYPE_DEMO) + MAIN_ITEMS = 4; + else if (NehGameType == TYPE_GAME) + MAIN_ITEMS = 5; + else + MAIN_ITEMS = 6; + } + else if (gamemode == GAME_TRANSFUSION) + { + s = "gfx/menu/mainmenu1"; + if (sv.active && !cl.intermission && cl.islocalgame) + MAIN_ITEMS = 8; + else + MAIN_ITEMS = 7; + } + else + MAIN_ITEMS = 6; + + // check if the game data is missing and use a different main menu if so + m_missingdata = !forceqmenu.integer && Draw_CachePic (s)->tex == r_texture_notexture; + if (m_missingdata) + MAIN_ITEMS = 2; + + /* + if (key_dest != key_menu) + { + m_save_demonum = cls.demonum; + cls.demonum = -1; + } + */ + key_dest = key_menu; + m_state = m_main; + m_entersound = true; + jni_BigScreenMode(1); +} + + +static void M_Main_Draw (void) +{ + int f; + cachepic_t *p; + char vabuf[1024]; + + if (m_missingdata) + { + //If we are in VR mode, switch out of it + if (vrMode > 0) { + vrMode = 0; + jni_SwitchVRMode(0); + showfps.integer = 0; + } + + float y; + const char *s; + M_Background(640, 480); //fall back is always to 640x480, this makes it most readable at that. + y = 480/3-16; + + if (gameAssetsDownloadStatus == -1) + { + s = "** YOU NEED TO COPY GAME FILES TO YOUR PHONE **"; + M_PrintRed_Big ((640-strlen(s)*12)*0.5, (480/3)-16, s);y+=32; + s = "Due to copyright, game data files can't be included";M_Print_Big (30, y, s);y+=20; + s = "Please download the shareware version from:";M_Print_Big(30, y, s);y+=20; + s = "http://bit.ly/1PTsnsb";M_Print_Big(30, y, s);y+=20; + s = "or copy the pak files from the full version ";M_Print_Big(30, y, s);y+=20; + s = "to the following folder :";M_Print_Big(30, y, s);y+=20; + s = "{PHONE_MEMORY} / QVR / id1";M_Print_Big(30, y, s);y+=28; + s = "Full instructions doc: http://bit.ly/21GHVXI";M_Print_Big(30, y, s);y+=20; + } + else if (gameAssetsDownloadStatus == 0) + { + s = "** SHAREWARE DOWNLOAD FAILED **"; + M_PrintRed_Big((640 - strlen(s) * 12) * 0.5, (480 / 3) - 16, s); + y += 32; + s = "Please restart QVR"; + M_Print_Big(30, y, s); + y += 20; + s = "and the download will try again"; + M_Print_Big(30, y, s); + y += 20; + s = "If you own the full game you can"; + M_Print_Big(30, y, s); + y += 20; + s = "copy the pak files from the full version "; + M_Print_Big(30, y, s); + y += 20; + s = "to the following folder :"; + M_Print_Big(30, y, s); + y += 20; + s = "{PHONE_MEMORY} / QVR / id1"; + M_Print_Big(30, y, s); + y += 28; + s = "Full instructions doc: http://bit.ly/21GHVXI"; + M_Print_Big(30, y, s); + y += 20; + } + else if (gameAssetsDownloadStatus == 1) { + s = "** SHAREWARE DOWNLOAD COMPLETED SUCCESSFULLY **"; + M_PrintRed_Big((640 - strlen(s) * 12) * 0.5, (480 / 3) - 16, s); + y += 32; + s = "Please restart QVR"; + M_Print_Big(30, y, s); + y += 20; + s = "If you own the full game you can"; + M_Print_Big(30, y, s); + y += 20; + s = "copy the pak files from the full version "; + M_Print_Big(30, y, s); + y += 20; + s = "to the following folder :"; + M_Print_Big(30, y, s); + y += 20; + s = "{PHONE_MEMORY} / QVR / id1"; + M_Print_Big(30, y, s); + y += 28; + s = "Full instructions doc: http://bit.ly/21GHVXI"; + M_Print_Big(30, y, s); + y += 20; + } + else if (gameAssetsDownloadStatus == 2) + { + s = "** GAME FILES NEED TO DOWNLOAD TO YOUR PHONE **"; + M_PrintRed_Big((640 - strlen(s) * 12) * 0.5, (480 / 3) - 16, s); + y += 32; + s = "Due to copyright, game data files cannot be included"; + M_Print_Big(30, y, s); + y += 20; + s = "The shareware version is downloading."; + M_Print_Big(30, y, s); + } + + M_Print_Big (640/2 - 128, 480/2 + 128, " ++ Tap Screen to Quit ++"); + + M_DrawCharacter(640/2 - 128, 480/2 + 128, 12+((int)(realtime*4)&1)); + return; + } + + if (gamemode == GAME_TRANSFUSION) { + int y1, y2, y3; + M_Background(640, 480); + p = Draw_CachePic ("gfx/menu/tb-transfusion"); + M_DrawPic (640/2 - p->width/2, 40, "gfx/menu/tb-transfusion"); + y2 = 120; + // 8 rather than MAIN_ITEMS to skip a number and not miss the last option + for (y1 = 1; y1 <= 8; y1++) + { + if (MAIN_ITEMS == 7 && y1 == 4) + y1++; + M_DrawPic (0, y2, va(vabuf, sizeof(vabuf), "gfx/menu/mainmenu%i", y1)); + y2 += 40; + } + if (MAIN_ITEMS == 7 && m_main_cursor > 2) + y3 = m_main_cursor + 2; + else + y3 = m_main_cursor + 1; + M_DrawPic (0, 120 + m_main_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/mainmenu%iselected", y3)); + return; + } + + M_Background(320, 200); + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/ttl_main"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_main"); + + M_DrawTextBox(72, 30, 28, 1); + char *mode = "Off"; + if (vrMode == 1) mode = "Side-by-Side"; + if (vrMode == 2) mode = "Cardboard"; + M_Print(86, 38, va(vabuf, sizeof(vabuf), "VR Mode: %s", mode)); + + +// Nehahra + if (gamemode == GAME_NEHAHRA) + { + if (NehGameType == TYPE_BOTH) + M_DrawPic (72, 54, "gfx/mainmenu"); + else if (NehGameType == TYPE_GAME) + M_DrawPic (72, 54, "gfx/gamemenu"); + else + M_DrawPic (72, 54, "gfx/demomenu"); + } + else + M_DrawPic (72, 54, "gfx/mainmenu"); + + f = (int)(realtime * 10)%6; + + M_DrawPic (54, 34 + m_main_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1)); +} + + +static void M_Main_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + key_dest = key_game; + m_state = m_none; + jni_BigScreenMode(0); + //cls.demonum = m_save_demonum; + //if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected) + // CL_NextDemo (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (++m_main_cursor >= MAIN_ITEMS) + m_main_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (--m_main_cursor < 0) + m_main_cursor = MAIN_ITEMS - 1; + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + + if (m_missingdata) + { + Host_Quit_f (); + key_dest = key_game; + m_state = m_none; + } + else if (gamemode == GAME_NEHAHRA) + { + switch (NehGameType) + { + case TYPE_BOTH: + switch (m_main_cursor) + { + case 0: + M_Menu_SinglePlayer_f (); + break; + + case 1: + M_Menu_Demos_f (); + break; + + case 2: + M_Menu_MultiPlayer_f (); + break; + + case 3: + M_Menu_Options_f (); + break; + + case 4: + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("playdemo endcred\n"); + break; + + case 5: + M_Menu_Quit_f (); + break; + } + break; + case TYPE_GAME: + 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: + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("playdemo endcred\n"); + break; + + case 4: + M_Menu_Quit_f (); + break; + } + break; + case TYPE_DEMO: + switch (m_main_cursor) + { + case 0: + M_Menu_Demos_f (); + break; + + case 1: + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("playdemo endcred\n"); + break; + + case 2: + M_Menu_Options_f (); + break; + + case 3: + M_Menu_Quit_f (); + break; + } + break; + } + } + else if (gamemode == GAME_TRANSFUSION) { + if (MAIN_ITEMS == 7) + { + switch (m_main_cursor) + { + case 0: + M_Menu_Transfusion_Episode_f (); + break; + + case 1: + M_Menu_MultiPlayer_f (); + break; + + case 2: + M_Menu_Options_f (); + break; + + case 3: + M_Menu_Load_f (); + break; + + case 4: + M_Menu_Help_f (); + break; + + case 5: + M_Menu_Credits_f (); + break; + + case 6: + M_Menu_Quit_f (); + break; + } + } + else + { + switch (m_main_cursor) + { + case 0: + M_Menu_Transfusion_Episode_f (); + break; + + case 1: + M_Menu_MultiPlayer_f (); + break; + + case 2: + M_Menu_Options_f (); + break; + + case 3: + M_Menu_Save_f (); + break; + + case 4: + M_Menu_Load_f (); + break; + + case 5: + M_Menu_Help_f (); + break; + + case 6: + M_Menu_Credits_f (); + break; + + case 7: + M_Menu_Quit_f (); + break; + } + } + } + else + { + switch (m_main_cursor) + { + case 0: + vrMode = (vrMode + 1) % 3; + jni_SwitchVRMode(vrMode); + break; + + case 1: + M_Menu_SinglePlayer_f (); + break; + + case 2: + M_Menu_MultiPlayer_f (); + break; + + case 3: + M_Menu_Options_f (); + break; + + case 4: + M_Menu_Help_f (); + break; + + case 5: + M_Menu_Quit_f (); + break; + + } + } + } +} + +//============================================================================= +/* SINGLE PLAYER MENU */ + +static 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; +} + + +static void M_SinglePlayer_Draw (void) +{ + cachepic_t *p; + char vabuf[1024]; + + M_Background(320, 200); + + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/ttl_sgl"); + + // Some mods don't have a single player mode + if (gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH) + { + M_DrawPic ((320 - p->width) / 2, 4, "gfx/ttl_sgl"); + + M_DrawTextBox (60, 8 * 8, 23, 4); + if (gamemode == GAME_GOODVSBAD2) + M_Print(95, 10 * 8, "Good Vs Bad 2 is for"); + else // if (gamemode == GAME_BATTLEMECH) + M_Print(95, 10 * 8, "Battlemech is for"); + M_Print(83, 11 * 8, "multiplayer play only"); + } + else + { + int f; + + M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_sgl"); + M_DrawPic (72, 32, "gfx/sp_menu"); + + f = (int)(realtime * 10)%6; + + M_DrawPic (54, 32 + m_singleplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1)); + } +} + + +static void M_SinglePlayer_Key (int key, int ascii) +{ + if (gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH) + { + if (key == K_ESCAPE || key == K_ENTER || key == K_MOUSE1) + m_state = m_main; + return; + } + + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS) + m_singleplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (--m_singleplayer_cursor < 0) + m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + + switch (m_singleplayer_cursor) + { + case 0: + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("maxplayers 1\n"); + Cbuf_AddText ("deathmatch 0\n"); + Cbuf_AddText ("coop 0\n"); + if (gamemode == GAME_TRANSFUSION) + { + key_dest = key_menu; + M_Menu_Transfusion_Episode_f (); + break; + } + Cbuf_AddText ("startmap_sp\n"); + break; + + case 1: + M_Menu_Load_f (); + break; + + case 2: + M_Menu_Save_f (); + break; + } + } +} + +//============================================================================= +/* LOAD/SAVE MENU */ + +static int load_cursor; ///< 0 < load_cursor < MAX_SAVEGAMES + +static char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1]; +static int loadable[MAX_SAVEGAMES]; + +static void M_ScanSaves (void) +{ + int i, j; + size_t len; + char name[MAX_OSPATH]; + char buf[SAVEGAME_COMMENT_LENGTH + 256]; + const char *t; + qfile_t *f; +// int version; + + for (i=0 ; iwidth)/2, 4, "gfx/p_load" ); + + 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)); +} + + +static void M_Save_Draw (void) +{ + int i; + cachepic_t *p; + + M_Background(320, 200); + + p = Draw_CachePic ("gfx/p_save"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/p_save"); + + for (i=0 ; i= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + + +static void M_Save_Key (int k, int ascii) +{ + char vabuf[1024]; + switch (k) + { + case K_ESCAPE: + if (gamemode == GAME_TRANSFUSION) + M_Menu_Main_f (); + else + M_Menu_SinglePlayer_f (); + break; + case K_MOUSE1: + case K_ENTER: + m_state = m_none; + key_dest = key_game; + jni_BigScreenMode(0); + Cbuf_AddText (va(vabuf, sizeof(vabuf), "save s%i\n", load_cursor)); + return; + + case K_UPARROW: + case K_LEFTARROW: + case 'a': + S_LocalSound ("sound/misc/menu1.wav"); + load_cursor--; + if (load_cursor < 0) + load_cursor = MAX_SAVEGAMES-1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + case 'd': + S_LocalSound ("sound/misc/menu1.wav"); + load_cursor++; + if (load_cursor >= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + +//============================================================================= +/* Transfusion Single Player Episode Menu */ + +static int m_episode_cursor; +#define EPISODE_ITEMS 6 + +void M_Menu_Transfusion_Episode_f (void) +{ + m_entersound = true; + m_state = m_transfusion_episode; + key_dest = key_menu; +} + +static void M_Transfusion_Episode_Draw (void) +{ + int y; + cachepic_t *p; + char vabuf[1024]; + M_Background(640, 480); + + p = Draw_CachePic ("gfx/menu/tb-episodes"); + M_DrawPic (640/2 - p->width/2, 40, "gfx/menu/tb-episodes"); + for (y = 0; y < EPISODE_ITEMS; y++){ + M_DrawPic (0, 160 + y * 40, va(vabuf, sizeof(vabuf), "gfx/menu/episode%i", y+1)); + } + + M_DrawPic (0, 120 + (m_episode_cursor + 1) * 40, va(vabuf, sizeof(vabuf), "gfx/menu/episode%iselected", m_episode_cursor + 1)); +} + +static void M_Transfusion_Episode_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + m_episode_cursor++; + if (m_episode_cursor >= EPISODE_ITEMS) + m_episode_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + m_episode_cursor--; + if (m_episode_cursor < 0) + m_episode_cursor = EPISODE_ITEMS - 1; + break; + case K_MOUSE1: + case K_ENTER: + Cbuf_AddText ("deathmatch 0\n"); + m_entersound = true; + M_Menu_Transfusion_Skill_f (); + } +} + +//============================================================================= +/* Transfusion Single Player Skill Menu */ + +static int m_skill_cursor = 2; +#define SKILL_ITEMS 5 + +void M_Menu_Transfusion_Skill_f (void) +{ + m_entersound = true; + m_state = m_transfusion_skill; + key_dest = key_menu; +} + +static void M_Transfusion_Skill_Draw (void) +{ + int y; + cachepic_t *p; + char vabuf[1024]; + M_Background(640, 480); + + p = Draw_CachePic ("gfx/menu/tb-difficulty"); + M_DrawPic(640/2 - p->width/2, 40, "gfx/menu/tb-difficulty"); + + for (y = 0; y < SKILL_ITEMS; y++) + { + M_DrawPic (0, 180 + y * 40, va(vabuf, sizeof(vabuf), "gfx/menu/difficulty%i", y+1)); + } + M_DrawPic (0, 140 + (m_skill_cursor + 1) *40, va(vabuf, sizeof(vabuf), "gfx/menu/difficulty%iselected", m_skill_cursor + 1)); +} + +static void M_Transfusion_Skill_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Transfusion_Episode_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + m_skill_cursor++; + if (m_skill_cursor >= SKILL_ITEMS) + m_skill_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + m_skill_cursor--; + if (m_skill_cursor < 0) + m_skill_cursor = SKILL_ITEMS - 1; + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + switch (m_skill_cursor) + { + case 0: + Cbuf_AddText ("skill 1\n"); + break; + case 1: + Cbuf_AddText ("skill 2\n"); + break; + case 2: + Cbuf_AddText ("skill 3\n"); + break; + case 3: + Cbuf_AddText ("skill 4\n"); + break; + case 4: + Cbuf_AddText ("skill 5\n"); + break; + } + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("maxplayers 1\n"); + Cbuf_AddText ("deathmatch 0\n"); + Cbuf_AddText ("coop 0\n"); + switch (m_episode_cursor) + { + case 0: + Cbuf_AddText ("map e1m1\n"); + break; + case 1: + Cbuf_AddText ("map e2m1\n"); + break; + case 2: + Cbuf_AddText ("map e3m1\n"); + break; + case 3: + Cbuf_AddText ("map e4m1\n"); + break; + case 4: + Cbuf_AddText ("map e6m1\n"); + break; + case 5: + Cbuf_AddText ("map cp01\n"); + break; + } + } +} +//============================================================================= +/* MULTIPLAYER MENU */ + +static int m_multiplayer_cursor; +#define MULTIPLAYER_ITEMS 3 + + +void M_Menu_MultiPlayer_f (void) +{ + key_dest = key_menu; + m_state = m_multiplayer; + m_entersound = true; +} + + +static void M_MultiPlayer_Draw (void) +{ + int f; + cachepic_t *p; + char vabuf[1024]; + + if (gamemode == GAME_TRANSFUSION) + { + M_Background(640, 480); + p = Draw_CachePic ("gfx/menu/tb-online"); + M_DrawPic (640/2 - p->width/2, 140, "gfx/menu/tb-online"); + for (f = 1; f <= MULTIPLAYER_ITEMS; f++) + M_DrawPic (0, 180 + f*40, va(vabuf, sizeof(vabuf), "gfx/menu/online%i", f)); + M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/online%iselected", m_multiplayer_cursor + 1)); + return; + } + M_Background(320, 200); + + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_multi"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + M_DrawPic (72, 32, "gfx/mp_menu"); + + f = (int)(realtime * 10)%6; + + M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1)); +} + + +static void M_MultiPlayer_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS) + m_multiplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (--m_multiplayer_cursor < 0) + m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + switch (m_multiplayer_cursor) + { + case 0: + case 1: + M_Menu_LanConfig_f (); + break; + + case 2: + M_Menu_Setup_f (); + break; + } + } +} + +//============================================================================= +/* SETUP MENU */ + +static int setup_cursor = 4; +static int setup_cursor_table[] = {40, 64, 88, 124, 140}; + +static char setup_myname[MAX_SCOREBOARDNAME]; +static int setup_oldtop; +static int setup_oldbottom; +static int setup_top; +static int setup_bottom; +static int setup_rate; +static int setup_oldrate; + +#define NUM_SETUP_CMDS 5 + +void M_Menu_Setup_f (void) +{ + key_dest = key_menu; + m_state = m_setup; + m_entersound = true; + strlcpy(setup_myname, cl_name.string, sizeof(setup_myname)); + setup_top = setup_oldtop = cl_color.integer >> 4; + setup_bottom = setup_oldbottom = cl_color.integer & 15; + setup_rate = cl_rate.integer; +} + +static int menuplyr_width, menuplyr_height, menuplyr_top, menuplyr_bottom, menuplyr_load; +static unsigned char *menuplyr_pixels; +static unsigned int *menuplyr_translated; + +typedef struct ratetable_s +{ + int rate; + const char *name; +} +ratetable_t; + +#define RATES ((int)(sizeof(setup_ratetable)/sizeof(setup_ratetable[0]))) +static ratetable_t setup_ratetable[] = +{ + {1000, "28.8 bad"}, + {1500, "28.8 mediocre"}, + {2000, "28.8 good"}, + {2500, "33.6 mediocre"}, + {3000, "33.6 good"}, + {3500, "56k bad"}, + {4000, "56k mediocre"}, + {4500, "56k adequate"}, + {5000, "56k good"}, + {7000, "64k ISDN"}, + {15000, "128k ISDN"}, + {25000, "broadband"} +}; + +static int setup_rateindex(int rate) +{ + int i; + for (i = 0;i < RATES;i++) + if (setup_ratetable[i].rate > setup_rate) + break; + return bound(1, i, RATES) - 1; +} + +static void M_Setup_Draw (void) +{ + int i, j; + cachepic_t *p; + char vabuf[1024]; + + M_Background(320, 200); + + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_multi"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + + M_Print(64, 40, "Your name"); + M_DrawTextBox (160, 32, 16, 1); + M_PrintColored(168, 40, setup_myname); + + if (gamemode != GAME_GOODVSBAD2) + { + M_Print(64, 64, "Shirt color"); + M_Print(64, 88, "Pants color"); + } + + M_Print(64, 124-8, "Network speed limit"); + M_Print(168, 124, va(vabuf, sizeof(vabuf), "%i (%s)", setup_rate, setup_ratetable[setup_rateindex(setup_rate)].name)); + + M_DrawTextBox (64, 140-8, 14, 1); + M_Print(72, 140, "Accept Changes"); + + // LordHavoc: rewrote this code greatly + if (menuplyr_load) + { + unsigned char *f; + fs_offset_t filesize; + menuplyr_load = false; + menuplyr_top = -1; + menuplyr_bottom = -1; + f = FS_LoadFile("gfx/menuplyr.lmp", tempmempool, true, &filesize); + if (f && filesize >= 9) + { + int width, height; + width = f[0] + f[1] * 256 + f[2] * 65536 + f[3] * 16777216; + height = f[4] + f[5] * 256 + f[6] * 65536 + f[7] * 16777216; + if (filesize >= 8 + width * height) + { + menuplyr_width = width; + menuplyr_height = height; + menuplyr_pixels = (unsigned char *)Mem_Alloc(cls.permanentmempool, width * height); + menuplyr_translated = (unsigned int *)Mem_Alloc(cls.permanentmempool, width * height * 4); + memcpy(menuplyr_pixels, f + 8, width * height); + } + } + if (f) + Mem_Free(f); + } + + if (menuplyr_pixels) + { + if (menuplyr_top != setup_top || menuplyr_bottom != setup_bottom) + { + menuplyr_top = setup_top; + menuplyr_bottom = setup_bottom; + + for (i = 0;i < menuplyr_width * menuplyr_height;i++) + { + j = menuplyr_pixels[i]; + if (j >= TOP_RANGE && j < TOP_RANGE + 16) + { + if (menuplyr_top < 8 || menuplyr_top == 14) + j = menuplyr_top * 16 + (j - TOP_RANGE); + else + j = menuplyr_top * 16 + 15-(j - TOP_RANGE); + } + else if (j >= BOTTOM_RANGE && j < BOTTOM_RANGE + 16) + { + if (menuplyr_bottom < 8 || menuplyr_bottom == 14) + j = menuplyr_bottom * 16 + (j - BOTTOM_RANGE); + else + j = menuplyr_bottom * 16 + 15-(j - BOTTOM_RANGE); + } + menuplyr_translated[i] = palette_bgra_transparent[j]; + } + Draw_NewPic("gfx/menuplyr", menuplyr_width, menuplyr_height, true, (unsigned char *)menuplyr_translated); + } + M_DrawPic(160, 48, "gfx/bigbox"); + M_DrawPic(172, 56, "gfx/menuplyr"); + } + + if (setup_cursor == 0) + M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); + else + M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1)); +} + + +static void M_Setup_Key (int k, int ascii) +{ + int l; + char vabuf[1024]; + + switch (k) + { + case K_ESCAPE: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + setup_cursor--; + if (setup_cursor < 0) + setup_cursor = NUM_SETUP_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + setup_cursor++; + if (setup_cursor >= NUM_SETUP_CMDS) + setup_cursor = 0; + break; + + case K_LEFTARROW: + case 'a': + if (setup_cursor < 1) + return; + S_LocalSound ("sound/misc/menu3.wav"); + if (setup_cursor == 1) + setup_top = setup_top - 1; + if (setup_cursor == 2) + setup_bottom = setup_bottom - 1; + if (setup_cursor == 3) + { + l = setup_rateindex(setup_rate) - 1; + if (l < 0) + l = RATES - 1; + setup_rate = setup_ratetable[l].rate; + } + break; + case K_RIGHTARROW: + case 'd': + if (setup_cursor < 1) + return; +forward: + S_LocalSound ("sound/misc/menu3.wav"); + if (setup_cursor == 1) + setup_top = setup_top + 1; + if (setup_cursor == 2) + setup_bottom = setup_bottom + 1; + if (setup_cursor == 3) + { + l = setup_rateindex(setup_rate) + 1; + if (l >= RATES) + l = 0; + setup_rate = setup_ratetable[l].rate; + } + break; + case K_MOUSE1: + case K_ENTER: + if (setup_cursor == 0) + return; + + if (setup_cursor == 1 || setup_cursor == 2 || setup_cursor == 3) + goto forward; + + // setup_cursor == 4 (Accept changes) + if (strcmp(cl_name.string, setup_myname) != 0) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "name \"%s\"\n", setup_myname) ); + if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "color %i %i\n", setup_top, setup_bottom) ); + if (setup_rate != setup_oldrate) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "rate %i\n", setup_rate)); + + m_entersound = true; + M_Menu_MultiPlayer_f (); + break; + + case K_BACKSPACE: + if (setup_cursor == 0) + { + if (strlen(setup_myname)) + setup_myname[strlen(setup_myname)-1] = 0; + } + break; + + default: + if (ascii < 32) + break; + if (setup_cursor == 0) + { + l = (int)strlen(setup_myname); + if (l < 15) + { + setup_myname[l+1] = 0; + setup_myname[l] = ascii; + } + } + } + + if (setup_top > 15) + setup_top = 0; + if (setup_top < 0) + setup_top = 15; + if (setup_bottom > 15) + setup_bottom = 0; + if (setup_bottom < 0) + setup_bottom = 15; +} + +//============================================================================= +/* OPTIONS MENU */ + +#define SLIDER_RANGE 10 + +static void M_DrawSlider (int x, int y, float num, float rangemin, float rangemax) +{ + char text[16]; + int i; + float range; + range = bound(0, (num - rangemin) / (rangemax - rangemin), 1); + M_DrawCharacter (x-8, y, 128); + for (i = 0;i < SLIDER_RANGE;i++) + M_DrawCharacter (x + i*8, y, 129); + M_DrawCharacter (x+i*8, y, 130); + M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131); + if (fabs((int)num - num) < 0.01) + dpsnprintf(text, sizeof(text), "%i", (int)num); + else + dpsnprintf(text, sizeof(text), "%.3f", num); + M_Print(x + (SLIDER_RANGE+2) * 8, y, text); +} + +static void M_DrawCheckbox (int x, int y, int on) +{ + if (on) + M_Print(x, y, "on"); + else + M_Print(x, y, "off"); +} + + +#define OPTIONS_ITEMS 25 + +static int options_cursor; + +void M_Menu_Options_f (void) +{ + key_dest = key_menu; + m_state = m_options; + m_entersound = true; +} + +extern cvar_t slowmo; +extern dllhandle_t jpeg_dll; +extern cvar_t gl_texture_anisotropy; +extern cvar_t r_textshadow; +extern cvar_t r_hdr_scenebrightness; + +static void M_Menu_Options_AdjustSliders (int dir) +{ + int optnum; + double f; + S_LocalSound ("sound/misc/menu3.wav"); + + optnum = 0; + if (options_cursor == optnum++) { + bigScreen = (bigScreen == 2 ? -1 : 2); + jni_BigScreenMode(bigScreen); + } + else if (options_cursor == optnum++) { + stereoMode = 1 - stereoMode; + jni_SwitchStereoMode(stereoMode); + } + else if (options_cursor == optnum++) ; + else if (options_cursor == optnum++) ; + else if (options_cursor == optnum++) ; + else if (options_cursor == optnum++) + { + if (vrMode == 2) { + if (dir == 1) { + v_eyebufferresolution.integer *= 2; + if (v_eyebufferresolution.integer > 2048) + v_eyebufferresolution.integer = 256; + } + else { + v_eyebufferresolution.integer /= 2; + if (v_eyebufferresolution.integer < 256) + v_eyebufferresolution.integer = 2048; + } + + Cvar_SetValueQuick(&v_eyebufferresolution, v_eyebufferresolution.integer); + } + } + else if (options_cursor == optnum++) ; + else if (options_cursor == optnum++) Cvar_SetValueQuick(&crosshair, bound(0, crosshair.integer + dir, 7)); + else if (options_cursor == optnum++) Cvar_SetValueQuick(&scr_fov, bound(1, scr_fov.integer + dir * 1, 170)); + else if (options_cursor == optnum++) + { + cl_forwardspeed.value += dir * 10; + if (cl_forwardspeed.value > 500) + cl_forwardspeed.value = 500; + if (cl_forwardspeed.value < 10) + cl_forwardspeed.value = 10; + + cl_backspeed.value += dir * 10; + if (cl_backspeed.value > 500) + cl_backspeed.value = 500; + if (cl_backspeed.value < 10) + cl_backspeed.value = 10; + + cl_sidespeed.value += dir * 10; + if (cl_sidespeed.value > 500) + cl_sidespeed.value = 500; + if (cl_sidespeed.value < 10) + cl_sidespeed.value = 10; + + Cvar_SetValueQuick (&cl_forwardspeed, cl_forwardspeed.value); + Cvar_SetValueQuick (&cl_backspeed, cl_backspeed.value); + Cvar_SetValueQuick (&cl_sidespeed, cl_sidespeed.value); + } + else if (options_cursor == optnum++) Cvar_SetValueQuick(&showfps, !showfps.integer); + else if (options_cursor == optnum++) ; + else if (options_cursor == optnum++) Cvar_SetValueQuick(&r_hdr_scenebrightness, bound(1, r_hdr_scenebrightness.value + dir * 0.0625, 4)); + else if (options_cursor == optnum++) Cvar_SetValueQuick(&v_contrast, bound(1, v_contrast.value + dir * 0.0625, 4)); + else if (options_cursor == optnum++) Cvar_SetValueQuick(&v_gamma, bound(0.5, v_gamma.value + dir * 0.0625, 3)); + else if (options_cursor == optnum++) + { + if (r_worldscale.value < 200.0f) + { + Cvar_SetValueQuick (&r_worldscale, 400.0f); + Cvar_SetValueQuick (&chase_active, 1); + } + else + { + Cvar_SetValueQuick (&r_worldscale, 40.0f); + Cvar_SetValueQuick (&chase_active, 0); + } + } +} + +static int optnum; +static int opty; +static int optcursor; + +static void M_Options_PrintCommand(const char *s, int enabled) +{ + if (opty >= 32) + { + if (optnum == optcursor) + DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0); + M_ItemPrint(0 + 48, opty, s, enabled); + } + opty += 8; + optnum++; +} + +static void M_Options_PrintCheckbox(const char *s, int enabled, int yes) +{ + if (opty >= 32) + { + if (optnum == optcursor) + DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0); + M_ItemPrint(0 + 48, opty, s, enabled); + M_DrawCheckbox(0 + 48 + (int)strlen(s) * 8 + 8, opty, yes); + } + opty += 8; + optnum++; +} + +static void M_Options_PrintSlider(const char *s, int enabled, float value, float minvalue, float maxvalue) +{ + if (opty >= 32) + { + if (optnum == optcursor) + DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0); + M_ItemPrint(0 + 48, opty, s, enabled); + M_DrawSlider(0 + 48 + (int)strlen(s) * 8 + 8, opty, value, minvalue, maxvalue); + } + opty += 8; + optnum++; +} + +static void M_Options_Draw (void) +{ + int visible; + cachepic_t *p; + + M_Background(320, bound(200, 32 + OPTIONS_ITEMS * 8, vid_conheight.integer)); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + + optnum = 0; + optcursor = options_cursor; + visible = (int)((menu_height - 32) / 8); + opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_ITEMS - visible)) * 8; + + if (bigScreen == 2) + M_Options_PrintCommand( " Big Screen Mode Enabled", true); + else + M_Options_PrintCommand( " Big Screen Mode Disabled", true); + + switch (stereoMode) + { + case 0: + M_Options_PrintCommand( " Stereo Mode: MONO", true); + break; + case 1: + M_Options_PrintCommand( " Stereo Mode: STEREO", true); + break; + } + + M_Options_PrintCommand( " Controller Settings", true); + M_Options_PrintCommand( " Open Quake Console", true); + M_Options_PrintCommand( " Reset to defaults", true); + if (vrMode == 2) { + if (v_eyebufferresolution.integer == 0) + v_eyebufferresolution.integer = andrw; + M_Options_PrintSlider(" Eye Buffer Resolution", true, v_eyebufferresolution.integer, 256, + 2048); + } + else + M_Options_PrintCommand( " Eye Buffer Resolution n/a", false); + char buf[356]; + M_Options_PrintCommand( " Key/Button Bindings", true); + M_Options_PrintSlider( " Crosshair", true, crosshair.value, 0, 7); + M_Options_PrintSlider( " Field of View", true, scr_fov.integer, 1, 170); + M_Options_PrintSlider( " Player Movement Speed", true, cl_forwardspeed.value, 10, 500); + M_Options_PrintCheckbox(" Show Framerate", true, showfps.integer); + M_Options_PrintCommand( " Custom Brightness", true); + M_Options_PrintSlider( " Game Brightness", true, r_hdr_scenebrightness.value, 1, 4); + M_Options_PrintSlider( " Brightness", true, v_contrast.value, 1, 2); + M_Options_PrintSlider( " Gamma", true, v_gamma.value, 0.5, 3); + M_Options_PrintCheckbox(" Toy Soldier Mode", true, r_worldscale.value > 200.0f); + M_Options_PrintCommand( " Customize Effects", true); + M_Options_PrintCommand( " Effects: Quake", true); + M_Options_PrintCommand( " Effects: Normal", true); + M_Options_PrintCommand( " Effects: High", true); + M_Options_PrintCommand( " Customize Graphics", true); + M_Options_PrintCommand( " Lighting: Flares", true); + M_Options_PrintCommand( " Lighting: Normal", true); + M_Options_PrintCommand( " Lighting: High", true); + M_Options_PrintCommand( " Lighting: Full", true); + M_Options_PrintCommand( " Browse Mods", true); +} + + +static void M_Options_Key (int k, int ascii) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + switch (options_cursor) + { + case 0: + bigScreen = (bigScreen == 2 ? -1 : 2); + jni_BigScreenMode(bigScreen); + break; + case 1: + stereoMode = 1 - stereoMode; + jni_SwitchStereoMode(stereoMode); + break; + case 2: + M_Menu_YawPitchControl_f (); + break; + case 3: + m_state = m_none; + key_dest = key_game; + Con_ToggleConsole_f (); + break; + case 4: + M_Menu_Reset_f (); + break; + case 6: + M_Menu_Keys_f (); + break; + case 11: + M_Menu_Options_ColorControl_f (); + break; + case 15: // Toy Soldier Mode + if (r_worldscale.value < 200.0f) + { + Cvar_SetValueQuick (&r_worldscale, 400.0f); + Cvar_SetValueQuick (&chase_active, 1); + } + else + { + Cvar_SetValueQuick (&r_worldscale, 40.0f); + Cvar_SetValueQuick (&chase_active, 0); + } + break; + case 16: // Customize Effects + M_Menu_Options_Effects_f (); + break; + case 17: // Effects: Quake + Cbuf_AddText("cl_particles 1;cl_particles_quake 1;cl_particles_quality 1;cl_particles_explosions_shell 0;r_explosionclip 1;cl_stainmaps 0;cl_stainmaps_clearonload 1;cl_particles_bulletimpacts 1;cl_particles_smoke 1;cl_particles_sparks 1;cl_particles_bubbles 1;cl_particles_blood 1;cl_particles_blood_alpha 1;cl_particles_blood_bloodhack 0;cl_beams_polygons 0;cl_beams_instantaimhack 0;cl_beams_quakepositionhack 1;cl_beams_lightatend 0;r_lerpmodels 1;r_lerpsprites 1;r_lerplightstyles 0;gl_polyblend 1;r_skyscroll1 1;r_skyscroll2 2;r_waterwarp 1;r_wateralpha 1;r_waterscroll 1\n"); + break; + case 18: // Effects: Normal + Cbuf_AddText("cl_particles 1;cl_particles_quake 0;cl_particles_quality 1;cl_particles_explosions_shell 0;r_explosionclip 1;cl_stainmaps 0;cl_stainmaps_clearonload 1;cl_particles_bulletimpacts 1;cl_particles_smoke 1;cl_particles_sparks 1;cl_particles_bubbles 1;cl_particles_blood 1;cl_particles_blood_alpha 1;cl_particles_blood_bloodhack 1;cl_beams_polygons 1;cl_beams_instantaimhack 0;cl_beams_quakepositionhack 1;cl_beams_lightatend 0;r_lerpmodels 1;r_lerpsprites 1;r_lerplightstyles 0;gl_polyblend 1;r_skyscroll1 1;r_skyscroll2 2;r_waterwarp 1;r_wateralpha 1;r_waterscroll 1\n"); + break; + case 19: // Effects: High + Cbuf_AddText("cl_particles 1;cl_particles_quake 0;cl_particles_quality 2;cl_particles_explosions_shell 0;r_explosionclip 1;cl_stainmaps 1;cl_stainmaps_clearonload 1;cl_particles_bulletimpacts 1;cl_particles_smoke 1;cl_particles_sparks 1;cl_particles_bubbles 1;cl_particles_blood 1;cl_particles_blood_alpha 1;cl_particles_blood_bloodhack 1;cl_beams_polygons 1;cl_beams_instantaimhack 0;cl_beams_quakepositionhack 1;cl_beams_lightatend 0;r_lerpmodels 1;r_lerpsprites 1;r_lerplightstyles 0;gl_polyblend 1;r_skyscroll1 1;r_skyscroll2 2;r_waterwarp 1;r_wateralpha 1;r_waterscroll 1\n"); + break; + case 20: + M_Menu_Options_Graphics_f (); + break; + case 21: // Lighting: Flares + Cbuf_AddText("r_coronas 1;gl_flashblend 1;r_shadow_gloss 0;r_shadow_realtime_dlight 0;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0"); + break; + case 22: // Lighting: Normal + Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0"); + break; + case 23: // Lighting: High + Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1"); + break; + case 24: // Lighting: Full + Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 1;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1"); + break; + case 25: + M_Menu_ModList_f (); + break; + default: + M_Menu_Options_AdjustSliders (1); + break; + } + return; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_cursor--; + if (options_cursor < 0) + options_cursor = OPTIONS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_cursor++; + if (options_cursor >= OPTIONS_ITEMS) + options_cursor = 0; + break; + + case K_LEFTARROW: + case 'a': + M_Menu_Options_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + case 'd': + M_Menu_Options_AdjustSliders (1); + break; + } +} + +#define OPTIONS_EFFECTS_ITEMS 35 + +static int options_effects_cursor; + +void M_Menu_Options_Effects_f (void) +{ + key_dest = key_menu; + m_state = m_options_effects; + m_entersound = true; +} + + +extern cvar_t cl_stainmaps; +extern cvar_t cl_stainmaps_clearonload; +extern cvar_t r_explosionclip; +extern cvar_t r_coronas; +extern cvar_t gl_flashblend; +extern cvar_t cl_beams_polygons; +extern cvar_t cl_beams_quakepositionhack; +extern cvar_t cl_beams_instantaimhack; +extern cvar_t cl_beams_lightatend; +extern cvar_t r_lightningbeam_thickness; +extern cvar_t r_lightningbeam_scroll; +extern cvar_t r_lightningbeam_repeatdistance; +extern cvar_t r_lightningbeam_color_red; +extern cvar_t r_lightningbeam_color_green; +extern cvar_t r_lightningbeam_color_blue; +extern cvar_t r_lightningbeam_qmbtexture; + +static void M_Menu_Options_Effects_AdjustSliders (int dir) +{ + int optnum; + S_LocalSound ("sound/misc/menu3.wav"); + + optnum = 0; + if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles, !cl_particles.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_quake, !cl_particles_quake.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_quality, bound(1, cl_particles_quality.value + dir * 0.5, 4)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_explosions_shell, !cl_particles_explosions_shell.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_explosionclip, !r_explosionclip.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_stainmaps, !cl_stainmaps.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_stainmaps_clearonload, !cl_stainmaps_clearonload.integer); + else if (options_effects_cursor == optnum++) ;//Cvar_SetValueQuick (&cl_decals, !cl_decals.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_bulletimpacts, !cl_particles_bulletimpacts.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_smoke, !cl_particles_smoke.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_sparks, !cl_particles_sparks.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_bubbles, !cl_particles_bubbles.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood, !cl_particles_blood.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood_alpha, bound(0.2, cl_particles_blood_alpha.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood_bloodhack, !cl_particles_blood_bloodhack.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_polygons, !cl_beams_polygons.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_instantaimhack, !cl_beams_instantaimhack.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_quakepositionhack, !cl_beams_quakepositionhack.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_lightatend, !cl_beams_lightatend.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_thickness, bound(1, r_lightningbeam_thickness.integer + dir, 10)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_scroll, bound(0, r_lightningbeam_scroll.integer + dir, 10)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_repeatdistance, bound(64, r_lightningbeam_repeatdistance.integer + dir * 64, 1024)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_color_red, bound(0, r_lightningbeam_color_red.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_color_green, bound(0, r_lightningbeam_color_green.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_color_blue, bound(0, r_lightningbeam_color_blue.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_qmbtexture, !r_lightningbeam_qmbtexture.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lerpmodels, !r_lerpmodels.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lerpsprites, !r_lerpsprites.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lerplightstyles, !r_lerplightstyles.integer); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&gl_polyblend, bound(0, gl_polyblend.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_skyscroll1, bound(-8, r_skyscroll1.value + dir * 0.1, 8)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_skyscroll2, bound(-8, r_skyscroll2.value + dir * 0.1, 8)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_waterwarp, bound(0, r_waterwarp.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_wateralpha, bound(0, r_wateralpha.value + dir * 0.1, 1)); + else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_waterscroll, bound(0, r_waterscroll.value + dir * 0.5, 10)); +} + +static void M_Options_Effects_Draw (void) +{ + int visible; + cachepic_t *p; + + M_Background(320, bound(200, 32 + OPTIONS_EFFECTS_ITEMS * 8, vid_conheight.integer)); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + + optcursor = options_effects_cursor; + optnum = 0; + visible = (int)((menu_height - 32) / 8); + opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_EFFECTS_ITEMS - visible)) * 8; + + M_Options_PrintCheckbox(" Particles", true, cl_particles.integer); + M_Options_PrintCheckbox(" Quake-style Particles", true, cl_particles_quake.integer); + M_Options_PrintSlider( " Particles Quality", true, cl_particles_quality.value, 1, 4); + M_Options_PrintCheckbox(" Explosion Shell", true, cl_particles_explosions_shell.integer); + M_Options_PrintCheckbox(" Explosion Shell Clip", true, r_explosionclip.integer); + M_Options_PrintCheckbox(" Stainmaps", true, cl_stainmaps.integer); + M_Options_PrintCheckbox("Onload Clear Stainmaps", true, cl_stainmaps_clearonload.integer); + M_Options_PrintCheckbox(" Decals", false, cl_decals.integer); + M_Options_PrintCheckbox(" Bullet Impacts", true, cl_particles_bulletimpacts.integer); + M_Options_PrintCheckbox(" Smoke", true, cl_particles_smoke.integer); + M_Options_PrintCheckbox(" Sparks", true, cl_particles_sparks.integer); + M_Options_PrintCheckbox(" Bubbles", true, cl_particles_bubbles.integer); + M_Options_PrintCheckbox(" Blood", true, cl_particles_blood.integer); + M_Options_PrintSlider( " Blood Opacity", true, cl_particles_blood_alpha.value, 0.2, 1); + M_Options_PrintCheckbox("Force New Blood Effect", true, cl_particles_blood_bloodhack.integer); + M_Options_PrintCheckbox(" Polygon Lightning", true, cl_beams_polygons.integer); + M_Options_PrintCheckbox("Smooth Sweep Lightning", true, cl_beams_instantaimhack.integer); + M_Options_PrintCheckbox(" Waist-level Lightning", true, cl_beams_quakepositionhack.integer); + M_Options_PrintCheckbox(" Lightning End Light", true, cl_beams_lightatend.integer); + M_Options_PrintSlider( " Lightning Thickness", cl_beams_polygons.integer, r_lightningbeam_thickness.integer, 1, 10); + M_Options_PrintSlider( " Lightning Scroll", cl_beams_polygons.integer, r_lightningbeam_scroll.integer, 0, 10); + M_Options_PrintSlider( " Lightning Repeat Dist", cl_beams_polygons.integer, r_lightningbeam_repeatdistance.integer, 64, 1024); + M_Options_PrintSlider( " Lightning Color Red", cl_beams_polygons.integer, r_lightningbeam_color_red.value, 0, 1); + M_Options_PrintSlider( " Lightning Color Green", cl_beams_polygons.integer, r_lightningbeam_color_green.value, 0, 1); + M_Options_PrintSlider( " Lightning Color Blue", cl_beams_polygons.integer, r_lightningbeam_color_blue.value, 0, 1); + M_Options_PrintCheckbox(" Lightning QMB Texture", cl_beams_polygons.integer, r_lightningbeam_qmbtexture.integer); + M_Options_PrintCheckbox(" Model Interpolation", true, r_lerpmodels.integer); + M_Options_PrintCheckbox(" Sprite Interpolation", true, r_lerpsprites.integer); + M_Options_PrintCheckbox(" Flicker Interpolation", true, r_lerplightstyles.integer); + M_Options_PrintSlider( " View Blend", true, gl_polyblend.value, 0, 1); + M_Options_PrintSlider( "Upper Sky Scroll Speed", true, r_skyscroll1.value, -8, 8); + M_Options_PrintSlider( "Lower Sky Scroll Speed", true, r_skyscroll2.value, -8, 8); + M_Options_PrintSlider( " Underwater View Warp", true, r_waterwarp.value, 0, 1); + M_Options_PrintSlider( " Water Alpha (opacity)", true, r_wateralpha.value, 0, 1); + M_Options_PrintSlider( " Water Movement", true, r_waterscroll.value, 0, 10); +} + + +static void M_Options_Effects_Key (int k, int ascii) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_Options_f (); + break; + case K_MOUSE1: + case K_ENTER: + M_Menu_Options_Effects_AdjustSliders (1); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_effects_cursor--; + if (options_effects_cursor < 0) + options_effects_cursor = OPTIONS_EFFECTS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_effects_cursor++; + if (options_effects_cursor >= OPTIONS_EFFECTS_ITEMS) + options_effects_cursor = 0; + break; + + case K_LEFTARROW: + case 'a': + M_Menu_Options_Effects_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + case 'd': + M_Menu_Options_Effects_AdjustSliders (1); + break; + } +} + + +#define OPTIONS_GRAPHICS_ITEMS 21 + +static int options_graphics_cursor; + +void M_Menu_Options_Graphics_f (void) +{ + key_dest = key_menu; + m_state = m_options_graphics; + m_entersound = true; +} + +extern cvar_t r_shadow_gloss; +extern cvar_t r_shadow_realtime_dlight; +extern cvar_t r_shadow_realtime_dlight_shadows; +extern cvar_t r_shadow_realtime_world; +extern cvar_t r_shadow_realtime_world_lightmaps; +extern cvar_t r_shadow_realtime_world_shadows; +extern cvar_t r_bloom; +extern cvar_t r_bloom_colorscale; +extern cvar_t r_bloom_colorsubtract; +extern cvar_t r_bloom_colorexponent; +extern cvar_t r_bloom_blur; +extern cvar_t r_bloom_brighten; +extern cvar_t r_bloom_resolution; +extern cvar_t r_hdr_scenebrightness; +extern cvar_t r_hdr_glowintensity; +extern cvar_t gl_picmip; + +static void M_Menu_Options_Graphics_AdjustSliders (int dir) +{ + int optnum; + S_LocalSound ("sound/misc/menu3.wav"); + + optnum = 0; + + if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&cl_autocentreoffset, bound(-200, cl_autocentreoffset.integer + dir * 5, 200)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_coronas, bound(0, r_coronas.value + dir * 0.125, 4)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&gl_flashblend, !gl_flashblend.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_gloss, bound(0, r_shadow_gloss.integer + dir, 2)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_dlight, !r_shadow_realtime_dlight.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_dlight_shadows, !r_shadow_realtime_dlight_shadows.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world, !r_shadow_realtime_world.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_lightmaps, bound(0, r_shadow_realtime_world_lightmaps.value + dir * 0.1, 1)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_shadows, !r_shadow_realtime_world_shadows.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom, !r_bloom.integer); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_scenebrightness, bound(0.25, r_hdr_scenebrightness.value + dir * 0.125, 4)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_glowintensity, bound(0, r_hdr_glowintensity.value + dir * 0.25, 4)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorscale, bound(0.0625, r_bloom_colorscale.value + dir * 0.0625, 1)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorsubtract, bound(0, r_bloom_colorsubtract.value + dir * 0.0625, 1-0.0625)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorexponent, bound(1, r_bloom_colorexponent.value * (dir > 0 ? 2.0 : 0.5), 8)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_brighten, bound(1, r_bloom_brighten.value + dir * 0.0625, 4)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_blur, bound(1, r_bloom_blur.value + dir * 1, 16)); + else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_resolution, bound(64, r_bloom_resolution.value + dir * 64, 2048)); + else if (options_graphics_cursor == optnum++) Cbuf_AddText ("r_restart\n"); +} + + +static void M_Options_Graphics_Draw (void) +{ + int visible; + cachepic_t *p; + + M_Background(320, bound(200, 32 + OPTIONS_GRAPHICS_ITEMS * 8, vid_conheight.integer)); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + + optcursor = options_graphics_cursor; + optnum = 0; + visible = (int)((menu_height - 32) / 8); + opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_GRAPHICS_ITEMS - visible)) * 8; + + M_Options_PrintSlider( " Lens Centre Offset", true, cl_autocentreoffset.integer, -200, 200); + M_Options_PrintSlider( " Corona Intensity", true, r_coronas.value, 0, 4); + M_Options_PrintCheckbox(" Use Only Coronas", true, gl_flashblend.integer); + M_Options_PrintSlider( " Gloss Mode", true, r_shadow_gloss.integer, 0, 2); + M_Options_PrintCheckbox(" RT DLights", !gl_flashblend.integer, r_shadow_realtime_dlight.integer); + M_Options_PrintCheckbox(" RT DLight Shadows", !gl_flashblend.integer, r_shadow_realtime_dlight_shadows.integer); + M_Options_PrintCheckbox(" RT World", true, r_shadow_realtime_world.integer); + M_Options_PrintSlider( " RT World Lightmaps", true, r_shadow_realtime_world_lightmaps.value, 0, 1); + M_Options_PrintCheckbox(" RT World Shadow", true, r_shadow_realtime_world_shadows.integer); + M_Options_PrintCheckbox(" Bloom Effect", true, r_bloom.integer); + M_Options_PrintSlider( " Scene Brightness", true, r_hdr_scenebrightness.value, 0.25, 4); + M_Options_PrintSlider( " Glow Brightness", true, r_hdr_glowintensity.value, 0, 4); + M_Options_PrintSlider( " Bloom Color Scale", r_bloom.integer, r_bloom_colorscale.value, 0.0625, 1); + M_Options_PrintSlider( " Bloom Color Subtract", r_bloom.integer, r_bloom_colorsubtract.value, 0, 1-0.0625); + M_Options_PrintSlider( " Bloom Color Exponent", r_bloom.integer, r_bloom_colorexponent.value, 1, 8); + M_Options_PrintSlider( " Bloom Intensity", r_bloom.integer, r_bloom_brighten.value, 1, 4); + M_Options_PrintSlider( " Bloom Blur", r_bloom.integer, r_bloom_blur.value, 1, 16); + M_Options_PrintSlider( " Bloom Resolution", r_bloom.integer, r_bloom_resolution.value, 64, 2048); + M_Options_PrintCommand( " Restart Renderer", true); +} + + +static void M_Options_Graphics_Key (int k, int ascii) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_Options_f (); + break; + case K_MOUSE1: + case K_ENTER: + M_Menu_Options_Graphics_AdjustSliders (1); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_graphics_cursor--; + if (options_graphics_cursor < 0) + options_graphics_cursor = OPTIONS_GRAPHICS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_graphics_cursor++; + if (options_graphics_cursor >= OPTIONS_GRAPHICS_ITEMS) + options_graphics_cursor = 0; + break; + + case K_LEFTARROW: + case 'a': + M_Menu_Options_Graphics_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + case 'd': + M_Menu_Options_Graphics_AdjustSliders (1); + break; + } +} + + +#define OPTIONS_COLORCONTROL_ITEMS 18 + +static int options_colorcontrol_cursor; + +// intensity value to match up to 50% dither to 'correct' quake +static cvar_t menu_options_colorcontrol_correctionvalue = {0, "menu_options_colorcontrol_correctionvalue", "0.5", "intensity value that matches up to white/black dither pattern, should be 0.5 for linear color"}; + +void M_Menu_Options_ColorControl_f (void) +{ + key_dest = key_menu; + m_state = m_options_colorcontrol; + m_entersound = true; +} + + +static void M_Menu_Options_ColorControl_AdjustSliders (int dir) +{ + int optnum; + float f; + S_LocalSound ("sound/misc/menu3.wav"); + + optnum = 1; + if (options_colorcontrol_cursor == optnum++) + Cvar_SetValueQuick (&v_hwgamma, !v_hwgamma.integer); + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 0); + Cvar_SetValueQuick (&v_gamma, bound(1, v_gamma.value + dir * 0.125, 5)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 0); + Cvar_SetValueQuick (&v_contrast, bound(1, v_contrast.value + dir * 0.125, 5)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 0); + Cvar_SetValueQuick (&v_brightness, bound(0, v_brightness.value + dir * 0.05, 0.8)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, !v_color_enable.integer); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_black_r, bound(0, v_color_black_r.value + dir * 0.0125, 0.8)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_black_g, bound(0, v_color_black_g.value + dir * 0.0125, 0.8)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_black_b, bound(0, v_color_black_b.value + dir * 0.0125, 0.8)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + f = bound(0, (v_color_black_r.value + v_color_black_g.value + v_color_black_b.value) / 3 + dir * 0.0125, 0.8); + Cvar_SetValueQuick (&v_color_black_r, f); + Cvar_SetValueQuick (&v_color_black_g, f); + Cvar_SetValueQuick (&v_color_black_b, f); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_grey_r, bound(0, v_color_grey_r.value + dir * 0.0125, 0.95)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_grey_g, bound(0, v_color_grey_g.value + dir * 0.0125, 0.95)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_grey_b, bound(0, v_color_grey_b.value + dir * 0.0125, 0.95)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + f = bound(0, (v_color_grey_r.value + v_color_grey_g.value + v_color_grey_b.value) / 3 + dir * 0.0125, 0.95); + Cvar_SetValueQuick (&v_color_grey_r, f); + Cvar_SetValueQuick (&v_color_grey_g, f); + Cvar_SetValueQuick (&v_color_grey_b, f); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_white_r, bound(1, v_color_white_r.value + dir * 0.125, 5)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_white_g, bound(1, v_color_white_g.value + dir * 0.125, 5)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + Cvar_SetValueQuick (&v_color_white_b, bound(1, v_color_white_b.value + dir * 0.125, 5)); + } + else if (options_colorcontrol_cursor == optnum++) + { + Cvar_SetValueQuick (&v_color_enable, 1); + f = bound(1, (v_color_white_r.value + v_color_white_g.value + v_color_white_b.value) / 3 + dir * 0.125, 5); + Cvar_SetValueQuick (&v_color_white_r, f); + Cvar_SetValueQuick (&v_color_white_g, f); + Cvar_SetValueQuick (&v_color_white_b, f); + } +} + +static void M_Options_ColorControl_Draw (void) +{ + int visible; + float x, c, s, t, u, v; + cachepic_t *p, *dither; + + dither = Draw_CachePic_Flags ("gfx/colorcontrol/ditherpattern", CACHEPICFLAG_NOCLAMP); + + M_Background(320, 256); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + + optcursor = options_colorcontrol_cursor; + optnum = 0; + visible = (int)((menu_height - 32) / 8); + opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_COLORCONTROL_ITEMS - visible)) * 8; + + M_Options_PrintCommand( " Reset to defaults", true); + M_Options_PrintCheckbox("Hardware Gamma Control", vid_hardwaregammasupported.integer, v_hwgamma.integer); + M_Options_PrintSlider( " Gamma", !v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_gamma.value, 1, 5); + M_Options_PrintSlider( " Contrast", !v_color_enable.integer, v_contrast.value, 1, 5); + M_Options_PrintSlider( " Brightness", !v_color_enable.integer, v_brightness.value, 0, 0.8); + M_Options_PrintCheckbox(" Color Level Controls", true, v_color_enable.integer); + M_Options_PrintSlider( " Black: Red ", v_color_enable.integer, v_color_black_r.value, 0, 0.8); + M_Options_PrintSlider( " Black: Green", v_color_enable.integer, v_color_black_g.value, 0, 0.8); + M_Options_PrintSlider( " Black: Blue ", v_color_enable.integer, v_color_black_b.value, 0, 0.8); + M_Options_PrintSlider( " Black: Grey ", v_color_enable.integer, (v_color_black_r.value + v_color_black_g.value + v_color_black_b.value) / 3, 0, 0.8); + M_Options_PrintSlider( " Grey: Red ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_r.value, 0, 0.95); + M_Options_PrintSlider( " Grey: Green", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_g.value, 0, 0.95); + M_Options_PrintSlider( " Grey: Blue ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_b.value, 0, 0.95); + M_Options_PrintSlider( " Grey: Grey ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, (v_color_grey_r.value + v_color_grey_g.value + v_color_grey_b.value) / 3, 0, 0.95); + M_Options_PrintSlider( " White: Red ", v_color_enable.integer, v_color_white_r.value, 1, 5); + M_Options_PrintSlider( " White: Green", v_color_enable.integer, v_color_white_g.value, 1, 5); + M_Options_PrintSlider( " White: Blue ", v_color_enable.integer, v_color_white_b.value, 1, 5); + M_Options_PrintSlider( " White: Grey ", v_color_enable.integer, (v_color_white_r.value + v_color_white_g.value + v_color_white_b.value) / 3, 1, 5); + + opty += 4; + DrawQ_Fill(menu_x, menu_y + opty, 320, 4 + 64 + 8 + 64 + 4, 0, 0, 0, 1, 0);opty += 4; + s = (float) 312 / 2 * vid.width / vid_conwidth.integer; + t = (float) 4 / 2 * vid.height / vid_conheight.integer; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL , 312, 4, 0,0, 0,0,0,1, 1,0, 1,0,0,1, 0,1, 0,0,0,1, 1,1, 1,0,0,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL , 312, 4, 0,0, 0,0,0,1, 1,0, 0,1,0,1, 0,1, 0,0,0,1, 1,1, 0,1,0,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL , 312, 4, 0,0, 0,0,0,1, 1,0, 0,0,1,1, 0,1, 0,0,0,1, 1,1, 0,0,1,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0);opty += 4; + DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL , 312, 4, 0,0, 0,0,0,1, 1,0, 1,1,1,1, 0,1, 0,0,0,1, 1,1, 1,1,1,1, 0);opty += 4; + + c = menu_options_colorcontrol_correctionvalue.value; // intensity value that should be matched up to a 50% dither to 'correct' quake + s = (float) 48 / 2 * vid.width / vid_conwidth.integer; + t = (float) 48 / 2 * vid.height / vid_conheight.integer; + u = s * 0.5; + v = t * 0.5; + opty += 8; + x = 4; + DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, c, 0, 0, 1, 0); + DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0); + DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 1,0,0,1, u,0, 1,0,0,1, 0,v, 1,0,0,1, u,v, 1,0,0,1, 0); + x += 80; + DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, 0, c, 0, 1, 0); + DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0); + DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 0,1,0,1, u,0, 0,1,0,1, 0,v, 0,1,0,1, u,v, 0,1,0,1, 0); + x += 80; + DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, 0, 0, c, 1, 0); + DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0); + DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 0,0,1,1, u,0, 0,0,1,1, 0,v, 0,0,1,1, u,v, 0,0,1,1, 0); + x += 80; + DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, c, c, c, 1, 0); + DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0); + DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 1,1,1,1, u,0, 1,1,1,1, 0,v, 1,1,1,1, u,v, 1,1,1,1, 0); +} + + +static void M_Options_ColorControl_Key (int k, int ascii) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_Options_f (); + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + switch (options_colorcontrol_cursor) + { + case 0: + Cvar_SetValueQuick(&v_hwgamma, 1); + Cvar_SetValueQuick(&v_gamma, 1); + Cvar_SetValueQuick(&v_contrast, 1); + Cvar_SetValueQuick(&v_brightness, 0); + Cvar_SetValueQuick(&v_color_enable, 0); + Cvar_SetValueQuick(&v_color_black_r, 0); + Cvar_SetValueQuick(&v_color_black_g, 0); + Cvar_SetValueQuick(&v_color_black_b, 0); + Cvar_SetValueQuick(&v_color_grey_r, 0); + Cvar_SetValueQuick(&v_color_grey_g, 0); + Cvar_SetValueQuick(&v_color_grey_b, 0); + Cvar_SetValueQuick(&v_color_white_r, 1); + Cvar_SetValueQuick(&v_color_white_g, 1); + Cvar_SetValueQuick(&v_color_white_b, 1); + break; + default: + M_Menu_Options_ColorControl_AdjustSliders (1); + break; + } + return; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_colorcontrol_cursor--; + if (options_colorcontrol_cursor < 0) + options_colorcontrol_cursor = OPTIONS_COLORCONTROL_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + options_colorcontrol_cursor++; + if (options_colorcontrol_cursor >= OPTIONS_COLORCONTROL_ITEMS) + options_colorcontrol_cursor = 0; + break; + + case K_LEFTARROW: + case 'a': + M_Menu_Options_ColorControl_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + case 'd': + M_Menu_Options_ColorControl_AdjustSliders (1); + break; + } +} + + +//============================================================================= +/* KEYS MENU */ + +static const char *quakebindnames[][2] = +{ +{"+attack", "attack"}, +{"impulse 10", "next weapon"}, +{"impulse 12", "previous 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"} +}; + +static const char *transfusionbindnames[][2] = +{ +{"", "Movement"}, // Movement commands +{"+forward", "walk forward"}, +{"+back", "backpedal"}, +{"+left", "turn left"}, +{"+right", "turn right"}, +{"+moveleft", "step left"}, +{"+moveright", "step right"}, +{"+jump", "jump / swim up"}, +{"+movedown", "swim down"}, +{"", "Combat"}, // Combat commands +{"impulse 1", "Pitch Fork"}, +{"impulse 2", "Flare Gun"}, +{"impulse 3", "Shotgun"}, +{"impulse 4", "Machine Gun"}, +{"impulse 5", "Incinerator"}, +{"impulse 6", "Bombs (TNT)"}, +{"impulse 35", "Proximity Bomb"}, +{"impulse 36", "Remote Detonator"}, +{"impulse 7", "Aerosol Can"}, +{"impulse 8", "Tesla Cannon"}, +{"impulse 9", "Life Leech"}, +{"impulse 10", "Voodoo Doll"}, +{"impulse 21", "next weapon"}, +{"impulse 22", "previous weapon"}, +{"+attack", "attack"}, +{"+button3", "altfire"}, +{"", "Inventory"}, // Inventory commands +{"impulse 40", "Dr.'s Bag"}, +{"impulse 41", "Crystal Ball"}, +{"impulse 42", "Beast Vision"}, +{"impulse 43", "Jump Boots"}, +{"impulse 23", "next item"}, +{"impulse 24", "previous item"}, +{"impulse 25", "use item"}, +{"", "Misc"}, // Misc commands +{"+button4", "use"}, +{"impulse 50", "add bot (red)"}, +{"impulse 51", "add bot (blue)"}, +{"impulse 52", "kick a bot"}, +{"impulse 26", "next armor type"}, +{"impulse 27", "identify player"}, +{"impulse 55", "voting menu"}, +{"impulse 56", "observer mode"}, +{"", "Taunts"}, // Taunts +{"impulse 70", "taunt 0"}, +{"impulse 71", "taunt 1"}, +{"impulse 72", "taunt 2"}, +{"impulse 73", "taunt 3"}, +{"impulse 74", "taunt 4"}, +{"impulse 75", "taunt 5"}, +{"impulse 76", "taunt 6"}, +{"impulse 77", "taunt 7"}, +{"impulse 78", "taunt 8"}, +{"impulse 79", "taunt 9"} +}; + +static const char *goodvsbad2bindnames[][2] = +{ +{"impulse 69", "Power 1"}, +{"impulse 70", "Power 2"}, +{"impulse 71", "Power 3"}, +{"+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"}, +{"kill", "kill yourself"}, +{"+moveup", "swim up"}, +{"+movedown", "swim down"} +}; + +static int numcommands; +static const char *(*bindnames)[2]; + +/* +typedef struct binditem_s +{ + char *command, *description; + struct binditem_s *next; +} +binditem_t; + +typedef struct bindcategory_s +{ + char *name; + binditem_t *binds; + struct bindcategory_s *next; +} +bindcategory_t; + +static bindcategory_t *bindcategories = NULL; + +static void M_ClearBinds (void) +{ + for (c = bindcategories;c;c = cnext) + { + cnext = c->next; + for (b = c->binds;b;b = bnext) + { + bnext = b->next; + Z_Free(b); + } + Z_Free(c); + } + bindcategories = NULL; +} + +static void M_AddBindToCategory(bindcategory_t *c, char *command, char *description) +{ + for (b = &c->binds;*b;*b = &(*b)->next); + *b = Z_Alloc(sizeof(binditem_t) + strlen(command) + 1 + strlen(description) + 1); + *b->command = (char *)((*b) + 1); + *b->description = *b->command + strlen(command) + 1; + strlcpy(*b->command, command, strlen(command) + 1); + strlcpy(*b->description, description, strlen(description) + 1); +} + +static void M_AddBind (char *category, char *command, char *description) +{ + for (c = &bindcategories;*c;c = &(*c)->next) + { + if (!strcmp(category, (*c)->name)) + { + M_AddBindToCategory(*c, command, description); + return; + } + } + *c = Z_Alloc(sizeof(bindcategory_t)); + M_AddBindToCategory(*c, command, description); +} + +static void M_DefaultBinds (void) +{ + M_ClearBinds(); + M_AddBind("movement", "+jump", "jump / swim up"); + M_AddBind("movement", "+forward", "walk forward"); + M_AddBind("movement", "+back", "backpedal"); + M_AddBind("movement", "+left", "turn left"); + M_AddBind("movement", "+right", "turn right"); + M_AddBind("movement", "+speed", "run"); + M_AddBind("movement", "+moveleft", "step left"); + M_AddBind("movement", "+moveright", "step right"); + M_AddBind("movement", "+strafe", "sidestep"); + M_AddBind("movement", "+lookup", "look up"); + M_AddBind("movement", "+lookdown", "look down"); + M_AddBind("movement", "centerview", "center view"); + M_AddBind("movement", "+mlook", "mouse look"); + M_AddBind("movement", "+klook", "keyboard look"); + M_AddBind("movement", "+moveup", "swim up"); + M_AddBind("movement", "+movedown", "swim down"); + M_AddBind("weapons", "+attack", "attack"); + M_AddBind("weapons", "impulse 10", "next weapon"); + M_AddBind("weapons", "impulse 12", "previous weapon"); + M_AddBind("weapons", "impulse 1", "select weapon 1 (axe)"); + M_AddBind("weapons", "impulse 2", "select weapon 2 (shotgun)"); + M_AddBind("weapons", "impulse 3", "select weapon 3 (super )"); + M_AddBind("weapons", "impulse 4", "select weapon 4 (nailgun)"); + M_AddBind("weapons", "impulse 5", "select weapon 5 (super nailgun)"); + M_AddBind("weapons", "impulse 6", "select weapon 6 (grenade launcher)"); + M_AddBind("weapons", "impulse 7", "select weapon 7 (rocket launcher)"); + M_AddBind("weapons", "impulse 8", "select weapon 8 (lightning gun)"); +} +*/ + + +static int keys_cursor; +static int bind_grab; + +void M_Menu_Keys_f (void) +{ + key_dest = key_menu_grabbed; + m_state = m_keys; + m_entersound = true; + + if (gamemode == GAME_TRANSFUSION) + { + numcommands = sizeof(transfusionbindnames) / sizeof(transfusionbindnames[0]); + bindnames = transfusionbindnames; + } + else if (gamemode == GAME_GOODVSBAD2) + { + numcommands = sizeof(goodvsbad2bindnames) / sizeof(goodvsbad2bindnames[0]); + bindnames = goodvsbad2bindnames; + } + else + { + numcommands = sizeof(quakebindnames) / sizeof(quakebindnames[0]); + bindnames = quakebindnames; + } + + // Make sure "keys_cursor" doesn't start on a section in the binding list + keys_cursor = 0; + while (bindnames[keys_cursor][0][0] == '\0') + { + keys_cursor++; + + // Only sections? There may be a problem somewhere... + if (keys_cursor >= numcommands) + Sys_Error ("M_Init: The key binding list only contains sections"); + } +} + +#define NUMKEYS 5 + +static void M_UnbindCommand (const char *command) +{ + int j; + const char *b; + + for (j = 0; j < (int)sizeof (keybindings[0]) / (int)sizeof (keybindings[0][0]); j++) + { + b = keybindings[0][j]; + if (!b) + continue; + if (!strcmp (b, command)) + Key_SetBinding (j, 0, ""); + } +} + + +static void M_Keys_Draw (void) +{ + int i, j; + int keys[NUMKEYS]; + int y; + cachepic_t *p; + char keystring[MAX_INPUTLINE]; + + M_Background(320, 48 + 8 * numcommands); + + p = Draw_CachePic ("gfx/ttl_cstm"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_cstm"); + + 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 0) + strlcat(keystring, " or ", sizeof(keystring)); + strlcat(keystring, Key_KeynumToString (keys[j], tinystr, sizeof(tinystr)), sizeof(keystring)); + } + } + } + M_Print(150, y, keystring); + } + + if (bind_grab) + M_DrawCharacter (140, 48 + keys_cursor*8, '='); + else + M_DrawCharacter (140, 48 + keys_cursor*8, 12+((int)(realtime*4)&1)); +} + + +static void M_Keys_Key (int k, int ascii) +{ + char cmd[80]; + int keys[NUMKEYS]; + char tinystr[2]; + + if (bind_grab) + { // defining a key + S_LocalSound ("sound/misc/menu1.wav"); + if (k == K_ESCAPE) + { + bind_grab = false; + } + else //if (k != '`') + { + dpsnprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString (k, tinystr, sizeof(tinystr)), bindnames[keys_cursor][0]); + Cbuf_InsertText (cmd); + } + + bind_grab = false; + return; + } + + switch (k) + { + case K_ESCAPE: + M_Menu_Options_f (); + break; + + case K_LEFTARROW: + case 'a': + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + do + { + keys_cursor--; + if (keys_cursor < 0) + keys_cursor = numcommands-1; + } + while (bindnames[keys_cursor][0][0] == '\0'); // skip sections + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + case 'd': + S_LocalSound ("sound/misc/menu1.wav"); + do + { + keys_cursor++; + if (keys_cursor >= numcommands) + keys_cursor = 0; + } + while (bindnames[keys_cursor][0][0] == '\0'); // skip sections + break; + case K_MOUSE1: + case K_ENTER: // go into bind mode + Key_FindKeysForCommand (bindnames[keys_cursor][0], keys, NUMKEYS, 0); + S_LocalSound ("sound/misc/menu2.wav"); + if (keys[NUMKEYS - 1] != -1) + M_UnbindCommand (bindnames[keys_cursor][0]); + bind_grab = true; + break; + + case K_BACKSPACE: // delete bindings + case K_DEL: // delete bindings + S_LocalSound ("sound/misc/menu2.wav"); + M_UnbindCommand (bindnames[keys_cursor][0]); + break; + } +} + +void M_Menu_Reset_f (void) +{ + key_dest = key_menu; + m_state = m_reset; + m_entersound = true; +} + + +static void M_Reset_Key (int key, int ascii) +{ + switch (key) + { + case 'Y': + case 'y': + jni_BigScreenMode(0); + Cbuf_AddText ("cvar_resettodefaults_all;exec default.cfg\n"); + // no break here since we also exit the menu + + case K_ESCAPE: + case 'n': + case 'N': + m_state = m_options; + m_entersound = true; + break; + + default: + break; + } +} + +static void M_Reset_Draw (void) +{ + int lines = 2, linelength = 20; + M_Background(linelength * 8 + 16, lines * 8 + 16); + M_DrawTextBox(0, 0, linelength, lines); + M_Print(8 + 4 * (linelength - 19), 8, "Really wanna reset?"); + M_Print(8 + 4 * (linelength - 11), 16, "Press y / n"); +} + +#define YAWCONTROL_ITEMS 5 + +static int yawpitchcontrol_cursor; + +void M_Menu_YawPitchControl_f (void) +{ + key_dest = key_menu; + m_state = m_yawpitchcontrol; + m_entersound = true; +} + +static void M_Menu_YawPitchControl_AdjustSliders (int dir) +{ + int optnum; + S_LocalSound ("sound/misc/menu3.wav"); + + optnum = 0; + + if (yawpitchcontrol_cursor == optnum++) ; + else if (yawpitchcontrol_cursor == optnum++) ; + else if (yawpitchcontrol_cursor == optnum++) ; + else if (yawpitchcontrol_cursor == optnum++ && cl_yawmode.integer == 1) + { + float value = 45.0f; + if (dir == 1) + { + if (cl_comfort.value == 30.0f) + value = 45.0f; + else if (cl_comfort.value == 45.0f) + value = 60.0f; + else if (cl_comfort.value == 60.0f) + value = 90.0f; + else if (cl_comfort.value == 90.0f) + value = 180.0f; + else if (cl_comfort.value == 180.0f) + value = 30.0f; + } + else + { + if (cl_comfort.value == 30.0f) + value = 180.0f; + else if (cl_comfort.value == 180.0f) + value = 90.0f; + else if (cl_comfort.value == 90.0f) + value = 60.0f; + else if (cl_comfort.value == 60.0f) + value = 45.0f; + else if (cl_comfort.value == 45.0f) + value = 30.0f; + } + + Cvar_SetValueQuick (&cl_comfort, value); + } + else if (yawpitchcontrol_cursor == optnum++ && cl_yawmode.integer == 2) + Cvar_SetValueQuick (&sensitivity, bound(1, (sensitivity.value + (dir * 0.25)), 10)); +} + +static void M_Menu_YawPitchControl_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (++yawpitchcontrol_cursor >= YAWCONTROL_ITEMS) + yawpitchcontrol_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + if (--yawpitchcontrol_cursor < 0) + yawpitchcontrol_cursor = YAWCONTROL_ITEMS - 1; + break; + + case 'a': + case K_LEFTARROW: + if (yawpitchcontrol_cursor == 0) + { + headtracking = !headtracking; + } + else if (yawpitchcontrol_cursor == 1) + { + int newPitchMode = cl_pitchmode.integer; + if (--newPitchMode < 0) + newPitchMode = 2; + Cvar_SetValueQuick (&cl_pitchmode, newPitchMode); + } + else if (yawpitchcontrol_cursor == 2) + { + int newYawMode = cl_yawmode.integer; + if (--newYawMode < 0) + newYawMode = 3; + + Cvar_SetValueQuick (&cl_yawmode, newYawMode); + } + else + M_Menu_YawPitchControl_AdjustSliders(-1); + break; + + case 'd': + case K_RIGHTARROW: + if (yawpitchcontrol_cursor == 0) + { + headtracking = !headtracking; + } + else if (yawpitchcontrol_cursor == 1) + { + int newPitchMode = cl_pitchmode.integer; + if (++newPitchMode > 2) + newPitchMode = 0; + Cvar_SetValueQuick (&cl_pitchmode, newPitchMode); + } + else if (yawpitchcontrol_cursor == 2) + { + int newYawMode = cl_yawmode.integer; + if (++newYawMode > 3) + newYawMode = 0; + + Cvar_SetValueQuick (&cl_yawmode, newYawMode); + } + else + M_Menu_YawPitchControl_AdjustSliders(1); + break; + + default: + break; + } +} + +static void M_Menu_YawPitchControl_Draw (void) +{ + int visible; + cachepic_t *p; + + M_Background(320, bound(200, 32 + OPTIONS_ITEMS * 8, vid_conheight.integer)); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((320-p->width)/2, 4, "gfx/p_option"); + + optnum = 0; + optcursor = yawpitchcontrol_cursor; + visible = (int)((menu_height - 32) / 8); + opty = 32 - bound(0, optcursor - (visible >> 1), max(0, YAWCONTROL_ITEMS - visible)) * 8; + + if (!headtracking) + M_Options_PrintCommand(" Sensor Headtracking: Disabled", true); + else + M_Options_PrintCommand(" Sensor Headtracking: Enabled", true); + + if (cl_pitchmode.integer == 0) + M_Options_PrintCommand(" Pitch Mode: Head-tracked Only (default)", true); + else if (cl_pitchmode.integer == 1) + M_Options_PrintCommand(" Pitch Mode: Free", true); + else if (cl_pitchmode.integer == 2) + M_Options_PrintCommand(" Pitch Mode: Free (inverted)", true); + + if (cl_yawmode.integer == 0) + M_Options_PrintCommand(" Yaw Mode: Swivel-Chair", true); + else if (cl_yawmode.integer == 1) + M_Options_PrintCommand(" Yaw Mode: Comfort-Mode", true); + else if (cl_yawmode.integer == 2) + M_Options_PrintCommand(" Yaw Mode: Stick-Yaw", true); + else + M_Options_PrintCommand(" Yaw Mode: Look-To-Turn", true); + + M_Options_PrintSlider( "Comfort Mode Turn Angle", cl_yawmode.integer == 1, cl_comfort.value, 30, 180); + M_Options_PrintSlider( " Stick Yaw Turn Speed", cl_yawmode.integer == 2, sensitivity.value, 1, 10); + if (cl_yawmode.integer >= 2) + { + M_Options_PrintCommand(" ", true); + M_Options_PrintCommand(" ", true); + M_Options_PrintCommand("WARNING: Yaw rotation", true); + M_Options_PrintCommand("can induce severe nausea in ", true); + M_Options_PrintCommand("those not used to it.", true); + M_Options_PrintCommand(" ", true); + M_Options_PrintCommand("* Use this mode at your own risk! *", true); + } +} + +//============================================================================= +/* VIDEO MENU */ + +video_resolution_t video_resolutions_hardcoded[] = +{ +{"Standard 4x3" , 320, 240, 320, 240, 1 }, +{"Standard 4x3" , 400, 300, 400, 300, 1 }, +{"Standard 4x3" , 512, 384, 512, 384, 1 }, +{"Standard 4x3" , 640, 480, 640, 480, 1 }, +{"Standard 4x3" , 800, 600, 640, 480, 1 }, +{"Standard 4x3" , 1024, 768, 640, 480, 1 }, +{"Standard 4x3" , 1152, 864, 640, 480, 1 }, +{"Standard 4x3" , 1280, 960, 640, 480, 1 }, +{"Standard 4x3" , 1400,1050, 640, 480, 1 }, +{"Standard 4x3" , 1600,1200, 640, 480, 1 }, +{"Standard 4x3" , 1792,1344, 640, 480, 1 }, +{"Standard 4x3" , 1856,1392, 640, 480, 1 }, +{"Standard 4x3" , 1920,1440, 640, 480, 1 }, +{"Standard 4x3" , 2048,1536, 640, 480, 1 }, +{"Short Pixel (CRT) 5x4" , 320, 256, 320, 256, 0.9375}, +{"Short Pixel (CRT) 5x4" , 640, 512, 640, 512, 0.9375}, +{"Short Pixel (CRT) 5x4" , 1280,1024, 640, 512, 0.9375}, +{"Tall Pixel (CRT) 8x5" , 320, 200, 320, 200, 1.2 }, +{"Tall Pixel (CRT) 8x5" , 640, 400, 640, 400, 1.2 }, +{"Tall Pixel (CRT) 8x5" , 840, 525, 640, 400, 1.2 }, +{"Tall Pixel (CRT) 8x5" , 960, 600, 640, 400, 1.2 }, +{"Tall Pixel (CRT) 8x5" , 1680,1050, 640, 400, 1.2 }, +{"Tall Pixel (CRT) 8x5" , 1920,1200, 640, 400, 1.2 }, +{"Square Pixel (LCD) 5x4" , 320, 256, 320, 256, 1 }, +{"Square Pixel (LCD) 5x4" , 640, 512, 640, 512, 1 }, +{"Square Pixel (LCD) 5x4" , 1280,1024, 640, 512, 1 }, +{"WideScreen 5x3" , 640, 384, 640, 384, 1 }, +{"WideScreen 5x3" , 1280, 768, 640, 384, 1 }, +{"WideScreen 8x5" , 320, 200, 320, 200, 1 }, +{"WideScreen 8x5" , 640, 400, 640, 400, 1 }, +{"WideScreen 8x5" , 720, 450, 720, 450, 1 }, +{"WideScreen 8x5" , 840, 525, 640, 400, 1 }, +{"WideScreen 8x5" , 960, 600, 640, 400, 1 }, +{"WideScreen 8x5" , 1280, 800, 640, 400, 1 }, +{"WideScreen 8x5" , 1440, 900, 720, 450, 1 }, +{"WideScreen 8x5" , 1680,1050, 640, 400, 1 }, +{"WideScreen 8x5" , 1920,1200, 640, 400, 1 }, +{"WideScreen 8x5" , 2560,1600, 640, 400, 1 }, +{"WideScreen 8x5" , 3840,2400, 640, 400, 1 }, +{"WideScreen 14x9" , 840, 540, 640, 400, 1 }, +{"WideScreen 14x9" , 1680,1080, 640, 400, 1 }, +{"WideScreen 16x9" , 640, 360, 640, 360, 1 }, +{"WideScreen 16x9" , 683, 384, 683, 384, 1 }, +{"WideScreen 16x9" , 960, 540, 640, 360, 1 }, +{"WideScreen 16x9" , 1280, 720, 640, 360, 1 }, +{"WideScreen 16x9" , 1360, 768, 680, 384, 1 }, +{"WideScreen 16x9" , 1366, 768, 683, 384, 1 }, +{"WideScreen 16x9" , 1920,1080, 640, 360, 1 }, +{"WideScreen 16x9" , 2560,1440, 640, 360, 1 }, +{"WideScreen 16x9" , 3840,2160, 640, 360, 1 }, +{"NTSC 3x2" , 360, 240, 360, 240, 1.125 }, +{"NTSC 3x2" , 720, 480, 720, 480, 1.125 }, +{"PAL 14x11" , 360, 283, 360, 283, 0.9545}, +{"PAL 14x11" , 720, 566, 720, 566, 0.9545}, +{"NES 8x7" , 256, 224, 256, 224, 1.1667}, +{"SNES 8x7" , 512, 448, 512, 448, 1.1667}, +{NULL, 0, 0, 0, 0, 0} +}; +// this is the number of the default mode (640x480) in the list above +int video_resolutions_hardcoded_count = sizeof(video_resolutions_hardcoded) / sizeof(*video_resolutions_hardcoded) - 1; + +#define VIDEO_ITEMS 11 +static int video_cursor = 0; +static int video_cursor_table[VIDEO_ITEMS] = {68, 88, 96, 104, 112, 120, 128, 136, 144, 152, 168}; +static int menu_video_resolution; + +video_resolution_t *video_resolutions; +int video_resolutions_count; + +static video_resolution_t *menu_video_resolutions; +static int menu_video_resolutions_count; +static qboolean menu_video_resolutions_forfullscreen; + +static void M_Menu_Video_FindResolution(int w, int h, float a) +{ + int i; + + if(menu_video_resolutions_forfullscreen) + { + menu_video_resolutions = video_resolutions; + menu_video_resolutions_count = video_resolutions_count; + } + else + { + menu_video_resolutions = video_resolutions_hardcoded; + menu_video_resolutions_count = video_resolutions_hardcoded_count; + } + + // Look for the closest match to the current resolution + menu_video_resolution = 0; + for (i = 1;i < menu_video_resolutions_count;i++) + { + // if the new mode would be a worse match in width, skip it + if (abs(menu_video_resolutions[i].width - w) > abs(menu_video_resolutions[menu_video_resolution].width - w)) + continue; + // if it is equal in width, check height + if (menu_video_resolutions[i].width == w && menu_video_resolutions[menu_video_resolution].width == w) + { + // if the new mode would be a worse match in height, skip it + if (abs(menu_video_resolutions[i].height - h) > abs(menu_video_resolutions[menu_video_resolution].height - h)) + continue; + // if it is equal in width and height, check pixel aspect + if (menu_video_resolutions[i].height == h && menu_video_resolutions[menu_video_resolution].height == h) + { + // if the new mode would be a worse match in pixel aspect, skip it + if (abs(menu_video_resolutions[i].pixelheight - a) > abs(menu_video_resolutions[menu_video_resolution].pixelheight - a)) + continue; + // if it is equal in everything, skip it (prefer earlier modes) + if (menu_video_resolutions[i].pixelheight == a && menu_video_resolutions[menu_video_resolution].pixelheight == a) + continue; + // better match for width, height, and pixel aspect + menu_video_resolution = i; + } + else // better match for width and height + menu_video_resolution = i; + } + else // better match for width + menu_video_resolution = i; + } +} + +void M_Menu_Video_f (void) +{ + key_dest = key_menu; + m_state = m_video; + m_entersound = true; + + M_Menu_Video_FindResolution(vid.width, vid.height, vid_pixelheight.value); +} + + +static void M_Video_Draw (void) +{ + int t; + cachepic_t *p; + char vabuf[1024]; + + if(!!vid_fullscreen.integer != menu_video_resolutions_forfullscreen) + { + video_resolution_t *res = &menu_video_resolutions[menu_video_resolution]; + menu_video_resolutions_forfullscreen = !!vid_fullscreen.integer; + M_Menu_Video_FindResolution(res->width, res->height, res->pixelheight); + } + + M_Background(320, 200); + + M_DrawPic(16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/vidmodes"); + M_DrawPic((320-p->width)/2, 4, "gfx/vidmodes"); + + t = 0; + + // Current and Proposed Resolution + M_Print(16, video_cursor_table[t] - 12, " Current Resolution"); + if (vid_supportrefreshrate && vid.userefreshrate && vid.fullscreen) + M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d %.2fhz", vid.width, vid.height, vid.refreshrate)); + else + M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d", vid.width, vid.height)); + M_Print(16, video_cursor_table[t], " New Resolution"); + M_Print(220, video_cursor_table[t], va(vabuf, sizeof(vabuf), "%dx%d", menu_video_resolutions[menu_video_resolution].width, menu_video_resolutions[menu_video_resolution].height)); + M_Print(96, video_cursor_table[t] + 8, va(vabuf, sizeof(vabuf), "Type: %s", menu_video_resolutions[menu_video_resolution].type)); + t++; + + // Bits per pixel + M_Print(16, video_cursor_table[t], " Bits per pixel"); + M_Print(220, video_cursor_table[t], (vid_bitsperpixel.integer == 32) ? "32" : "16"); + t++; + + // Bits per pixel + M_Print(16, video_cursor_table[t], " Antialiasing"); + M_DrawSlider(220, video_cursor_table[t], vid_samples.value, 1, 32); + t++; + + // Refresh Rate + M_ItemPrint(16, video_cursor_table[t], " Use Refresh Rate", vid_supportrefreshrate); + M_DrawCheckbox(220, video_cursor_table[t], vid_userefreshrate.integer); + t++; + + // Refresh Rate + M_ItemPrint(16, video_cursor_table[t], " Refresh Rate", vid_supportrefreshrate && vid_userefreshrate.integer); + M_DrawSlider(220, video_cursor_table[t], vid_refreshrate.value, 50, 150); + t++; + + // Fullscreen + M_Print(16, video_cursor_table[t], " Fullscreen"); + M_DrawCheckbox(220, video_cursor_table[t], vid_fullscreen.integer); + t++; + + // Vertical Sync + M_ItemPrint(16, video_cursor_table[t], " Vertical Sync", true); + M_DrawCheckbox(220, video_cursor_table[t], vid_vsync.integer); + t++; + + M_ItemPrint(16, video_cursor_table[t], " Anisotropic Filter", vid.support.ext_texture_filter_anisotropic); + M_DrawSlider(220, video_cursor_table[t], gl_texture_anisotropy.integer, 1, vid.max_anisotropy); + t++; + + M_ItemPrint(16, video_cursor_table[t], " Texture Quality", true); + M_DrawSlider(220, video_cursor_table[t], gl_picmip.value, 3, 0); + t++; + + M_ItemPrint(16, video_cursor_table[t], " Texture Compression", vid.support.arb_texture_compression); + M_DrawCheckbox(220, video_cursor_table[t], gl_texturecompression.integer); + t++; + + // "Apply" button + M_Print(220, video_cursor_table[t], "Apply"); + t++; + + // Cursor + M_DrawCharacter(200, video_cursor_table[video_cursor], 12+((int)(realtime*4)&1)); +} + + +static void M_Menu_Video_AdjustSliders (int dir) +{ + int t; + + S_LocalSound ("sound/misc/menu3.wav"); + + t = 0; + if (video_cursor == t++) + { + // Resolution + int r; + for(r = 0;r < menu_video_resolutions_count;r++) + { + menu_video_resolution += dir; + if (menu_video_resolution >= menu_video_resolutions_count) + menu_video_resolution = 0; + if (menu_video_resolution < 0) + menu_video_resolution = menu_video_resolutions_count - 1; + if (menu_video_resolutions[menu_video_resolution].width >= vid_minwidth.integer && menu_video_resolutions[menu_video_resolution].height >= vid_minheight.integer) + break; + } + } + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_bitsperpixel, (vid_bitsperpixel.integer == 32) ? 16 : 32); + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_samples, bound(1, vid_samples.value * (dir > 0 ? 2 : 0.5), 32)); + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_userefreshrate, !vid_userefreshrate.integer); + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_refreshrate, bound(50, vid_refreshrate.value + dir, 150)); + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_fullscreen, !vid_fullscreen.integer); + else if (video_cursor == t++) + Cvar_SetValueQuick (&vid_vsync, !vid_vsync.integer); + else if (video_cursor == t++) + Cvar_SetValueQuick (&gl_texture_anisotropy, bound(1, gl_texture_anisotropy.value * (dir < 0 ? 0.5 : 2.0), vid.max_anisotropy)); + else if (video_cursor == t++) + Cvar_SetValueQuick (&gl_picmip, bound(0, gl_picmip.value - dir, 3)); + else if (video_cursor == t++) + Cvar_SetValueQuick (&gl_texturecompression, !gl_texturecompression.integer); +} + + +static void M_Video_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + // vid_shared.c has a copy of the current video config. We restore it + Cvar_SetValueQuick(&vid_fullscreen, vid.fullscreen); + Cvar_SetValueQuick(&vid_bitsperpixel, vid.bitsperpixel); + Cvar_SetValueQuick(&vid_samples, vid.samples); + if (vid_supportrefreshrate) + Cvar_SetValueQuick(&vid_refreshrate, vid.refreshrate); + Cvar_SetValueQuick(&vid_userefreshrate, vid.userefreshrate); + + S_LocalSound ("sound/misc/menu1.wav"); + M_Menu_Options_f (); + break; + case K_MOUSE1: + case K_ENTER: + m_entersound = true; + switch (video_cursor) + { + case (VIDEO_ITEMS - 1): + Cvar_SetValueQuick (&vid_width, menu_video_resolutions[menu_video_resolution].width); + Cvar_SetValueQuick (&vid_height, menu_video_resolutions[menu_video_resolution].height); + Cvar_SetValueQuick (&vid_conwidth, menu_video_resolutions[menu_video_resolution].conwidth); + Cvar_SetValueQuick (&vid_conheight, menu_video_resolutions[menu_video_resolution].conheight); + Cvar_SetValueQuick (&vid_pixelheight, menu_video_resolutions[menu_video_resolution].pixelheight); + Cbuf_AddText ("vid_restart\n"); + M_Menu_Options_f (); + break; + default: + M_Menu_Video_AdjustSliders (1); + } + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + video_cursor--; + if (video_cursor < 0) + video_cursor = VIDEO_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + video_cursor++; + if (video_cursor >= VIDEO_ITEMS) + video_cursor = 0; + break; + case 'a': + case K_LEFTARROW: + M_Menu_Video_AdjustSliders (-1); + break; + case 'd': + case K_RIGHTARROW: + M_Menu_Video_AdjustSliders (1); + break; + } +} + +//============================================================================= +/* HELP MENU */ + +static 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; +} + + + +static void M_Help_Draw (void) +{ + char vabuf[1024]; + M_Background(320, 200); + M_DrawPic (0, 0, va(vabuf, sizeof(vabuf), "gfx/help%i", help_page)); +} + + +static void M_Help_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_UPARROW: + case K_RIGHTARROW: + case 'd': + m_entersound = true; + if (++help_page >= NUM_HELP_PAGES) + help_page = 0; + break; + + case K_DOWNARROW: + case K_LEFTARROW: + case 'a': + m_entersound = true; + if (--help_page < 0) + help_page = NUM_HELP_PAGES-1; + break; + } + +} + +//============================================================================= +/* CEDITS MENU */ + +void M_Menu_Credits_f (void) +{ + key_dest = key_menu; + m_state = m_credits; + m_entersound = true; +} + + +static const char *m_credits_message[11]; +static int M_CreditsMessage(const char *line1, const char *line2, + const char *line3, const char *line4, + const char *line5, const char *line6, + const char *line7, const char *line8) +{ + int line = 0; + m_credits_message[line++] = line1; + m_credits_message[line++] = line2; + m_credits_message[line++] = line3; + m_credits_message[line++] = line4; + m_credits_message[line++] = line5; + m_credits_message[line++] = line6; + m_credits_message[line++] = line7; + m_credits_message[line++] = line8; + m_credits_message[line++] = NULL; + return 1; +} + +static void M_Credits_Draw (void) +{ + M_CreditsMessage( + " -= QVR "QVR_VERSION" =- ", + "", + " DarkPlaces Engine - LordHavoc ", + " Cardboard Port - Dr. Beef", + "", + "", + "", + " ** Please Press Any Button ** "); + + int i, l, linelength, firstline, lastline, lines; + for (i = 0, linelength = 0, firstline = 9999, lastline = -1;m_credits_message[i];i++) + { + if ((l = (int)strlen(m_credits_message[i]))) + { + if (firstline > i) + firstline = i; + if (lastline < i) + lastline = i; + if (linelength < l) + linelength = l; + } + } + lines = (lastline - firstline) + 1; + M_Background(linelength * 8 + 16, lines * 8 + 16); + M_DrawTextBox(0, -48, linelength, lines); //this is less obtrusive than hacking up the M_DrawTextBox function + for (i = 0, l = firstline;i < lines;i++, l++) + M_Print(8 + 4 * (linelength - strlen(m_credits_message[l])), -40 + 8 * i, m_credits_message[l]); +} + + +static void M_Credits_Key (int key, int ascii) +{ + M_Menu_Main_f (); +} + +//============================================================================= +/* QUIT MENU */ + +static const char *m_quit_message[9]; +static int m_quit_prevstate; +static qboolean wasInMenus; + + +static int M_QuitMessage(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6, const char *line7, const char *line8) +{ + m_quit_message[0] = line1; + m_quit_message[1] = line2; + m_quit_message[2] = line3; + m_quit_message[3] = line4; + m_quit_message[4] = line5; + m_quit_message[5] = line6; + m_quit_message[6] = line7; + m_quit_message[7] = line8; + m_quit_message[8] = NULL; + return 1; +} + +static int M_ChooseQuitMessage(int request) +{ + switch (gamemode) + { + case GAME_NORMAL: + case GAME_HIPNOTIC: + case GAME_ROGUE: + case GAME_QUOTH: + case GAME_NEHAHRA: + case GAME_DEFEATINDETAIL2: + if (request-- == 0) return M_QuitMessage("Are you gonna quit","this game just like","everything else?",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Milord, methinks that","thou art a lowly","quitter. Is this true?",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Do I need to bust your","face open for trying","to quit?",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Man, I oughta smack you","for trying to quit!","Press Y to get","smacked out.",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Press Y to quit like a","big loser in life.","Press N to stay proud","and successful!",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("If you press Y to","quit, I will summon","Satan all over your","hard drive!",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Um, Asmodeus dislikes","his children trying to","quit. Press Y to return","to your Tinkertoys.",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("If you quit now, I'll","throw a blanket-party","for you next time!",NULL,NULL,NULL,NULL,NULL); + break; + case GAME_GOODVSBAD2: + if (request-- == 0) return M_QuitMessage("Press Yes To Quit","...","Yes",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Do you really want to","Quit?","Play Good vs bad 3!",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("All your quit are","belong to long duck","dong",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Press Y to quit","","But are you too legit?",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("This game was made by","e@chip-web.com","It is by far the best","game ever made.",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Even I really dont","know of a game better","Press Y to quit","like rougue chedder",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("After you stop playing","tell the guys who made","counterstrike to just","kill themselves now",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Press Y to exit to DOS","","SSH login as user Y","to exit to Linux",NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Press Y like you","were waanderers","from Ys'",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("This game was made in","Nippon like the SS","announcer's saying ipon",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("you","want to quit?",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Please stop playing","this stupid game",NULL,NULL,NULL,NULL,NULL,NULL); + break; + case GAME_BATTLEMECH: + if (request-- == 0) return M_QuitMessage("? WHY ?","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Leave now and your mech is scrap!","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Accept Defeat?","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Wait! There are more mechs to destroy!","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Where's your bloodlust?","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Your mech here is way more impressive","than your car out there...","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Quitting won't reduce your debt","Press Y to quit, N to keep fraggin'",NULL,NULL,NULL,NULL,NULL,NULL); + break; + case GAME_OPENQUARTZ: + if (request-- == 0) return M_QuitMessage("There is nothing like free beer!","Press Y to quit, N to stay",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("GNU is not Unix!","Press Y to quit, N to stay",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("You prefer free beer over free speech?","Press Y to quit, N to stay",NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Is OpenQuartz Propaganda?","Press Y to quit, N to stay",NULL,NULL,NULL,NULL,NULL,NULL); + break; + default: + if (request-- == 0) return M_QuitMessage("Tired of fragging already?",NULL,NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Quit now and forfeit your bodycount?",NULL,NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Are you sure you want to quit?",NULL,NULL,NULL,NULL,NULL,NULL,NULL); + if (request-- == 0) return M_QuitMessage("Off to do something constructive?",NULL,NULL,NULL,NULL,NULL,NULL,NULL); + break; + } + return 0; +} + +void M_Menu_Quit_f (void) +{ + int n; + if (m_state == m_quit) + return; + wasInMenus = (key_dest == key_menu || key_dest == key_menu_grabbed); + key_dest = key_menu; + m_quit_prevstate = m_state; + m_state = m_quit; + m_entersound = true; + // count how many there are + for (n = 1;M_ChooseQuitMessage(n);n++); + // choose one + M_ChooseQuitMessage(rand() % n); +} + + +static void M_Quit_Key (int key, int ascii) +{ + switch (key) + { + case K_ESCAPE: + case 'n': + case 'N': + if (wasInMenus) + { + m_state = (enum m_state_e)m_quit_prevstate; + m_entersound = true; + } + else + { + key_dest = key_game; + m_state = m_none; + } + break; + + default: + { + Host_Quit_f (); + key_dest = key_game; + m_state = m_none; + } + break; + } +} + +static void M_Quit_Draw (void) +{ + int i, l, linelength, firstline, lastline, lines; + for (i = 0, linelength = 0, firstline = 9999, lastline = -1;m_quit_message[i];i++) + { + if ((l = (int)strlen(m_quit_message[i]))) + { + if (firstline > i) + firstline = i; + if (lastline < i) + lastline = i; + if (linelength < l) + linelength = l; + } + } + lines = (lastline - firstline) + 1; + M_Background(linelength * 8 + 16, lines * 8 + 16); + if (!m_missingdata) //since this is a fallback menu for missing data, it is very hard to read with the box + M_DrawTextBox(0, 0, linelength, lines); //this is less obtrusive than hacking up the M_DrawTextBox function + for (i = 0, l = firstline;i < lines;i++, l++) + M_Print(8 + 4 * (linelength - strlen(m_quit_message[l])), 8 + 8 * i, m_quit_message[l]); +} + +//============================================================================= +/* LAN CONFIG MENU */ + +static int lanConfig_cursor = -1; +static int lanConfig_cursor_table [] = {56, 76, 84, 120}; +#define NUM_LANCONFIG_CMDS 4 + +static int lanConfig_port; +static char lanConfig_portname[6]; +static char lanConfig_joinname[40]; + +void M_Menu_LanConfig_f (void) +{ + key_dest = key_menu; + m_state = m_lanconfig; + m_entersound = true; + if (lanConfig_cursor == -1) + { + if (JoiningGame) + lanConfig_cursor = 1; + } + if (StartingGame) + lanConfig_cursor = 1; + lanConfig_port = 26000; + dpsnprintf(lanConfig_portname, sizeof(lanConfig_portname), "%u", (unsigned int) lanConfig_port); + + M_Update_Return_Reason(""); +} + + +static void M_LanConfig_Draw (void) +{ + cachepic_t *p; + int basex; + const char *startJoin; + const char *protocol; + char vabuf[1024]; + + M_Background(320, 200); + + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_multi"); + basex = (320-p->width)/2; + M_DrawPic (basex, 4, "gfx/p_multi"); + + if (StartingGame) + startJoin = "New Game"; + else + startJoin = "Join Game"; + protocol = "TCP/IP"; + M_Print(basex, 32, va(vabuf, sizeof(vabuf), "%s - %s", startJoin, protocol)); + basex += 8; + + M_Print(basex, lanConfig_cursor_table[0], "Port"); + M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, sizeof(lanConfig_portname), 1); + M_Print(basex+9*8, lanConfig_cursor_table[0], lanConfig_portname); + + if (JoiningGame) + { + M_Print(basex, lanConfig_cursor_table[1], "Search for DarkPlaces games..."); + M_Print(basex, lanConfig_cursor_table[2], "Search for QuakeWorld games..."); + M_Print(basex, lanConfig_cursor_table[3]-16, "Join game at:"); + M_DrawTextBox (basex+8, lanConfig_cursor_table[3]-8, sizeof(lanConfig_joinname), 1); + M_Print(basex+16, lanConfig_cursor_table[3], 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 [lanConfig_cursor], 10+((int)(realtime*4)&1)); + + if (lanConfig_cursor == 3) + M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [lanConfig_cursor], 10+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_Print(basex, 168, m_return_reason); +} + + +static void M_LanConfig_Key (int key, int ascii) +{ + int l; + char vabuf[1024]; + + switch (key) + { + case K_ESCAPE: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + lanConfig_cursor--; + if (lanConfig_cursor < 0) + lanConfig_cursor = NUM_LANCONFIG_CMDS-1; + // when in start game menu, skip the unused search qw servers item + if (StartingGame && lanConfig_cursor == 2) + lanConfig_cursor = 1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + lanConfig_cursor++; + if (lanConfig_cursor >= NUM_LANCONFIG_CMDS) + lanConfig_cursor = 0; + // when in start game menu, skip the unused search qw servers item + if (StartingGame && lanConfig_cursor == 1) + lanConfig_cursor = 2; + break; + case K_MOUSE1: + case K_ENTER: + if (lanConfig_cursor == 0) + break; + + m_entersound = true; + + Cbuf_AddText ("stopdemo\n"); + + Cvar_SetValue("port", lanConfig_port); + + if (lanConfig_cursor == 1 || lanConfig_cursor == 2) + { + if (StartingGame) + { + M_Menu_GameOptions_f (); + break; + } + M_Menu_ServerList_f(); + break; + } + + if (lanConfig_cursor == 3) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", lanConfig_joinname) ); + break; + + case K_BACKSPACE: + if (lanConfig_cursor == 0) + { + if (strlen(lanConfig_portname)) + lanConfig_portname[strlen(lanConfig_portname)-1] = 0; + } + + if (lanConfig_cursor == 3) + { + if (strlen(lanConfig_joinname)) + lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0; + } + break; + + default: + if (ascii < 32) + break; + + if (lanConfig_cursor == 3) + { + l = (int)strlen(lanConfig_joinname); + if (l < (int)sizeof(lanConfig_joinname) - 1) + { + lanConfig_joinname[l+1] = 0; + lanConfig_joinname[l] = ascii; + } + } + + if (ascii < '0' || ascii > '9') + break; + if (lanConfig_cursor == 0) + { + l = (int)strlen(lanConfig_portname); + if (l < (int)sizeof(lanConfig_portname) - 1) + { + lanConfig_portname[l+1] = 0; + lanConfig_portname[l] = ascii; + } + } + } + + if (StartingGame && lanConfig_cursor == 3) + { + if (key == K_UPARROW) + lanConfig_cursor = 1; + else + lanConfig_cursor = 0; + } + + l = atoi(lanConfig_portname); + if (l <= 65535) + lanConfig_port = l; + dpsnprintf(lanConfig_portname, sizeof(lanConfig_portname), "%u", (unsigned int) lanConfig_port); +} + +//============================================================================= +/* GAME OPTIONS MENU */ + +typedef struct level_s +{ + const char *name; + const char *description; +} level_t; + +typedef struct episode_s +{ + const char *description; + int firstLevel; + int levels; +} episode_t; + +typedef struct gamelevels_s +{ + const char *gamename; + level_t *levels; + episode_t *episodes; + int numepisodes; +} +gamelevels_t; + +static level_t quakelevels[] = +{ + {"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"} +}; + +static episode_t quakeepisodes[] = +{ + {"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 levels +static 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 +}; + +//MED 01/06/97 added hipnotic episodes +static 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 levels +//PGM 03/02/97 added dmatch level +static 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"} +}; + +//PGM 01/07/97 added rogue episodes +//PGM 03/02/97 added dmatch episode +static episode_t rogueepisodes[] = +{ + {"Introduction", 0, 1}, + {"Hell's Fortress", 1, 7}, + {"Corridors of Time", 8, 8}, + {"Deathmatch Arena", 16, 1} +}; + +static level_t nehahralevels[] = +{ + {"nehstart", "Welcome to Nehahra"}, + {"neh1m1", "Forge City1: Slipgates"}, + {"neh1m2", "Forge City2: Boiler"}, + {"neh1m3", "Forge City3: Escape"}, + {"neh1m4", "Grind Core"}, + {"neh1m5", "Industrial Silence"}, + {"neh1m6", "Locked-Up Anger"}, + {"neh1m7", "Wanderer of the Wastes"}, + {"neh1m8", "Artemis System Net"}, + {"neh1m9", "To the Death"}, + {"neh2m1", "The Gates of Ghoro"}, + {"neh2m2", "Sacred Trinity"}, + {"neh2m3", "Realm of the Ancients"}, + {"neh2m4", "Temple of the Ancients"}, + {"neh2m5", "Dreams Made Flesh"}, + {"neh2m6", "Your Last Cup of Sorrow"}, + {"nehsec", "Ogre's Bane"}, + {"nehahra", "Nehahra's Den"}, + {"nehend", "Quintessence"} +}; + +static episode_t nehahraepisodes[] = +{ + {"Welcome to Nehahra", 0, 1}, + {"The Fall of Forge", 1, 9}, + {"The Outlands", 10, 7}, + {"Dimension of the Lost", 17, 2} +}; + +// Map list for Transfusion +static level_t transfusionlevels[] = +{ + {"e1m1", "Cradle to Grave"}, + {"e1m2", "Wrong Side of the Tracks"}, + {"e1m3", "Phantom Express"}, + {"e1m4", "Dark Carnival"}, + {"e1m5", "Hallowed Grounds"}, + {"e1m6", "The Great Temple"}, + {"e1m7", "Altar of Stone"}, + {"e1m8", "House of Horrors"}, + + {"e2m1", "Shipwrecked"}, + {"e2m2", "The Lumber Mill"}, + {"e2m3", "Rest for the Wicked"}, + {"e2m4", "The Overlooked Hotel"}, + {"e2m5", "The Haunting"}, + {"e2m6", "The Cold Rush"}, + {"e2m7", "Bowels of the Earth"}, + {"e2m8", "The Lair of Shial"}, + {"e2m9", "Thin Ice"}, + + {"e3m1", "Ghost Town"}, + {"e3m2", "The Siege"}, + {"e3m3", "Raw Sewage"}, + {"e3m4", "The Sick Ward"}, + {"e3m5", "Spare Parts"}, + {"e3m6", "Monster Bait"}, + {"e3m7", "The Pit of Cerberus"}, + {"e3m8", "Catacombs"}, + + {"e4m1", "Butchery Loves Company"}, + {"e4m2", "Breeding Grounds"}, + {"e4m3", "Charnel House"}, + {"e4m4", "Crystal Lake"}, + {"e4m5", "Fire and Brimstone"}, + {"e4m6", "The Ganglion Depths"}, + {"e4m7", "In the Flesh"}, + {"e4m8", "The Hall of the Epiphany"}, + {"e4m9", "Mall of the Dead"}, + + {"bb1", "The Stronghold"}, + {"bb2", "Winter Wonderland"}, + {"bb3", "Bodies"}, + {"bb4", "The Tower"}, + {"bb5", "Click!"}, + {"bb6", "Twin Fortress"}, + {"bb7", "Midgard"}, + {"bb8", "Fun With Heads"}, + {"dm1", "Monolith Building 11"}, + {"dm2", "Power!"}, + {"dm3", "Area 15"}, + + {"e6m1", "Welcome to Your Life"}, + {"e6m2", "They Are Here"}, + {"e6m3", "Public Storage"}, + {"e6m4", "Aqueducts"}, + {"e6m5", "The Ruined Temple"}, + {"e6m6", "Forbidden Rituals"}, + {"e6m7", "The Dungeon"}, + {"e6m8", "Beauty and the Beast"}, + {"e6m9", "Forgotten Catacombs"}, + + {"cp01", "Boat Docks"}, + {"cp02", "Old Opera House"}, + {"cp03", "Gothic Library"}, + {"cp04", "Lost Monastery"}, + {"cp05", "Steamboat"}, + {"cp06", "Graveyard"}, + {"cp07", "Mountain Pass"}, + {"cp08", "Abysmal Mine"}, + {"cp09", "Castle"}, + {"cps1", "Boggy Creek"}, + + {"cpbb01", "Crypt of Despair"}, + {"cpbb02", "Pits of Blood"}, + {"cpbb03", "Unholy Cathedral"}, + {"cpbb04", "Deadly Inspirations"}, + + {"b2a15", "Area 15 (B2)"}, + {"b2bodies", "BB_Bodies (B2)"}, + {"b2cabana", "BB_Cabana"}, + {"b2power", "BB_Power"}, + {"barena", "Blood Arena"}, + {"bkeep", "Blood Keep"}, + {"bstar", "Brown Star"}, + {"crypt", "The Crypt"}, + + {"bb3_2k1", "Bodies Infusion"}, + {"captasao", "Captasao"}, + {"curandero", "Curandero"}, + {"dcamp", "DeathCamp"}, + {"highnoon", "HighNoon"}, + {"qbb1", "The Confluence"}, + {"qbb2", "KathartiK"}, + {"qbb3", "Caleb's Woodland Retreat"}, + {"zoo", "Zoo"}, + + {"dranzbb6", "Black Coffee"}, + {"fragm", "Frag'M"}, + {"maim", "Maim"}, + {"qe1m7", "The House of Chthon"}, + {"qdm1", "Place of Two Deaths"}, + {"qdm4", "The Bad Place"}, + {"qdm5", "The Cistern"}, + {"qmorbias", "DM-Morbias"}, + {"simple", "Dead Simple"} +}; + +static episode_t transfusionepisodes[] = +{ + {"The Way of All Flesh", 0, 8}, + {"Even Death May Die", 8, 9}, + {"Farewell to Arms", 17, 8}, + {"Dead Reckoning", 25, 9}, + {"BloodBath", 34, 11}, + {"Post Mortem", 45, 9}, + {"Cryptic Passage", 54, 10}, + {"Cryptic BloodBath", 64, 4}, + {"Blood 2", 68, 8}, + {"Transfusion", 76, 9}, + {"Conversions", 85, 9} +}; + +static level_t goodvsbad2levels[] = +{ + {"rts", "Many Paths"}, // 0 + {"chess", "Chess, Scott Hess"}, // 1 + {"dot", "Big Wall"}, + {"city2", "The Big City"}, + {"bwall", "0 G like Psychic TV"}, + {"snow", "Wireframed"}, + {"telep", "Infinite Falling"}, + {"faces", "Facing Bases"}, + {"island", "Adventure Islands"}, +}; + +static episode_t goodvsbad2episodes[] = +{ + {"Levels? Bevels!", 0, 8}, +}; + +static level_t battlemechlevels[] = +{ + {"start", "Parking Level"}, + {"dm1", "Hot Dump"}, // 1 + {"dm2", "The Pits"}, + {"dm3", "Dimber Died"}, + {"dm4", "Fire in the Hole"}, + {"dm5", "Clubhouses"}, + {"dm6", "Army go Underground"}, +}; + +static episode_t battlemechepisodes[] = +{ + {"Time for Battle", 0, 7}, +}; + +static level_t openquartzlevels[] = +{ + {"start", "Welcome to Openquartz"}, + + {"void1", "The center of nowhere"}, // 1 + {"void2", "The place with no name"}, + {"void3", "The lost supply base"}, + {"void4", "Past the outer limits"}, + {"void5", "Into the nonexistance"}, + {"void6", "Void walk"}, + + {"vtest", "Warp Central"}, + {"box", "The deathmatch box"}, + {"bunkers", "Void command"}, + {"house", "House of chaos"}, + {"office", "Overnight office kill"}, + {"am1", "The nameless chambers"}, +}; + +static episode_t openquartzepisodes[] = +{ + {"Single Player", 0, 1}, + {"Void Deathmatch", 1, 6}, + {"Contrib", 7, 6}, +}; + +static level_t defeatindetail2levels[] = +{ + {"atac3", "River Crossing"}, + {"atac4", "Canyon Chaos"}, + {"atac7", "Desert Stormer"}, +}; + +static episode_t defeatindetail2episodes[] = +{ + {"ATAC Campaign", 0, 3}, +}; + +static level_t prydonlevels[] = +{ + {"curig2", "Capel Curig"}, // 0 + + {"tdastart", "Gateway"}, // 1 +}; + +static episode_t prydonepisodes[] = +{ + {"Prydon Gate", 0, 1}, + {"The Dark Age", 1, 1} +}; + +static gamelevels_t sharewarequakegame = {"Shareware Quake", quakelevels, quakeepisodes, 2}; +static gamelevels_t registeredquakegame = {"Quake", quakelevels, quakeepisodes, 7}; +static gamelevels_t hipnoticgame = {"Scourge of Armagon", hipnoticlevels, hipnoticepisodes, 6}; +static gamelevels_t roguegame = {"Dissolution of Eternity", roguelevels, rogueepisodes, 4}; +static gamelevels_t nehahragame = {"Nehahra", nehahralevels, nehahraepisodes, 4}; +static gamelevels_t transfusiongame = {"Transfusion", transfusionlevels, transfusionepisodes, 11}; +static gamelevels_t goodvsbad2game = {"Good Vs. Bad 2", goodvsbad2levels, goodvsbad2episodes, 1}; +static gamelevels_t battlemechgame = {"Battlemech", battlemechlevels, battlemechepisodes, 1}; +static gamelevels_t openquartzgame = {"OpenQuartz", openquartzlevels, openquartzepisodes, 3}; +static gamelevels_t defeatindetail2game = {"Defeat In Detail 2", defeatindetail2levels, defeatindetail2episodes, 1}; +static gamelevels_t prydongame = {"Prydon Gate", prydonlevels, prydonepisodes, 2}; + +typedef struct gameinfo_s +{ + gamemode_t gameid; + gamelevels_t *notregistered; + gamelevels_t *registered; +} +gameinfo_t; + +static gameinfo_t gamelist[] = +{ + {GAME_NORMAL, &sharewarequakegame, ®isteredquakegame}, + {GAME_HIPNOTIC, &hipnoticgame, &hipnoticgame}, + {GAME_ROGUE, &roguegame, &roguegame}, + {GAME_QUOTH, &sharewarequakegame, ®isteredquakegame}, + {GAME_NEHAHRA, &nehahragame, &nehahragame}, + {GAME_TRANSFUSION, &transfusiongame, &transfusiongame}, + {GAME_GOODVSBAD2, &goodvsbad2game, &goodvsbad2game}, + {GAME_BATTLEMECH, &battlemechgame, &battlemechgame}, + {GAME_OPENQUARTZ, &openquartzgame, &openquartzgame}, + {GAME_DEFEATINDETAIL2, &defeatindetail2game, &defeatindetail2game}, + {GAME_PRYDON, &prydongame, &prydongame}, +}; + +static gamelevels_t *gameoptions_levels = NULL; + +static int startepisode; +static int startlevel; +static int maxplayers; +static qboolean m_serverInfoMessage = false; +static double m_serverInfoMessageTime; + +void M_Menu_GameOptions_f (void) +{ + int i; + key_dest = key_menu; + m_state = m_gameoptions; + m_entersound = true; + if (maxplayers == 0) + maxplayers = svs.maxclients; + if (maxplayers < 2) + maxplayers = min(8, MAX_SCOREBOARD); + // pick game level list based on gamemode (use GAME_NORMAL if no matches) + gameoptions_levels = registered.integer ? gamelist[0].registered : gamelist[0].notregistered; + for (i = 0;i < (int)(sizeof(gamelist)/sizeof(gamelist[0]));i++) + if (gamelist[i].gameid == gamemode) + gameoptions_levels = registered.integer ? gamelist[i].registered : gamelist[i].notregistered; +} + + +static int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 104, 112, 140, 160, 168}; +#define NUM_GAMEOPTIONS 12 +static int gameoptions_cursor; + +void M_GameOptions_Draw (void) +{ + cachepic_t *p; + int x; + char vabuf[1024]; + + M_Background(320, 200); + + M_DrawPic (16, 4, "gfx/qplaque"); + p = Draw_CachePic ("gfx/p_multi"); + M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi"); + + M_DrawTextBox (152, 32, 10, 1); + M_Print(160, 40, "begin game"); + + M_Print(0, 56, " Max players"); + M_Print(160, 56, va(vabuf, sizeof(vabuf), "%i", maxplayers) ); + + if (gamemode != GAME_GOODVSBAD2) + { + M_Print(0, 64, " Game Type"); + if (gamemode == GAME_TRANSFUSION) + { + if (!coop.integer && !deathmatch.integer) + Cvar_SetValue("deathmatch", 1); + if (deathmatch.integer == 0) + M_Print(160, 64, "Cooperative"); + else if (deathmatch.integer == 2) + M_Print(160, 64, "Capture the Flag"); + else + M_Print(160, 64, "Blood Bath"); + } + else if (gamemode == GAME_BATTLEMECH) + { + if (!deathmatch.integer) + Cvar_SetValue("deathmatch", 1); + if (deathmatch.integer == 2) + M_Print(160, 64, "Rambo Match"); + else + M_Print(160, 64, "Deathmatch"); + } + else + { + if (!coop.integer && !deathmatch.integer) + Cvar_SetValue("deathmatch", 1); + if (coop.integer) + M_Print(160, 64, "Cooperative"); + else + M_Print(160, 64, "Deathmatch"); + } + + M_Print(0, 72, " Teamplay"); + if (gamemode == GAME_ROGUE) + { + const char *msg; + + switch((int)teamplay.integer) + { + 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 + { + const char *msg; + + switch (teamplay.integer) + { + case 0: msg = "Off"; break; + case 2: msg = "Friendly Fire"; break; + default: msg = "No Friendly Fire"; break; + } + M_Print(160, 72, msg); + } + M_Print(0, 80, " Skill"); + if (gamemode == GAME_TRANSFUSION) + { + if (skill.integer == 1) + M_Print(160, 80, "Still Kicking"); + else if (skill.integer == 2) + M_Print(160, 80, "Pink On The Inside"); + else if (skill.integer == 3) + M_Print(160, 80, "Lightly Broiled"); + else if (skill.integer == 4) + M_Print(160, 80, "Well Done"); + else + M_Print(160, 80, "Extra Crispy"); + } + else + { + if (skill.integer == 0) + M_Print(160, 80, "Easy difficulty"); + else if (skill.integer == 1) + M_Print(160, 80, "Normal difficulty"); + else if (skill.integer == 2) + M_Print(160, 80, "Hard difficulty"); + else + M_Print(160, 80, "Nightmare difficulty"); + } + M_Print(0, 88, " Frag Limit"); + if (fraglimit.integer == 0) + M_Print(160, 88, "none"); + else + M_Print(160, 88, va(vabuf, sizeof(vabuf), "%i frags", fraglimit.integer)); + + M_Print(0, 96, " Time Limit"); + if (timelimit.integer == 0) + M_Print(160, 96, "none"); + else + M_Print(160, 96, va(vabuf, sizeof(vabuf), "%i minutes", timelimit.integer)); + } + + M_Print(0, 104, " Public server"); + M_Print(160, 104, (sv_public.integer == 0) ? "no" : "yes"); + + M_Print(0, 112, " Server maxrate"); + M_Print(160, 112, va(vabuf, sizeof(vabuf), "%i", sv_maxrate.integer)); + + M_Print(0, 128, " Server name"); + M_DrawTextBox (0, 132, 38, 1); + M_Print(8, 140, hostname.string); + + if (gamemode != GAME_GOODVSBAD2) + { + M_Print(0, 160, " Episode"); + M_Print(160, 160, gameoptions_levels->episodes[startepisode].description); + } + + M_Print(0, 168, " Level"); + M_Print(160, 168, gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].description); + M_Print(160, 176, gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name); + +// line cursor + if (gameoptions_cursor == 9) + M_DrawCharacter (8 + 8 * strlen(hostname.string), gameoptions_cursor_table[gameoptions_cursor], 10+((int)(realtime*4)&1)); + else + M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1)); + + if (m_serverInfoMessage) + { + if ((realtime - m_serverInfoMessageTime) < 5.0) + { + x = (320-26*8)/2; + M_DrawTextBox (x, 138, 24, 4); + x += 8; + M_Print(x, 146, " More than 255 players??"); + M_Print(x, 154, " First, question your "); + M_Print(x, 162, " sanity, then email "); + M_Print(x, 170, " lordhavoc@ghdigital.com"); + } + else + m_serverInfoMessage = false; + } +} + + +static void M_NetStart_Change (int dir) +{ + int count; + + switch (gameoptions_cursor) + { + case 1: + maxplayers += dir; + if (maxplayers > MAX_SCOREBOARD) + { + maxplayers = MAX_SCOREBOARD; + m_serverInfoMessage = true; + m_serverInfoMessageTime = realtime; + } + if (maxplayers < 2) + maxplayers = 2; + break; + + case 2: + if (gamemode == GAME_GOODVSBAD2) + break; + if (gamemode == GAME_TRANSFUSION) + { + switch (deathmatch.integer) + { + // From Cooperative to BloodBath + case 0: + Cvar_SetValueQuick (&coop, 0); + Cvar_SetValueQuick (&deathmatch, 1); + break; + + // From BloodBath to CTF + case 1: + Cvar_SetValueQuick (&coop, 0); + Cvar_SetValueQuick (&deathmatch, 2); + break; + + // From CTF to Cooperative + //case 2: + default: + Cvar_SetValueQuick (&coop, 1); + Cvar_SetValueQuick (&deathmatch, 0); + } + } + else if (gamemode == GAME_BATTLEMECH) + { + if (deathmatch.integer == 2) // changing from Rambo to Deathmatch + Cvar_SetValueQuick (&deathmatch, 0); + else // changing from Deathmatch to Rambo + Cvar_SetValueQuick (&deathmatch, 2); + } + else + { + if (deathmatch.integer) // changing from deathmatch to coop + { + Cvar_SetValueQuick (&coop, 1); + Cvar_SetValueQuick (&deathmatch, 0); + } + else // changing from coop to deathmatch + { + Cvar_SetValueQuick (&coop, 0); + Cvar_SetValueQuick (&deathmatch, 1); + } + } + break; + + case 3: + if (gamemode == GAME_GOODVSBAD2) + break; + if (gamemode == GAME_ROGUE) + count = 6; + else + count = 2; + + Cvar_SetValueQuick (&teamplay, teamplay.integer + dir); + if (teamplay.integer > count) + Cvar_SetValueQuick (&teamplay, 0); + else if (teamplay.integer < 0) + Cvar_SetValueQuick (&teamplay, count); + break; + + case 4: + if (gamemode == GAME_GOODVSBAD2) + break; + Cvar_SetValueQuick (&skill, skill.integer + dir); + if (gamemode == GAME_TRANSFUSION) + { + if (skill.integer > 5) + Cvar_SetValueQuick (&skill, 1); + if (skill.integer < 1) + Cvar_SetValueQuick (&skill, 5); + } + else + { + if (skill.integer > 3) + Cvar_SetValueQuick (&skill, 0); + if (skill.integer < 0) + Cvar_SetValueQuick (&skill, 3); + } + break; + + case 5: + if (gamemode == GAME_GOODVSBAD2) + break; + Cvar_SetValueQuick (&fraglimit, fraglimit.integer + dir*10); + if (fraglimit.integer > 100) + Cvar_SetValueQuick (&fraglimit, 0); + if (fraglimit.integer < 0) + Cvar_SetValueQuick (&fraglimit, 100); + break; + + case 6: + if (gamemode == GAME_GOODVSBAD2) + break; + Cvar_SetValueQuick (&timelimit, timelimit.value + dir*5); + if (timelimit.value > 60) + Cvar_SetValueQuick (&timelimit, 0); + if (timelimit.value < 0) + Cvar_SetValueQuick (&timelimit, 60); + break; + + case 7: + Cvar_SetValueQuick (&sv_public, !sv_public.integer); + break; + + case 8: + Cvar_SetValueQuick (&sv_maxrate, sv_maxrate.integer + dir*500); + if (sv_maxrate.integer < NET_MINRATE) + Cvar_SetValueQuick (&sv_maxrate, NET_MINRATE); + break; + + case 9: + break; + + case 10: + if (gamemode == GAME_GOODVSBAD2) + break; + startepisode += dir; + + if (startepisode < 0) + startepisode = gameoptions_levels->numepisodes - 1; + + if (startepisode >= gameoptions_levels->numepisodes) + startepisode = 0; + + startlevel = 0; + break; + + case 11: + startlevel += dir; + + if (startlevel < 0) + startlevel = gameoptions_levels->episodes[startepisode].levels - 1; + + if (startlevel >= gameoptions_levels->episodes[startepisode].levels) + startlevel = 0; + break; + } +} + +static void M_GameOptions_Key (int key, int ascii) +{ + int l; + char hostnamebuf[128]; + char vabuf[1024]; + + switch (key) + { + case K_ESCAPE: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + gameoptions_cursor--; + if (gameoptions_cursor < 0) + gameoptions_cursor = NUM_GAMEOPTIONS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + gameoptions_cursor++; + if (gameoptions_cursor >= NUM_GAMEOPTIONS) + gameoptions_cursor = 0; + break; + case 'a': + case K_LEFTARROW: + if (gameoptions_cursor == 0) + break; + S_LocalSound ("sound/misc/menu3.wav"); + M_NetStart_Change (-1); + break; + + case K_RIGHTARROW: + case 'd': + if (gameoptions_cursor == 0) + break; + S_LocalSound ("sound/misc/menu3.wav"); + M_NetStart_Change (1); + break; + case K_MOUSE1: + case K_ENTER: + S_LocalSound ("sound/misc/menu2.wav"); + if (gameoptions_cursor == 0) + { + if (sv.active) + Cbuf_AddText("disconnect\n"); + Cbuf_AddText(va(vabuf, sizeof(vabuf), "maxplayers %u\n", maxplayers) ); + + Cbuf_AddText(va(vabuf, sizeof(vabuf), "map %s\n", gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name) ); + return; + } + + M_NetStart_Change (1); + break; + + case K_BACKSPACE: + if (gameoptions_cursor == 9) + { + l = (int)strlen(hostname.string); + if (l) + { + l = min(l - 1, 37); + memcpy(hostnamebuf, hostname.string, l); + hostnamebuf[l] = 0; + Cvar_Set("hostname", hostnamebuf); + } + } + break; + + default: + if (ascii < 32) + break; + if (gameoptions_cursor == 9) + { + l = (int)strlen(hostname.string); + if (l < 37) + { + memcpy(hostnamebuf, hostname.string, l); + hostnamebuf[l] = ascii; + hostnamebuf[l+1] = 0; + Cvar_Set("hostname", hostnamebuf); + } + } + } +} + +//============================================================================= +/* SLIST MENU */ + +static int slist_cursor; + +void M_Menu_ServerList_f (void) +{ + key_dest = key_menu; + m_state = m_slist; + m_entersound = true; + slist_cursor = 0; + M_Update_Return_Reason(""); + if (lanConfig_cursor == 2) + Net_SlistQW_f(); + else + Net_Slist_f(); +} + + +static void M_ServerList_Draw (void) +{ + int n, y, visible, start, end, numplayers, maxplayers; + cachepic_t *p; + const char *s; + char vabuf[1024]; + + // use as much vertical space as available + if (gamemode == GAME_TRANSFUSION) + M_Background(640, vid_conheight.integer - 80); + else + M_Background(640, vid_conheight.integer); + // scroll the list as the cursor moves + ServerList_GetPlayerStatistics(&numplayers, &maxplayers); + s = va(vabuf, sizeof(vabuf), "%i/%i masters %i/%i servers %i/%i players", masterreplycount, masterquerycount, serverreplycount, serverquerycount, numplayers, maxplayers); + M_PrintRed((640 - strlen(s) * 8) / 2, 32, s); + if (*m_return_reason) + M_Print(16, menu_height - 8, m_return_reason); + y = 48; + visible = (int)((menu_height - 16 - y) / 8 / 2); + start = bound(0, slist_cursor - (visible >> 1), serverlist_viewcount - visible); + end = min(start + visible, serverlist_viewcount); + + p = Draw_CachePic ("gfx/p_multi"); + M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi"); + if (end > start) + { + for (n = start;n < end;n++) + { + serverlist_entry_t *entry = ServerList_GetViewEntry(n); + DrawQ_Fill(menu_x, menu_y + y, 640, 16, n == slist_cursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0); + M_PrintColored(0, y, entry->line1);y += 8; + M_PrintColored(0, y, entry->line2);y += 8; + } + } + else if (realtime - masterquerytime > 10) + { + if (masterquerycount) + M_Print(0, y, "No servers found"); + else + M_Print(0, y, "No master servers found (network problem?)"); + } + else + { + if (serverquerycount) + M_Print(0, y, "Querying servers"); + else + M_Print(0, y, "Querying master servers"); + } +} + + +static void M_ServerList_Key(int k, int ascii) +{ + char vabuf[1024]; + switch (k) + { + case K_ESCAPE: + M_Menu_LanConfig_f(); + break; + + case K_SPACE: + if (lanConfig_cursor == 2) + Net_SlistQW_f(); + else + Net_Slist_f(); + break; + + case K_UPARROW: + case K_LEFTARROW: + case 'a': + S_LocalSound ("sound/misc/menu1.wav"); + slist_cursor--; + if (slist_cursor < 0) + slist_cursor = serverlist_viewcount - 1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + case 'd': + S_LocalSound ("sound/misc/menu1.wav"); + slist_cursor++; + if (slist_cursor >= serverlist_viewcount) + slist_cursor = 0; + break; + case K_MOUSE1: + case K_ENTER: + S_LocalSound ("sound/misc/menu2.wav"); + if (serverlist_viewcount) + Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", ServerList_GetViewEntry(slist_cursor)->info.cname)); + break; + + default: + break; + } + +} + +//============================================================================= +/* MODLIST MENU */ +// same limit of mod dirs as in fs.c +#define MODLIST_MAXDIRS 16 +static int modlist_enabled [MODLIST_MAXDIRS]; //array of indexs to modlist +static int modlist_numenabled; //number of enabled (or in process to be..) mods + +typedef struct modlist_entry_s +{ + qboolean loaded; // used to determine whether this entry is loaded and running + int enabled; // index to array of modlist_enabled + + // name of the modification, this is (will...be) displayed on the menu entry + char name[128]; + // directory where we will find it + char dir[MAX_QPATH]; +} modlist_entry_t; + +static int modlist_cursor; +//static int modlist_viewcount; + +static int modlist_count = 0; +static modlist_entry_t modlist[MODLIST_TOTALSIZE]; + +static void ModList_RebuildList(void) +{ + int i,j; + stringlist_t list; + + stringlistinit(&list); + listdirectory(&list, fs_basedir, ""); + stringlistsort(&list, true); + modlist_count = 0; + modlist_numenabled = fs_numgamedirs; + for (i = 0;i < list.numstrings;i++) + { + if (modlist_count >= MODLIST_TOTALSIZE) break; + // check all dirs to see if they "appear" to be mods + // reject any dirs that are part of the base game + if (gamedirname1 && !strcasecmp(gamedirname1, list.strings[i])) continue; + //if (gamedirname2 && !strcasecmp(gamedirname2, list.strings[i])) continue; + if (FS_CheckNastyPath (list.strings[i], true)) continue; + if (!FS_CheckGameDir(list.strings[i])) continue; + + strlcpy (modlist[modlist_count].dir, list.strings[i], sizeof(modlist[modlist_count].dir)); + //check currently loaded mods + modlist[modlist_count].loaded = false; + if (fs_numgamedirs) + for (j = 0; j < fs_numgamedirs; j++) + if (!strcasecmp(fs_gamedirs[j], modlist[modlist_count].dir)) + { + modlist[modlist_count].loaded = true; + modlist[modlist_count].enabled = j; + modlist_enabled[j] = modlist_count; + break; + } + modlist_count ++; + } + stringlistfreecontents(&list); +} + +static void ModList_Enable (void) +{ + int i; + int numgamedirs; + char gamedirs[MODLIST_MAXDIRS][MAX_QPATH]; + + // copy our mod list into an array for FS_ChangeGameDirs + numgamedirs = modlist_numenabled; + for (i = 0; i < modlist_numenabled; i++) + strlcpy (gamedirs[i], modlist[modlist_enabled[i]].dir,sizeof (gamedirs[i])); + + // this code snippet is from FS_ChangeGameDirs + if (fs_numgamedirs == numgamedirs) + { + for (i = 0;i < numgamedirs;i++) + if (strcasecmp(fs_gamedirs[i], gamedirs[i])) + break; + if (i == numgamedirs) + return; // already using this set of gamedirs, do nothing + } + + // this part is basically the same as the FS_GameDir_f function + if ((cls.state == ca_connected && !cls.demoplayback) || sv.active) + { + // actually, changing during game would work fine, but would be stupid + Con_Printf("Can not change gamedir while client is connected or server is running!\n"); + return; + } + + FS_ChangeGameDirs (modlist_numenabled, gamedirs, true, true); +} + +void M_Menu_ModList_f (void) +{ + key_dest = key_menu; + m_state = m_modlist; + m_entersound = true; + modlist_cursor = 0; + M_Update_Return_Reason(""); + ModList_RebuildList(); +} + +static void M_Menu_ModList_AdjustSliders (int dir) +{ + int i; + S_LocalSound ("sound/misc/menu3.wav"); + + // stop adding mods, we reach the limit + if (!modlist[modlist_cursor].loaded && (modlist_numenabled == MODLIST_MAXDIRS)) return; + modlist[modlist_cursor].loaded = !modlist[modlist_cursor].loaded; + if (modlist[modlist_cursor].loaded) + { + modlist[modlist_cursor].enabled = modlist_numenabled; + //push the value on the enabled list + modlist_enabled[modlist_numenabled++] = modlist_cursor; + } + else + { + //eliminate the value from the enabled list + for (i = modlist[modlist_cursor].enabled; i < modlist_numenabled; i++) + { + modlist_enabled[i] = modlist_enabled[i+1]; + modlist[modlist_enabled[i]].enabled--; + } + modlist_numenabled--; + } +} + +static void M_ModList_Draw (void) +{ + int n, y, visible, start, end; + cachepic_t *p; + const char *s_available = "Available Mods"; + const char *s_enabled = "Enabled Mods"; + + // use as much vertical space as available + if (gamemode == GAME_TRANSFUSION) + M_Background(640, vid_conheight.integer - 80); + else + M_Background(640, vid_conheight.integer); + + M_PrintRed(48 + 32, 32, s_available); + M_PrintRed(432, 32, s_enabled); + // Draw a list box with all enabled mods + DrawQ_Pic(menu_x + 432, menu_y + 48, NULL, 172, 8 * modlist_numenabled, 0, 0, 0, 0.5, 0); + for (y = 0; y < modlist_numenabled; y++) + M_PrintRed(432, 48 + y * 8, modlist[modlist_enabled[y]].dir); + + if (*m_return_reason) + M_Print(16, menu_height - 8, m_return_reason); + // scroll the list as the cursor moves + y = 48; + visible = (int)((menu_height - 16 - y) / 8 / 2); + start = bound(0, modlist_cursor - (visible >> 1), modlist_count - visible); + end = min(start + visible, modlist_count); + + p = Draw_CachePic ("gfx/p_option"); + M_DrawPic((640 - p->width) / 2, 4, "gfx/p_option"); + if (end > start) + { + for (n = start;n < end;n++) + { + DrawQ_Pic(menu_x + 40, menu_y + y, NULL, 360, 8, n == modlist_cursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0); + M_ItemPrint(80, y, modlist[n].dir, true); + M_DrawCheckbox(48, y, modlist[n].loaded); + y +=8; + } + } + else + { + M_Print(80, y, "No Mods found"); + } +} + +static void M_ModList_Key(int k, int ascii) +{ + switch (k) + { + case K_ESCAPE: + ModList_Enable (); + M_Menu_Options_f(); + break; + + case K_SPACE: + S_LocalSound ("sound/misc/menu2.wav"); + ModList_RebuildList(); + break; + + case K_UPARROW: + S_LocalSound ("sound/misc/menu1.wav"); + modlist_cursor--; + if (modlist_cursor < 0) + modlist_cursor = modlist_count - 1; + break; + + case K_LEFTARROW: + case 'a': + M_Menu_ModList_AdjustSliders (-1); + break; + + case K_DOWNARROW: + S_LocalSound ("sound/misc/menu1.wav"); + modlist_cursor++; + if (modlist_cursor >= modlist_count) + modlist_cursor = 0; + break; + + case K_RIGHTARROW: + case 'd': + M_Menu_ModList_AdjustSliders (1); + break; + case K_MOUSE1: + case K_ENTER: + S_LocalSound ("sound/misc/menu2.wav"); + ModList_Enable (); + break; + + default: + break; + } + +} + +//============================================================================= +/* Menu Subsystem */ + +static void M_KeyEvent(int key, int ascii, qboolean downevent); +static void M_Draw(void); +void M_ToggleMenu(int mode); +static void M_Shutdown(void); + +static void M_Init (void) +{ + menuplyr_load = true; + menuplyr_pixels = NULL; + + Cmd_AddCommand ("menu_main", M_Menu_Main_f, "open the main menu"); + Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f, "open the singleplayer menu"); + Cmd_AddCommand ("menu_load", M_Menu_Load_f, "open the loadgame menu"); + Cmd_AddCommand ("menu_save", M_Menu_Save_f, "open the savegame menu"); + Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f, "open the multiplayer menu"); + Cmd_AddCommand ("menu_setup", M_Menu_Setup_f, "open the player setup menu"); + Cmd_AddCommand ("menu_options", M_Menu_Options_f, "open the options menu"); + Cmd_AddCommand ("menu_options_effects", M_Menu_Options_Effects_f, "open the effects options menu"); + Cmd_AddCommand ("menu_options_graphics", M_Menu_Options_Graphics_f, "open the graphics options menu"); + Cmd_AddCommand ("menu_options_colorcontrol", M_Menu_Options_ColorControl_f, "open the color control menu"); + Cmd_AddCommand ("menu_keys", M_Menu_Keys_f, "open the key binding menu"); + Cmd_AddCommand ("menu_video", M_Menu_Video_f, "open the video options menu"); + Cmd_AddCommand ("menu_reset", M_Menu_Reset_f, "open the reset to defaults menu"); + Cmd_AddCommand ("menu_reset", M_Menu_YawPitchControl_f, "open the yaw/pitch control menu"); + Cmd_AddCommand ("menu_mods", M_Menu_ModList_f, "open the mods browser menu"); + Cmd_AddCommand ("help", M_Menu_Help_f, "open the help menu"); + Cmd_AddCommand ("menu_quit", M_Menu_Quit_f, "open the quit menu"); + Cmd_AddCommand ("menu_transfusion_episode", M_Menu_Transfusion_Episode_f, "open the transfusion episode select menu"); + Cmd_AddCommand ("menu_transfusion_skill", M_Menu_Transfusion_Skill_f, "open the transfusion skill select menu"); + Cmd_AddCommand ("menu_credits", M_Menu_Credits_f, "open the credits menu"); +} + +void M_Draw (void) +{ + char vabuf[1024]; + if (key_dest != key_menu && key_dest != key_menu_grabbed) { + m_state = m_none; + jni_BigScreenMode(0); + } + + if (m_state == m_none) + return; + + switch (m_state) + { + case m_none: + break; + + case m_main: + M_Main_Draw (); + break; + + case m_demo: + M_Demo_Draw (); + break; + + case m_singleplayer: + M_SinglePlayer_Draw (); + break; + + case m_transfusion_episode: + M_Transfusion_Episode_Draw (); + break; + + case m_transfusion_skill: + M_Transfusion_Skill_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_options: + M_Options_Draw (); + break; + + case m_options_effects: + M_Options_Effects_Draw (); + break; + + case m_options_graphics: + M_Options_Graphics_Draw (); + break; + + case m_options_colorcontrol: + M_Options_ColorControl_Draw (); + break; + + case m_keys: + M_Keys_Draw (); + break; + + case m_reset: + M_Reset_Draw (); + break; + + case m_video: + M_Video_Draw (); + break; + + case m_yawpitchcontrol: + M_Menu_YawPitchControl_Draw (); + break; + + case m_help: + M_Help_Draw (); + break; + + case m_credits: + M_Credits_Draw (); + break; + + case m_quit: + M_Quit_Draw (); + break; + + case m_lanconfig: + M_LanConfig_Draw (); + break; + + case m_gameoptions: + M_GameOptions_Draw (); + break; + + case m_slist: + M_ServerList_Draw (); + break; + + case m_modlist: + M_ModList_Draw (); + break; + } + + if (gamemode == GAME_TRANSFUSION && !m_missingdata) { + if (m_state != m_credits) { + cachepic_t *p, *drop1, *drop2, *drop3; + int g, scale_x, scale_y, scale_y_repeat, top_offset; + float scale_y_rate; + scale_y_repeat = vid_conheight.integer * 2; + g = (int)(realtime * 64)%96; + scale_y_rate = (float)(g+1) / 96; + top_offset = (g+12)/12; + p = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/menu/blooddrip%i", top_offset)); + drop1 = Draw_CachePic ("gfx/menu/blooddrop1"); + drop2 = Draw_CachePic ("gfx/menu/blooddrop2"); + drop3 = Draw_CachePic ("gfx/menu/blooddrop3"); + for (scale_x = 0; scale_x <= vid_conwidth.integer; scale_x += p->width) { + for (scale_y = -scale_y_repeat; scale_y <= vid_conheight.integer; scale_y += scale_y_repeat) { + DrawQ_Pic (scale_x + 21, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 116, scale_y_repeat + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 180, scale_y_repeat * .275 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 242, scale_y_repeat * .75 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 304, scale_y_repeat * .25 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 362, scale_y_repeat * .46125 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 402, scale_y_repeat * .1725 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 438, scale_y_repeat * .9 + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 484, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 557, scale_y_repeat * .9425 + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0); + DrawQ_Pic (scale_x + 606, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop2, 0, 0, 1, 1, 1, 1, 0); + } + DrawQ_Pic (scale_x, -1, Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/menu/blooddrip%i", top_offset)), 0, 0, 1, 1, 1, 1, 0); + } + } + } + + if (m_entersound) + { + S_LocalSound ("sound/misc/menu2.wav"); + m_entersound = false; + } + + S_ExtraUpdate (); +} + + +void M_KeyEvent (int key, int ascii, qboolean downevent) +{ + if (!downevent) + return; + switch (m_state) + { + case m_none: + return; + + case m_main: + M_Main_Key (key, ascii); + return; + + case m_demo: + M_Demo_Key (key, ascii); + return; + + case m_singleplayer: + M_SinglePlayer_Key (key, ascii); + return; + + case m_transfusion_episode: + M_Transfusion_Episode_Key (key, ascii); + return; + + case m_transfusion_skill: + M_Transfusion_Skill_Key (key, ascii); + return; + + case m_load: + M_Load_Key (key, ascii); + return; + + case m_save: + M_Save_Key (key, ascii); + return; + + case m_multiplayer: + M_MultiPlayer_Key (key, ascii); + return; + + case m_setup: + M_Setup_Key (key, ascii); + return; + + case m_options: + M_Options_Key (key, ascii); + return; + + case m_options_effects: + M_Options_Effects_Key (key, ascii); + return; + + case m_options_graphics: + M_Options_Graphics_Key (key, ascii); + return; + + case m_options_colorcontrol: + M_Options_ColorControl_Key (key, ascii); + return; + + case m_keys: + M_Keys_Key (key, ascii); + return; + + case m_reset: + M_Reset_Key (key, ascii); + return; + + case m_video: + M_Video_Key (key, ascii); + return; + + case m_yawpitchcontrol: + M_Menu_YawPitchControl_Key (key, ascii); + return; + + case m_help: + M_Help_Key (key, ascii); + return; + + case m_credits: + M_Credits_Key (key, ascii); + return; + + case m_quit: + M_Quit_Key (key, ascii); + return; + + case m_lanconfig: + M_LanConfig_Key (key, ascii); + return; + + case m_gameoptions: + M_GameOptions_Key (key, ascii); + return; + + case m_slist: + M_ServerList_Key (key, ascii); + return; + + case m_modlist: + M_ModList_Key (key, ascii); + return; + } + +} + +static void M_NewMap(void) +{ +} + +void M_Shutdown(void) +{ + // reset key_dest + key_dest = key_game; +} + +//============================================================================ +// Menu prog handling + +static const char *m_required_func[] = { +"m_init", +"m_keydown", +"m_draw", +"m_toggle", +"m_shutdown", +}; + +static int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*); + +static prvm_required_field_t m_required_fields[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) {ev_float, #x}, +#define PRVM_DECLARE_menufieldvector(x) {ev_vector, #x}, +#define PRVM_DECLARE_menufieldstring(x) {ev_string, #x}, +#define PRVM_DECLARE_menufieldedict(x) {ev_entity, #x}, +#define PRVM_DECLARE_menufieldfunction(x) {ev_function, #x}, +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + +static int m_numrequiredfields = sizeof(m_required_fields) / sizeof(m_required_fields[0]); + +static prvm_required_field_t m_required_globals[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) {ev_float, #x}, +#define PRVM_DECLARE_menuglobalvector(x) {ev_vector, #x}, +#define PRVM_DECLARE_menuglobalstring(x) {ev_string, #x}, +#define PRVM_DECLARE_menuglobaledict(x) {ev_entity, #x}, +#define PRVM_DECLARE_menuglobalfunction(x) {ev_function, #x}, +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + +static int m_numrequiredglobals = sizeof(m_required_globals) / sizeof(m_required_globals[0]); + +void MR_SetRouting (qboolean forceold); + +void MVM_error_cmd(const char *format, ...) DP_FUNC_PRINTF(1); +void MVM_error_cmd(const char *format, ...) +{ + prvm_prog_t *prog = MVM_prog; + static qboolean processingError = false; + char errorstring[MAX_INPUTLINE]; + va_list argptr; + + va_start (argptr, format); + dpvsnprintf (errorstring, sizeof(errorstring), format, argptr); + va_end (argptr); + Con_Printf( "Menu_Error: %s\n", errorstring ); + + if( !processingError ) { + processingError = true; + PRVM_Crash(prog); + processingError = false; + } else { + Con_Printf( "Menu_Error: Recursive call to MVM_error_cmd (from PRVM_Crash)!\n" ); + } + + // fall back to the normal menu + + // say it + Con_Print("Falling back to normal menu\n"); + + key_dest = key_game; + + // init the normal menu now -> this will also correct the menu router pointers + MR_SetRouting (TRUE); + + // reset the active scene, too (to be on the safe side ;)) + R_SelectScene( RST_CLIENT ); + + Host_AbortCurrentFrame(); +} + +static void MVM_begin_increase_edicts(prvm_prog_t *prog) +{ +} + +static void MVM_end_increase_edicts(prvm_prog_t *prog) +{ +} + +static void MVM_init_edict(prvm_prog_t *prog, prvm_edict_t *edict) +{ +} + +static void MVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed) +{ +} + +static void MVM_count_edicts(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + int active; + + active = 0; + for (i=0 ; inum_edicts ; i++) + { + ent = PRVM_EDICT_NUM(i); + if (ent->priv.required->free) + continue; + active++; + } + + Con_Printf("num_edicts:%3i\n", prog->num_edicts); + Con_Printf("active :%3i\n", active); +} + +static qboolean MVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent) +{ + return true; +} + +static void MP_KeyEvent (int key, int ascii, qboolean downevent) +{ + prvm_prog_t *prog = MVM_prog; + + // pass key + prog->globals.fp[OFS_PARM0] = (prvm_vec_t) key; + prog->globals.fp[OFS_PARM1] = (prvm_vec_t) ascii; + if (downevent) + prog->ExecuteProgram(prog, PRVM_menufunction(m_keydown),"m_keydown(float key, float ascii) required"); + else if (PRVM_menufunction(m_keyup)) + prog->ExecuteProgram(prog, PRVM_menufunction(m_keyup),"m_keyup(float key, float ascii) required"); +} + +static void MP_Draw (void) +{ + prvm_prog_t *prog = MVM_prog; + // declarations that are needed right now + + float oldquality; + + R_SelectScene( RST_MENU ); + + // reset the temp entities each frame + r_refdef.scene.numtempentities = 0; + + // menu scenes do not use reduced rendering quality + oldquality = r_refdef.view.quality; + r_refdef.view.quality = 1; + // TODO: this needs to be exposed to R_SetView (or something similar) ASAP [2/5/2008 Andreas] + r_refdef.scene.time = realtime; + + // FIXME: this really shouldnt error out lest we have a very broken refdef state...? + // or does it kill the server too? + prog->ExecuteProgram(prog, PRVM_menufunction(m_draw),"m_draw() required"); + + // TODO: imo this should be moved into scene, too [1/27/2008 Andreas] + r_refdef.view.quality = oldquality; + + R_SelectScene( RST_CLIENT ); +} + +static void MP_ToggleMenu(int mode) +{ + prvm_prog_t *prog = MVM_prog; + + prog->globals.fp[OFS_PARM0] = (prvm_vec_t) mode; + prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle(float mode) required"); +} + +static void MP_NewMap(void) +{ + prvm_prog_t *prog = MVM_prog; + if (PRVM_menufunction(m_newmap)) + prog->ExecuteProgram(prog, PRVM_menufunction(m_newmap),"m_newmap() required"); +} + +static void MP_Shutdown (void) +{ + prvm_prog_t *prog = MVM_prog; + + prog->ExecuteProgram(prog, PRVM_menufunction(m_shutdown),"m_shutdown() required"); + + // reset key_dest + key_dest = key_game; + + // AK not using this cause Im not sure whether this is useful at all instead : + PRVM_Prog_Reset(prog); +} + +static void MP_Init (void) +{ + prvm_prog_t *prog = MVM_prog; + PRVM_Prog_Init(prog); + + prog->edictprivate_size = 0; // no private struct used + prog->name = "menu"; + prog->num_edicts = 1; + prog->limit_edicts = M_MAX_EDICTS; + prog->extensionstring = vm_m_extensions; + prog->builtins = vm_m_builtins; + prog->numbuiltins = vm_m_numbuiltins; + + // all callbacks must be defined (pointers are not checked before calling) + prog->begin_increase_edicts = MVM_begin_increase_edicts; + prog->end_increase_edicts = MVM_end_increase_edicts; + prog->init_edict = MVM_init_edict; + prog->free_edict = MVM_free_edict; + prog->count_edicts = MVM_count_edicts; + prog->load_edict = MVM_load_edict; + prog->init_cmd = MVM_init_cmd; + prog->reset_cmd = MVM_reset_cmd; + prog->error_cmd = MVM_error_cmd; + prog->ExecuteProgram = MVM_ExecuteProgram; + + // allocate the mempools + prog->progs_mempool = Mem_AllocPool(menu_progs.string, 0, NULL); + + PRVM_Prog_Load(prog, menu_progs.string, NULL, 0, m_numrequiredfunc, m_required_func, m_numrequiredfields, m_required_fields, m_numrequiredglobals, m_required_globals); + + // note: OP_STATE is not supported by menu qc, we don't even try to detect + // it here + + in_client_mouse = true; + + // call the prog init + prog->ExecuteProgram(prog, PRVM_menufunction(m_init),"m_init() required"); +} + +//============================================================================ +// Menu router + +void (*MR_KeyEvent) (int key, int ascii, qboolean downevent); +void (*MR_Draw) (void); +void (*MR_ToggleMenu) (int mode); +void (*MR_Shutdown) (void); +void (*MR_NewMap) (void); + +void MR_SetRouting(qboolean forceold) +{ + // if the menu prog isnt available or forceqmenu ist set, use the old menu + if(!FS_FileExists(menu_progs.string) || forceqmenu.integer || forceold) + { + // set menu router function pointers + MR_KeyEvent = M_KeyEvent; + MR_Draw = M_Draw; + MR_ToggleMenu = M_ToggleMenu; + MR_Shutdown = M_Shutdown; + MR_NewMap = M_NewMap; + M_Init(); + } + else + { + // set menu router function pointers + MR_KeyEvent = MP_KeyEvent; + MR_Draw = MP_Draw; + MR_ToggleMenu = MP_ToggleMenu; + MR_Shutdown = MP_Shutdown; + MR_NewMap = MP_NewMap; + MP_Init(); + } +} + +void MR_Restart(void) +{ + if(MR_Shutdown) + MR_Shutdown (); + MR_SetRouting (FALSE); +} + +static void Call_MR_ToggleMenu_f(void) +{ + int m; + m = ((Cmd_Argc() < 2) ? -1 : atoi(Cmd_Argv(1))); + Host_StartVideo(); + if(MR_ToggleMenu) + MR_ToggleMenu(m); +} + +void MR_Init_Commands(void) +{ + // set router console commands + Cvar_RegisterVariable (&forceqmenu); + Cvar_RegisterVariable (&menu_options_colorcontrol_correctionvalue); + Cvar_RegisterVariable (&menu_progs); + Cmd_AddCommand ("menu_restart",MR_Restart, "restart menu system (reloads menu.dat)"); + Cmd_AddCommand ("togglemenu", Call_MR_ToggleMenu_f, "opens or closes menu"); +} + +void MR_Init(void) +{ + vid_mode_t res[1024]; + size_t res_count, i; + + res_count = VID_ListModes(res, sizeof(res) / sizeof(*res)); + res_count = VID_SortModes(res, res_count, false, false, true); + if(res_count) + { + video_resolutions_count = res_count; + video_resolutions = (video_resolution_t *) Mem_Alloc(cls.permanentmempool, sizeof(*video_resolutions) * (video_resolutions_count + 1)); + memset(&video_resolutions[video_resolutions_count], 0, sizeof(video_resolutions[video_resolutions_count])); + for(i = 0; i < res_count; ++i) + { + int n, d, t; + video_resolutions[i].type = "Detected mode"; // FIXME make this more dynamic + video_resolutions[i].width = res[i].width; + video_resolutions[i].height = res[i].height; + video_resolutions[i].pixelheight = res[i].pixelheight_num / (double) res[i].pixelheight_denom; + n = res[i].pixelheight_denom * video_resolutions[i].width; + d = res[i].pixelheight_num * video_resolutions[i].height; + while(d) + { + t = n; + n = d; + d = t % d; + } + d = (res[i].pixelheight_num * video_resolutions[i].height) / n; + n = (res[i].pixelheight_denom * video_resolutions[i].width) / n; + switch(n * 0x10000 | d) + { + case 0x00040003: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "Standard 4x3"; + break; + case 0x00050004: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 512; + if(res[i].pixelheight_denom == res[i].pixelheight_num) + video_resolutions[i].type = "Square Pixel (LCD) 5x4"; + else + video_resolutions[i].type = "Short Pixel (CRT) 5x4"; + break; + case 0x00080005: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 400; + if(res[i].pixelheight_denom == res[i].pixelheight_num) + video_resolutions[i].type = "Widescreen 8x5"; + else + video_resolutions[i].type = "Tall Pixel (CRT) 8x5"; + + break; + case 0x00050003: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 384; + video_resolutions[i].type = "Widescreen 5x3"; + break; + case 0x000D0009: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 400; + video_resolutions[i].type = "Widescreen 14x9"; + break; + case 0x00100009: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "Widescreen 16x9"; + break; + case 0x00030002: + video_resolutions[i].conwidth = 720; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "NTSC 3x2"; + break; + case 0x000D000B: + video_resolutions[i].conwidth = 720; + video_resolutions[i].conheight = 566; + video_resolutions[i].type = "PAL 14x11"; + break; + case 0x00080007: + if(video_resolutions[i].width >= 512) + { + video_resolutions[i].conwidth = 512; + video_resolutions[i].conheight = 448; + video_resolutions[i].type = "SNES 8x7"; + } + else + { + video_resolutions[i].conwidth = 256; + video_resolutions[i].conheight = 224; + video_resolutions[i].type = "NES 8x7"; + } + break; + default: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 640 * d / n; + video_resolutions[i].type = "Detected mode"; + break; + } + if(video_resolutions[i].conwidth > video_resolutions[i].width || video_resolutions[i].conheight > video_resolutions[i].height) + { + int f1, f2; + f1 = video_resolutions[i].conwidth > video_resolutions[i].width; + f2 = video_resolutions[i].conheight > video_resolutions[i].height; + if(f1 > f2) + { + video_resolutions[i].conwidth = video_resolutions[i].width; + video_resolutions[i].conheight = video_resolutions[i].conheight / f1; + } + else + { + video_resolutions[i].conwidth = video_resolutions[i].conwidth / f2; + video_resolutions[i].conheight = video_resolutions[i].height; + } + } + } + } + else + { + video_resolutions = video_resolutions_hardcoded; + video_resolutions_count = sizeof(video_resolutions_hardcoded) / sizeof(*video_resolutions_hardcoded) - 1; + } + + menu_video_resolutions_forfullscreen = !!vid_fullscreen.integer; + M_Menu_Video_FindResolution(vid.width, vid.height, vid_pixelheight.value); + + // use -forceqmenu to use always the normal quake menu (it sets forceqmenu to 1) +// COMMANDLINEOPTION: Client: -forceqmenu disables menu.dat (same as +forceqmenu 1) + if(COM_CheckParm("-forceqmenu")) + Cvar_SetValueQuick(&forceqmenu,1); + // use -useqmenu for debugging proposes, cause it starts + // the normal quake menu only the first time +// COMMANDLINEOPTION: Client: -useqmenu causes the first time you open the menu to use the quake menu, then reverts to menu.dat (if forceqmenu is 0) + if(COM_CheckParm("-useqmenu")) + MR_SetRouting (TRUE); + else + MR_SetRouting (FALSE); +} diff --git a/app/jni/menu.h b/app/jni/menu.h new file mode 100644 index 0000000..baab931 --- /dev/null +++ b/app/jni/menu.h @@ -0,0 +1,99 @@ +/* +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 MENU_H +#define MENU_H + +enum m_state_e { + m_none, + m_main, + m_demo, + m_singleplayer, + m_transfusion_episode, + m_transfusion_skill, + m_load, + m_save, + m_multiplayer, + m_setup, + m_options, + m_video, + m_yawpitchcontrol, + m_keys, + m_help, + m_credits, + m_quit, + m_lanconfig, + m_gameoptions, + m_slist, + m_options_effects, + m_options_graphics, + m_options_colorcontrol, + m_reset, + m_modlist +}; + +extern enum m_state_e m_state; +extern char m_return_reason[128]; +void M_Update_Return_Reason(const char *s); + +/* +// hard-coded menus +// +void M_Init (void); +void M_KeyEvent (int key); +void M_Draw (void); +void M_ToggleMenu (int mode); + +// +// menu prog menu +// +void MP_Init (void); +void MP_KeyEvent (int key); +void MP_Draw (void); +void MP_ToggleMenu (int mode); +void MP_Shutdown (void);*/ + +// +// menu router +// + +void MR_Init_Commands (void); +void MR_Init (void); +void MR_Restart (void); +extern void (*MR_KeyEvent) (int key, int ascii, qboolean downevent); +extern void (*MR_Draw) (void); +extern void (*MR_ToggleMenu) (int mode); +extern void (*MR_Shutdown) (void); +extern void (*MR_NewMap) (void); + +typedef struct video_resolution_s +{ + const char *type; + int width, height; + int conwidth, conheight; + double pixelheight; ///< pixel aspect +} +video_resolution_t; +extern video_resolution_t *video_resolutions; +extern int video_resolutions_count; +extern video_resolution_t video_resolutions_hardcoded[]; +extern int video_resolutions_hardcoded_count; +#endif + diff --git a/app/jni/meshqueue.c b/app/jni/meshqueue.c new file mode 100644 index 0000000..2bcf720 --- /dev/null +++ b/app/jni/meshqueue.c @@ -0,0 +1,151 @@ + +#include "quakedef.h" +#include "meshqueue.h" + +typedef struct meshqueue_s +{ + struct meshqueue_s *next; + void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices); + const entity_render_t *ent; + int surfacenumber; + const rtlight_t *rtlight; + float dist; + dptransparentsortcategory_t category; +} +meshqueue_t; + +int trans_sortarraysize; +meshqueue_t **trans_hash = NULL; +meshqueue_t ***trans_hashpointer = NULL; + +float mqt_viewplanedist; +float mqt_viewmaxdist; +meshqueue_t *mqt_array; +int mqt_count; +int mqt_total; + +void R_MeshQueue_BeginScene(void) +{ + mqt_count = 0; + mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward); + mqt_viewmaxdist = 0; +} + +void R_MeshQueue_AddTransparent(dptransparentsortcategory_t category, const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) +{ + meshqueue_t *mq; + if (mqt_count >= mqt_total || !mqt_array) + { + int newtotal = max(1024, mqt_total * 2); + meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t)); + if (mqt_array) + { + memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t)); + Mem_Free(mqt_array); + } + mqt_array = newarray; + mqt_total = newtotal; + } + mq = &mqt_array[mqt_count++]; + mq->callback = callback; + mq->ent = ent; + mq->surfacenumber = surfacenumber; + mq->rtlight = rtlight; + mq->category = category; + if (r_transparent_useplanardistance.integer) + mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist; + else + mq->dist = VectorDistance(center, r_refdef.view.origin); + mq->next = NULL; + mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist); +} + +void R_MeshQueue_RenderTransparent(void) +{ + int i, hashindex, maxhashindex, batchnumsurfaces; + float distscale; + const entity_render_t *ent; + const rtlight_t *rtlight; + void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices); + int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE]; + meshqueue_t *mqt; + + if (!mqt_count) + return; + + // check for bad cvars + if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768)); + if (r_transparent_sortmindist.integer < 1 || r_transparent_sortmindist.integer >= r_transparent_sortmaxdist.integer) + Cvar_SetValueQuick(&r_transparent_sortmindist, 1); + if (r_transparent_sortmaxdist.integer < r_transparent_sortmindist.integer || r_transparent_sortmaxdist.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer, 32768)); + + // update hash array + if (trans_sortarraysize != r_transparent_sortarraysize.integer) + { + trans_sortarraysize = r_transparent_sortarraysize.integer; + if (trans_hash) + Mem_Free(trans_hash); + trans_hash = (meshqueue_t **)Mem_Alloc(cls.permanentmempool, sizeof(trans_hash) * trans_sortarraysize); + if (trans_hashpointer) + Mem_Free(trans_hashpointer); + trans_hashpointer = (meshqueue_t ***)Mem_Alloc(cls.permanentmempool, sizeof(trans_hashpointer) * trans_sortarraysize); + } + + // build index + memset(trans_hash, 0, sizeof(trans_hash) * trans_sortarraysize); + for (i = 0; i < trans_sortarraysize; i++) + trans_hashpointer[i] = &trans_hash[i]; + distscale = (trans_sortarraysize - 1) / min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer); + maxhashindex = trans_sortarraysize - 1; + for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++) + { + switch(mqt->category) + { + default: + case TRANSPARENTSORT_HUD: + hashindex = 0; + break; + case TRANSPARENTSORT_DISTANCE: + // this could use a reduced range if we need more categories + hashindex = bound(0, (int)(bound(0, mqt->dist - r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer) * distscale), maxhashindex); + break; + case TRANSPARENTSORT_SKY: + hashindex = maxhashindex; + break; + } + // link to tail of hash chain (to preserve render order) + mqt->next = NULL; + *trans_hashpointer[hashindex] = mqt; + trans_hashpointer[hashindex] = &mqt->next; + } + callback = NULL; + ent = NULL; + rtlight = NULL; + batchnumsurfaces = 0; + + // draw + for (i = maxhashindex; i >= 0; i--) + { + if (trans_hash[i]) + { + for (mqt = trans_hash[i]; mqt; mqt = mqt->next) + { + if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE) + { + if (batchnumsurfaces) + callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex); + batchnumsurfaces = 0; + ent = mqt->ent; + rtlight = mqt->rtlight; + callback = mqt->callback; + } + batchsurfaceindex[batchnumsurfaces++] = mqt->surfacenumber; + } + } + } + if (batchnumsurfaces) + callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex); + mqt_count = 0; +} diff --git a/app/jni/meshqueue.h b/app/jni/meshqueue.h new file mode 100644 index 0000000..68fa4d0 --- /dev/null +++ b/app/jni/meshqueue.h @@ -0,0 +1,12 @@ + +#ifndef MESHQUEUE_H +#define MESHQUEUE_H + +// VorteX: seems this value is hardcoded in other several defines as it's changing makes mess +#define MESHQUEUE_TRANSPARENT_BATCHSIZE 256 + +void R_MeshQueue_BeginScene(void); +void R_MeshQueue_AddTransparent(dptransparentsortcategory_t category, const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight); +void R_MeshQueue_RenderTransparent(void); + +#endif diff --git a/app/jni/mod_skeletal_animatevertices_generic.c b/app/jni/mod_skeletal_animatevertices_generic.c new file mode 100644 index 0000000..4356345 --- /dev/null +++ b/app/jni/mod_skeletal_animatevertices_generic.c @@ -0,0 +1,136 @@ +#include "mod_skeletal_animatevertices_generic.h" + +void Mod_Skeletal_AnimateVertices_Generic(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ + // vertex weighted skeletal + int i, k; + float *bonepose; + float *boneposerelative; + const blendweights_t * RESTRICT weights; + + //unsigned long long ts = rdtsc(); + bonepose = (float *) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * (model->num_bones*2 + model->surfmesh.num_blends)); + boneposerelative = bonepose + model->num_bones * 12; + + Mod_Skeletal_BuildTransforms(model, frameblend, skeleton, bonepose, boneposerelative); + + // generate matrices for all blend combinations + weights = model->surfmesh.data_blendweights; + for (i = 0;i < model->surfmesh.num_blends;i++, weights++) + { + float * RESTRICT b = boneposerelative + 12 * (model->num_bones + i); + const float * RESTRICT m = boneposerelative + 12 * (unsigned int)weights->index[0]; + float f = weights->influence[0] * (1.0f / 255.0f); + b[ 0] = f*m[ 0]; b[ 1] = f*m[ 1]; b[ 2] = f*m[ 2]; b[ 3] = f*m[ 3]; + b[ 4] = f*m[ 4]; b[ 5] = f*m[ 5]; b[ 6] = f*m[ 6]; b[ 7] = f*m[ 7]; + b[ 8] = f*m[ 8]; b[ 9] = f*m[ 9]; b[10] = f*m[10]; b[11] = f*m[11]; + for (k = 1;k < 4 && weights->influence[k];k++) + { + m = boneposerelative + 12 * (unsigned int)weights->index[k]; + f = weights->influence[k] * (1.0f / 255.0f); + b[ 0] += f*m[ 0]; b[ 1] += f*m[ 1]; b[ 2] += f*m[ 2]; b[ 3] += f*m[ 3]; + b[ 4] += f*m[ 4]; b[ 5] += f*m[ 5]; b[ 6] += f*m[ 6]; b[ 7] += f*m[ 7]; + b[ 8] += f*m[ 8]; b[ 9] += f*m[ 9]; b[10] += f*m[10]; b[11] += f*m[11]; + } + } + +#define LOAD_MATRIX_SCALAR() const float * RESTRICT m = boneposerelative + 12 * (unsigned int)*b + +#define LOAD_MATRIX3() \ + LOAD_MATRIX_SCALAR() +#define LOAD_MATRIX4() \ + LOAD_MATRIX_SCALAR() + +#define TRANSFORM_POSITION_SCALAR(in, out) \ + (out)[0] = ((in)[0] * m[0] + (in)[1] * m[1] + (in)[2] * m[ 2] + m[3]); \ + (out)[1] = ((in)[0] * m[4] + (in)[1] * m[5] + (in)[2] * m[ 6] + m[7]); \ + (out)[2] = ((in)[0] * m[8] + (in)[1] * m[9] + (in)[2] * m[10] + m[11]); +#define TRANSFORM_VECTOR_SCALAR(in, out) \ + (out)[0] = ((in)[0] * m[0] + (in)[1] * m[1] + (in)[2] * m[ 2]); \ + (out)[1] = ((in)[0] * m[4] + (in)[1] * m[5] + (in)[2] * m[ 6]); \ + (out)[2] = ((in)[0] * m[8] + (in)[1] * m[9] + (in)[2] * m[10]); + +#define TRANSFORM_POSITION(in, out) \ + TRANSFORM_POSITION_SCALAR(in, out) +#define TRANSFORM_VECTOR(in, out) \ + TRANSFORM_VECTOR_SCALAR(in, out) + + // transform vertex attributes by blended matrices + if (vertex3f) + { + const float * RESTRICT v = model->surfmesh.data_vertex3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + // special case common combinations of attributes to avoid repeated loading of matrices + if (normal3f) + { + const float * RESTRICT n = model->surfmesh.data_normal3f; + if (svector3f && tvector3f) + { + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + + // Note that for SSE each iteration stores one element past end, so we break one vertex short + // and handle that with scalars in that case + for (i = 0; i < model->surfmesh.num_vertices; i++, v += 3, n += 3, sv += 3, tv += 3, b++, + vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + TRANSFORM_VECTOR(n, normal3f); + TRANSFORM_VECTOR(sv, svector3f); + TRANSFORM_VECTOR(tv, tvector3f); + } + + return; + } + + for (i = 0;i < model->surfmesh.num_vertices; i++, v += 3, n += 3, b++, vertex3f += 3, normal3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + TRANSFORM_VECTOR(n, normal3f); + } + } + else + { + for (i = 0;i < model->surfmesh.num_vertices; i++, v += 3, b++, vertex3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + } + } + } + + else if (normal3f) + { + const float * RESTRICT n = model->surfmesh.data_normal3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < model->surfmesh.num_vertices; i++, n += 3, b++, normal3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(n, normal3f); + } + } + + if (svector3f) + { + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < model->surfmesh.num_vertices; i++, sv += 3, b++, svector3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(sv, svector3f); + } + } + + if (tvector3f) + { + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < model->surfmesh.num_vertices; i++, tv += 3, b++, tvector3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(tv, tvector3f); + } + } +} diff --git a/app/jni/mod_skeletal_animatevertices_generic.h b/app/jni/mod_skeletal_animatevertices_generic.h new file mode 100644 index 0000000..2ad97eb --- /dev/null +++ b/app/jni/mod_skeletal_animatevertices_generic.h @@ -0,0 +1,8 @@ +#ifndef MOD_SKELETAL_ANIMATEVERTICES_GENERIC_H +#define MOD_H + +#include "quakedef.h" + +void Mod_Skeletal_AnimateVertices_Generic(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f); + +#endif diff --git a/app/jni/mod_skeletal_animatevertices_sse.c b/app/jni/mod_skeletal_animatevertices_sse.c new file mode 100644 index 0000000..648ab31 --- /dev/null +++ b/app/jni/mod_skeletal_animatevertices_sse.c @@ -0,0 +1,446 @@ +#include "mod_skeletal_animatevertices_sse.h" + +#ifdef SSE_POSSIBLE + +#ifdef MATRIX4x4_OPENGLORIENTATION +#error "SSE skeletal requires D3D matrix layout" +#endif + +#include + +void Mod_Skeletal_AnimateVertices_SSE(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ + // vertex weighted skeletal + int i, k; + int blends; + matrix4x4_t *bonepose; + matrix4x4_t *boneposerelative; + float m[12]; + const blendweights_t * RESTRICT weights; + int num_vertices_minus_one; + + num_vertices_minus_one = model->surfmesh.num_vertices - 1; + + //unsigned long long ts = rdtsc(); + bonepose = (matrix4x4_t *) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(matrix4x4_t) * (model->num_bones*2 + model->surfmesh.num_blends)); + boneposerelative = bonepose + model->num_bones; + + if (skeleton && !skeleton->relativetransforms) + skeleton = NULL; + + // interpolate matrices + if (skeleton) + { + for (i = 0;i < model->num_bones;i++) + { + const float * RESTRICT n = model->data_baseboneposeinverse + i * 12; + matrix4x4_t * RESTRICT s = &skeleton->relativetransforms[i]; + matrix4x4_t * RESTRICT b = &bonepose[i]; + matrix4x4_t * RESTRICT r = &boneposerelative[i]; + __m128 b0, b1, b2, b3, r0, r1, r2, r3, nr; + if (model->data_bones[i].parent >= 0) + { + const matrix4x4_t * RESTRICT p = &bonepose[model->data_bones[i].parent]; + __m128 s0 = _mm_loadu_ps(s->m[0]), s1 = _mm_loadu_ps(s->m[1]), s2 = _mm_loadu_ps(s->m[2]); +#ifdef OPENGLORIENTATION + __m128 s3 = _mm_loadu_ps(s->m[3]); +#define SKELETON_MATRIX(r, c) _mm_shuffle_ps(s##c, s##c, _MM_SHUFFLE(r, r, r, r)) +#else +#define SKELETON_MATRIX(r, c) _mm_shuffle_ps(s##r, s##r, _MM_SHUFFLE(c, c, c, c)) +#endif + __m128 pr = _mm_load_ps(p->m[0]); + b0 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 0)); + b1 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 1)); + b2 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 2)); + b3 = _mm_mul_ps(pr, SKELETON_MATRIX(0, 3)); + pr = _mm_load_ps(p->m[1]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, SKELETON_MATRIX(1, 0))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, SKELETON_MATRIX(1, 1))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, SKELETON_MATRIX(1, 2))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, SKELETON_MATRIX(1, 3))); + pr = _mm_load_ps(p->m[2]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, SKELETON_MATRIX(2, 0))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, SKELETON_MATRIX(2, 1))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, SKELETON_MATRIX(2, 2))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, SKELETON_MATRIX(2, 3))); + b3 = _mm_add_ps(b3, _mm_load_ps(p->m[3])); + } + else + { + b0 = _mm_loadu_ps(s->m[0]); + b1 = _mm_loadu_ps(s->m[1]); + b2 = _mm_loadu_ps(s->m[2]); + b3 = _mm_loadu_ps(s->m[3]); +#ifndef OPENGLORIENTATION + _MM_TRANSPOSE4_PS(b0, b1, b2, b3); +#endif + } + _mm_store_ps(b->m[0], b0); + _mm_store_ps(b->m[1], b1); + _mm_store_ps(b->m[2], b2); + _mm_store_ps(b->m[3], b3); + nr = _mm_loadu_ps(n); + r0 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0))); + r1 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1))); + r2 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2))); + r3 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3))); + nr = _mm_loadu_ps(n+4); + r0 = _mm_add_ps(r0, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + nr = _mm_loadu_ps(n+8); + r0 = _mm_add_ps(r0, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + r3 = _mm_add_ps(r3, b3); + _mm_store_ps(r->m[0], r0); + _mm_store_ps(r->m[1], r1); + _mm_store_ps(r->m[2], r2); + _mm_store_ps(r->m[3], r3); + } + } + else + { + for (i = 0;i < model->num_bones;i++) + { + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i); + float lerp = frameblend[0].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + rx = pose7s[3] * lerp, + ry = pose7s[4] * lerp, + rz = pose7s[5] * lerp, + rw = pose7s[6] * lerp, + dx = tx*rw + ty*rz - tz*ry, + dy = -tx*rz + ty*rw + tz*rx, + dz = tx*ry - ty*rx + tz*rw, + dw = -tx*rx - ty*ry - tz*rz, + scale, sx, sy, sz, sw; + for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) + { + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i); + float lerp = frameblend[blends].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6]; + if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp; + qx *= lerp; + qy *= lerp; + qz *= lerp; + qw *= lerp; + rx += qx; + ry += qy; + rz += qz; + rw += qw; + dx += tx*qw + ty*qz - tz*qy; + dy += -tx*qz + ty*qw + tz*qx; + dz += tx*qy - ty*qx + tz*qw; + dw += -tx*qx - ty*qy - tz*qz; + } + scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw); + sx = rx * scale; + sy = ry * scale; + sz = rz * scale; + sw = rw * scale; + m[0] = sw*rw + sx*rx - sy*ry - sz*rz; + m[1] = 2*(sx*ry - sw*rz); + m[2] = 2*(sx*rz + sw*ry); + m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx); + m[4] = 2*(sx*ry + sw*rz); + m[5] = sw*rw + sy*ry - sx*rx - sz*rz; + m[6] = 2*(sy*rz - sw*rx); + m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy); + m[8] = 2*(sx*rz - sw*ry); + m[9] = 2*(sy*rz + sw*rx); + m[10] = sw*rw + sz*rz - sx*rx - sy*ry; + m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz); + if (i == r_skeletal_debugbone.integer) + m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value; + m[3] *= r_skeletal_debugtranslatex.value; + m[7] *= r_skeletal_debugtranslatey.value; + m[11] *= r_skeletal_debugtranslatez.value; + { + const float * RESTRICT n = model->data_baseboneposeinverse + i * 12; + matrix4x4_t * RESTRICT b = &bonepose[i]; + matrix4x4_t * RESTRICT r = &boneposerelative[i]; + __m128 b0, b1, b2, b3, r0, r1, r2, r3, nr; + if (model->data_bones[i].parent >= 0) + { + const matrix4x4_t * RESTRICT p = &bonepose[model->data_bones[i].parent]; + __m128 pr = _mm_load_ps(p->m[0]); + b0 = _mm_mul_ps(pr, _mm_set1_ps(m[0])); + b1 = _mm_mul_ps(pr, _mm_set1_ps(m[1])); + b2 = _mm_mul_ps(pr, _mm_set1_ps(m[2])); + b3 = _mm_mul_ps(pr, _mm_set1_ps(m[3])); + pr = _mm_load_ps(p->m[1]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, _mm_set1_ps(m[4]))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, _mm_set1_ps(m[5]))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, _mm_set1_ps(m[6]))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, _mm_set1_ps(m[7]))); + pr = _mm_load_ps(p->m[2]); + b0 = _mm_add_ps(b0, _mm_mul_ps(pr, _mm_set1_ps(m[8]))); + b1 = _mm_add_ps(b1, _mm_mul_ps(pr, _mm_set1_ps(m[9]))); + b2 = _mm_add_ps(b2, _mm_mul_ps(pr, _mm_set1_ps(m[10]))); + b3 = _mm_add_ps(b3, _mm_mul_ps(pr, _mm_set1_ps(m[11]))); + b3 = _mm_add_ps(b3, _mm_load_ps(p->m[3])); + } + else + { + b0 = _mm_setr_ps(m[0], m[4], m[8], 0.0f); + b1 = _mm_setr_ps(m[1], m[5], m[9], 0.0f); + b2 = _mm_setr_ps(m[2], m[6], m[10], 0.0f); + b3 = _mm_setr_ps(m[3], m[7], m[11], 1.0f); + } + _mm_store_ps(b->m[0], b0); + _mm_store_ps(b->m[1], b1); + _mm_store_ps(b->m[2], b2); + _mm_store_ps(b->m[3], b3); + nr = _mm_loadu_ps(n); + r0 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0))); + r1 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1))); + r2 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2))); + r3 = _mm_mul_ps(b0, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3))); + nr = _mm_loadu_ps(n+4); + r0 = _mm_add_ps(r0, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b1, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + nr = _mm_loadu_ps(n+8); + r0 = _mm_add_ps(r0, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(0, 0, 0, 0)))); + r1 = _mm_add_ps(r1, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(1, 1, 1, 1)))); + r2 = _mm_add_ps(r2, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(2, 2, 2, 2)))); + r3 = _mm_add_ps(r3, _mm_mul_ps(b2, _mm_shuffle_ps(nr, nr, _MM_SHUFFLE(3, 3, 3, 3)))); + r3 = _mm_add_ps(r3, b3); + _mm_store_ps(r->m[0], r0); + _mm_store_ps(r->m[1], r1); + _mm_store_ps(r->m[2], r2); + _mm_store_ps(r->m[3], r3); + } + } + } + + // generate matrices for all blend combinations + weights = model->surfmesh.data_blendweights; + for (i = 0;i < model->surfmesh.num_blends;i++, weights++) + { + float * RESTRICT b = &boneposerelative[model->num_bones + i].m[0][0]; + const float * RESTRICT m = &boneposerelative[weights->index[0]].m[0][0]; + float f = weights->influence[0] * (1.0f / 255.0f); + __m128 fv = _mm_set_ps1(f); + __m128 b0 = _mm_load_ps(m); + __m128 b1 = _mm_load_ps(m+4); + __m128 b2 = _mm_load_ps(m+8); + __m128 b3 = _mm_load_ps(m+12); + __m128 m0, m1, m2, m3; + b0 = _mm_mul_ps(b0, fv); + b1 = _mm_mul_ps(b1, fv); + b2 = _mm_mul_ps(b2, fv); + b3 = _mm_mul_ps(b3, fv); + for (k = 1;k < 4 && weights->influence[k];k++) + { + m = &boneposerelative[weights->index[k]].m[0][0]; + f = weights->influence[k] * (1.0f / 255.0f); + fv = _mm_set_ps1(f); + m0 = _mm_load_ps(m); + m1 = _mm_load_ps(m+4); + m2 = _mm_load_ps(m+8); + m3 = _mm_load_ps(m+12); + m0 = _mm_mul_ps(m0, fv); + m1 = _mm_mul_ps(m1, fv); + m2 = _mm_mul_ps(m2, fv); + m3 = _mm_mul_ps(m3, fv); + b0 = _mm_add_ps(m0, b0); + b1 = _mm_add_ps(m1, b1); + b2 = _mm_add_ps(m2, b2); + b3 = _mm_add_ps(m3, b3); + } + _mm_store_ps(b, b0); + _mm_store_ps(b+4, b1); + _mm_store_ps(b+8, b2); + _mm_store_ps(b+12, b3); + } + +#define LOAD_MATRIX_SCALAR() const float * RESTRICT m = &boneposerelative[*b].m[0][0] + +#define LOAD_MATRIX3() \ + const float * RESTRICT m = &boneposerelative[*b].m[0][0]; \ + /* bonepose array is 16 byte aligned */ \ + __m128 m1 = _mm_load_ps((m)); \ + __m128 m2 = _mm_load_ps((m)+4); \ + __m128 m3 = _mm_load_ps((m)+8); +#define LOAD_MATRIX4() \ + const float * RESTRICT m = &boneposerelative[*b].m[0][0]; \ + /* bonepose array is 16 byte aligned */ \ + __m128 m1 = _mm_load_ps((m)); \ + __m128 m2 = _mm_load_ps((m)+4); \ + __m128 m3 = _mm_load_ps((m)+8); \ + __m128 m4 = _mm_load_ps((m)+12) + + /* Note that matrix is 4x4 and transposed compared to non-USE_SSE codepath */ +#define TRANSFORM_POSITION_SCALAR(in, out) \ + (out)[0] = ((in)[0] * m[0] + (in)[1] * m[4] + (in)[2] * m[ 8] + m[12]); \ + (out)[1] = ((in)[0] * m[1] + (in)[1] * m[5] + (in)[2] * m[ 9] + m[13]); \ + (out)[2] = ((in)[0] * m[2] + (in)[1] * m[6] + (in)[2] * m[10] + m[14]); +#define TRANSFORM_VECTOR_SCALAR(in, out) \ + (out)[0] = ((in)[0] * m[0] + (in)[1] * m[4] + (in)[2] * m[ 8]); \ + (out)[1] = ((in)[0] * m[1] + (in)[1] * m[5] + (in)[2] * m[ 9]); \ + (out)[2] = ((in)[0] * m[2] + (in)[1] * m[6] + (in)[2] * m[10]); + +#define TRANSFORM_POSITION(in, out) { \ + __m128 pin = _mm_loadu_ps(in); /* we ignore the value in the last element (x from the next vertex) */ \ + __m128 x = _mm_shuffle_ps(pin, pin, 0x0); \ + __m128 t1 = _mm_mul_ps(x, m1); \ + \ + /* y, + x */ \ + __m128 y = _mm_shuffle_ps(pin, pin, 0x55); \ + __m128 t2 = _mm_mul_ps(y, m2); \ + __m128 t3 = _mm_add_ps(t1, t2); \ + \ + /* z, + (y+x) */ \ + __m128 z = _mm_shuffle_ps(pin, pin, 0xaa); \ + __m128 t4 = _mm_mul_ps(z, m3); \ + __m128 t5 = _mm_add_ps(t3, t4); \ + \ + /* + m3 */ \ + __m128 pout = _mm_add_ps(t5, m4); \ + _mm_storeu_ps((out), pout); \ + } + +#define TRANSFORM_VECTOR(in, out) { \ + __m128 vin = _mm_loadu_ps(in); \ + \ + /* x */ \ + __m128 x = _mm_shuffle_ps(vin, vin, 0x0); \ + __m128 t1 = _mm_mul_ps(x, m1); \ + \ + /* y, + x */ \ + __m128 y = _mm_shuffle_ps(vin, vin, 0x55); \ + __m128 t2 = _mm_mul_ps(y, m2); \ + __m128 t3 = _mm_add_ps(t1, t2); \ + \ + /* nz, + (ny + nx) */ \ + __m128 z = _mm_shuffle_ps(vin, vin, 0xaa); \ + __m128 t4 = _mm_mul_ps(z, m3); \ + __m128 vout = _mm_add_ps(t3, t4); \ + _mm_storeu_ps((out), vout); \ + } + + // transform vertex attributes by blended matrices + if (vertex3f) + { + const float * RESTRICT v = model->surfmesh.data_vertex3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + // special case common combinations of attributes to avoid repeated loading of matrices + if (normal3f) + { + const float * RESTRICT n = model->surfmesh.data_normal3f; + if (svector3f && tvector3f) + { + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + + // Note that for SSE each iteration stores one element past end, so we break one vertex short + // and handle that with scalars in that case + for (i = 0; i < num_vertices_minus_one; i++, v += 3, n += 3, sv += 3, tv += 3, b++, + vertex3f += 3, normal3f += 3, svector3f += 3, tvector3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + TRANSFORM_VECTOR(n, normal3f); + TRANSFORM_VECTOR(sv, svector3f); + TRANSFORM_VECTOR(tv, tvector3f); + } + + // Last vertex needs to be done with scalars to avoid reading/writing 1 word past end of arrays + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_POSITION_SCALAR(v, vertex3f); + TRANSFORM_VECTOR_SCALAR(n, normal3f); + TRANSFORM_VECTOR_SCALAR(sv, svector3f); + TRANSFORM_VECTOR_SCALAR(tv, tvector3f); + } + //printf("elapsed ticks: %llu\n", rdtsc() - ts); // XXX + return; + } + + for (i = 0;i < num_vertices_minus_one; i++, v += 3, n += 3, b++, vertex3f += 3, normal3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + TRANSFORM_VECTOR(n, normal3f); + } + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_POSITION_SCALAR(v, vertex3f); + TRANSFORM_VECTOR_SCALAR(n, normal3f); + } + } + else + { + for (i = 0;i < num_vertices_minus_one; i++, v += 3, b++, vertex3f += 3) + { + LOAD_MATRIX4(); + TRANSFORM_POSITION(v, vertex3f); + } + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_POSITION_SCALAR(v, vertex3f); + } + } + } + + else if (normal3f) + { + const float * RESTRICT n = model->surfmesh.data_normal3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < num_vertices_minus_one; i++, n += 3, b++, normal3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(n, normal3f); + } + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_VECTOR_SCALAR(n, normal3f); + } + } + + if (svector3f) + { + const float * RESTRICT sv = model->surfmesh.data_svector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < num_vertices_minus_one; i++, sv += 3, b++, svector3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(sv, svector3f); + } + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_VECTOR_SCALAR(sv, svector3f); + } + } + + if (tvector3f) + { + const float * RESTRICT tv = model->surfmesh.data_tvector3f; + const unsigned short * RESTRICT b = model->surfmesh.blends; + for (i = 0; i < num_vertices_minus_one; i++, tv += 3, b++, tvector3f += 3) + { + LOAD_MATRIX3(); + TRANSFORM_VECTOR(tv, tvector3f); + } + { + LOAD_MATRIX_SCALAR(); + TRANSFORM_VECTOR_SCALAR(tv, tvector3f); + } + } + +#undef LOAD_MATRIX3 +#undef LOAD_MATRIX4 +#undef TRANSFORM_POSITION +#undef TRANSFORM_VECTOR +#undef LOAD_MATRIX_SCALAR +#undef TRANSFORM_POSITION_SCALAR +#undef TRANSFORM_VECTOR_SCALAR +} + +#endif diff --git a/app/jni/mod_skeletal_animatevertices_sse.h b/app/jni/mod_skeletal_animatevertices_sse.h new file mode 100644 index 0000000..7de55ca --- /dev/null +++ b/app/jni/mod_skeletal_animatevertices_sse.h @@ -0,0 +1,10 @@ +#ifndef MOD_SKELTAL_ANIMATEVERTICES_SSE_H +#define MOD_SKELTAL_ANIMATEVERTICES_SSE_H + +#include "quakedef.h" + +#ifdef SSE_POSSIBLE +void Mod_Skeletal_AnimateVertices_SSE(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f); +#endif + +#endif diff --git a/app/jni/model_alias.c b/app/jni/model_alias.c new file mode 100644 index 0000000..ddcd849 --- /dev/null +++ b/app/jni/model_alias.c @@ -0,0 +1,4044 @@ +/* +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 "image.h" +#include "r_shadow.h" +#include "mod_skeletal_animatevertices_generic.h" +#ifdef SSE_POSSIBLE +#include "mod_skeletal_animatevertices_sse.h" +#endif + +#ifdef SSE_POSSIBLE +static qboolean r_skeletal_use_sse_defined = false; +cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"}; +#endif +cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"}; +cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"}; +cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"}; +cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"}; +cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"}; +cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"}; +cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"}; +cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"}; + +float mod_md3_sin[320]; + +static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0; +static void *Mod_Skeletal_AnimateVertices_bonepose = NULL; +void Mod_Skeletal_FreeBuffers(void) +{ + if(Mod_Skeletal_AnimateVertices_bonepose) + Mem_Free(Mod_Skeletal_AnimateVertices_bonepose); + Mod_Skeletal_AnimateVertices_maxbonepose = 0; + Mod_Skeletal_AnimateVertices_bonepose = NULL; +} +void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes) +{ + if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes) + { + if(Mod_Skeletal_AnimateVertices_bonepose) + Mem_Free(Mod_Skeletal_AnimateVertices_bonepose); + Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes); + Mod_Skeletal_AnimateVertices_maxbonepose = nbytes; + } + return Mod_Skeletal_AnimateVertices_bonepose; +} + +void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative) +{ + int i, blends; + float m[12]; + + if (!bonepose) + bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones); + + if (skeleton && !skeleton->relativetransforms) + skeleton = NULL; + + // interpolate matrices + if (skeleton) + { + for (i = 0;i < model->num_bones;i++) + { + Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m); + if (model->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12); + else + memcpy(bonepose + i * 12, m, sizeof(m)); + + // create a relative deformation matrix to describe displacement + // from the base mesh, which is used by the actual weighting + R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12); + } + } + else + { + for (i = 0;i < model->num_bones;i++) + { + // blend by transform each quaternion/translation into a dual-quaternion first, then blending + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i); + float lerp = frameblend[0].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + rx = pose7s[3] * lerp, + ry = pose7s[4] * lerp, + rz = pose7s[5] * lerp, + rw = pose7s[6] * lerp, + dx = tx*rw + ty*rz - tz*ry, + dy = -tx*rz + ty*rw + tz*rx, + dz = tx*ry - ty*rx + tz*rw, + dw = -tx*rx - ty*ry - tz*rz, + scale, sx, sy, sz, sw; + for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++) + { + const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i); + float lerp = frameblend[blends].lerp, + tx = pose7s[0], ty = pose7s[1], tz = pose7s[2], + qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6]; + if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp; + qx *= lerp; + qy *= lerp; + qz *= lerp; + qw *= lerp; + rx += qx; + ry += qy; + rz += qz; + rw += qw; + dx += tx*qw + ty*qz - tz*qy; + dy += -tx*qz + ty*qw + tz*qx; + dz += tx*qy - ty*qx + tz*qw; + dw += -tx*qx - ty*qy - tz*qz; + } + // generate a matrix from the dual-quaternion, implicitly normalizing it in the process + scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw); + sx = rx * scale; + sy = ry * scale; + sz = rz * scale; + sw = rw * scale; + m[0] = sw*rw + sx*rx - sy*ry - sz*rz; + m[1] = 2*(sx*ry - sw*rz); + m[2] = 2*(sx*rz + sw*ry); + m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx); + m[4] = 2*(sx*ry + sw*rz); + m[5] = sw*rw + sy*ry - sx*rx - sz*rz; + m[6] = 2*(sy*rz - sw*rx); + m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy); + m[8] = 2*(sx*rz - sw*ry); + m[9] = 2*(sy*rz + sw*rx); + m[10] = sw*rw + sz*rz - sx*rx - sy*ry; + m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz); + if (i == r_skeletal_debugbone.integer) + m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value; + m[3] *= r_skeletal_debugtranslatex.value; + m[7] *= r_skeletal_debugtranslatey.value; + m[11] *= r_skeletal_debugtranslatez.value; + if (model->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12); + else + memcpy(bonepose + i * 12, m, sizeof(m)); + // create a relative deformation matrix to describe displacement + // from the base mesh, which is used by the actual weighting + R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12); + } + } +} + +static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ + + if (!model->surfmesh.num_vertices) + return; + + if (!model->num_bones) + { + if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3])); + if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3])); + if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3])); + if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3])); + return; + } + +#ifdef SSE_POSSIBLE + if(r_skeletal_use_sse_defined) + if(r_skeletal_use_sse.integer) + { + Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f); + return; + } +#endif + Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f); +} + +void Mod_AliasInit (void) +{ + int i; + Cvar_RegisterVariable(&r_skeletal_debugbone); + Cvar_RegisterVariable(&r_skeletal_debugbonecomponent); + Cvar_RegisterVariable(&r_skeletal_debugbonevalue); + Cvar_RegisterVariable(&r_skeletal_debugtranslatex); + Cvar_RegisterVariable(&r_skeletal_debugtranslatey); + Cvar_RegisterVariable(&r_skeletal_debugtranslatez); + Cvar_RegisterVariable(&mod_alias_supporttagscale); + Cvar_RegisterVariable(&mod_alias_force_animated); + for (i = 0;i < 320;i++) + mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0); +#ifdef SSE_POSSIBLE + if(Sys_HaveSSE()) + { + Con_Printf("Skeletal animation uses SSE code path\n"); + r_skeletal_use_sse_defined = true; + Cvar_RegisterVariable(&r_skeletal_use_sse); + } + else + Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n"); +#else + Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n"); +#endif +} + +static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights) +{ + int i; + blendweights_t *weights; + if(!newweights->influence[1]) + return newweights->index[0]; + weights = model->surfmesh.data_blendweights; + for (i = 0;i < model->surfmesh.num_blends;i++, weights++) + { + if (!memcmp(weights, newweights, sizeof(blendweights_t))) + return model->num_bones + i; + } + model->surfmesh.num_blends++; + memcpy(weights, newweights, sizeof(blendweights_t)); + return model->num_bones + i; +} + +static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence) +{ + int i, total; + float scale; + blendweights_t newweights; + if(!newinfluence[1]) + return newindex[0]; + scale = 0; + for (i = 0;i < 4;i++) + scale += newinfluence[i]; + scale = 255.0f / scale; + total = 0; + for (i = 0;i < 4;i++) + { + newweights.index[i] = newindex[i]; + newweights.influence[i] = (unsigned char)(newinfluence[i] * scale); + total += newweights.influence[i]; + } + while (total > 255) + { + for (i = 0;i < 4;i++) + { + if(newweights.influence[i] > 0 && total > 255) + { + newweights.influence[i]--; + total--; + } + } + } + while (total < 255) + { + for (i = 0; i < 4;i++) + { + if(newweights.influence[i] < 255 && total < 255) + { + newweights.influence[i]++; + total++; + } + } + } + return Mod_Skeletal_AddBlend(model, &newweights); +} + +static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ + // vertex morph + int i, numblends, blendnum; + int numverts = model->surfmesh.num_vertices; + numblends = 0; + for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++) + { + //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate); + if (frameblend[blendnum].lerp > 0) + numblends = blendnum + 1; + } + // special case for the first blend because it avoids some adds and the need to memset the arrays first + for (blendnum = 0;blendnum < numblends;blendnum++) + { + const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe; + if (vertex3f) + { + float scale = frameblend[blendnum].lerp * (1.0f / 64.0f); + if (blendnum == 0) + { + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] = verts[i].origin[0] * scale; + vertex3f[i * 3 + 1] = verts[i].origin[1] * scale; + vertex3f[i * 3 + 2] = verts[i].origin[2] * scale; + } + } + else + { + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] += verts[i].origin[0] * scale; + vertex3f[i * 3 + 1] += verts[i].origin[1] * scale; + vertex3f[i * 3 + 2] += verts[i].origin[2] * scale; + } + } + } + // the yaw and pitch stored in md3 models are 8bit quantized angles + // (0-255), and as such a lookup table is very well suited to + // decoding them, and since cosine is equivalent to sine with an + // extra 45 degree rotation, this uses one lookup table for both + // sine and cosine with a +64 bias to get cosine. + if (normal3f) + { + float lerp = frameblend[blendnum].lerp; + if (blendnum == 0) + { + for (i = 0;i < numverts;i++) + { + normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp; + } + } + else + { + for (i = 0;i < numverts;i++) + { + normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp; + normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp; + } + } + } + if (svector3f) + { + const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe; + float f = frameblend[blendnum].lerp * (1.0f / 127.0f); + if (blendnum == 0) + { + for (i = 0;i < numverts;i++, texvecvert++) + { + VectorScale(texvecvert->svec, f, svector3f + i*3); + VectorScale(texvecvert->tvec, f, tvector3f + i*3); + } + } + else + { + for (i = 0;i < numverts;i++, texvecvert++) + { + VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3); + VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3); + } + } + } + } +} +static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f) +{ + // vertex morph + int i, numblends, blendnum; + int numverts = model->surfmesh.num_vertices; + float translate[3]; + VectorClear(translate); + numblends = 0; + // blend the frame translates to avoid redundantly doing so on each vertex + // (a bit of a brain twister but it works) + for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++) + { + if (model->surfmesh.data_morphmd2framesize6f) + VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate); + else + VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate); + if (frameblend[blendnum].lerp > 0) + numblends = blendnum + 1; + } + // special case for the first blend because it avoids some adds and the need to memset the arrays first + for (blendnum = 0;blendnum < numblends;blendnum++) + { + const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe; + if (vertex3f) + { + float scale[3]; + if (model->surfmesh.data_morphmd2framesize6f) + VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale); + else + VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale); + if (blendnum == 0) + { + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0]; + vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1]; + vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2]; + } + } + else + { + for (i = 0;i < numverts;i++) + { + vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0]; + vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1]; + vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2]; + } + } + } + // the vertex normals in mdl models are an index into a table of + // 162 unique values, this very crude quantization reduces the + // vertex normal to only one byte, which saves a lot of space but + // also makes lighting pretty coarse + if (normal3f) + { + float lerp = frameblend[blendnum].lerp; + if (blendnum == 0) + { + for (i = 0;i < numverts;i++) + { + const float *vn = m_bytenormals[verts[i].lightnormalindex]; + VectorScale(vn, lerp, normal3f + i*3); + } + } + else + { + for (i = 0;i < numverts;i++) + { + const float *vn = m_bytenormals[verts[i].lightnormalindex]; + VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3); + } + } + } + if (svector3f) + { + const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe; + float f = frameblend[blendnum].lerp * (1.0f / 127.0f); + if (blendnum == 0) + { + for (i = 0;i < numverts;i++, texvecvert++) + { + VectorScale(texvecvert->svec, f, svector3f + i*3); + VectorScale(texvecvert->tvec, f, tvector3f + i*3); + } + } + else + { + for (i = 0;i < numverts;i++, texvecvert++) + { + VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3); + VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3); + } + } + } + } +} + +int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix) +{ + matrix4x4_t temp; + matrix4x4_t parentbonematrix; + matrix4x4_t tempbonematrix; + matrix4x4_t bonematrix; + matrix4x4_t blendmatrix; + int blendindex; + int parenttagindex; + int k; + float lerp; + const float *input; + float blendtag[12]; + *outmatrix = identitymatrix; + if (skeleton && skeleton->relativetransforms) + { + if (tagindex < 0 || tagindex >= skeleton->model->num_bones) + return 4; + *outmatrix = skeleton->relativetransforms[tagindex]; + while ((tagindex = model->data_bones[tagindex].parent) >= 0) + { + temp = *outmatrix; + Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp); + } + } + else if (model->num_bones) + { + if (tagindex < 0 || tagindex >= model->num_bones) + return 4; + Matrix4x4_Clear(&blendmatrix); + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + parenttagindex = tagindex; + while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0) + { + Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex)); + tempbonematrix = bonematrix; + Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix); + } + Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp); + } + *outmatrix = blendmatrix; + } + else if (model->num_tags) + { + if (tagindex < 0 || tagindex >= model->num_tags) + return 4; + for (k = 0;k < 12;k++) + blendtag[k] = 0; + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl; + for (k = 0;k < 12;k++) + blendtag[k] += input[k] * lerp; + } + Matrix4x4_FromArray12FloatGL(outmatrix, blendtag); + } + + if(!mod_alias_supporttagscale.integer) + Matrix4x4_Normalize3(outmatrix, outmatrix); + + return 0; +} + +int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix) +{ + int blendindex; + int k; + float lerp; + matrix4x4_t bonematrix; + matrix4x4_t blendmatrix; + const float *input; + float blendtag[12]; + + if (skeleton && skeleton->relativetransforms) + { + if (tagindex < 0 || tagindex >= skeleton->model->num_bones) + return 1; + *parentindex = skeleton->model->data_bones[tagindex].parent; + *tagname = skeleton->model->data_bones[tagindex].name; + *tag_localmatrix = skeleton->relativetransforms[tagindex]; + return 0; + } + else if (model->num_bones) + { + if (tagindex < 0 || tagindex >= model->num_bones) + return 1; + *parentindex = model->data_bones[tagindex].parent; + *tagname = model->data_bones[tagindex].name; + Matrix4x4_Clear(&blendmatrix); + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex)); + Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp); + } + *tag_localmatrix = blendmatrix; + return 0; + } + else if (model->num_tags) + { + if (tagindex < 0 || tagindex >= model->num_tags) + return 1; + *parentindex = -1; + *tagname = model->data_tags[tagindex].name; + for (k = 0;k < 12;k++) + blendtag[k] = 0; + for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++) + { + lerp = frameblend[blendindex].lerp; + input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl; + for (k = 0;k < 12;k++) + blendtag[k] += input[k] * lerp; + } + Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag); + return 0; + } + + return 2; +} + +int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname) +{ + int i; + if(skin >= (unsigned int)model->numskins) + skin = 0; + if (model->num_bones) + for (i = 0;i < model->num_bones;i++) + if (!strcasecmp(tagname, model->data_bones[i].name)) + return i + 1; + if (model->num_tags) + for (i = 0;i < model->num_tags;i++) + if (!strcasecmp(tagname, model->data_tags[i].name)) + return i + 1; + return 0; +} + +static void Mod_BuildBaseBonePoses(void) +{ + int boneindex; + matrix4x4_t *basebonepose; + float *outinvmatrix = loadmodel->data_baseboneposeinverse; + matrix4x4_t bonematrix; + matrix4x4_t tempbonematrix; + if (!loadmodel->num_bones) + return; + basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t)); + for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++) + { + Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex); + if (loadmodel->data_bones[boneindex].parent >= 0) + { + tempbonematrix = bonematrix; + Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix); + } + basebonepose[boneindex] = bonematrix; + Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex); + Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex); + } + Mem_Free(basebonepose); +} + +static qboolean Mod_Alias_CalculateBoundingBox(void) +{ + int vnum; + qboolean firstvertex = true; + float dist, yawradius, radius; + float *v; + qboolean isanimated = false; + VectorClear(loadmodel->normalmins); + VectorClear(loadmodel->normalmaxs); + yawradius = 0; + radius = 0; + if (loadmodel->AnimateVertices) + { + float *vertex3f, *refvertex3f; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + memset(frameblend, 0, sizeof(frameblend)); + frameblend[0].lerp = 1; + vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2); + refvertex3f = NULL; + for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++) + { + loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL); + if (!refvertex3f) + { + // make a copy of the first frame for comparing all others + refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3; + memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])); + } + else + { + if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]))) + isanimated = true; + } + for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3) + { + if (firstvertex) + { + firstvertex = false; + VectorCopy(v, loadmodel->normalmins); + VectorCopy(v, loadmodel->normalmaxs); + } + else + { + if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0]; + if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1]; + if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2]; + if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0]; + if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1]; + if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2]; + } + dist = v[0] * v[0] + v[1] * v[1]; + if (yawradius < dist) + yawradius = dist; + dist += v[2] * v[2]; + if (radius < dist) + radius = dist; + } + } + if (vertex3f) + Mem_Free(vertex3f); + } + else + { + for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3) + { + if (firstvertex) + { + firstvertex = false; + VectorCopy(v, loadmodel->normalmins); + VectorCopy(v, loadmodel->normalmaxs); + } + else + { + if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0]; + if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1]; + if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2]; + if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0]; + if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1]; + if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2]; + } + dist = v[0] * v[0] + v[1] * v[1]; + if (yawradius < dist) + yawradius = dist; + dist += v[2] * v[2]; + if (radius < dist) + radius = dist; + } + } + radius = sqrt(radius); + yawradius = sqrt(yawradius); + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius; + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius; + loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius; + loadmodel->radius = radius; + loadmodel->radius2 = radius * radius; + return isanimated; +} + +static void Mod_Alias_MorphMesh_CompileFrames(void) +{ + int i, j; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + unsigned char *datapointer; + memset(frameblend, 0, sizeof(frameblend)); + frameblend[0].lerp = 1; + datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t))); + loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t); + // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there) + for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--) + { + frameblend[0].subframe = i; + loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + // encode the svector and tvector in 3 byte format for permanent storage + for (j = 0;j < loadmodel->surfmesh.num_vertices;j++) + { + VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec); + VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec); + } + } +} + +static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + int i; + float segmentmins[3], segmentmaxs[3]; + msurface_t *surface; + float vertex3fbuf[1024*3]; + float *vertex3f = vertex3fbuf; + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + if (model->surfmesh.num_vertices > 1024) + vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3])); + segmentmins[0] = min(start[0], end[0]) - 1; + segmentmins[1] = min(start[1], end[1]) - 1; + segmentmins[2] = min(start[2], end[2]) - 1; + segmentmaxs[0] = max(start[0], end[0]) + 1; + segmentmaxs[1] = max(start[1], end[1]) + 1; + segmentmaxs[2] = max(start[2], end[2]) + 1; + model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL); + for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) + Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs); + if (vertex3f != vertex3fbuf) + Mem_Free(vertex3f); +} + +static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) +{ + int i; + vec3_t shiftstart, shiftend; + float segmentmins[3], segmentmaxs[3]; + msurface_t *surface; + float vertex3fbuf[1024*3]; + float *vertex3f = vertex3fbuf; + colboxbrushf_t thisbrush_start, thisbrush_end; + vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; + + if (VectorCompare(boxmins, boxmaxs)) + { + VectorAdd(start, boxmins, shiftstart); + VectorAdd(end, boxmins, shiftend); + Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask); + VectorSubtract(trace->endpos, boxmins, trace->endpos); + return; + } + + // box trace, performed as brush trace + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + if (model->surfmesh.num_vertices > 1024) + vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3])); + segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1; + segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1; + segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1; + segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1; + segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1; + segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1; + VectorAdd(start, boxmins, boxstartmins); + VectorAdd(start, boxmaxs, boxstartmaxs); + VectorAdd(end, boxmins, boxendmins); + VectorAdd(end, boxmaxs, boxendmaxs); + Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL); + model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL); + for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++) + Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs); + if (vertex3f != vertex3fbuf) + Mem_Free(vertex3f); +} + +static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap) +{ + int i, j; + for (i = 0;i < inverts;i++) + { + if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply... + continue; + j = vertremap[i]; // not onseam + if (j >= 0) + out[j] = v[i]; + j = vertremap[i+inverts]; // onseam + if (j >= 0) + out[j] = v[i]; + } +} + +static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap) +{ + int i, f, pose, groupframes; + float interval; + daliasframetype_t *pframetype; + daliasframe_t *pinframe; + daliasgroup_t *group; + daliasinterval_t *intervals; + animscene_t *scene; + pose = 0; + scene = loadmodel->animscenes; + for (f = 0;f < loadmodel->numframes;f++) + { + pframetype = (daliasframetype_t *)datapointer; + datapointer += sizeof(daliasframetype_t); + if (LittleLong (pframetype->type) == ALIAS_SINGLE) + { + // a single frame is still treated as a group + interval = 0.1f; + groupframes = 1; + } + else + { + // read group header + group = (daliasgroup_t *)datapointer; + datapointer += sizeof(daliasgroup_t); + groupframes = LittleLong (group->numframes); + + // intervals (time per frame) + intervals = (daliasinterval_t *)datapointer; + datapointer += sizeof(daliasinterval_t) * groupframes; + + interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups + if (interval < 0.01f) + { + Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval); + interval = 0.1f; + } + } + + // get scene name from first frame + pinframe = (daliasframe_t *)datapointer; + + strlcpy(scene->name, pinframe->name, sizeof(scene->name)); + scene->firstframe = pose; + scene->framecount = groupframes; + scene->framerate = 1.0f / interval; + scene->loop = true; + scene++; + + // read frames + for (i = 0;i < groupframes;i++) + { + datapointer += sizeof(daliasframe_t); + Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap); + datapointer += sizeof(trivertx_t) * inverts; + pose++; + } + } +} + +static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe) +{ + if (cls.state == ca_dedicated) + return; + // hack + if (!skinframe) + skinframe = R_SkinFrame_LoadMissing(); + memset(texture, 0, sizeof(*texture)); + texture->currentframe = texture; + //texture->animated = false; + texture->numskinframes = 1; + texture->skinframerate = 1; + texture->skinframes[0] = skinframe; + texture->currentskinframe = skinframe; + //texture->backgroundnumskinframes = 0; + //texture->customblendfunc[0] = 0; + //texture->customblendfunc[1] = 0; + //texture->surfaceflags = 0; + //texture->supercontents = 0; + //texture->surfaceparms = 0; + //texture->textureflags = 0; + + texture->basematerialflags = MATERIALFLAG_WALL; + if (texture->currentskinframe->hasalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + texture->currentmaterialflags = texture->basematerialflags; + texture->offsetmapping = OFFSETMAPPING_DEFAULT; + texture->offsetscale = 1; + texture->offsetbias = 0; + texture->specularscalemod = 1; + texture->specularpowermod = 1; + texture->surfaceflags = 0; + texture->supercontents = SUPERCONTENTS_SOLID; + if (!(texture->basematerialflags & MATERIALFLAG_BLENDED)) + texture->supercontents |= SUPERCONTENTS_OPAQUE; + texture->transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". +} + +void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername) +{ + int i; + char stripbuf[MAX_QPATH]; + skinfileitem_t *skinfileitem; + if(developer_extra.integer) + Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername); + if (skinfile) + { + // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces] + for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces) + { + memset(skin, 0, sizeof(*skin)); + // see if a mesh + for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next) + { + // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw" + if (!strcmp(skinfileitem->name, meshname)) + { + Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf)); + if(developer_extra.integer) + Con_DPrintf("--> got %s from skin file\n", stripbuf); + Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + break; + } + } + if (!skinfileitem) + { + // don't render unmentioned meshes + Mod_BuildAliasSkinFromSkinFrame(skin, NULL); + if(developer_extra.integer) + Con_DPrintf("--> skipping\n"); + skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW; + } + } + } + else + { + if(developer_extra.integer) + Con_DPrintf("--> using default\n"); + Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf)); + Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + } +} + +#define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX); +#define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX); +void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts; + float scales, scalet, interval; + msurface_t *surface; + unsigned char *data; + mdl_t *pinmodel; + stvert_t *pinstverts; + dtriangle_t *pintriangles; + daliasskintype_t *pinskintype; + daliasskingroup_t *pinskingroup; + daliasskininterval_t *pinskinintervals; + daliasframetype_t *pinframetype; + daliasgroup_t *pinframegroup; + unsigned char *datapointer, *startframes, *startskins; + char name[MAX_QPATH]; + skinframe_t *tempskinframe; + animscene_t *tempskinscenes; + texture_t *tempaliasskins; + float *vertst; + int *vertonseam, *vertremap; + skinfile_t *skinfiles; + char vabuf[1024]; + + datapointer = (unsigned char *)buffer; + pinmodel = (mdl_t *)datapointer; + datapointer += sizeof(mdl_t); + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + Host_Error ("%s has wrong version number (%i should be %i)", + loadmodel->name, version, ALIAS_VERSION); + + loadmodel->modeldatatypestring = "MDL"; + + loadmodel->type = mod_alias; + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + // FIXME add TraceBrush! + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; + + loadmodel->num_surfaces = 1; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int)); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces[0] = 0; + + loadmodel->numskins = LittleLong(pinmodel->numskins); + BOUNDI(loadmodel->numskins,0,65536); + skinwidth = LittleLong (pinmodel->skinwidth); + BOUNDI(skinwidth,0,65536); + skinheight = LittleLong (pinmodel->skinheight); + BOUNDI(skinheight,0,65536); + numverts = LittleLong(pinmodel->numverts); + BOUNDI(numverts,0,65536); + loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris); + BOUNDI(loadmodel->surfmesh.num_triangles,0,65536); + loadmodel->numframes = LittleLong(pinmodel->numframes); + BOUNDI(loadmodel->numframes,0,65536); + loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype); + BOUNDI((int)loadmodel->synctype,0,2); + // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc) + i = LittleLong (pinmodel->flags); + loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00); + + for (i = 0;i < 3;i++) + { + loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]); + loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]); + } + + startskins = datapointer; + totalskins = 0; + for (i = 0;i < loadmodel->numskins;i++) + { + pinskintype = (daliasskintype_t *)datapointer; + datapointer += sizeof(daliasskintype_t); + if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE) + groupskins = 1; + else + { + pinskingroup = (daliasskingroup_t *)datapointer; + datapointer += sizeof(daliasskingroup_t); + groupskins = LittleLong(pinskingroup->numskins); + datapointer += sizeof(daliasskininterval_t) * groupskins; + } + + for (j = 0;j < groupskins;j++) + { + datapointer += skinwidth * skinheight; + totalskins++; + } + } + + pinstverts = (stvert_t *)datapointer; + datapointer += sizeof(stvert_t) * numverts; + + pintriangles = (dtriangle_t *)datapointer; + datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles; + + startframes = datapointer; + loadmodel->surfmesh.num_morphframes = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + pinframetype = (daliasframetype_t *)datapointer; + datapointer += sizeof(daliasframetype_t); + if (LittleLong (pinframetype->type) == ALIAS_SINGLE) + groupframes = 1; + else + { + pinframegroup = (daliasgroup_t *)datapointer; + datapointer += sizeof(daliasgroup_t); + groupframes = LittleLong(pinframegroup->numframes); + datapointer += sizeof(daliasinterval_t) * groupframes; + } + + for (j = 0;j < groupframes;j++) + { + datapointer += sizeof(daliasframe_t); + datapointer += sizeof(trivertx_t) * numverts; + loadmodel->surfmesh.num_morphframes++; + } + } + loadmodel->num_poses = loadmodel->surfmesh.num_morphframes; + + // store texture coordinates into temporary array, they will be stored + // after usage is determined (triangle data) + vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2])); + vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int)); + vertonseam = vertremap + numverts * 2; + + scales = 1.0 / skinwidth; + scalet = 1.0 / skinheight; + for (i = 0;i < numverts;i++) + { + vertonseam[i] = LittleLong(pinstverts[i].onseam); + vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales; + vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet; + vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5; + vertst[(i+numverts)*2+1] = vertst[i*2+1]; + } + +// load triangle data + loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles); + + // read the triangle elements + for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) + for (j = 0;j < 3;j++) + loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]); + // validate (note numverts is used because this is the original data) + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__); + // now butcher the elements according to vertonseam and tri->facesfront + // and then compact the vertex set to remove duplicates + for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) + if (!LittleLong(pintriangles[i].facesfront)) // backface + for (j = 0;j < 3;j++) + if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]]) + loadmodel->surfmesh.data_element3i[i*3+j] += numverts; + // count the usage + // (this uses vertremap to count usage to save some memory) + for (i = 0;i < numverts*2;i++) + vertremap[i] = 0; + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + vertremap[loadmodel->surfmesh.data_element3i[i]]++; + // build remapping table and compact array + loadmodel->surfmesh.num_vertices = 0; + for (i = 0;i < numverts*2;i++) + { + if (vertremap[i]) + { + vertremap[i] = loadmodel->surfmesh.num_vertices; + vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0]; + vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1]; + loadmodel->surfmesh.num_vertices++; + } + else + vertremap[i] = -1; // not used at all + } + // remap the elements to the new vertex set + for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++) + loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]]; + // store the texture coordinates + loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices); + for (i = 0;i < loadmodel->surfmesh.num_vertices;i++) + { + loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0]; + loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1]; + } + + // generate ushort elements array if possible + if (loadmodel->surfmesh.num_vertices <= 65536) + loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + +// load the frames + loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); + loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3])); + } + Mod_MDL_LoadFrames (startframes, numverts, vertremap); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + Mod_Alias_MorphMesh_CompileFrames(); + + Mem_Free(vertst); + Mem_Free(vertremap); + + // load the skins + skinfiles = Mod_LoadSkinFiles(); + if (skinfiles) + { + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t)); + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", ""); + Mod_FreeSkinFiles(skinfiles); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + } + else + { + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t)); + loadmodel->num_textures = loadmodel->num_surfaces * totalskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t)); + totalskins = 0; + datapointer = startskins; + for (i = 0;i < loadmodel->numskins;i++) + { + pinskintype = (daliasskintype_t *)datapointer; + datapointer += sizeof(daliasskintype_t); + + if (pinskintype->type == ALIAS_SKIN_SINGLE) + { + groupskins = 1; + interval = 0.1f; + } + else + { + pinskingroup = (daliasskingroup_t *)datapointer; + datapointer += sizeof(daliasskingroup_t); + + groupskins = LittleLong (pinskingroup->numskins); + + pinskinintervals = (daliasskininterval_t *)datapointer; + datapointer += sizeof(daliasskininterval_t) * groupskins; + + interval = LittleFloat(pinskinintervals[0].interval); + if (interval < 0.01f) + { + Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval); + interval = 0.1f; + } + } + + dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i); + loadmodel->skinscenes[i].firstframe = totalskins; + loadmodel->skinscenes[i].framecount = groupskins; + loadmodel->skinscenes[i].framerate = 1.0f / interval; + loadmodel->skinscenes[i].loop = true; + + for (j = 0;j < groupskins;j++) + { + if (groupskins > 1) + dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j); + else + dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); + if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS)) + Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight)); + datapointer += skinwidth * skinheight; + totalskins++; + } + } + // check for skins that don't exist in the model, but do exist as external images + // (this was added because yummyluv kept pestering me about support for it) + // TODO: support shaders here? + while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false))) + { + // expand the arrays to make room + tempskinscenes = loadmodel->skinscenes; + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, (loadmodel->numskins + 1) * sizeof(animscene_t)); + memcpy(loadmodel->skinscenes, tempskinscenes, loadmodel->numskins * sizeof(animscene_t)); + Mem_Free(tempskinscenes); + + tempaliasskins = loadmodel->data_textures; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * (totalskins + 1) * sizeof(texture_t)); + memcpy(loadmodel->data_textures, tempaliasskins, loadmodel->num_surfaces * totalskins * sizeof(texture_t)); + Mem_Free(tempaliasskins); + + // store the info about the new skin + Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, tempskinframe); + strlcpy(loadmodel->skinscenes[loadmodel->numskins].name, name, sizeof(loadmodel->skinscenes[loadmodel->numskins].name)); + loadmodel->skinscenes[loadmodel->numskins].firstframe = totalskins; + loadmodel->skinscenes[loadmodel->numskins].framecount = 1; + loadmodel->skinscenes[loadmodel->numskins].framerate = 10.0f; + loadmodel->skinscenes[loadmodel->numskins].loop = true; + + //increase skin counts + loadmodel->numskins++; + totalskins++; + + // fix up the pointers since they are pointing at the old textures array + // FIXME: this is a hack! + for (j = 0;j < loadmodel->numskins * loadmodel->num_surfaces;j++) + loadmodel->data_textures[j].currentframe = &loadmodel->data_textures[j]; + } + } + + surface = loadmodel->data_surfaces; + surface->texture = loadmodel->data_textures; + surface->num_firsttriangle = 0; + surface->num_triangles = loadmodel->surfmesh.num_triangles; + surface->num_firstvertex = 0; + surface->num_vertices = loadmodel->surfmesh.num_vertices; + + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, hashindex, numxyz, numst, xyz, st, skinwidth, skinheight, *vertremap, version, end; + float iskinwidth, iskinheight; + unsigned char *data; + msurface_t *surface; + md2_t *pinmodel; + unsigned char *base, *datapointer; + md2frame_t *pinframe; + char *inskin; + md2triangle_t *intri; + unsigned short *inst; + struct md2verthash_s + { + struct md2verthash_s *next; + unsigned short xyz; + unsigned short st; + } + *hash, **md2verthash, *md2verthashdata; + skinfile_t *skinfiles; + + pinmodel = (md2_t *)buffer; + base = (unsigned char *)buffer; + + version = LittleLong (pinmodel->version); + if (version != MD2ALIAS_VERSION) + Host_Error ("%s has wrong version number (%i should be %i)", + loadmodel->name, version, MD2ALIAS_VERSION); + + loadmodel->modeldatatypestring = "MD2"; + + loadmodel->type = mod_alias; + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_MDL_AnimateVertices; + + if (LittleLong(pinmodel->num_tris) < 1 || LittleLong(pinmodel->num_tris) > 65536) + Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris)); + if (LittleLong(pinmodel->num_xyz) < 1 || LittleLong(pinmodel->num_xyz) > 65536) + Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz)); + if (LittleLong(pinmodel->num_frames) < 1 || LittleLong(pinmodel->num_frames) > 65536) + Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames)); + if (LittleLong(pinmodel->num_skins) < 0 || LittleLong(pinmodel->num_skins) > 256) + Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins)); + + end = LittleLong(pinmodel->ofs_end); + if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins) <= 0 || LittleLong(pinmodel->ofs_skins) >= end)) + Host_Error ("%s is not a valid model", loadmodel->name); + if (LittleLong(pinmodel->ofs_st) <= 0 || LittleLong(pinmodel->ofs_st) >= end) + Host_Error ("%s is not a valid model", loadmodel->name); + if (LittleLong(pinmodel->ofs_tris) <= 0 || LittleLong(pinmodel->ofs_tris) >= end) + Host_Error ("%s is not a valid model", loadmodel->name); + if (LittleLong(pinmodel->ofs_frames) <= 0 || LittleLong(pinmodel->ofs_frames) >= end) + Host_Error ("%s is not a valid model", loadmodel->name); + if (LittleLong(pinmodel->ofs_glcmds) <= 0 || LittleLong(pinmodel->ofs_glcmds) >= end) + Host_Error ("%s is not a valid model", loadmodel->name); + + loadmodel->numskins = LittleLong(pinmodel->num_skins); + numxyz = LittleLong(pinmodel->num_xyz); + numst = LittleLong(pinmodel->num_st); + loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->num_tris); + loadmodel->numframes = LittleLong(pinmodel->num_frames); + loadmodel->surfmesh.num_morphframes = loadmodel->numframes; + loadmodel->num_poses = loadmodel->surfmesh.num_morphframes; + skinwidth = LittleLong(pinmodel->skinwidth); + skinheight = LittleLong(pinmodel->skinheight); + iskinwidth = 1.0f / skinwidth; + iskinheight = 1.0f / skinheight; + + loadmodel->num_surfaces = 1; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0)); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->sortedmodelsurfaces[0] = 0; + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); + loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + } + + loadmodel->synctype = ST_RAND; + + // load the skins + inskin = (char *)(base + LittleLong(pinmodel->ofs_skins)); + skinfiles = Mod_LoadSkinFiles(); + if (skinfiles) + { + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", ""); + Mod_FreeSkinFiles(skinfiles); + } + else if (loadmodel->numskins) + { + // skins found (most likely not a player model) + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + for (i = 0;i < loadmodel->numskins;i++, inskin += MD2_SKINNAME) + Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i * loadmodel->num_surfaces, inskin, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS); + } + else + { + // no skins (most likely a player model) + loadmodel->numskins = 1; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t)); + Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures, NULL); + } + + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // load the triangles and stvert data + inst = (unsigned short *)(base + LittleLong(pinmodel->ofs_st)); + intri = (md2triangle_t *)(base + LittleLong(pinmodel->ofs_tris)); + md2verthash = (struct md2verthash_s **)Mem_Alloc(tempmempool, 65536 * sizeof(hash)); + md2verthashdata = (struct md2verthash_s *)Mem_Alloc(tempmempool, loadmodel->surfmesh.num_triangles * 3 * sizeof(*hash)); + // swap the triangle list + loadmodel->surfmesh.num_vertices = 0; + for (i = 0;i < loadmodel->surfmesh.num_triangles;i++) + { + for (j = 0;j < 3;j++) + { + xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]); + st = (unsigned short) LittleShort (intri[i].index_st[j]); + if (xyz >= numxyz) + { + Con_Printf("%s has an invalid xyz index (%i) on triangle %i, resetting to 0\n", loadmodel->name, xyz, i); + xyz = 0; + } + if (st >= numst) + { + Con_Printf("%s has an invalid st index (%i) on triangle %i, resetting to 0\n", loadmodel->name, st, i); + st = 0; + } + hashindex = (xyz * 256 + st) & 65535; + for (hash = md2verthash[hashindex];hash;hash = hash->next) + if (hash->xyz == xyz && hash->st == st) + break; + if (hash == NULL) + { + hash = md2verthashdata + loadmodel->surfmesh.num_vertices++; + hash->xyz = xyz; + hash->st = st; + hash->next = md2verthash[hashindex]; + md2verthash[hashindex] = hash; + } + loadmodel->surfmesh.data_element3i[i*3+j] = (hash - md2verthashdata); + } + } + + vertremap = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(int)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t)); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)data;data += loadmodel->surfmesh.num_vertices * loadmodel->surfmesh.num_morphframes * sizeof(trivertx_t); + for (i = 0;i < loadmodel->surfmesh.num_vertices;i++) + { + int sts, stt; + hash = md2verthashdata + i; + vertremap[i] = hash->xyz; + sts = LittleShort(inst[hash->st*2+0]); + stt = LittleShort(inst[hash->st*2+1]); + if (sts < 0 || sts >= skinwidth || stt < 0 || stt >= skinheight) + { + Con_Printf("%s has an invalid skin coordinate (%i %i) on vert %i, changing to 0 0\n", loadmodel->name, sts, stt, i); + sts = 0; + stt = 0; + } + loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = sts * iskinwidth; + loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = stt * iskinheight; + } + + Mem_Free(md2verthash); + Mem_Free(md2verthashdata); + + // generate ushort elements array if possible + if (loadmodel->surfmesh.num_vertices <= 65536) + loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + + // load the frames + datapointer = (base + LittleLong(pinmodel->ofs_frames)); + for (i = 0;i < loadmodel->surfmesh.num_morphframes;i++) + { + int k; + trivertx_t *v; + trivertx_t *out; + pinframe = (md2frame_t *)datapointer; + datapointer += sizeof(md2frame_t); + // store the frame scale/translate into the appropriate array + for (j = 0;j < 3;j++) + { + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+j] = LittleFloat(pinframe->scale[j]); + loadmodel->surfmesh.data_morphmd2framesize6f[i*6+3+j] = LittleFloat(pinframe->translate[j]); + } + // convert the vertices + v = (trivertx_t *)datapointer; + out = loadmodel->surfmesh.data_morphmdlvertex + i * loadmodel->surfmesh.num_vertices; + for (k = 0;k < loadmodel->surfmesh.num_vertices;k++) + out[k] = v[vertremap[k]]; + datapointer += numxyz * sizeof(trivertx_t); + + strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name)); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].framerate = 10; + loadmodel->animscenes[i].loop = true; + } + + Mem_Free(vertremap); + + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + Mod_Alias_MorphMesh_CompileFrames(); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + surface = loadmodel->data_surfaces; + surface->texture = loadmodel->data_textures; + surface->num_firsttriangle = 0; + surface->num_triangles = loadmodel->surfmesh.num_triangles; + surface->num_firstvertex = 0; + surface->num_vertices = loadmodel->surfmesh.num_vertices; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, k, version, meshvertices, meshtriangles; + unsigned char *data; + msurface_t *surface; + md3modelheader_t *pinmodel; + md3frameinfo_t *pinframe; + md3mesh_t *pinmesh; + md3tag_t *pintag; + skinfile_t *skinfiles; + + pinmodel = (md3modelheader_t *)buffer; + + if (memcmp(pinmodel->identifier, "IDP3", 4)) + Host_Error ("%s is not a MD3 (IDP3) file", loadmodel->name); + version = LittleLong (pinmodel->version); + if (version != MD3VERSION) + Host_Error ("%s has wrong version number (%i should be %i)", + loadmodel->name, version, MD3VERSION); + + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + + loadmodel->modeldatatypestring = "MD3"; + + loadmodel->type = mod_alias; + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_MD3_AnimateVertices; + loadmodel->synctype = ST_RAND; + // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc) + i = LittleLong (pinmodel->flags); + loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00); + + // set up some global info about the model + loadmodel->numframes = LittleLong(pinmodel->num_frames); + loadmodel->num_surfaces = LittleLong(pinmodel->num_meshes); + + // make skinscenes for the skins (no groups) + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // load frameinfo + loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t)); + for (i = 0, pinframe = (md3frameinfo_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_frameinfo));i < loadmodel->numframes;i++, pinframe++) + { + strlcpy(loadmodel->animscenes[i].name, pinframe->name, sizeof(loadmodel->animscenes[i].name)); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].framerate = 10; + loadmodel->animscenes[i].loop = true; + } + + // load tags + loadmodel->num_tagframes = loadmodel->numframes; + loadmodel->num_tags = LittleLong(pinmodel->num_tags); + loadmodel->data_tags = (aliastag_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_tagframes * loadmodel->num_tags * sizeof(aliastag_t)); + for (i = 0, pintag = (md3tag_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_tags));i < loadmodel->num_tagframes * loadmodel->num_tags;i++, pintag++) + { + strlcpy(loadmodel->data_tags[i].name, pintag->name, sizeof(loadmodel->data_tags[i].name)); + for (j = 0;j < 9;j++) + loadmodel->data_tags[i].matrixgl[j] = LittleFloat(pintag->rotationmatrix[j]); + for (j = 0;j < 3;j++) + loadmodel->data_tags[i].matrixgl[9+j] = LittleFloat(pintag->origin[j]); + //Con_Printf("model \"%s\" frame #%i tag #%i \"%s\"\n", loadmodel->name, i / loadmodel->num_tags, i % loadmodel->num_tags, loadmodel->data_tags[i].name); + } + + // load meshes + meshvertices = 0; + meshtriangles = 0; + for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end))) + { + if (memcmp(pinmesh->identifier, "IDP3", 4)) + Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)"); + if (LittleLong(pinmesh->num_frames) != loadmodel->numframes) + Host_Error("Mod_IDP3_Load: mesh numframes differs from header"); + meshvertices += LittleLong(pinmesh->num_vertices); + meshtriangles += LittleLong(pinmesh->num_triangles); + } + + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * sizeof(float[2]) + meshvertices * loadmodel->numframes * sizeof(md3vertex_t)); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.num_vertices = meshvertices; + loadmodel->surfmesh.num_triangles = meshtriangles; + loadmodel->surfmesh.num_morphframes = loadmodel->numframes; // TODO: remove? + loadmodel->num_poses = loadmodel->surfmesh.num_morphframes; + loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + } + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); + loadmodel->surfmesh.data_morphmd3vertex = (md3vertex_t *)data;data += meshvertices * loadmodel->numframes * sizeof(md3vertex_t); + if (meshvertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); + } + + meshvertices = 0; + meshtriangles = 0; + for (i = 0, pinmesh = (md3mesh_t *)((unsigned char *)pinmodel + LittleLong(pinmodel->lump_meshes));i < loadmodel->num_surfaces;i++, pinmesh = (md3mesh_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_end))) + { + if (memcmp(pinmesh->identifier, "IDP3", 4)) + Host_Error("Mod_IDP3_Load: invalid mesh identifier (not IDP3)"); + loadmodel->sortedmodelsurfaces[i] = i; + surface = loadmodel->data_surfaces + i; + surface->texture = loadmodel->data_textures + i; + surface->num_firsttriangle = meshtriangles; + surface->num_triangles = LittleLong(pinmesh->num_triangles); + surface->num_firstvertex = meshvertices; + surface->num_vertices = LittleLong(pinmesh->num_vertices); + meshvertices += surface->num_vertices; + meshtriangles += surface->num_triangles; + + for (j = 0;j < surface->num_triangles * 3;j++) + loadmodel->surfmesh.data_element3i[j + surface->num_firsttriangle * 3] = surface->num_firstvertex + LittleLong(((int *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_elements)))[j]); + for (j = 0;j < surface->num_vertices;j++) + { + loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 0] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 0]); + loadmodel->surfmesh.data_texcoordtexture2f[(j + surface->num_firstvertex) * 2 + 1] = LittleFloat(((float *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_texcoords)))[j * 2 + 1]); + } + for (j = 0;j < loadmodel->numframes;j++) + { + const md3vertex_t *in = (md3vertex_t *)((unsigned char *)pinmesh + LittleLong(pinmesh->lump_framevertices)) + j * surface->num_vertices; + md3vertex_t *out = loadmodel->surfmesh.data_morphmd3vertex + surface->num_firstvertex + j * loadmodel->surfmesh.num_vertices; + for (k = 0;k < surface->num_vertices;k++, in++, out++) + { + out->origin[0] = LittleShort(in->origin[0]); + out->origin[1] = LittleShort(in->origin[1]); + out->origin[2] = LittleShort(in->origin[2]); + out->pitch = in->pitch; + out->yaw = in->yaw; + } + } + + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, pinmesh->name, LittleLong(pinmesh->num_shaders) >= 1 ? ((md3shader_t *)((unsigned char *) pinmesh + LittleLong(pinmesh->lump_shaders)))->name : ""); + + Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__); + } + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + Mod_Alias_MorphMesh_CompileFrames(); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + Mod_FreeSkinFiles(skinfiles); + Mod_MakeSortedSurfaces(loadmodel); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + zymtype1header_t *pinmodel, *pheader; + unsigned char *pbase; + int i, j, k, numposes, meshvertices, meshtriangles, *bonecount, *vertbonecounts, count, *renderlist, *renderlistend, *outelements; + float modelradius, corner[2], *poses, *intexcoord2f, *outtexcoord2f, *bonepose, f, biggestorigin, tempvec[3], modelscale; + zymvertex_t *verts, *vertdata; + zymscene_t *scene; + zymbone_t *bone; + char *shadername; + skinfile_t *skinfiles; + unsigned char *data; + msurface_t *surface; + + pinmodel = (zymtype1header_t *)buffer; + pbase = (unsigned char *)buffer; + if (memcmp(pinmodel->id, "ZYMOTICMODEL", 12)) + Host_Error ("Mod_ZYMOTICMODEL_Load: %s is not a zymotic model", loadmodel->name); + if (BigLong(pinmodel->type) != 1) + Host_Error ("Mod_ZYMOTICMODEL_Load: only type 1 (skeletal pose) models are currently supported (name = %s)", loadmodel->name); + + loadmodel->modeldatatypestring = "ZYM"; + + loadmodel->type = mod_alias; + loadmodel->synctype = ST_RAND; + + // byteswap header + pheader = pinmodel; + pheader->type = BigLong(pinmodel->type); + pheader->filesize = BigLong(pinmodel->filesize); + pheader->mins[0] = BigFloat(pinmodel->mins[0]); + pheader->mins[1] = BigFloat(pinmodel->mins[1]); + pheader->mins[2] = BigFloat(pinmodel->mins[2]); + pheader->maxs[0] = BigFloat(pinmodel->maxs[0]); + pheader->maxs[1] = BigFloat(pinmodel->maxs[1]); + pheader->maxs[2] = BigFloat(pinmodel->maxs[2]); + pheader->radius = BigFloat(pinmodel->radius); + pheader->numverts = BigLong(pinmodel->numverts); + pheader->numtris = BigLong(pinmodel->numtris); + pheader->numshaders = BigLong(pinmodel->numshaders); + pheader->numbones = BigLong(pinmodel->numbones); + pheader->numscenes = BigLong(pinmodel->numscenes); + pheader->lump_scenes.start = BigLong(pinmodel->lump_scenes.start); + pheader->lump_scenes.length = BigLong(pinmodel->lump_scenes.length); + pheader->lump_poses.start = BigLong(pinmodel->lump_poses.start); + pheader->lump_poses.length = BigLong(pinmodel->lump_poses.length); + pheader->lump_bones.start = BigLong(pinmodel->lump_bones.start); + pheader->lump_bones.length = BigLong(pinmodel->lump_bones.length); + pheader->lump_vertbonecounts.start = BigLong(pinmodel->lump_vertbonecounts.start); + pheader->lump_vertbonecounts.length = BigLong(pinmodel->lump_vertbonecounts.length); + pheader->lump_verts.start = BigLong(pinmodel->lump_verts.start); + pheader->lump_verts.length = BigLong(pinmodel->lump_verts.length); + pheader->lump_texcoords.start = BigLong(pinmodel->lump_texcoords.start); + pheader->lump_texcoords.length = BigLong(pinmodel->lump_texcoords.length); + pheader->lump_render.start = BigLong(pinmodel->lump_render.start); + pheader->lump_render.length = BigLong(pinmodel->lump_render.length); + pheader->lump_shaders.start = BigLong(pinmodel->lump_shaders.start); + pheader->lump_shaders.length = BigLong(pinmodel->lump_shaders.length); + pheader->lump_trizone.start = BigLong(pinmodel->lump_trizone.start); + pheader->lump_trizone.length = BigLong(pinmodel->lump_trizone.length); + + if (pheader->numtris < 1 || pheader->numverts < 3 || pheader->numshaders < 1) + { + Con_Printf("%s has no geometry\n", loadmodel->name); + return; + } + if (pheader->numscenes < 1 || pheader->lump_poses.length < (int)sizeof(float[3][4])) + { + Con_Printf("%s has no animations\n", loadmodel->name); + return; + } + + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; + + loadmodel->numframes = pheader->numscenes; + loadmodel->num_surfaces = pheader->numshaders; + + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + + // make skinscenes for the skins (no groups) + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // model bbox + // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox() + modelradius = pheader->radius; + for (i = 0;i < 3;i++) + { + loadmodel->normalmins[i] = pheader->mins[i]; + loadmodel->normalmaxs[i] = pheader->maxs[i]; + loadmodel->rotatedmins[i] = -modelradius; + loadmodel->rotatedmaxs[i] = modelradius; + } + corner[0] = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0])); + corner[1] = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1])); + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = sqrt(corner[0]*corner[0]+corner[1]*corner[1]); + if (loadmodel->yawmaxs[0] > modelradius) + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelradius; + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -loadmodel->yawmaxs[0]; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; + + // go through the lumps, swapping things + + //zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct) + loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); + scene = (zymscene_t *) (pheader->lump_scenes.start + pbase); + numposes = pheader->lump_poses.length / pheader->numbones / sizeof(float[3][4]); + for (i = 0;i < pheader->numscenes;i++) + { + memcpy(loadmodel->animscenes[i].name, scene->name, 32); + loadmodel->animscenes[i].firstframe = BigLong(scene->start); + loadmodel->animscenes[i].framecount = BigLong(scene->length); + loadmodel->animscenes[i].framerate = BigFloat(scene->framerate); + loadmodel->animscenes[i].loop = (BigLong(scene->flags) & ZYMSCENEFLAG_NOLOOP) == 0; + if ((unsigned int) loadmodel->animscenes[i].firstframe >= (unsigned int) numposes) + Host_Error("%s scene->firstframe (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, numposes); + if ((unsigned int) loadmodel->animscenes[i].firstframe + (unsigned int) loadmodel->animscenes[i].framecount > (unsigned int) numposes) + Host_Error("%s scene->firstframe (%i) + framecount (%i) >= numposes (%i)", loadmodel->name, loadmodel->animscenes[i].firstframe, loadmodel->animscenes[i].framecount, numposes); + if (loadmodel->animscenes[i].framerate < 0) + Host_Error("%s scene->framerate (%f) < 0", loadmodel->name, loadmodel->animscenes[i].framerate); + scene++; + } + + //zymlump_t lump_bones; // zymbone_t bone[numbones]; + loadmodel->num_bones = pheader->numbones; + loadmodel->data_bones = (aliasbone_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(aliasbone_t)); + bone = (zymbone_t *) (pheader->lump_bones.start + pbase); + for (i = 0;i < pheader->numbones;i++) + { + memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name)); + loadmodel->data_bones[i].flags = BigLong(bone[i].flags); + loadmodel->data_bones[i].parent = BigLong(bone[i].parent); + if (loadmodel->data_bones[i].parent >= i) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i); + } + + //zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better) + vertbonecounts = (int *)Mem_Alloc(loadmodel->mempool, pheader->numverts * sizeof(int)); + bonecount = (int *) (pheader->lump_vertbonecounts.start + pbase); + for (i = 0;i < pheader->numverts;i++) + { + vertbonecounts[i] = BigLong(bonecount[i]); + if (vertbonecounts[i] != 1) + Host_Error("%s bonecount[%i] != 1 (vertex weight support is impossible in this format)", loadmodel->name, i); + } + + loadmodel->num_poses = pheader->lump_poses.length / sizeof(float[3][4]) / loadmodel->num_bones; + + meshvertices = pheader->numverts; + meshtriangles = pheader->numtris; + + loadmodel->nummodelsurfaces = loadmodel->num_surfaces; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12])); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.num_vertices = meshvertices; + loadmodel->surfmesh.num_triangles = meshtriangles; + loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + } + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); + loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); + if (loadmodel->surfmesh.num_vertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); + } + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); + loadmodel->surfmesh.data_blendweights = NULL; + + //zymlump_t lump_poses; // float pose[numposes][numbones][3][4]; // animation data + poses = (float *) (pheader->lump_poses.start + pbase); + // figure out scale of model from root bone, for compatibility with old zmodel versions + tempvec[0] = BigFloat(poses[0]); + tempvec[1] = BigFloat(poses[1]); + tempvec[2] = BigFloat(poses[2]); + modelscale = VectorLength(tempvec); + biggestorigin = 0; + for (i = 0;i < loadmodel->num_bones * numposes * 12;i++) + { + f = fabs(BigFloat(poses[i])); + biggestorigin = max(biggestorigin, f); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + for (i = 0;i < numposes;i++) + { + const float *frameposes = (float *) (pheader->lump_poses.start + pbase) + 12*i*loadmodel->num_bones; + for (j = 0;j < loadmodel->num_bones;j++) + { + float pose[12]; + matrix4x4_t posematrix; + for (k = 0;k < 12;k++) + pose[k] = BigFloat(frameposes[j*12+k]); + //if (j < loadmodel->num_bones) + // Con_Printf("%s: bone %i = %f %f %f %f : %f %f %f %f : %f %f %f %f : scale = %f\n", loadmodel->name, j, pose[0], pose[1], pose[2], pose[3], pose[4], pose[5], pose[6], pose[7], pose[8], pose[9], pose[10], pose[11], VectorLength(pose)); + // scale child bones to match the root scale + if (loadmodel->data_bones[j].parent >= 0) + { + pose[3] *= modelscale; + pose[7] *= modelscale; + pose[11] *= modelscale; + } + // normalize rotation matrix + VectorNormalize(pose + 0); + VectorNormalize(pose + 4); + VectorNormalize(pose + 8); + Matrix4x4_FromArray12FloatD3D(&posematrix, pose); + Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j)); + } + } + + //zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct + verts = (zymvertex_t *)Mem_Alloc(loadmodel->mempool, pheader->lump_verts.length); + vertdata = (zymvertex_t *) (pheader->lump_verts.start + pbase); + // reconstruct frame 0 matrices to allow reconstruction of the base mesh + // (converting from weight-blending skeletal animation to + // deformation-based skeletal animation) + bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12])); + for (i = 0;i < loadmodel->num_bones;i++) + { + float m[12]; + for (k = 0;k < 12;k++) + m[k] = BigFloat(poses[i*12+k]); + if (loadmodel->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); + else + for (k = 0;k < 12;k++) + bonepose[12*i+k] = m[k]; + } + for (j = 0;j < pheader->numverts;j++) + { + // this format really should have had a per vertexweight weight value... + // but since it does not, the weighting is completely ignored and + // only one weight is allowed per vertex + int boneindex = BigLong(vertdata[j].bonenum); + const float *m = bonepose + 12 * boneindex; + float relativeorigin[3]; + relativeorigin[0] = BigFloat(vertdata[j].origin[0]); + relativeorigin[1] = BigFloat(vertdata[j].origin[1]); + relativeorigin[2] = BigFloat(vertdata[j].origin[2]); + // transform the vertex bone weight into the base mesh + loadmodel->surfmesh.data_vertex3f[j*3+0] = relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + m[ 3]; + loadmodel->surfmesh.data_vertex3f[j*3+1] = relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + m[ 7]; + loadmodel->surfmesh.data_vertex3f[j*3+2] = relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + m[11]; + // store the weight as the primary weight on this vertex + loadmodel->surfmesh.blends[j] = boneindex; + loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = boneindex; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = 0; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = 0; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = 0; + loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = 255; + loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = 0; + loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = 0; + loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = 0; + } + Z_Free(bonepose); + // normals and tangents are calculated after elements are loaded + + //zymlump_t lump_texcoords; // float texcoords[numvertices][2]; + outtexcoord2f = loadmodel->surfmesh.data_texcoordtexture2f; + intexcoord2f = (float *) (pheader->lump_texcoords.start + pbase); + for (i = 0;i < pheader->numverts;i++) + { + outtexcoord2f[i*2+0] = BigFloat(intexcoord2f[i*2+0]); + // flip T coordinate for OpenGL + outtexcoord2f[i*2+1] = 1 - BigFloat(intexcoord2f[i*2+1]); + } + + //zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation + //loadmodel->alias.zymdata_trizone = Mem_Alloc(loadmodel->mempool, pheader->numtris); + //memcpy(loadmodel->alias.zymdata_trizone, (void *) (pheader->lump_trizone.start + pbase), pheader->numtris); + + //zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model + //zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices) + // byteswap, validate, and swap winding order of tris + count = pheader->numshaders * sizeof(int) + pheader->numtris * sizeof(int[3]); + if (pheader->lump_render.length != count) + Host_Error("%s renderlist is wrong size (%i bytes, should be %i bytes)", loadmodel->name, pheader->lump_render.length, count); + renderlist = (int *) (pheader->lump_render.start + pbase); + renderlistend = (int *) ((unsigned char *) renderlist + pheader->lump_render.length); + meshtriangles = 0; + for (i = 0;i < loadmodel->num_surfaces;i++) + { + int firstvertex, lastvertex; + if (renderlist >= renderlistend) + Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name); + count = BigLong(*renderlist);renderlist++; + if (renderlist + count * 3 > renderlistend || (i == pheader->numshaders - 1 && renderlist + count * 3 != renderlistend)) + Host_Error("%s corrupt renderlist (wrong size)", loadmodel->name); + + loadmodel->sortedmodelsurfaces[i] = i; + surface = loadmodel->data_surfaces + i; + surface->texture = loadmodel->data_textures + i; + surface->num_firsttriangle = meshtriangles; + surface->num_triangles = count; + meshtriangles += surface->num_triangles; + + // load the elements + outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3; + for (j = 0;j < surface->num_triangles;j++, renderlist += 3) + { + outelements[j*3+2] = BigLong(renderlist[0]); + outelements[j*3+1] = BigLong(renderlist[1]); + outelements[j*3+0] = BigLong(renderlist[2]); + } + // validate the elements and find the used vertex range + firstvertex = meshvertices; + lastvertex = 0; + for (j = 0;j < surface->num_triangles * 3;j++) + { + if ((unsigned int)outelements[j] >= (unsigned int)meshvertices) + Host_Error("%s corrupt renderlist (out of bounds index)", loadmodel->name); + firstvertex = min(firstvertex, outelements[j]); + lastvertex = max(lastvertex, outelements[j]); + } + surface->num_firstvertex = firstvertex; + surface->num_vertices = lastvertex + 1 - firstvertex; + + // since zym models do not have named sections, reuse their shader + // name as the section name + shadername = (char *) (pheader->lump_shaders.start + pbase) + i * 32; + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, shadername, shadername); + } + Mod_FreeSkinFiles(skinfiles); + Mem_Free(vertbonecounts); + Mem_Free(verts); + Mod_MakeSortedSurfaces(loadmodel); + + // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); + Mod_BuildBaseBonePoses(); + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + dpmheader_t *pheader; + dpmframe_t *frames; + dpmbone_t *bone; + dpmmesh_t *dpmmesh; + unsigned char *pbase; + int i, j, k, meshvertices, meshtriangles; + skinfile_t *skinfiles; + unsigned char *data; + float *bonepose; + float biggestorigin, tempvec[3], modelscale; + float f; + float *poses; + + pheader = (dpmheader_t *)buffer; + pbase = (unsigned char *)buffer; + if (memcmp(pheader->id, "DARKPLACESMODEL\0", 16)) + Host_Error ("Mod_DARKPLACESMODEL_Load: %s is not a darkplaces model", loadmodel->name); + if (BigLong(pheader->type) != 2) + Host_Error ("Mod_DARKPLACESMODEL_Load: only type 2 (hierarchical skeletal pose) models are currently supported (name = %s)", loadmodel->name); + + loadmodel->modeldatatypestring = "DPM"; + + loadmodel->type = mod_alias; + loadmodel->synctype = ST_RAND; + + // byteswap header + pheader->type = BigLong(pheader->type); + pheader->filesize = BigLong(pheader->filesize); + pheader->mins[0] = BigFloat(pheader->mins[0]); + pheader->mins[1] = BigFloat(pheader->mins[1]); + pheader->mins[2] = BigFloat(pheader->mins[2]); + pheader->maxs[0] = BigFloat(pheader->maxs[0]); + pheader->maxs[1] = BigFloat(pheader->maxs[1]); + pheader->maxs[2] = BigFloat(pheader->maxs[2]); + pheader->yawradius = BigFloat(pheader->yawradius); + pheader->allradius = BigFloat(pheader->allradius); + pheader->num_bones = BigLong(pheader->num_bones); + pheader->num_meshs = BigLong(pheader->num_meshs); + pheader->num_frames = BigLong(pheader->num_frames); + pheader->ofs_bones = BigLong(pheader->ofs_bones); + pheader->ofs_meshs = BigLong(pheader->ofs_meshs); + pheader->ofs_frames = BigLong(pheader->ofs_frames); + + if (pheader->num_bones < 1 || pheader->num_meshs < 1) + { + Con_Printf("%s has no geometry\n", loadmodel->name); + return; + } + if (pheader->num_frames < 1) + { + Con_Printf("%s has no frames\n", loadmodel->name); + return; + } + + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; + + // model bbox + // LordHavoc: actually we blow this away later with Mod_Alias_CalculateBoundingBox() + for (i = 0;i < 3;i++) + { + loadmodel->normalmins[i] = pheader->mins[i]; + loadmodel->normalmaxs[i] = pheader->maxs[i]; + loadmodel->yawmins[i] = i != 2 ? -pheader->yawradius : pheader->mins[i]; + loadmodel->yawmaxs[i] = i != 2 ? pheader->yawradius : pheader->maxs[i]; + loadmodel->rotatedmins[i] = -pheader->allradius; + loadmodel->rotatedmaxs[i] = pheader->allradius; + } + loadmodel->radius = pheader->allradius; + loadmodel->radius2 = pheader->allradius * pheader->allradius; + + // load external .skin files if present + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + + meshvertices = 0; + meshtriangles = 0; + + // gather combined statistics from the meshes + dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs); + for (i = 0;i < (int)pheader->num_meshs;i++) + { + int numverts = BigLong(dpmmesh->num_verts); + meshvertices += numverts; + meshtriangles += BigLong(dpmmesh->num_tris); + dpmmesh++; + } + + loadmodel->numframes = pheader->num_frames; + loadmodel->num_bones = pheader->num_bones; + loadmodel->num_poses = loadmodel->numframes; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces = pheader->num_meshs; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + // do most allocations as one merged chunk + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + sizeof(unsigned short) + sizeof(unsigned char[2][4])) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.num_vertices = meshvertices; + loadmodel->surfmesh.num_triangles = meshtriangles; + loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + } + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); + loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]); + loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t); + loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t); + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); + if (meshvertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); + } + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); + + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // load the bone info + bone = (dpmbone_t *) (pbase + pheader->ofs_bones); + for (i = 0;i < loadmodel->num_bones;i++) + { + memcpy(loadmodel->data_bones[i].name, bone[i].name, sizeof(bone[i].name)); + loadmodel->data_bones[i].flags = BigLong(bone[i].flags); + loadmodel->data_bones[i].parent = BigLong(bone[i].parent); + if (loadmodel->data_bones[i].parent >= i) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i); + } + + // load the frames + frames = (dpmframe_t *) (pbase + pheader->ofs_frames); + // figure out scale of model from root bone, for compatibility with old dpmodel versions + poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions)); + tempvec[0] = BigFloat(poses[0]); + tempvec[1] = BigFloat(poses[1]); + tempvec[2] = BigFloat(poses[2]); + modelscale = VectorLength(tempvec); + biggestorigin = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + memcpy(loadmodel->animscenes[i].name, frames[i].name, sizeof(frames[i].name)); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].loop = true; + loadmodel->animscenes[i].framerate = 10; + // load the bone poses for this frame + poses = (float *) (pbase + BigLong(frames[i].ofs_bonepositions)); + for (j = 0;j < loadmodel->num_bones*12;j++) + { + f = fabs(BigFloat(poses[j])); + biggestorigin = max(biggestorigin, f); + } + // stuff not processed here: mins, maxs, yawradius, allradius + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + for (i = 0;i < loadmodel->numframes;i++) + { + const float *frameposes = (float *) (pbase + BigLong(frames[i].ofs_bonepositions)); + for (j = 0;j < loadmodel->num_bones;j++) + { + float pose[12]; + matrix4x4_t posematrix; + for (k = 0;k < 12;k++) + pose[k] = BigFloat(frameposes[j*12+k]); + // scale child bones to match the root scale + if (loadmodel->data_bones[j].parent >= 0) + { + pose[3] *= modelscale; + pose[7] *= modelscale; + pose[11] *= modelscale; + } + // normalize rotation matrix + VectorNormalize(pose + 0); + VectorNormalize(pose + 4); + VectorNormalize(pose + 8); + Matrix4x4_FromArray12FloatD3D(&posematrix, pose); + Matrix4x4_ToBonePose7s(&posematrix, loadmodel->num_poseinvscale, loadmodel->data_poses7s + 7*(i*loadmodel->num_bones+j)); + } + } + + // load the meshes now + dpmmesh = (dpmmesh_t *) (pbase + pheader->ofs_meshs); + meshvertices = 0; + meshtriangles = 0; + // reconstruct frame 0 matrices to allow reconstruction of the base mesh + // (converting from weight-blending skeletal animation to + // deformation-based skeletal animation) + poses = (float *) (pbase + BigLong(frames[0].ofs_bonepositions)); + bonepose = (float *)Z_Malloc(loadmodel->num_bones * sizeof(float[12])); + for (i = 0;i < loadmodel->num_bones;i++) + { + float m[12]; + for (k = 0;k < 12;k++) + m[k] = BigFloat(poses[i*12+k]); + if (loadmodel->data_bones[i].parent >= 0) + R_ConcatTransforms(bonepose + 12 * loadmodel->data_bones[i].parent, m, bonepose + 12 * i); + else + for (k = 0;k < 12;k++) + bonepose[12*i+k] = m[k]; + } + for (i = 0;i < loadmodel->num_surfaces;i++, dpmmesh++) + { + const int *inelements; + int *outelements; + const float *intexcoord; + msurface_t *surface; + + loadmodel->sortedmodelsurfaces[i] = i; + surface = loadmodel->data_surfaces + i; + surface->texture = loadmodel->data_textures + i; + surface->num_firsttriangle = meshtriangles; + surface->num_triangles = BigLong(dpmmesh->num_tris); + surface->num_firstvertex = meshvertices; + surface->num_vertices = BigLong(dpmmesh->num_verts); + meshvertices += surface->num_vertices; + meshtriangles += surface->num_triangles; + + inelements = (int *) (pbase + BigLong(dpmmesh->ofs_indices)); + outelements = loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3; + for (j = 0;j < surface->num_triangles;j++) + { + // swap element order to flip triangles, because Quake uses clockwise (rare) and dpm uses counterclockwise (standard) + outelements[0] = surface->num_firstvertex + BigLong(inelements[2]); + outelements[1] = surface->num_firstvertex + BigLong(inelements[1]); + outelements[2] = surface->num_firstvertex + BigLong(inelements[0]); + inelements += 3; + outelements += 3; + } + + intexcoord = (float *) (pbase + BigLong(dpmmesh->ofs_texcoords)); + for (j = 0;j < surface->num_vertices*2;j++) + loadmodel->surfmesh.data_texcoordtexture2f[j + surface->num_firstvertex * 2] = BigFloat(intexcoord[j]); + + data = (unsigned char *) (pbase + BigLong(dpmmesh->ofs_verts)); + for (j = surface->num_firstvertex;j < surface->num_firstvertex + surface->num_vertices;j++) + { + int weightindex[4] = { 0, 0, 0, 0 }; + float weightinfluence[4] = { 0, 0, 0, 0 }; + int l; + int numweights = BigLong(((dpmvertex_t *)data)->numbones); + data += sizeof(dpmvertex_t); + for (k = 0;k < numweights;k++) + { + const dpmbonevert_t *vert = (dpmbonevert_t *) data; + int boneindex = BigLong(vert->bonenum); + const float *m = bonepose + 12 * boneindex; + float influence = BigFloat(vert->influence); + float relativeorigin[3], relativenormal[3]; + relativeorigin[0] = BigFloat(vert->origin[0]); + relativeorigin[1] = BigFloat(vert->origin[1]); + relativeorigin[2] = BigFloat(vert->origin[2]); + relativenormal[0] = BigFloat(vert->normal[0]); + relativenormal[1] = BigFloat(vert->normal[1]); + relativenormal[2] = BigFloat(vert->normal[2]); + // blend the vertex bone weights into the base mesh + loadmodel->surfmesh.data_vertex3f[j*3+0] += relativeorigin[0] * m[0] + relativeorigin[1] * m[1] + relativeorigin[2] * m[ 2] + influence * m[ 3]; + loadmodel->surfmesh.data_vertex3f[j*3+1] += relativeorigin[0] * m[4] + relativeorigin[1] * m[5] + relativeorigin[2] * m[ 6] + influence * m[ 7]; + loadmodel->surfmesh.data_vertex3f[j*3+2] += relativeorigin[0] * m[8] + relativeorigin[1] * m[9] + relativeorigin[2] * m[10] + influence * m[11]; + loadmodel->surfmesh.data_normal3f[j*3+0] += relativenormal[0] * m[0] + relativenormal[1] * m[1] + relativenormal[2] * m[ 2]; + loadmodel->surfmesh.data_normal3f[j*3+1] += relativenormal[0] * m[4] + relativenormal[1] * m[5] + relativenormal[2] * m[ 6]; + loadmodel->surfmesh.data_normal3f[j*3+2] += relativenormal[0] * m[8] + relativenormal[1] * m[9] + relativenormal[2] * m[10]; + if (!k) + { + // store the first (and often only) weight + weightinfluence[0] = influence; + weightindex[0] = boneindex; + } + else + { + // sort the new weight into this vertex's weight table + // (which only accepts up to 4 bones per vertex) + for (l = 0;l < 4;l++) + { + if (weightinfluence[l] < influence) + { + // move weaker influence weights out of the way first + int l2; + for (l2 = 3;l2 > l;l2--) + { + weightinfluence[l2] = weightinfluence[l2-1]; + weightindex[l2] = weightindex[l2-1]; + } + // store the new weight + weightinfluence[l] = influence; + weightindex[l] = boneindex; + break; + } + } + } + data += sizeof(dpmbonevert_t); + } + loadmodel->surfmesh.blends[j] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence); + loadmodel->surfmesh.data_skeletalindex4ub[j*4 ] = weightindex[0]; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+1] = weightindex[1]; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+2] = weightindex[2]; + loadmodel->surfmesh.data_skeletalindex4ub[j*4+3] = weightindex[3]; + loadmodel->surfmesh.data_skeletalweight4ub[j*4 ] = (unsigned char)(weightinfluence[0]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[j*4+1] = (unsigned char)(weightinfluence[1]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[j*4+2] = (unsigned char)(weightinfluence[2]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[j*4+3] = (unsigned char)(weightinfluence[3]*255.0f); + } + + // since dpm models do not have named sections, reuse their shader name as the section name + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, dpmmesh->shadername, dpmmesh->shadername); + + Mod_ValidateElements(loadmodel->surfmesh.data_element3i + surface->num_firsttriangle * 3, surface->num_triangles, surface->num_firstvertex, surface->num_vertices, __FILE__, __LINE__); + } + if (loadmodel->surfmesh.num_blends < meshvertices) + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t)); + Z_Free(bonepose); + Mod_FreeSkinFiles(skinfiles); + Mod_MakeSortedSurfaces(loadmodel); + + // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + Mod_BuildBaseBonePoses(); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +// no idea why PSK/PSA files contain weird quaternions but they do... +#define PSKQUATNEGATIONS +void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, index, version, recordsize, numrecords, meshvertices, meshtriangles; + int numpnts, numvtxw, numfaces, nummatts, numbones, numrawweights, numanimbones, numanims, numanimkeys; + fs_offset_t filesize; + pskpnts_t *pnts; + pskvtxw_t *vtxw; + pskface_t *faces; + pskmatt_t *matts; + pskboneinfo_t *bones; + pskrawweights_t *rawweights; + //pskboneinfo_t *animbones; + pskaniminfo_t *anims; + pskanimkeys_t *animkeys; + void *animfilebuffer, *animbuffer, *animbufferend; + unsigned char *data; + pskchunk_t *pchunk; + skinfile_t *skinfiles; + char animname[MAX_QPATH]; + size_t size; + float biggestorigin; + + pchunk = (pskchunk_t *)buffer; + if (strcmp(pchunk->id, "ACTRHEAD")) + Host_Error ("Mod_PSKMODEL_Load: %s is not an Unreal Engine ActorX (.psk + .psa) model", loadmodel->name); + + loadmodel->modeldatatypestring = "PSK"; + + loadmodel->type = mod_alias; + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; + loadmodel->synctype = ST_RAND; + + FS_StripExtension(loadmodel->name, animname, sizeof(animname)); + strlcat(animname, ".psa", sizeof(animname)); + animbuffer = animfilebuffer = FS_LoadFile(animname, loadmodel->mempool, false, &filesize); + animbufferend = (void *)((unsigned char*)animbuffer + (int)filesize); + if (!animbuffer) + animbufferend = animbuffer; + + numpnts = 0; + pnts = NULL; + numvtxw = 0; + vtxw = NULL; + numfaces = 0; + faces = NULL; + nummatts = 0; + matts = NULL; + numbones = 0; + bones = NULL; + numrawweights = 0; + rawweights = NULL; + numanims = 0; + anims = NULL; + numanimkeys = 0; + animkeys = NULL; + + while (buffer < bufferend) + { + pchunk = (pskchunk_t *)buffer; + buffer = (void *)((unsigned char *)buffer + sizeof(pskchunk_t)); + version = LittleLong(pchunk->version); + recordsize = LittleLong(pchunk->recordsize); + numrecords = LittleLong(pchunk->numrecords); + if (developer_extra.integer) + Con_DPrintf("%s: %s %x: %i * %i = %i\n", loadmodel->name, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); + if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0) + Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", loadmodel->name, pchunk->id, version); + if (!strcmp(pchunk->id, "ACTRHEAD")) + { + // nothing to do + } + else if (!strcmp(pchunk->id, "PNTS0000")) + { + pskpnts_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + numpnts = numrecords; + pnts = (pskpnts_t *)buffer; + for (index = 0, p = (pskpnts_t *)buffer;index < numrecords;index++, p++) + { + p->origin[0] = LittleFloat(p->origin[0]); + p->origin[1] = LittleFloat(p->origin[1]); + p->origin[2] = LittleFloat(p->origin[2]); + } + buffer = p; + } + else if (!strcmp(pchunk->id, "VTXW0000")) + { + pskvtxw_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + numvtxw = numrecords; + vtxw = (pskvtxw_t *)buffer; + for (index = 0, p = (pskvtxw_t *)buffer;index < numrecords;index++, p++) + { + p->pntsindex = LittleShort(p->pntsindex); + p->texcoord[0] = LittleFloat(p->texcoord[0]); + p->texcoord[1] = LittleFloat(p->texcoord[1]); + if (p->pntsindex >= numpnts) + { + Con_Printf("%s: vtxw->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts); + p->pntsindex = 0; + } + } + buffer = p; + } + else if (!strcmp(pchunk->id, "FACE0000")) + { + pskface_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + numfaces = numrecords; + faces = (pskface_t *)buffer; + for (index = 0, p = (pskface_t *)buffer;index < numrecords;index++, p++) + { + p->vtxwindex[0] = LittleShort(p->vtxwindex[0]); + p->vtxwindex[1] = LittleShort(p->vtxwindex[1]); + p->vtxwindex[2] = LittleShort(p->vtxwindex[2]); + p->group = LittleLong(p->group); + if (p->vtxwindex[0] >= numvtxw) + { + Con_Printf("%s: face->vtxwindex[0] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[0], numvtxw); + p->vtxwindex[0] = 0; + } + if (p->vtxwindex[1] >= numvtxw) + { + Con_Printf("%s: face->vtxwindex[1] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[1], numvtxw); + p->vtxwindex[1] = 0; + } + if (p->vtxwindex[2] >= numvtxw) + { + Con_Printf("%s: face->vtxwindex[2] %i >= numvtxw %i\n", loadmodel->name, p->vtxwindex[2], numvtxw); + p->vtxwindex[2] = 0; + } + } + buffer = p; + } + else if (!strcmp(pchunk->id, "MATT0000")) + { + pskmatt_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + nummatts = numrecords; + matts = (pskmatt_t *)buffer; + for (index = 0, p = (pskmatt_t *)buffer;index < numrecords;index++, p++) + { + // nothing to do + } + buffer = p; + } + else if (!strcmp(pchunk->id, "REFSKELT")) + { + pskboneinfo_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + numbones = numrecords; + bones = (pskboneinfo_t *)buffer; + for (index = 0, p = (pskboneinfo_t *)buffer;index < numrecords;index++, p++) + { + p->numchildren = LittleLong(p->numchildren); + p->parent = LittleLong(p->parent); + p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]); + p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]); + p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]); + p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]); + p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]); + p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]); + p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]); + p->basepose.unknown = LittleFloat(p->basepose.unknown); + p->basepose.size[0] = LittleFloat(p->basepose.size[0]); + p->basepose.size[1] = LittleFloat(p->basepose.size[1]); + p->basepose.size[2] = LittleFloat(p->basepose.size[2]); +#ifdef PSKQUATNEGATIONS + if (index) + { + p->basepose.quat[0] *= -1; + p->basepose.quat[1] *= -1; + p->basepose.quat[2] *= -1; + } + else + { + p->basepose.quat[0] *= 1; + p->basepose.quat[1] *= -1; + p->basepose.quat[2] *= 1; + } +#endif + if (p->parent < 0 || p->parent >= numbones) + { + Con_Printf("%s: bone->parent %i >= numbones %i\n", loadmodel->name, p->parent, numbones); + p->parent = 0; + } + } + buffer = p; + } + else if (!strcmp(pchunk->id, "RAWWEIGHTS")) + { + pskrawweights_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", loadmodel->name, pchunk->id); + // byteswap in place and keep the pointer + numrawweights = numrecords; + rawweights = (pskrawweights_t *)buffer; + for (index = 0, p = (pskrawweights_t *)buffer;index < numrecords;index++, p++) + { + p->weight = LittleFloat(p->weight); + p->pntsindex = LittleLong(p->pntsindex); + p->boneindex = LittleLong(p->boneindex); + if (p->pntsindex < 0 || p->pntsindex >= numpnts) + { + Con_Printf("%s: weight->pntsindex %i >= numpnts %i\n", loadmodel->name, p->pntsindex, numpnts); + p->pntsindex = 0; + } + if (p->boneindex < 0 || p->boneindex >= numbones) + { + Con_Printf("%s: weight->boneindex %i >= numbones %i\n", loadmodel->name, p->boneindex, numbones); + p->boneindex = 0; + } + } + buffer = p; + } + } + + while (animbuffer < animbufferend) + { + pchunk = (pskchunk_t *)animbuffer; + animbuffer = (void *)((unsigned char *)animbuffer + sizeof(pskchunk_t)); + version = LittleLong(pchunk->version); + recordsize = LittleLong(pchunk->recordsize); + numrecords = LittleLong(pchunk->numrecords); + if (developer_extra.integer) + Con_DPrintf("%s: %s %x: %i * %i = %i\n", animname, pchunk->id, version, recordsize, numrecords, recordsize * numrecords); + if (version != 0x1e83b9 && version != 0x1e9179 && version != 0x2e && version != 0x12f2bc && version != 0x12f2f0) + Con_Printf ("%s: chunk %s has unknown version %x (0x1e83b9, 0x1e9179, 0x2e, 0x12f2bc, 0x12f2f0 are currently supported), trying to load anyway!\n", animname, pchunk->id, version); + if (!strcmp(pchunk->id, "ANIMHEAD")) + { + // nothing to do + } + else if (!strcmp(pchunk->id, "BONENAMES")) + { + pskboneinfo_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id); + // byteswap in place and keep the pointer + numanimbones = numrecords; + //animbones = (pskboneinfo_t *)animbuffer; + // NOTE: supposedly psa does not need to match the psk model, the + // bones missing from the psa would simply use their base + // positions from the psk, but this is hard for me to implement + // and people can easily make animations that match. + if (numanimbones != numbones) + Host_Error("%s: this loader only supports animations with the same bones as the mesh", loadmodel->name); + for (index = 0, p = (pskboneinfo_t *)animbuffer;index < numrecords;index++, p++) + { + p->numchildren = LittleLong(p->numchildren); + p->parent = LittleLong(p->parent); + p->basepose.quat[0] = LittleFloat(p->basepose.quat[0]); + p->basepose.quat[1] = LittleFloat(p->basepose.quat[1]); + p->basepose.quat[2] = LittleFloat(p->basepose.quat[2]); + p->basepose.quat[3] = LittleFloat(p->basepose.quat[3]); + p->basepose.origin[0] = LittleFloat(p->basepose.origin[0]); + p->basepose.origin[1] = LittleFloat(p->basepose.origin[1]); + p->basepose.origin[2] = LittleFloat(p->basepose.origin[2]); + p->basepose.unknown = LittleFloat(p->basepose.unknown); + p->basepose.size[0] = LittleFloat(p->basepose.size[0]); + p->basepose.size[1] = LittleFloat(p->basepose.size[1]); + p->basepose.size[2] = LittleFloat(p->basepose.size[2]); +#ifdef PSKQUATNEGATIONS + if (index) + { + p->basepose.quat[0] *= -1; + p->basepose.quat[1] *= -1; + p->basepose.quat[2] *= -1; + } + else + { + p->basepose.quat[0] *= 1; + p->basepose.quat[1] *= -1; + p->basepose.quat[2] *= 1; + } +#endif + if (p->parent < 0 || p->parent >= numanimbones) + { + Con_Printf("%s: bone->parent %i >= numanimbones %i\n", animname, p->parent, numanimbones); + p->parent = 0; + } + // check that bones are the same as in the base + if (strcmp(p->name, bones[index].name) || p->parent != bones[index].parent) + Host_Error("%s: this loader only supports animations with the same bones as the mesh", animname); + } + animbuffer = p; + } + else if (!strcmp(pchunk->id, "ANIMINFO")) + { + pskaniminfo_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id); + // byteswap in place and keep the pointer + numanims = numrecords; + anims = (pskaniminfo_t *)animbuffer; + for (index = 0, p = (pskaniminfo_t *)animbuffer;index < numrecords;index++, p++) + { + p->numbones = LittleLong(p->numbones); + p->playtime = LittleFloat(p->playtime); + p->fps = LittleFloat(p->fps); + p->firstframe = LittleLong(p->firstframe); + p->numframes = LittleLong(p->numframes); + if (p->numbones != numbones) + Con_Printf("%s: animinfo->numbones != numbones, trying to load anyway!\n", animname); + } + animbuffer = p; + } + else if (!strcmp(pchunk->id, "ANIMKEYS")) + { + pskanimkeys_t *p; + if (recordsize != sizeof(*p)) + Host_Error("%s: %s has unsupported recordsize", animname, pchunk->id); + numanimkeys = numrecords; + animkeys = (pskanimkeys_t *)animbuffer; + for (index = 0, p = (pskanimkeys_t *)animbuffer;index < numrecords;index++, p++) + { + p->origin[0] = LittleFloat(p->origin[0]); + p->origin[1] = LittleFloat(p->origin[1]); + p->origin[2] = LittleFloat(p->origin[2]); + p->quat[0] = LittleFloat(p->quat[0]); + p->quat[1] = LittleFloat(p->quat[1]); + p->quat[2] = LittleFloat(p->quat[2]); + p->quat[3] = LittleFloat(p->quat[3]); + p->frametime = LittleFloat(p->frametime); +#ifdef PSKQUATNEGATIONS + if (index % numbones) + { + p->quat[0] *= -1; + p->quat[1] *= -1; + p->quat[2] *= -1; + } + else + { + p->quat[0] *= 1; + p->quat[1] *= -1; + p->quat[2] *= 1; + } +#endif + } + animbuffer = p; + // TODO: allocate bonepose stuff + } + else + Con_Printf("%s: unknown chunk ID \"%s\"\n", animname, pchunk->id); + } + + if (!numpnts || !pnts || !numvtxw || !vtxw || !numfaces || !faces || !nummatts || !matts || !numbones || !bones || !numrawweights || !rawweights) + Host_Error("%s: missing required chunks", loadmodel->name); + + if (numanims) + { + loadmodel->numframes = 0; + for (index = 0;index < numanims;index++) + loadmodel->numframes += anims[index].numframes; + if (numanimkeys != numbones * loadmodel->numframes) + Host_Error("%s: %s has incorrect number of animation keys", animname, pchunk->id); + } + else + loadmodel->numframes = loadmodel->num_poses = 1; + + meshvertices = numvtxw; + meshtriangles = numfaces; + + // load external .skin files if present + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + loadmodel->num_bones = numbones; + loadmodel->num_poses = loadmodel->numframes; + loadmodel->nummodelsurfaces = loadmodel->num_surfaces = nummatts; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + loadmodel->surfmesh.num_vertices = meshvertices; + loadmodel->surfmesh.num_triangles = meshtriangles; + // do most allocations as one merged chunk + size = loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolumes.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[3]) + loadmodel->surfmesh.num_vertices * sizeof(float[2]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]) + loadmodel->surfmesh.num_vertices * sizeof(unsigned short) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t) + ((loadmodel->surfmesh.num_vertices <= 65536) ? (loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3])) : 0); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, size); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + } + loadmodel->surfmesh.data_vertex3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]); + loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t); + loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t); + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); + if (loadmodel->surfmesh.num_vertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); + } + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(blendweights_t)); + + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // create surfaces + for (index = 0, i = 0;index < nummatts;index++) + { + // since psk models do not have named sections, reuse their shader name as the section name + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + index, skinfiles, matts[index].name, matts[index].name); + loadmodel->sortedmodelsurfaces[index] = index; + loadmodel->data_surfaces[index].texture = loadmodel->data_textures + index; + loadmodel->data_surfaces[index].num_firstvertex = 0; + loadmodel->data_surfaces[index].num_vertices = loadmodel->surfmesh.num_vertices; + } + + // copy over the vertex locations and texcoords + for (index = 0;index < numvtxw;index++) + { + loadmodel->surfmesh.data_vertex3f[index*3+0] = pnts[vtxw[index].pntsindex].origin[0]; + loadmodel->surfmesh.data_vertex3f[index*3+1] = pnts[vtxw[index].pntsindex].origin[1]; + loadmodel->surfmesh.data_vertex3f[index*3+2] = pnts[vtxw[index].pntsindex].origin[2]; + loadmodel->surfmesh.data_texcoordtexture2f[index*2+0] = vtxw[index].texcoord[0]; + loadmodel->surfmesh.data_texcoordtexture2f[index*2+1] = vtxw[index].texcoord[1]; + } + + // loading the faces is complicated because we need to sort them into surfaces by mattindex + for (index = 0;index < numfaces;index++) + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++; + for (index = 0, i = 0;index < nummatts;index++) + { + loadmodel->data_surfaces[index].num_firsttriangle = i; + i += loadmodel->data_surfaces[index].num_triangles; + loadmodel->data_surfaces[index].num_triangles = 0; + } + for (index = 0;index < numfaces;index++) + { + i = (loadmodel->data_surfaces[faces[index].mattindex].num_firsttriangle + loadmodel->data_surfaces[faces[index].mattindex].num_triangles++)*3; + loadmodel->surfmesh.data_element3i[i+0] = faces[index].vtxwindex[0]; + loadmodel->surfmesh.data_element3i[i+1] = faces[index].vtxwindex[1]; + loadmodel->surfmesh.data_element3i[i+2] = faces[index].vtxwindex[2]; + } + + // copy over the bones + for (index = 0;index < numbones;index++) + { + strlcpy(loadmodel->data_bones[index].name, bones[index].name, sizeof(loadmodel->data_bones[index].name)); + loadmodel->data_bones[index].parent = (index || bones[index].parent > 0) ? bones[index].parent : -1; + if (loadmodel->data_bones[index].parent >= index) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, index, index); + } + + // convert the basepose data + if (loadmodel->num_bones) + { + int boneindex; + matrix4x4_t *basebonepose; + float *outinvmatrix = loadmodel->data_baseboneposeinverse; + matrix4x4_t bonematrix; + matrix4x4_t tempbonematrix; + basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t)); + for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++) + { + Matrix4x4_FromOriginQuat(&bonematrix, bones[boneindex].basepose.origin[0], bones[boneindex].basepose.origin[1], bones[boneindex].basepose.origin[2], bones[boneindex].basepose.quat[0], bones[boneindex].basepose.quat[1], bones[boneindex].basepose.quat[2], bones[boneindex].basepose.quat[3]); + if (loadmodel->data_bones[boneindex].parent >= 0) + { + tempbonematrix = bonematrix; + Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix); + } + basebonepose[boneindex] = bonematrix; + Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex); + Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex); + } + Mem_Free(basebonepose); + } + + // sort the psk point weights into the vertex weight tables + // (which only accept up to 4 bones per vertex) + for (index = 0;index < numvtxw;index++) + { + int weightindex[4] = { 0, 0, 0, 0 }; + float weightinfluence[4] = { 0, 0, 0, 0 }; + int l; + for (j = 0;j < numrawweights;j++) + { + if (rawweights[j].pntsindex == vtxw[index].pntsindex) + { + int boneindex = rawweights[j].boneindex; + float influence = rawweights[j].weight; + for (l = 0;l < 4;l++) + { + if (weightinfluence[l] < influence) + { + // move lower influence weights out of the way first + int l2; + for (l2 = 3;l2 > l;l2--) + { + weightinfluence[l2] = weightinfluence[l2-1]; + weightindex[l2] = weightindex[l2-1]; + } + // store the new weight + weightinfluence[l] = influence; + weightindex[l] = boneindex; + break; + } + } + } + } + loadmodel->surfmesh.blends[index] = Mod_Skeletal_CompressBlend(loadmodel, weightindex, weightinfluence); + loadmodel->surfmesh.data_skeletalindex4ub[index*4 ] = weightindex[0]; + loadmodel->surfmesh.data_skeletalindex4ub[index*4+1] = weightindex[1]; + loadmodel->surfmesh.data_skeletalindex4ub[index*4+2] = weightindex[2]; + loadmodel->surfmesh.data_skeletalindex4ub[index*4+3] = weightindex[3]; + loadmodel->surfmesh.data_skeletalweight4ub[index*4 ] = (unsigned char)(weightinfluence[0]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[index*4+1] = (unsigned char)(weightinfluence[1]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[index*4+2] = (unsigned char)(weightinfluence[2]*255.0f); + loadmodel->surfmesh.data_skeletalweight4ub[index*4+3] = (unsigned char)(weightinfluence[3]*255.0f); + } + if (loadmodel->surfmesh.num_blends < loadmodel->surfmesh.num_vertices) + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Realloc(loadmodel->mempool, loadmodel->surfmesh.data_blendweights, loadmodel->surfmesh.num_blends * sizeof(blendweights_t)); + + // set up the animscenes based on the anims + if (numanims) + { + for (index = 0, i = 0;index < numanims;index++) + { + for (j = 0;j < anims[index].numframes;j++, i++) + { + dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "%s_%d", anims[index].name, j); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].loop = true; + loadmodel->animscenes[i].framerate = anims[index].fps; + } + } + // calculate the scaling value for bone origins so they can be compressed to short + biggestorigin = 0; + for (index = 0;index < numanimkeys;index++) + { + pskanimkeys_t *k = animkeys + index; + biggestorigin = max(biggestorigin, fabs(k->origin[0])); + biggestorigin = max(biggestorigin, fabs(k->origin[1])); + biggestorigin = max(biggestorigin, fabs(k->origin[2])); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + + // load the poses from the animkeys + for (index = 0;index < numanimkeys;index++) + { + pskanimkeys_t *k = animkeys + index; + float quat[4]; + Vector4Copy(k->quat, quat); + if (quat[3] > 0) + Vector4Negate(quat, quat); + Vector4Normalize2(quat, quat); + // compress poses to the short[7] format for longterm storage + loadmodel->data_poses7s[index*7+0] = k->origin[0] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+1] = k->origin[1] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+2] = k->origin[2] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f; + loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f; + loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f; + loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f; + } + } + else + { + strlcpy(loadmodel->animscenes[0].name, "base", sizeof(loadmodel->animscenes[0].name)); + loadmodel->animscenes[0].firstframe = 0; + loadmodel->animscenes[0].framecount = 1; + loadmodel->animscenes[0].loop = true; + loadmodel->animscenes[0].framerate = 10; + + // calculate the scaling value for bone origins so they can be compressed to short + biggestorigin = 0; + for (index = 0;index < numbones;index++) + { + pskboneinfo_t *p = bones + index; + biggestorigin = max(biggestorigin, fabs(p->basepose.origin[0])); + biggestorigin = max(biggestorigin, fabs(p->basepose.origin[1])); + biggestorigin = max(biggestorigin, fabs(p->basepose.origin[2])); + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + + // load the basepose as a frame + for (index = 0;index < numbones;index++) + { + pskboneinfo_t *p = bones + index; + float quat[4]; + Vector4Copy(p->basepose.quat, quat); + if (quat[3] > 0) + Vector4Negate(quat, quat); + Vector4Normalize2(quat, quat); + // compress poses to the short[7] format for longterm storage + loadmodel->data_poses7s[index*7+0] = p->basepose.origin[0] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+1] = p->basepose.origin[1] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+2] = p->basepose.origin[2] * loadmodel->num_poseinvscale; + loadmodel->data_poses7s[index*7+3] = quat[0] * 32767.0f; + loadmodel->data_poses7s[index*7+4] = quat[1] * 32767.0f; + loadmodel->data_poses7s[index*7+5] = quat[2] * 32767.0f; + loadmodel->data_poses7s[index*7+6] = quat[3] * 32767.0f; + } + } + + Mod_FreeSkinFiles(skinfiles); + if (animfilebuffer) + Mem_Free(animfilebuffer); + Mod_MakeSortedSurfaces(loadmodel); + + // compute all the mesh information that was not loaded from the file + // TODO: honor smoothing groups somehow? + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox(); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + if (!loadmodel->surfmesh.isanimated) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} + +void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + unsigned char *data; + const char *text; + const unsigned char *pbase, *pend; + iqmheader_t header; + skinfile_t *skinfiles; + int i, j, k, meshvertices, meshtriangles; + float biggestorigin; + const unsigned int *inelements; + int *outelements; + const int *inneighbors; + int *outneighbors; + float *outvertex, *outnormal, *outtexcoord, *outsvector, *outtvector, *outcolor; + // this pointers into the file data are read only through Little* functions so they can be unaligned memory + const float *vnormal = NULL; + const float *vposition = NULL; + const float *vtangent = NULL; + const float *vtexcoord = NULL; + const float *vcolor4f = NULL; + const unsigned char *vblendindexes = NULL; + const unsigned char *vblendweights = NULL; + const unsigned char *vcolor4ub = NULL; + const unsigned short *framedata = NULL; + // temporary memory allocations (because the data in the file may be misaligned) + iqmanim_t *anims = NULL; + iqmbounds_t *bounds = NULL; + iqmjoint1_t *joint1 = NULL; + iqmjoint_t *joint = NULL; + iqmmesh_t *meshes = NULL; + iqmpose1_t *pose1 = NULL; + iqmpose_t *pose = NULL; + iqmvertexarray_t *vas = NULL; + + pbase = (unsigned char *)buffer; + pend = (unsigned char *)bufferend; + + if (pbase + sizeof(iqmheader_t) > pend) + Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model %d", loadmodel->name, (int)(pend - pbase)); + + // copy struct (otherwise it may be misaligned) + // LordHavoc: okay it's definitely not misaligned here, but for consistency... + memcpy(&header, pbase, sizeof(iqmheader_t)); + + if (memcmp(header.id, "INTERQUAKEMODEL", 16)) + Host_Error ("Mod_INTERQUAKEMODEL_Load: %s is not an Inter-Quake Model", loadmodel->name); + if (LittleLong(header.version) != 1 && LittleLong(header.version) != 2) + Host_Error ("Mod_INTERQUAKEMODEL_Load: only version 1 and 2 models are currently supported (name = %s)", loadmodel->name); + + loadmodel->modeldatatypestring = "IQM"; + + loadmodel->type = mod_alias; + loadmodel->synctype = ST_RAND; + + // byteswap header + header.version = LittleLong(header.version); + header.filesize = LittleLong(header.filesize); + header.flags = LittleLong(header.flags); + header.num_text = LittleLong(header.num_text); + header.ofs_text = LittleLong(header.ofs_text); + header.num_meshes = LittleLong(header.num_meshes); + header.ofs_meshes = LittleLong(header.ofs_meshes); + header.num_vertexarrays = LittleLong(header.num_vertexarrays); + header.num_vertexes = LittleLong(header.num_vertexes); + header.ofs_vertexarrays = LittleLong(header.ofs_vertexarrays); + header.num_triangles = LittleLong(header.num_triangles); + header.ofs_triangles = LittleLong(header.ofs_triangles); + header.ofs_neighbors = LittleLong(header.ofs_neighbors); + header.num_joints = LittleLong(header.num_joints); + header.ofs_joints = LittleLong(header.ofs_joints); + header.num_poses = LittleLong(header.num_poses); + header.ofs_poses = LittleLong(header.ofs_poses); + header.num_anims = LittleLong(header.num_anims); + header.ofs_anims = LittleLong(header.ofs_anims); + header.num_frames = LittleLong(header.num_frames); + header.num_framechannels = LittleLong(header.num_framechannels); + header.ofs_frames = LittleLong(header.ofs_frames); + header.ofs_bounds = LittleLong(header.ofs_bounds); + header.num_comment = LittleLong(header.num_comment); + header.ofs_comment = LittleLong(header.ofs_comment); + header.num_extensions = LittleLong(header.num_extensions); + header.ofs_extensions = LittleLong(header.ofs_extensions); + + if (header.version == 1) + { + if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint1_t) > pend || + pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose1_t) > pend) + { + Con_Printf("%s has invalid size or offset information\n", loadmodel->name); + return; + } + } + else + { + if (pbase + header.ofs_joints + header.num_joints*sizeof(iqmjoint_t) > pend || + pbase + header.ofs_poses + header.num_poses*sizeof(iqmpose_t) > pend) + { + Con_Printf("%s has invalid size or offset information\n", loadmodel->name); + return; + } + } + if (pbase + header.ofs_text + header.num_text > pend || + pbase + header.ofs_meshes + header.num_meshes*sizeof(iqmmesh_t) > pend || + pbase + header.ofs_vertexarrays + header.num_vertexarrays*sizeof(iqmvertexarray_t) > pend || + pbase + header.ofs_triangles + header.num_triangles*sizeof(int[3]) > pend || + (header.ofs_neighbors && pbase + header.ofs_neighbors + header.num_triangles*sizeof(int[3]) > pend) || + pbase + header.ofs_anims + header.num_anims*sizeof(iqmanim_t) > pend || + pbase + header.ofs_frames + header.num_frames*header.num_framechannels*sizeof(unsigned short) > pend || + (header.ofs_bounds && pbase + header.ofs_bounds + header.num_frames*sizeof(iqmbounds_t) > pend) || + pbase + header.ofs_comment + header.num_comment > pend) + { + Con_Printf("%s has invalid size or offset information\n", loadmodel->name); + return; + } + + // copy structs to make them aligned in memory (otherwise we crash on Sparc and PowerPC and others) + if (header.num_vertexarrays) + vas = (iqmvertexarray_t *)(pbase + header.ofs_vertexarrays); + if (header.num_anims) + anims = (iqmanim_t *)(pbase + header.ofs_anims); + if (header.ofs_bounds) + bounds = (iqmbounds_t *)(pbase + header.ofs_bounds); + if (header.num_meshes) + meshes = (iqmmesh_t *)(pbase + header.ofs_meshes); + + for (i = 0;i < (int)header.num_vertexarrays;i++) + { + iqmvertexarray_t va; + size_t vsize; + va.type = LittleLong(vas[i].type); + va.flags = LittleLong(vas[i].flags); + va.format = LittleLong(vas[i].format); + va.size = LittleLong(vas[i].size); + va.offset = LittleLong(vas[i].offset); + vsize = header.num_vertexes*va.size; + switch (va.format) + { + case IQM_FLOAT: vsize *= sizeof(float); break; + case IQM_UBYTE: vsize *= sizeof(unsigned char); break; + default: continue; + } + if (pbase + va.offset + vsize > pend) + continue; + // no need to copy the vertex data for alignment because LittleLong/LittleShort will be invoked on reading them, and the destination is aligned + switch (va.type) + { + case IQM_POSITION: + if (va.format == IQM_FLOAT && va.size == 3) + vposition = (const float *)(pbase + va.offset); + break; + case IQM_TEXCOORD: + if (va.format == IQM_FLOAT && va.size == 2) + vtexcoord = (const float *)(pbase + va.offset); + break; + case IQM_NORMAL: + if (va.format == IQM_FLOAT && va.size == 3) + vnormal = (const float *)(pbase + va.offset); + break; + case IQM_TANGENT: + if (va.format == IQM_FLOAT && va.size == 4) + vtangent = (const float *)(pbase + va.offset); + break; + case IQM_BLENDINDEXES: + if (va.format == IQM_UBYTE && va.size == 4) + vblendindexes = (const unsigned char *)(pbase + va.offset); + break; + case IQM_BLENDWEIGHTS: + if (va.format == IQM_UBYTE && va.size == 4) + vblendweights = (const unsigned char *)(pbase + va.offset); + break; + case IQM_COLOR: + if (va.format == IQM_FLOAT && va.size == 4) + vcolor4f = (const float *)(pbase + va.offset); + if (va.format == IQM_UBYTE && va.size == 4) + vcolor4ub = (const unsigned char *)(pbase + va.offset); + break; + } + } + if (header.num_vertexes > 0 && (!vposition || !vtexcoord || ((header.num_frames > 0 || header.num_anims > 0) && (!vblendindexes || !vblendweights)))) + { + Con_Printf("%s is missing vertex array data\n", loadmodel->name); + return; + } + + text = header.num_text && header.ofs_text ? (const char *)(pbase + header.ofs_text) : ""; + + loadmodel->DrawSky = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox; + loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine; + loadmodel->PointSuperContents = NULL; + loadmodel->AnimateVertices = Mod_Skeletal_AnimateVertices; + + // load external .skin files if present + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + + loadmodel->numframes = max(header.num_anims, 1); + loadmodel->num_bones = header.num_joints; + loadmodel->num_poses = max(header.num_frames, 1); + loadmodel->nummodelsurfaces = loadmodel->num_surfaces = header.num_meshes; + loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins; + loadmodel->num_texturesperskin = loadmodel->num_surfaces; + + meshvertices = header.num_vertexes; + meshtriangles = header.num_triangles; + + // do most allocations as one merged chunk + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + meshtriangles * sizeof(int[3]) + (meshvertices <= 65536 ? meshtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? meshtriangles * sizeof(int[3]) : 0) + meshvertices * (sizeof(float[14]) + (vcolor4f || vcolor4ub ? sizeof(float[4]) : 0)) + (vblendindexes && vblendweights ? meshvertices * (sizeof(unsigned short) + sizeof(unsigned char[2][4])) : 0) + loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]) + loadmodel->num_bones * sizeof(float[12]) + loadmodel->numskins * sizeof(animscene_t) + loadmodel->num_bones * sizeof(aliasbone_t) + loadmodel->numframes * sizeof(animscene_t)); + loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.num_vertices = meshvertices; + loadmodel->surfmesh.num_triangles = meshtriangles; + loadmodel->surfmesh.data_element3i = (int *)data;data += meshtriangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + { + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += meshtriangles * sizeof(int[3]); + } + loadmodel->surfmesh.data_vertex3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += meshvertices * sizeof(float[3]); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += meshvertices * sizeof(float[2]); + if (vcolor4f || vcolor4ub) + { + loadmodel->surfmesh.data_lightmapcolor4f = (float *)data;data += meshvertices * sizeof(float[4]); + } + if (vblendindexes && vblendweights) + { + loadmodel->surfmesh.data_skeletalindex4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.data_skeletalweight4ub = (unsigned char *)data;data += meshvertices * sizeof(unsigned char[4]); + } + loadmodel->data_baseboneposeinverse = (float *)data;data += loadmodel->num_bones * sizeof(float[12]); + loadmodel->skinscenes = (animscene_t *)data;data += loadmodel->numskins * sizeof(animscene_t); + loadmodel->data_bones = (aliasbone_t *)data;data += loadmodel->num_bones * sizeof(aliasbone_t); + loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); + if (vblendindexes && vblendweights) + { + loadmodel->surfmesh.num_blends = 0; + loadmodel->surfmesh.blends = (unsigned short *)data;data += meshvertices * sizeof(unsigned short); + } + if (meshvertices <= 65536) + { + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += meshtriangles * sizeof(unsigned short[3]); + } + loadmodel->data_poses7s = (short *)data;data += loadmodel->num_poses * loadmodel->num_bones * sizeof(short[7]); + if (vblendindexes && vblendweights) + loadmodel->surfmesh.data_blendweights = (blendweights_t *)Mem_Alloc(loadmodel->mempool, meshvertices * sizeof(blendweights_t)); + + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + // load the bone info + if (header.version == 1) + { + iqmjoint1_t *injoint1 = (iqmjoint1_t *)(pbase + header.ofs_joints); + if (loadmodel->num_bones) + joint1 = (iqmjoint1_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint1_t)); + for (i = 0;i < loadmodel->num_bones;i++) + { + matrix4x4_t relbase, relinvbase, pinvbase, invbase; + joint1[i].name = LittleLong(injoint1[i].name); + joint1[i].parent = LittleLong(injoint1[i].parent); + for (j = 0;j < 3;j++) + { + joint1[i].origin[j] = LittleFloat(injoint1[i].origin[j]); + joint1[i].rotation[j] = LittleFloat(injoint1[i].rotation[j]); + joint1[i].scale[j] = LittleFloat(injoint1[i].scale[j]); + } + strlcpy(loadmodel->data_bones[i].name, &text[joint1[i].name], sizeof(loadmodel->data_bones[i].name)); + loadmodel->data_bones[i].parent = joint1[i].parent; + if (loadmodel->data_bones[i].parent >= i) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i); + Matrix4x4_FromDoom3Joint(&relbase, joint1[i].origin[0], joint1[i].origin[1], joint1[i].origin[2], joint1[i].rotation[0], joint1[i].rotation[1], joint1[i].rotation[2]); + Matrix4x4_Invert_Simple(&relinvbase, &relbase); + if (loadmodel->data_bones[i].parent >= 0) + { + Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent); + Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase); + Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i); + } + else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i); + } + } + else + { + iqmjoint_t *injoint = (iqmjoint_t *)(pbase + header.ofs_joints); + if (header.num_joints) + joint = (iqmjoint_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_bones * sizeof(iqmjoint_t)); + for (i = 0;i < loadmodel->num_bones;i++) + { + matrix4x4_t relbase, relinvbase, pinvbase, invbase; + joint[i].name = LittleLong(injoint[i].name); + joint[i].parent = LittleLong(injoint[i].parent); + for (j = 0;j < 3;j++) + { + joint[i].origin[j] = LittleFloat(injoint[i].origin[j]); + joint[i].rotation[j] = LittleFloat(injoint[i].rotation[j]); + joint[i].scale[j] = LittleFloat(injoint[i].scale[j]); + } + joint[i].rotation[3] = LittleFloat(injoint[i].rotation[3]); + strlcpy(loadmodel->data_bones[i].name, &text[joint[i].name], sizeof(loadmodel->data_bones[i].name)); + loadmodel->data_bones[i].parent = joint[i].parent; + if (loadmodel->data_bones[i].parent >= i) + Host_Error("%s bone[%i].parent >= %i", loadmodel->name, i, i); + if (joint[i].rotation[3] > 0) + Vector4Negate(joint[i].rotation, joint[i].rotation); + Vector4Normalize2(joint[i].rotation, joint[i].rotation); + Matrix4x4_FromDoom3Joint(&relbase, joint[i].origin[0], joint[i].origin[1], joint[i].origin[2], joint[i].rotation[0], joint[i].rotation[1], joint[i].rotation[2]); + Matrix4x4_Invert_Simple(&relinvbase, &relbase); + if (loadmodel->data_bones[i].parent >= 0) + { + Matrix4x4_FromArray12FloatD3D(&pinvbase, loadmodel->data_baseboneposeinverse + 12*loadmodel->data_bones[i].parent); + Matrix4x4_Concat(&invbase, &relinvbase, &pinvbase); + Matrix4x4_ToArray12FloatD3D(&invbase, loadmodel->data_baseboneposeinverse + 12*i); + } + else Matrix4x4_ToArray12FloatD3D(&relinvbase, loadmodel->data_baseboneposeinverse + 12*i); + } + } + + // set up the animscenes based on the anims + for (i = 0;i < (int)header.num_anims;i++) + { + iqmanim_t anim; + anim.name = LittleLong(anims[i].name); + anim.first_frame = LittleLong(anims[i].first_frame); + anim.num_frames = LittleLong(anims[i].num_frames); + anim.framerate = LittleFloat(anims[i].framerate); + anim.flags = LittleLong(anims[i].flags); + strlcpy(loadmodel->animscenes[i].name, &text[anim.name], sizeof(loadmodel->animscenes[i].name)); + loadmodel->animscenes[i].firstframe = anim.first_frame; + loadmodel->animscenes[i].framecount = anim.num_frames; + loadmodel->animscenes[i].loop = ((anim.flags & IQM_LOOP) != 0); + loadmodel->animscenes[i].framerate = anim.framerate; + } + if (header.num_anims <= 0) + { + strlcpy(loadmodel->animscenes[0].name, "static", sizeof(loadmodel->animscenes[0].name)); + loadmodel->animscenes[0].firstframe = 0; + loadmodel->animscenes[0].framecount = 1; + loadmodel->animscenes[0].loop = true; + loadmodel->animscenes[0].framerate = 10; + } + + loadmodel->surfmesh.isanimated = loadmodel->num_bones > 1 || loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); + if(mod_alias_force_animated.string[0]) + loadmodel->surfmesh.isanimated = mod_alias_force_animated.integer != 0; + + biggestorigin = 0; + if (header.version == 1) + { + iqmpose1_t *inpose1 = (iqmpose1_t *)(pbase + header.ofs_poses); + if (header.num_poses) + pose1 = (iqmpose1_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose1_t)); + for (i = 0;i < (int)header.num_poses;i++) + { + float f; + pose1[i].parent = LittleLong(inpose1[i].parent); + pose1[i].channelmask = LittleLong(inpose1[i].channelmask); + for (j = 0;j < 9;j++) + { + pose1[i].channeloffset[j] = LittleFloat(inpose1[i].channeloffset[j]); + pose1[i].channelscale[j] = LittleFloat(inpose1[i].channelscale[j]); + } + f = fabs(pose1[i].channeloffset[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose1[i].channeloffset[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose1[i].channeloffset[2]); biggestorigin = max(biggestorigin, f); + f = fabs(pose1[i].channeloffset[0] + 0xFFFF*pose1[i].channelscale[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose1[i].channeloffset[1] + 0xFFFF*pose1[i].channelscale[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose1[i].channeloffset[2] + 0xFFFF*pose1[i].channelscale[2]); biggestorigin = max(biggestorigin, f); + } + if (header.num_frames <= 0) + { + for (i = 0;i < loadmodel->num_bones;i++) + { + float f; + f = fabs(joint1[i].origin[0]); biggestorigin = max(biggestorigin, f); + f = fabs(joint1[i].origin[1]); biggestorigin = max(biggestorigin, f); + f = fabs(joint1[i].origin[2]); biggestorigin = max(biggestorigin, f); + } + } + } + else + { + iqmpose_t *inpose = (iqmpose_t *)(pbase + header.ofs_poses); + if (header.num_poses) + pose = (iqmpose_t *)Mem_Alloc(loadmodel->mempool, header.num_poses * sizeof(iqmpose_t)); + for (i = 0;i < (int)header.num_poses;i++) + { + float f; + pose[i].parent = LittleLong(inpose[i].parent); + pose[i].channelmask = LittleLong(inpose[i].channelmask); + for (j = 0;j < 10;j++) + { + pose[i].channeloffset[j] = LittleFloat(inpose[i].channeloffset[j]); + pose[i].channelscale[j] = LittleFloat(inpose[i].channelscale[j]); + } + f = fabs(pose[i].channeloffset[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[2]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[0] + 0xFFFF*pose[i].channelscale[0]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[1] + 0xFFFF*pose[i].channelscale[1]); biggestorigin = max(biggestorigin, f); + f = fabs(pose[i].channeloffset[2] + 0xFFFF*pose[i].channelscale[2]); biggestorigin = max(biggestorigin, f); + } + if (header.num_frames <= 0) + { + for (i = 0;i < loadmodel->num_bones;i++) + { + float f; + f = fabs(joint[i].origin[0]); biggestorigin = max(biggestorigin, f); + f = fabs(joint[i].origin[1]); biggestorigin = max(biggestorigin, f); + f = fabs(joint[i].origin[2]); biggestorigin = max(biggestorigin, f); + } + } + } + loadmodel->num_posescale = biggestorigin / 32767.0f; + loadmodel->num_poseinvscale = 1.0f / loadmodel->num_posescale; + + // load the pose data + // this unaligned memory access is safe (LittleShort reads as bytes) + framedata = (const unsigned short *)(pbase + header.ofs_frames); + if (header.version == 1) + { + for (i = 0, k = 0;i < (int)header.num_frames;i++) + { + for (j = 0;j < (int)header.num_poses;j++, k++) + { + float qx, qy, qz, qw; + loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[0] + (pose1[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[0] : 0)); + loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[1] + (pose1[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[1] : 0)); + loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose1[j].channeloffset[2] + (pose1[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[2] : 0)); + qx = pose1[j].channeloffset[3] + (pose1[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[3] : 0); + qy = pose1[j].channeloffset[4] + (pose1[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[4] : 0); + qz = pose1[j].channeloffset[5] + (pose1[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose1[j].channelscale[5] : 0); + qw = 1.0f - (qx*qx + qy*qy + qz*qz); + qw = qw > 0.0f ? -sqrt(qw) : 0.0f; + loadmodel->data_poses7s[k*7 + 3] = 32767.0f * qx; + loadmodel->data_poses7s[k*7 + 4] = 32767.0f * qy; + loadmodel->data_poses7s[k*7 + 5] = 32767.0f * qz; + loadmodel->data_poses7s[k*7 + 6] = 32767.0f * qw; + // skip scale data for now + if(pose1[j].channelmask&64) framedata++; + if(pose1[j].channelmask&128) framedata++; + if(pose1[j].channelmask&256) framedata++; + } + } + if (header.num_frames <= 0) + { + for (i = 0;i < loadmodel->num_bones;i++) + { + float qx, qy, qz, qw; + loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint1[i].origin[0]; + loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint1[i].origin[1]; + loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint1[i].origin[2]; + qx = joint1[i].rotation[0]; + qy = joint1[i].rotation[1]; + qz = joint1[i].rotation[2]; + qw = 1.0f - (qx*qx + qy*qy + qz*qz); + qw = qw > 0.0f ? -sqrt(qw) : 0.0f; + loadmodel->data_poses7s[i*7 + 3] = 32767.0f * qx; + loadmodel->data_poses7s[i*7 + 4] = 32767.0f * qy; + loadmodel->data_poses7s[i*7 + 5] = 32767.0f * qz; + loadmodel->data_poses7s[i*7 + 6] = 32767.0f * qw; + } + } + } + else + { + for (i = 0, k = 0;i < (int)header.num_frames;i++) + { + for (j = 0;j < (int)header.num_poses;j++, k++) + { + float rot[4]; + loadmodel->data_poses7s[k*7 + 0] = loadmodel->num_poseinvscale * (pose[j].channeloffset[0] + (pose[j].channelmask&1 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[0] : 0)); + loadmodel->data_poses7s[k*7 + 1] = loadmodel->num_poseinvscale * (pose[j].channeloffset[1] + (pose[j].channelmask&2 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[1] : 0)); + loadmodel->data_poses7s[k*7 + 2] = loadmodel->num_poseinvscale * (pose[j].channeloffset[2] + (pose[j].channelmask&4 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[2] : 0)); + rot[0] = pose[j].channeloffset[3] + (pose[j].channelmask&8 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[3] : 0); + rot[1] = pose[j].channeloffset[4] + (pose[j].channelmask&16 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[4] : 0); + rot[2] = pose[j].channeloffset[5] + (pose[j].channelmask&32 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[5] : 0); + rot[3] = pose[j].channeloffset[6] + (pose[j].channelmask&64 ? (unsigned short)LittleShort(*framedata++) * pose[j].channelscale[6] : 0); + if (rot[3] > 0) + Vector4Negate(rot, rot); + Vector4Normalize2(rot, rot); + loadmodel->data_poses7s[k*7 + 3] = 32767.0f * rot[0]; + loadmodel->data_poses7s[k*7 + 4] = 32767.0f * rot[1]; + loadmodel->data_poses7s[k*7 + 5] = 32767.0f * rot[2]; + loadmodel->data_poses7s[k*7 + 6] = 32767.0f * rot[3]; + // skip scale data for now + if(pose[j].channelmask&128) framedata++; + if(pose[j].channelmask&256) framedata++; + if(pose[j].channelmask&512) framedata++; + } + } + if (header.num_frames <= 0) + { + for (i = 0;i < loadmodel->num_bones;i++) + { + loadmodel->data_poses7s[i*7 + 0] = loadmodel->num_poseinvscale * joint[i].origin[0]; + loadmodel->data_poses7s[i*7 + 1] = loadmodel->num_poseinvscale * joint[i].origin[1]; + loadmodel->data_poses7s[i*7 + 2] = loadmodel->num_poseinvscale * joint[i].origin[2]; + loadmodel->data_poses7s[i*7 + 3] = 32767.0f * joint[i].rotation[0]; + loadmodel->data_poses7s[i*7 + 4] = 32767.0f * joint[i].rotation[1]; + loadmodel->data_poses7s[i*7 + 5] = 32767.0f * joint[i].rotation[2]; + loadmodel->data_poses7s[i*7 + 6] = 32767.0f * joint[i].rotation[3]; + } + } + } + + // load bounding box data + if (header.ofs_bounds) + { + float xyradius = 0, radius = 0; + VectorClear(loadmodel->normalmins); + VectorClear(loadmodel->normalmaxs); + for (i = 0; i < (int)header.num_frames;i++) + { + iqmbounds_t bound; + bound.mins[0] = LittleFloat(bounds[i].mins[0]); + bound.mins[1] = LittleFloat(bounds[i].mins[1]); + bound.mins[2] = LittleFloat(bounds[i].mins[2]); + bound.maxs[0] = LittleFloat(bounds[i].maxs[0]); + bound.maxs[1] = LittleFloat(bounds[i].maxs[1]); + bound.maxs[2] = LittleFloat(bounds[i].maxs[2]); + bound.xyradius = LittleFloat(bounds[i].xyradius); + bound.radius = LittleFloat(bounds[i].radius); + if (!i) + { + VectorCopy(bound.mins, loadmodel->normalmins); + VectorCopy(bound.maxs, loadmodel->normalmaxs); + } + else + { + if (loadmodel->normalmins[0] > bound.mins[0]) loadmodel->normalmins[0] = bound.mins[0]; + if (loadmodel->normalmins[1] > bound.mins[1]) loadmodel->normalmins[1] = bound.mins[1]; + if (loadmodel->normalmins[2] > bound.mins[2]) loadmodel->normalmins[2] = bound.mins[2]; + if (loadmodel->normalmaxs[0] < bound.maxs[0]) loadmodel->normalmaxs[0] = bound.maxs[0]; + if (loadmodel->normalmaxs[1] < bound.maxs[1]) loadmodel->normalmaxs[1] = bound.maxs[1]; + if (loadmodel->normalmaxs[2] < bound.maxs[2]) loadmodel->normalmaxs[2] = bound.maxs[2]; + } + if (bound.xyradius > xyradius) + xyradius = bound.xyradius; + if (bound.radius > radius) + radius = bound.radius; + } + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -xyradius; + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = xyradius; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius; + loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius; + loadmodel->radius = radius; + loadmodel->radius2 = radius * radius; + } + + // load triangle data + // this unaligned memory access is safe (LittleLong reads as bytes) + inelements = (const unsigned int *)(pbase + header.ofs_triangles); + outelements = loadmodel->surfmesh.data_element3i; + for (i = 0;i < (int)header.num_triangles;i++) + { + outelements[0] = LittleLong(inelements[0]); + outelements[1] = LittleLong(inelements[1]); + outelements[2] = LittleLong(inelements[2]); + outelements += 3; + inelements += 3; + } + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, header.num_vertexes, __FILE__, __LINE__); + + if (header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i) + { + // this unaligned memory access is safe (LittleLong reads as bytes) + inneighbors = (const int *)(pbase + header.ofs_neighbors); + outneighbors = loadmodel->surfmesh.data_neighbor3i; + for (i = 0;i < (int)header.num_triangles;i++) + { + outneighbors[0] = LittleLong(inneighbors[0]); + outneighbors[1] = LittleLong(inneighbors[1]); + outneighbors[2] = LittleLong(inneighbors[2]); + outneighbors += 3; + inneighbors += 3; + } + } + + // load vertex data + // this unaligned memory access is safe (LittleFloat reads as bytes) + outvertex = loadmodel->surfmesh.data_vertex3f; + for (i = 0;i < (int)header.num_vertexes;i++) + { + outvertex[0] = LittleFloat(vposition[0]); + outvertex[1] = LittleFloat(vposition[1]); + outvertex[2] = LittleFloat(vposition[2]); + vposition += 3; + outvertex += 3; + } + + outtexcoord = loadmodel->surfmesh.data_texcoordtexture2f; + // this unaligned memory access is safe (LittleFloat reads as bytes) + for (i = 0;i < (int)header.num_vertexes;i++) + { + outtexcoord[0] = LittleFloat(vtexcoord[0]); + outtexcoord[1] = LittleFloat(vtexcoord[1]); + vtexcoord += 2; + outtexcoord += 2; + } + + // this unaligned memory access is safe (LittleFloat reads as bytes) + if(vnormal) + { + outnormal = loadmodel->surfmesh.data_normal3f; + for (i = 0;i < (int)header.num_vertexes;i++) + { + outnormal[0] = LittleFloat(vnormal[0]); + outnormal[1] = LittleFloat(vnormal[1]); + outnormal[2] = LittleFloat(vnormal[2]); + vnormal += 3; + outnormal += 3; + } + } + + // this unaligned memory access is safe (LittleFloat reads as bytes) + if(vnormal && vtangent) + { + outnormal = loadmodel->surfmesh.data_normal3f; + outsvector = loadmodel->surfmesh.data_svector3f; + outtvector = loadmodel->surfmesh.data_tvector3f; + for (i = 0;i < (int)header.num_vertexes;i++) + { + outsvector[0] = LittleFloat(vtangent[0]); + outsvector[1] = LittleFloat(vtangent[1]); + outsvector[2] = LittleFloat(vtangent[2]); + if(LittleFloat(vtangent[3]) < 0) + CrossProduct(outsvector, outnormal, outtvector); + else + CrossProduct(outnormal, outsvector, outtvector); + vtangent += 4; + outnormal += 3; + outsvector += 3; + outtvector += 3; + } + } + + // this unaligned memory access is safe (all bytes) + if (vblendindexes && vblendweights) + { + for (i = 0; i < (int)header.num_vertexes;i++) + { + blendweights_t weights; + memcpy(weights.index, vblendindexes + i*4, 4); + memcpy(weights.influence, vblendweights + i*4, 4); + loadmodel->surfmesh.blends[i] = Mod_Skeletal_AddBlend(loadmodel, &weights); + loadmodel->surfmesh.data_skeletalindex4ub[i*4 ] = weights.index[0]; + loadmodel->surfmesh.data_skeletalindex4ub[i*4+1] = weights.index[1]; + loadmodel->surfmesh.data_skeletalindex4ub[i*4+2] = weights.index[2]; + loadmodel->surfmesh.data_skeletalindex4ub[i*4+3] = weights.index[3]; + loadmodel->surfmesh.data_skeletalweight4ub[i*4 ] = weights.influence[0]; + loadmodel->surfmesh.data_skeletalweight4ub[i*4+1] = weights.influence[1]; + loadmodel->surfmesh.data_skeletalweight4ub[i*4+2] = weights.influence[2]; + loadmodel->surfmesh.data_skeletalweight4ub[i*4+3] = weights.influence[3]; + } + } + + if (vcolor4f) + { + outcolor = loadmodel->surfmesh.data_lightmapcolor4f; + // this unaligned memory access is safe (LittleFloat reads as bytes) + for (i = 0;i < (int)header.num_vertexes;i++) + { + outcolor[0] = LittleFloat(vcolor4f[0]); + outcolor[1] = LittleFloat(vcolor4f[1]); + outcolor[2] = LittleFloat(vcolor4f[2]); + outcolor[3] = LittleFloat(vcolor4f[3]); + vcolor4f += 4; + outcolor += 4; + } + } + else if (vcolor4ub) + { + outcolor = loadmodel->surfmesh.data_lightmapcolor4f; + // this unaligned memory access is safe (all bytes) + for (i = 0;i < (int)header.num_vertexes;i++) + { + outcolor[0] = vcolor4ub[0] * (1.0f / 255.0f); + outcolor[1] = vcolor4ub[1] * (1.0f / 255.0f); + outcolor[2] = vcolor4ub[2] * (1.0f / 255.0f); + outcolor[3] = vcolor4ub[3] * (1.0f / 255.0f); + vcolor4ub += 4; + outcolor += 4; + } + } + + // load meshes + for (i = 0;i < (int)header.num_meshes;i++) + { + iqmmesh_t mesh; + msurface_t *surface; + + mesh.name = LittleLong(meshes[i].name); + mesh.material = LittleLong(meshes[i].material); + mesh.first_vertex = LittleLong(meshes[i].first_vertex); + mesh.num_vertexes = LittleLong(meshes[i].num_vertexes); + mesh.first_triangle = LittleLong(meshes[i].first_triangle); + mesh.num_triangles = LittleLong(meshes[i].num_triangles); + + loadmodel->sortedmodelsurfaces[i] = i; + surface = loadmodel->data_surfaces + i; + surface->texture = loadmodel->data_textures + i; + surface->num_firsttriangle = mesh.first_triangle; + surface->num_triangles = mesh.num_triangles; + surface->num_firstvertex = mesh.first_vertex; + surface->num_vertices = mesh.num_vertexes; + + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + i, skinfiles, &text[mesh.name], &text[mesh.material]); + } + + Mod_FreeSkinFiles(skinfiles); + Mod_MakeSortedSurfaces(loadmodel); + + // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + if (!vnormal) + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); + if (!vnormal || !vtangent) + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + if (!header.ofs_neighbors && loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + if (!header.ofs_bounds) + Mod_Alias_CalculateBoundingBox(); + + if (!loadmodel->surfmesh.isanimated && loadmodel->surfmesh.num_triangles >= 1) + { + Mod_MakeCollisionBIH(loadmodel, true, &loadmodel->collision_bih); + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + } + + if (joint ) Mem_Free(joint );joint = NULL; + if (joint1 ) Mem_Free(joint1 );joint1 = NULL; + if (pose ) Mem_Free(pose );pose = NULL; + if (pose1 ) Mem_Free(pose1 );pose1 = NULL; + + // because shaders can do somewhat unexpected things, check for unusual features now + for (i = 0;i < loadmodel->num_textures;i++) + { + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_SKY)) + mod->DrawSky = R_Q1BSP_DrawSky; + if (loadmodel->data_textures[i].basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + } +} diff --git a/app/jni/model_alias.h b/app/jni/model_alias.h new file mode 100644 index 0000000..61c1099 --- /dev/null +++ b/app/jni/model_alias.h @@ -0,0 +1,252 @@ +/* +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_ALIAS_H +#define MODEL_ALIAS_H + +/* +============================================================================== + +ALIAS MODELS + +Alias models are position independent, so the cache manager can move them. +============================================================================== +*/ + +#include "modelgen.h" + +typedef struct daliashdr_s +{ + 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; +} +daliashdr_t; + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +// LordHavoc: grabbed this from the Q2 utility source, +// renamed a things to avoid conflicts + +#define MD2ALIAS_VERSION 8 +#define MD2_SKINNAME 64 + +typedef struct md2stvert_s +{ + short s; + short t; +} md2stvert_t; + +typedef struct md2triangle_s +{ + short index_xyz[3]; + short index_st[3]; +} md2triangle_t; + +typedef struct md2frame_s +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing +} md2frame_t; + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct md2_s +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file +} md2_t; + +// all md3 ints, floats, and shorts, are little endian, and thus need to be +// passed through LittleLong/LittleFloat/LittleShort to avoid breaking on +// bigendian machines +#define MD3VERSION 15 +#define MD3NAME 64 +#define MD3FRAMENAME 16 + +// the origin is at 1/64th scale +// the pitch and yaw are encoded as 8 bits each +typedef struct md3vertex_s +{ + short origin[3]; + unsigned char pitch; + unsigned char yaw; +} +md3vertex_t; + +// one per frame +typedef struct md3frameinfo_s +{ + float mins[3]; + float maxs[3]; + float origin[3]; + float radius; + char name[MD3FRAMENAME]; +} +md3frameinfo_t; + +// one per tag per frame +typedef struct md3tag_s +{ + char name[MD3NAME]; + float origin[3]; + float rotationmatrix[9]; +} +md3tag_t; + +// one per shader per mesh +typedef struct md3shader_s +{ + char name[MD3NAME]; + // engine field (yes this empty int does exist in the file) + int shadernum; +} +md3shader_t; + +// one per mesh per model +// +// note that the lump_ offsets in this struct are relative to the beginning +// of the mesh struct +// +// to find the next mesh in the file, you must go to lump_end, which puts you +// at the beginning of the next mesh +typedef struct md3mesh_s +{ + char identifier[4]; // "IDP3" + char name[MD3NAME]; + int flags; + int num_frames; + int num_shaders; + int num_vertices; + int num_triangles; + int lump_elements; + int lump_shaders; + int lump_texcoords; + int lump_framevertices; + int lump_end; +} +md3mesh_t; + +// this struct is at the beginning of the md3 file +// +// note that the lump_ offsets in this struct are relative to the beginning +// of the header struct (which is the beginning of the file) +typedef struct md3modelheader_s +{ + char identifier[4]; // "IDP3" + int version; // 15 + char name[MD3NAME]; + int flags; + int num_frames; + int num_tags; + int num_meshes; + int num_skins; + int lump_frameinfo; + int lump_tags; + int lump_meshes; + int lump_end; +} +md3modelheader_t; + +typedef struct aliastag_s +{ + char name[MD3NAME]; + float matrixgl[12]; +} +aliastag_t; + +typedef struct aliasbone_s +{ + char name[MD3NAME]; + int flags; + int parent; // -1 for no parent +} +aliasbone_t; + +#include "model_zymotic.h" + +#include "model_dpmodel.h" + +#include "model_psk.h" + +#include "model_iqm.h" + +// for decoding md3 model latlong vertex normals +extern float mod_md3_sin[320]; + +extern cvar_t r_skeletal_debugbone; +extern cvar_t r_skeletal_debugbonecomponent; +extern cvar_t r_skeletal_debugbonevalue; +extern cvar_t r_skeletal_debugtranslatex; +extern cvar_t r_skeletal_debugtranslatey; +extern cvar_t r_skeletal_debugtranslatez; + +struct model_s; +struct frameblend_s; + +void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes); +void Mod_Skeletal_BuildTransforms(const struct model_s * RESTRICT model, const struct frameblend_s * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative); + +#endif + diff --git a/app/jni/model_brush.c b/app/jni/model_brush.c new file mode 100644 index 0000000..b8e64da --- /dev/null +++ b/app/jni/model_brush.c @@ -0,0 +1,8071 @@ +/* +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 "image.h" +#include "r_shadow.h" +#include "polygon.h" +#include "curves.h" +#include "wad.h" + + +//cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"}; +cvar_t mod_bsp_portalize = {0, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"}; +cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"}; +cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"}; +cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"}; +cvar_t r_subdivisions_mintess = {0, "r_subdivisions_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"}; +cvar_t r_subdivisions_maxtess = {0, "r_subdivisions_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"}; +cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536", "maximum vertices allowed per subdivided curve"}; +cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15", "maximum error tolerance on curve subdivision for collision purposes (usually a larger error tolerance than for rendering)"}; +cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"}; +cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"}; +cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"}; +cvar_t r_trippy = {0, "r_trippy", "0", "easter egg"}; +cvar_t mod_noshader_default_offsetmapping = {CVAR_SAVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"}; +cvar_t mod_obj_orientation = {0, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"}; +cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"}; +cvar_t mod_q3bsp_curves_collisions_stride = {0, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"}; +cvar_t mod_q3bsp_curves_stride = {0, "mod_q3bsp_curves_stride", "16", "particle effect collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"}; +cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1", "whether to use optimized traceline code for line traces (as opposed to tracebox code)"}; +cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"}; +cvar_t mod_q3bsp_lightmapmergepower = {CVAR_SAVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."}; +cvar_t mod_q3bsp_nolightmaps = {CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"}; +cvar_t mod_q3bsp_tracelineofsight_brushes = {0, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"}; +cvar_t mod_q3bsp_sRGBlightmaps = {0, "mod_q3bsp_sRGBlightmaps", "0", "treat lightmaps from Q3 maps as sRGB when vid_sRGB is active"}; +cvar_t mod_q3shader_default_offsetmapping = {CVAR_SAVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are using q3 shader files"}; +cvar_t mod_q3shader_default_offsetmapping_scale = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_scale", "1", "default scale used for offsetmapping"}; +cvar_t mod_q3shader_default_offsetmapping_bias = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_bias", "0", "default bias used for offsetmapping"}; +cvar_t mod_q3shader_default_polygonfactor = {0, "mod_q3shader_default_polygonfactor", "0", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"}; +cvar_t mod_q3shader_default_polygonoffset = {0, "mod_q3shader_default_polygonoffset", "-2", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"}; +cvar_t mod_q3shader_force_addalpha = {0, "mod_q3shader_force_addalpha", "0", "treat GL_ONE GL_ONE (or add) blendfunc as GL_SRC_ALPHA GL_ONE for compatibility with older DarkPlaces releases"}; +cvar_t mod_q3shader_force_terrain_alphaflag = {0, "mod_q3shader_force_terrain_alphaflag", "0", "for multilayered terrain shaders force TEXF_ALPHA flag on both layers"}; + +cvar_t mod_q1bsp_polygoncollisions = {0, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"}; +cvar_t mod_collision_bih = {0, "mod_collision_bih", "1", "enables use of generated Bounding Interval Hierarchy tree instead of compiled bsp tree in collision code"}; +cvar_t mod_recalculatenodeboxes = {0, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"}; + +static texture_t mod_q1bsp_texture_solid; +static texture_t mod_q1bsp_texture_sky; +static texture_t mod_q1bsp_texture_lava; +static texture_t mod_q1bsp_texture_slime; +static texture_t mod_q1bsp_texture_water; + +void Mod_BrushInit(void) +{ +// Cvar_RegisterVariable(&r_subdivide_size); + Cvar_RegisterVariable(&mod_bsp_portalize); + Cvar_RegisterVariable(&r_novis); + Cvar_RegisterVariable(&r_nosurftextures); + Cvar_RegisterVariable(&r_subdivisions_tolerance); + Cvar_RegisterVariable(&r_subdivisions_mintess); + Cvar_RegisterVariable(&r_subdivisions_maxtess); + Cvar_RegisterVariable(&r_subdivisions_maxvertices); + Cvar_RegisterVariable(&r_subdivisions_collision_tolerance); + Cvar_RegisterVariable(&r_subdivisions_collision_mintess); + Cvar_RegisterVariable(&r_subdivisions_collision_maxtess); + Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices); + Cvar_RegisterVariable(&r_trippy); + Cvar_RegisterVariable(&mod_noshader_default_offsetmapping); + Cvar_RegisterVariable(&mod_obj_orientation); + Cvar_RegisterVariable(&mod_q3bsp_curves_collisions); + Cvar_RegisterVariable(&mod_q3bsp_curves_collisions_stride); + Cvar_RegisterVariable(&mod_q3bsp_curves_stride); + Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline); + Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush); + Cvar_RegisterVariable(&mod_q3bsp_lightmapmergepower); + Cvar_RegisterVariable(&mod_q3bsp_nolightmaps); + Cvar_RegisterVariable(&mod_q3bsp_sRGBlightmaps); + Cvar_RegisterVariable(&mod_q3bsp_tracelineofsight_brushes); + Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping); + Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping_scale); + Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping_bias); + Cvar_RegisterVariable(&mod_q3shader_default_polygonfactor); + Cvar_RegisterVariable(&mod_q3shader_default_polygonoffset); + Cvar_RegisterVariable(&mod_q3shader_force_addalpha); + Cvar_RegisterVariable(&mod_q3shader_force_terrain_alphaflag); + Cvar_RegisterVariable(&mod_q1bsp_polygoncollisions); + Cvar_RegisterVariable(&mod_collision_bih); + Cvar_RegisterVariable(&mod_recalculatenodeboxes); + + // these games were made for older DP engines and are no longer + // maintained; use this hack to show their textures properly + if(gamemode == GAME_NEXUIZ) + Cvar_SetQuick(&mod_q3shader_force_addalpha, "1"); + + memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid)); + strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name)); + mod_q1bsp_texture_solid.surfaceflags = 0; + mod_q1bsp_texture_solid.supercontents = SUPERCONTENTS_SOLID; + + mod_q1bsp_texture_sky = mod_q1bsp_texture_solid; + strlcpy(mod_q1bsp_texture_sky.name, "sky", sizeof(mod_q1bsp_texture_sky.name)); + mod_q1bsp_texture_sky.surfaceflags = Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT | Q3SURFACEFLAG_NOMARKS | Q3SURFACEFLAG_NODLIGHT | Q3SURFACEFLAG_NOLIGHTMAP; + mod_q1bsp_texture_sky.supercontents = SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP; + + mod_q1bsp_texture_lava = mod_q1bsp_texture_solid; + strlcpy(mod_q1bsp_texture_lava.name, "*lava", sizeof(mod_q1bsp_texture_lava.name)); + mod_q1bsp_texture_lava.surfaceflags = Q3SURFACEFLAG_NOMARKS; + mod_q1bsp_texture_lava.supercontents = SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP; + + mod_q1bsp_texture_slime = mod_q1bsp_texture_solid; + strlcpy(mod_q1bsp_texture_slime.name, "*slime", sizeof(mod_q1bsp_texture_slime.name)); + mod_q1bsp_texture_slime.surfaceflags = Q3SURFACEFLAG_NOMARKS; + mod_q1bsp_texture_slime.supercontents = SUPERCONTENTS_SLIME; + + mod_q1bsp_texture_water = mod_q1bsp_texture_solid; + strlcpy(mod_q1bsp_texture_water.name, "*water", sizeof(mod_q1bsp_texture_water.name)); + mod_q1bsp_texture_water.surfaceflags = Q3SURFACEFLAG_NOMARKS; + mod_q1bsp_texture_water.supercontents = SUPERCONTENTS_WATER; +} + +static mleaf_t *Mod_Q1BSP_PointInLeaf(dp_model_t *model, const vec3_t p) +{ + mnode_t *node; + + if (model == NULL) + return NULL; + + // LordHavoc: modified to start at first clip node, + // in other words: first node of the (sub)model + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + while (node->plane) + node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; + + return (mleaf_t *)node; +} + +static void Mod_Q1BSP_AmbientSoundLevelsForPoint(dp_model_t *model, const vec3_t p, unsigned char *out, int outsize) +{ + int i; + mleaf_t *leaf; + leaf = Mod_Q1BSP_PointInLeaf(model, p); + if (leaf) + { + i = min(outsize, (int)sizeof(leaf->ambient_sound_level)); + if (i) + { + memcpy(out, leaf->ambient_sound_level, i); + out += i; + outsize -= i; + } + } + if (outsize) + memset(out, 0, outsize); +} + +static int Mod_Q1BSP_FindBoxClusters(dp_model_t *model, const vec3_t mins, const vec3_t maxs, int maxclusters, int *clusterlist) +{ + int numclusters = 0; + int nodestackindex = 0; + mnode_t *node, *nodestack[1024]; + if (!model->brush.num_pvsclusters) + return -1; + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + for (;;) + { +#if 1 + if (node->plane) + { + // node - recurse down the BSP tree + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) + { + if (sides == 0) + return -1; // ERROR: NAN bounding box! + // box is on one side of plane, take that path + node = node->children[sides-1]; + } + else + { + // box crosses plane, take one path and remember the other + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + } + continue; + } + else + { + // leaf - add clusterindex to list + if (numclusters < maxclusters) + clusterlist[numclusters] = ((mleaf_t *)node)->clusterindex; + numclusters++; + } +#else + if (BoxesOverlap(mins, maxs, node->mins, node->maxs)) + { + if (node->plane) + { + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + continue; + } + else + { + // leaf - add clusterindex to list + if (numclusters < maxclusters) + clusterlist[numclusters] = ((mleaf_t *)node)->clusterindex; + numclusters++; + } + } +#endif + // try another path we didn't take earlier + if (nodestackindex == 0) + break; + node = nodestack[--nodestackindex]; + } + // return number of clusters found (even if more than the maxclusters) + return numclusters; +} + +static int Mod_Q1BSP_BoxTouchingPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs) +{ + int nodestackindex = 0; + mnode_t *node, *nodestack[1024]; + if (!model->brush.num_pvsclusters) + return true; + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + for (;;) + { +#if 1 + if (node->plane) + { + // node - recurse down the BSP tree + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) + { + if (sides == 0) + return -1; // ERROR: NAN bounding box! + // box is on one side of plane, take that path + node = node->children[sides-1]; + } + else + { + // box crosses plane, take one path and remember the other + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + } + continue; + } + else + { + // leaf - check cluster bit + int clusterindex = ((mleaf_t *)node)->clusterindex; + if (CHECKPVSBIT(pvs, clusterindex)) + { + // it is visible, return immediately with the news + return true; + } + } +#else + if (BoxesOverlap(mins, maxs, node->mins, node->maxs)) + { + if (node->plane) + { + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + continue; + } + else + { + // leaf - check cluster bit + int clusterindex = ((mleaf_t *)node)->clusterindex; + if (CHECKPVSBIT(pvs, clusterindex)) + { + // it is visible, return immediately with the news + return true; + } + } + } +#endif + // nothing to see here, try another path we didn't take earlier + if (nodestackindex == 0) + break; + node = nodestack[--nodestackindex]; + } + // it is not visible + return false; +} + +static int Mod_Q1BSP_BoxTouchingLeafPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs) +{ + int nodestackindex = 0; + mnode_t *node, *nodestack[1024]; + if (!model->brush.num_leafs) + return true; + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + for (;;) + { +#if 1 + if (node->plane) + { + // node - recurse down the BSP tree + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) + { + if (sides == 0) + return -1; // ERROR: NAN bounding box! + // box is on one side of plane, take that path + node = node->children[sides-1]; + } + else + { + // box crosses plane, take one path and remember the other + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + } + continue; + } + else + { + // leaf - check cluster bit + int clusterindex = ((mleaf_t *)node) - model->brush.data_leafs; + if (CHECKPVSBIT(pvs, clusterindex)) + { + // it is visible, return immediately with the news + return true; + } + } +#else + if (BoxesOverlap(mins, maxs, node->mins, node->maxs)) + { + if (node->plane) + { + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + continue; + } + else + { + // leaf - check cluster bit + int clusterindex = ((mleaf_t *)node) - model->brush.data_leafs; + if (CHECKPVSBIT(pvs, clusterindex)) + { + // it is visible, return immediately with the news + return true; + } + } + } +#endif + // nothing to see here, try another path we didn't take earlier + if (nodestackindex == 0) + break; + node = nodestack[--nodestackindex]; + } + // it is not visible + return false; +} + +static int Mod_Q1BSP_BoxTouchingVisibleLeafs(dp_model_t *model, const unsigned char *visibleleafs, const vec3_t mins, const vec3_t maxs) +{ + int nodestackindex = 0; + mnode_t *node, *nodestack[1024]; + if (!model->brush.num_leafs) + return true; + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + for (;;) + { +#if 1 + if (node->plane) + { + // node - recurse down the BSP tree + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) + { + if (sides == 0) + return -1; // ERROR: NAN bounding box! + // box is on one side of plane, take that path + node = node->children[sides-1]; + } + else + { + // box crosses plane, take one path and remember the other + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + } + continue; + } + else + { + // leaf - check if it is visible + if (visibleleafs[(mleaf_t *)node - model->brush.data_leafs]) + { + // it is visible, return immediately with the news + return true; + } + } +#else + if (BoxesOverlap(mins, maxs, node->mins, node->maxs)) + { + if (node->plane) + { + if (nodestackindex < 1024) + nodestack[nodestackindex++] = node->children[0]; + node = node->children[1]; + continue; + } + else + { + // leaf - check if it is visible + if (visibleleafs[(mleaf_t *)node - model->brush.data_leafs]) + { + // it is visible, return immediately with the news + return true; + } + } + } +#endif + // nothing to see here, try another path we didn't take earlier + if (nodestackindex == 0) + break; + node = nodestack[--nodestackindex]; + } + // it is not visible + return false; +} + +typedef struct findnonsolidlocationinfo_s +{ + vec3_t center; + vec3_t absmin, absmax; + vec_t radius; + vec3_t nudge; + vec_t bestdist; + dp_model_t *model; +} +findnonsolidlocationinfo_t; + +static void Mod_Q1BSP_FindNonSolidLocation_r_Triangle(findnonsolidlocationinfo_t *info, msurface_t *surface, int k) +{ + int i, *tri; + float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3]; + + tri = (info->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle) + k * 3; + VectorCopy((info->model->surfmesh.data_vertex3f + tri[0] * 3), vert[0]); + VectorCopy((info->model->surfmesh.data_vertex3f + tri[1] * 3), vert[1]); + VectorCopy((info->model->surfmesh.data_vertex3f + tri[2] * 3), vert[2]); + VectorSubtract(vert[1], vert[0], edge[0]); + VectorSubtract(vert[2], vert[1], edge[1]); + CrossProduct(edge[1], edge[0], facenormal); + if (facenormal[0] || facenormal[1] || facenormal[2]) + { + VectorNormalize(facenormal); + f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal); + if (f <= info->bestdist && f >= -info->bestdist) + { + VectorSubtract(vert[0], vert[2], edge[2]); + VectorNormalize(edge[0]); + VectorNormalize(edge[1]); + VectorNormalize(edge[2]); + CrossProduct(facenormal, edge[0], edgenormal[0]); + CrossProduct(facenormal, edge[1], edgenormal[1]); + CrossProduct(facenormal, edge[2], edgenormal[2]); + // face distance + if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0]) + && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1]) + && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2])) + { + // we got lucky, the center is within the face + dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal); + if (dist < 0) + { + dist = -dist; + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(facenormal, (info->radius - -dist), info->nudge); + } + } + else + { + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(facenormal, (info->radius - dist), info->nudge); + } + } + } + else + { + // check which edge or vertex the center is nearest + for (i = 0;i < 3;i++) + { + f = DotProduct(info->center, edge[i]); + if (f >= DotProduct(vert[0], edge[i]) + && f <= DotProduct(vert[1], edge[i])) + { + // on edge + VectorMA(info->center, -f, edge[i], point); + dist = sqrt(DotProduct(point, point)); + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(point, (info->radius / dist), info->nudge); + } + // skip both vertex checks + // (both are further away than this edge) + i++; + } + else + { + // not on edge, check first vertex of edge + VectorSubtract(info->center, vert[i], point); + dist = sqrt(DotProduct(point, point)); + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(point, (info->radius / dist), info->nudge); + } + } + } + } + } + } +} + +static void Mod_Q1BSP_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf) +{ + int surfacenum, k, *mark; + msurface_t *surface; + for (surfacenum = 0, mark = leaf->firstleafsurface;surfacenum < leaf->numleafsurfaces;surfacenum++, mark++) + { + surface = info->model->data_surfaces + *mark; + if (surface->texture->supercontents & SUPERCONTENTS_SOLID) + { + if(surface->deprecatedq3num_bboxstride > 0) + { + int i, cnt, tri; + cnt = (surface->num_triangles + surface->deprecatedq3num_bboxstride - 1) / surface->deprecatedq3num_bboxstride; + for(i = 0; i < cnt; ++i) + { + if(BoxesOverlap(surface->deprecatedq3data_bbox6f + i * 6, surface->deprecatedq3data_bbox6f + i * 6 + 3, info->absmin, info->absmax)) + { + for(k = 0; k < surface->deprecatedq3num_bboxstride; ++k) + { + tri = i * surface->deprecatedq3num_bboxstride + k; + if(tri >= surface->num_triangles) + break; + Mod_Q1BSP_FindNonSolidLocation_r_Triangle(info, surface, tri); + } + } + } + } + else + { + for (k = 0;k < surface->num_triangles;k++) + { + Mod_Q1BSP_FindNonSolidLocation_r_Triangle(info, surface, k); + } + } + } + } +} + +static void Mod_Q1BSP_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node) +{ + if (node->plane) + { + float f = PlaneDiff(info->center, node->plane); + if (f >= -info->bestdist) + Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[0]); + if (f <= info->bestdist) + Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[1]); + } + else + { + if (((mleaf_t *)node)->numleafsurfaces) + Mod_Q1BSP_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node); + } +} + +static void Mod_Q1BSP_FindNonSolidLocation(dp_model_t *model, const vec3_t in, vec3_t out, float radius) +{ + int i; + findnonsolidlocationinfo_t info; + if (model == NULL) + { + VectorCopy(in, out); + return; + } + VectorCopy(in, info.center); + info.radius = radius; + info.model = model; + i = 0; + do + { + VectorClear(info.nudge); + info.bestdist = radius; + VectorCopy(info.center, info.absmin); + VectorCopy(info.center, info.absmax); + info.absmin[0] -= info.radius + 1; + info.absmin[1] -= info.radius + 1; + info.absmin[2] -= info.radius + 1; + info.absmax[0] += info.radius + 1; + info.absmax[1] += info.radius + 1; + info.absmax[2] += info.radius + 1; + Mod_Q1BSP_FindNonSolidLocation_r(&info, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode); + VectorAdd(info.center, info.nudge, info.center); + } + while (info.bestdist < radius && ++i < 10); + VectorCopy(info.center, out); +} + +int Mod_Q1BSP_SuperContentsFromNativeContents(dp_model_t *model, int nativecontents) +{ + switch(nativecontents) + { + case CONTENTS_EMPTY: + return 0; + case CONTENTS_SOLID: + return SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + case CONTENTS_WATER: + return SUPERCONTENTS_WATER; + case CONTENTS_SLIME: + return SUPERCONTENTS_SLIME; + case CONTENTS_LAVA: + return SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP; + case CONTENTS_SKY: + return SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP | SUPERCONTENTS_OPAQUE; // to match behaviour of Q3 maps, let sky count as opaque + } + return 0; +} + +int Mod_Q1BSP_NativeContentsFromSuperContents(dp_model_t *model, int supercontents) +{ + if (supercontents & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)) + return CONTENTS_SOLID; + if (supercontents & SUPERCONTENTS_SKY) + return CONTENTS_SKY; + if (supercontents & SUPERCONTENTS_LAVA) + return CONTENTS_LAVA; + if (supercontents & SUPERCONTENTS_SLIME) + return CONTENTS_SLIME; + if (supercontents & SUPERCONTENTS_WATER) + return CONTENTS_WATER; + return CONTENTS_EMPTY; +} + +typedef struct RecursiveHullCheckTraceInfo_s +{ + // the hull we're tracing through + const hull_t *hull; + + // the trace structure to fill in + trace_t *trace; + + // start, end, and end - start (in model space) + double start[3]; + double end[3]; + double dist[3]; +} +RecursiveHullCheckTraceInfo_t; + +// 1/32 epsilon to keep floating point happy +#define DIST_EPSILON (0.03125) + +#define HULLCHECKSTATE_EMPTY 0 +#define HULLCHECKSTATE_SOLID 1 +#define HULLCHECKSTATE_DONE 2 + +extern cvar_t collision_prefernudgedfraction; +static int Mod_Q1BSP_RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3]) +{ + // status variables, these don't need to be saved on the stack when + // recursing... but are because this should be thread-safe + // (note: tracing against a bbox is not thread-safe, yet) + int ret; + mplane_t *plane; + double t1, t2; + + // variables that need to be stored on the stack when recursing + mclipnode_t *node; + int side; + double midf, mid[3]; + + // LordHavoc: a goto! everyone flee in terror... :) +loc0: + // check for empty + if (num < 0) + { + num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num); + if (!t->trace->startfound) + { + t->trace->startfound = true; + t->trace->startsupercontents |= num; + } + if (num & SUPERCONTENTS_LIQUIDSMASK) + t->trace->inwater = true; + if (num == 0) + t->trace->inopen = true; + if (num & SUPERCONTENTS_SOLID) + t->trace->hittexture = &mod_q1bsp_texture_solid; + else if (num & SUPERCONTENTS_SKY) + t->trace->hittexture = &mod_q1bsp_texture_sky; + else if (num & SUPERCONTENTS_LAVA) + t->trace->hittexture = &mod_q1bsp_texture_lava; + else if (num & SUPERCONTENTS_SLIME) + t->trace->hittexture = &mod_q1bsp_texture_slime; + else + t->trace->hittexture = &mod_q1bsp_texture_water; + t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags; + t->trace->hitsupercontents = num; + if (num & t->trace->hitsupercontentsmask) + { + // if the first leaf is solid, set startsolid + if (t->trace->allsolid) + t->trace->startsolid = true; +#if COLLISIONPARANOID >= 3 + Con_Print("S"); +#endif + return HULLCHECKSTATE_SOLID; + } + else + { + t->trace->allsolid = false; +#if COLLISIONPARANOID >= 3 + Con_Print("E"); +#endif + return HULLCHECKSTATE_EMPTY; + } + } + + // find the point distances + node = t->hull->clipnodes + num; + + plane = t->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 (t1 < 0) + { + if (t2 < 0) + { +#if COLLISIONPARANOID >= 3 + Con_Print("<"); +#endif + num = node->children[1]; + goto loc0; + } + side = 1; + } + else + { + if (t2 >= 0) + { +#if COLLISIONPARANOID >= 3 + Con_Print(">"); +#endif + num = node->children[0]; + goto loc0; + } + side = 0; + } + + // the line intersects, find intersection point + // LordHavoc: this uses the original trace for maximum accuracy +#if COLLISIONPARANOID >= 3 + Con_Print("M"); +#endif + if (plane->type < 3) + { + t1 = t->start[plane->type] - plane->dist; + t2 = t->end[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, t->start) - plane->dist; + t2 = DotProduct (plane->normal, t->end) - plane->dist; + } + + midf = t1 / (t1 - t2); + midf = bound(p1f, midf, p2f); + VectorMA(t->start, midf, t->dist, mid); + + // recurse both sides, front side first + ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side], p1f, midf, p1, mid); + // if this side is not empty, return what it is (solid or done) + if (ret != HULLCHECKSTATE_EMPTY) + return ret; + + ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side ^ 1], midf, p2f, mid, p2); + // if other side is not solid, return what it is (empty or done) + if (ret != HULLCHECKSTATE_SOLID) + return ret; + + // front is air and back is solid, this is the impact point... + if (side) + { + t->trace->plane.dist = -plane->dist; + VectorNegate (plane->normal, t->trace->plane.normal); + } + else + { + t->trace->plane.dist = plane->dist; + VectorCopy (plane->normal, t->trace->plane.normal); + } + + // calculate the true fraction + t1 = DotProduct(t->trace->plane.normal, t->start) - t->trace->plane.dist; + t2 = DotProduct(t->trace->plane.normal, t->end) - t->trace->plane.dist; + midf = t1 / (t1 - t2); + t->trace->realfraction = bound(0, midf, 1); + + // calculate the return fraction which is nudged off the surface a bit + midf = (t1 - DIST_EPSILON) / (t1 - t2); + t->trace->fraction = bound(0, midf, 1); + + if (collision_prefernudgedfraction.integer) + t->trace->realfraction = t->trace->fraction; + +#if COLLISIONPARANOID >= 3 + Con_Print("D"); +#endif + return HULLCHECKSTATE_DONE; +} + +//#if COLLISIONPARANOID < 2 +static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, int num) +{ + mplane_t *plane; + mclipnode_t *nodes = t->hull->clipnodes; + mplane_t *planes = t->hull->planes; + vec3_t point; + VectorCopy(t->start, point); + while (num >= 0) + { + plane = planes + nodes[num].planenum; + num = nodes[num].children[(plane->type < 3 ? point[plane->type] : DotProduct(plane->normal, point)) < plane->dist]; + } + num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num); + t->trace->startsupercontents |= num; + if (num & SUPERCONTENTS_LIQUIDSMASK) + t->trace->inwater = true; + if (num == 0) + t->trace->inopen = true; + if (num & t->trace->hitsupercontentsmask) + { + t->trace->allsolid = t->trace->startsolid = true; + return HULLCHECKSTATE_SOLID; + } + else + { + t->trace->allsolid = t->trace->startsolid = false; + return HULLCHECKSTATE_EMPTY; + } +} +//#endif + +static void Mod_Q1BSP_TracePoint(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask) +{ + RecursiveHullCheckTraceInfo_t rhc; + + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + rhc.trace = trace; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 + VectorCopy(start, rhc.start); + VectorCopy(start, rhc.end); + Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); +} + +static void Mod_Q1BSP_TraceLineAgainstSurfaces(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); + +static void Mod_Q1BSP_TraceLine(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + RecursiveHullCheckTraceInfo_t rhc; + + if (VectorCompare(start, end)) + { + Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + return; + } + + // sometimes we want to traceline against polygons so we can report the texture that was hit rather than merely a contents, but using this method breaks one of negke's maps so it must be a cvar check... + if (sv_gameplayfix_q1bsptracelinereportstexture.integer) + { + Mod_Q1BSP_TraceLineAgainstSurfaces(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + return; + } + + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + rhc.trace = trace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 + VectorCopy(start, rhc.start); + VectorCopy(end, rhc.end); + VectorSubtract(rhc.end, rhc.start, rhc.dist); +#if COLLISIONPARANOID >= 2 + Con_Printf("t(%f %f %f,%f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2]); + Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); + { + + double test[3]; + trace_t testtrace; + VectorLerp(rhc.start, rhc.trace->fraction, rhc.end, test); + memset(&testtrace, 0, sizeof(trace_t)); + rhc.trace = &testtrace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + VectorCopy(test, rhc.start); + VectorCopy(test, rhc.end); + VectorClear(rhc.dist); + Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); + //Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, test, test); + if (!trace->startsolid && testtrace.startsolid) + Con_Printf(" - ended in solid!\n"); + } + Con_Print("\n"); +#else + if (VectorLength2(rhc.dist)) + Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); + else + Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); +#endif +} + +static void Mod_Q1BSP_TraceBox(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) +{ + // this function currently only supports same size start and end + double boxsize[3]; + RecursiveHullCheckTraceInfo_t rhc; + + if (VectorCompare(boxmins, boxmaxs)) + { + if (VectorCompare(start, end)) + Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + else + Mod_Q1BSP_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + return; + } + + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + rhc.trace = trace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + VectorSubtract(boxmaxs, boxmins, boxsize); + if (boxsize[0] < 3) + rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 + else if (model->brush.ishlbsp) + { + // LordHavoc: this has to have a minor tolerance (the .1) because of + // minor float precision errors from the box being transformed around + if (boxsize[0] < 32.1) + { + if (boxsize[2] < 54) // pick the nearest of 36 or 72 + rhc.hull = &model->brushq1.hulls[3]; // 32x32x36 + else + rhc.hull = &model->brushq1.hulls[1]; // 32x32x72 + } + else + rhc.hull = &model->brushq1.hulls[2]; // 64x64x64 + } + else + { + // LordHavoc: this has to have a minor tolerance (the .1) because of + // minor float precision errors from the box being transformed around + if (boxsize[0] < 32.1) + rhc.hull = &model->brushq1.hulls[1]; // 32x32x56 + else + rhc.hull = &model->brushq1.hulls[2]; // 64x64x88 + } + VectorMAMAM(1, start, 1, boxmins, -1, rhc.hull->clip_mins, rhc.start); + VectorMAMAM(1, end, 1, boxmins, -1, rhc.hull->clip_mins, rhc.end); + VectorSubtract(rhc.end, rhc.start, rhc.dist); +#if COLLISIONPARANOID >= 2 + Con_Printf("t(%f %f %f,%f %f %f,%i %f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2], rhc.hull - model->brushq1.hulls, rhc.hull->clip_mins[0], rhc.hull->clip_mins[1], rhc.hull->clip_mins[2]); + Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); + { + + double test[3]; + trace_t testtrace; + VectorLerp(rhc.start, rhc.trace->fraction, rhc.end, test); + memset(&testtrace, 0, sizeof(trace_t)); + rhc.trace = &testtrace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + VectorCopy(test, rhc.start); + VectorCopy(test, rhc.end); + VectorClear(rhc.dist); + Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); + //Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, test, test); + if (!trace->startsolid && testtrace.startsolid) + Con_Printf(" - ended in solid!\n"); + } + Con_Print("\n"); +#else + if (VectorLength2(rhc.dist)) + Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); + else + Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); +#endif +} + +static int Mod_Q1BSP_PointSuperContents(struct model_s *model, int frame, const vec3_t point) +{ + int num = model->brushq1.hulls[0].firstclipnode; + mplane_t *plane; + mclipnode_t *nodes = model->brushq1.hulls[0].clipnodes; + mplane_t *planes = model->brushq1.hulls[0].planes; + while (num >= 0) + { + plane = planes + nodes[num].planenum; + num = nodes[num].children[(plane->type < 3 ? point[plane->type] : DotProduct(plane->normal, point)) < plane->dist]; + } + return Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num); +} + +void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture) +{ +#if 1 + colbrushf_t cbox; + colplanef_t cbox_planes[6]; + cbox.isaabb = true; + cbox.hasaabbplanes = true; + cbox.supercontents = boxsupercontents; + cbox.numplanes = 6; + cbox.numpoints = 0; + cbox.numtriangles = 0; + cbox.planes = cbox_planes; + cbox.points = NULL; + cbox.elements = NULL; + cbox.markframe = 0; + cbox.mins[0] = 0; + cbox.mins[1] = 0; + cbox.mins[2] = 0; + cbox.maxs[0] = 0; + cbox.maxs[1] = 0; + cbox.maxs[2] = 0; + cbox_planes[0].normal[0] = 1;cbox_planes[0].normal[1] = 0;cbox_planes[0].normal[2] = 0;cbox_planes[0].dist = cmaxs[0] - mins[0]; + cbox_planes[1].normal[0] = -1;cbox_planes[1].normal[1] = 0;cbox_planes[1].normal[2] = 0;cbox_planes[1].dist = maxs[0] - cmins[0]; + cbox_planes[2].normal[0] = 0;cbox_planes[2].normal[1] = 1;cbox_planes[2].normal[2] = 0;cbox_planes[2].dist = cmaxs[1] - mins[1]; + cbox_planes[3].normal[0] = 0;cbox_planes[3].normal[1] = -1;cbox_planes[3].normal[2] = 0;cbox_planes[3].dist = maxs[1] - cmins[1]; + cbox_planes[4].normal[0] = 0;cbox_planes[4].normal[1] = 0;cbox_planes[4].normal[2] = 1;cbox_planes[4].dist = cmaxs[2] - mins[2]; + cbox_planes[5].normal[0] = 0;cbox_planes[5].normal[1] = 0;cbox_planes[5].normal[2] = -1;cbox_planes[5].dist = maxs[2] - cmins[2]; + cbox_planes[0].q3surfaceflags = boxq3surfaceflags;cbox_planes[0].texture = boxtexture; + cbox_planes[1].q3surfaceflags = boxq3surfaceflags;cbox_planes[1].texture = boxtexture; + cbox_planes[2].q3surfaceflags = boxq3surfaceflags;cbox_planes[2].texture = boxtexture; + cbox_planes[3].q3surfaceflags = boxq3surfaceflags;cbox_planes[3].texture = boxtexture; + cbox_planes[4].q3surfaceflags = boxq3surfaceflags;cbox_planes[4].texture = boxtexture; + cbox_planes[5].q3surfaceflags = boxq3surfaceflags;cbox_planes[5].texture = boxtexture; + memset(trace, 0, sizeof(trace_t)); + trace->hitsupercontentsmask = hitsupercontentsmask; + trace->fraction = 1; + trace->realfraction = 1; + Collision_TraceLineBrushFloat(trace, start, end, &cbox, &cbox); +#else + RecursiveHullCheckTraceInfo_t rhc; + static hull_t box_hull; + static mclipnode_t box_clipnodes[6]; + static mplane_t box_planes[6]; + // fill in a default trace + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + //To keep everything totally uniform, bounding boxes are turned into small + //BSP trees instead of being compared directly. + // create a temp hull from bounding box sizes + box_planes[0].dist = cmaxs[0] - mins[0]; + box_planes[1].dist = cmins[0] - maxs[0]; + box_planes[2].dist = cmaxs[1] - mins[1]; + box_planes[3].dist = cmins[1] - maxs[1]; + box_planes[4].dist = cmaxs[2] - mins[2]; + box_planes[5].dist = cmins[2] - maxs[2]; +#if COLLISIONPARANOID >= 3 + Con_Printf("box_planes %f:%f %f:%f %f:%f\ncbox %f %f %f:%f %f %f\nbox %f %f %f:%f %f %f\n", box_planes[0].dist, box_planes[1].dist, box_planes[2].dist, box_planes[3].dist, box_planes[4].dist, box_planes[5].dist, cmins[0], cmins[1], cmins[2], cmaxs[0], cmaxs[1], cmaxs[2], mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); +#endif + + if (box_hull.clipnodes == NULL) + { + int i, side; + + //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. + + 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; + } + } + + // trace a line through the generated clipping hull + //rhc.boxsupercontents = boxsupercontents; + rhc.hull = &box_hull; + rhc.trace = trace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + VectorCopy(start, rhc.start); + VectorCopy(end, rhc.end); + VectorSubtract(rhc.end, rhc.start, rhc.dist); + Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); + //VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos); + if (rhc.trace->startsupercontents) + rhc.trace->startsupercontents = boxsupercontents; +#endif +} + +void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture) +{ + memset(trace, 0, sizeof(trace_t)); + trace->fraction = 1; + trace->realfraction = 1; + if (BoxesOverlap(start, start, cmins, cmaxs)) + { + trace->startsupercontents |= boxsupercontents; + if (hitsupercontentsmask & boxsupercontents) + { + trace->startsolid = true; + trace->allsolid = true; + } + } +} + +static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end) +{ + trace_t trace; + Mod_Q1BSP_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK); + return trace.fraction == 1; +} + +static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz) +{ + int side; + float front, back; + float mid, distz = endz - startz; + +loc0: + if (!node->plane) + return false; // didn't hit anything + + switch (node->plane->type) + { + case PLANE_X: + node = node->children[x < node->plane->dist]; + goto loc0; + case PLANE_Y: + node = node->children[y < node->plane->dist]; + goto loc0; + case PLANE_Z: + side = startz < node->plane->dist; + if ((endz < node->plane->dist) == side) + { + node = node->children[side]; + goto loc0; + } + // found an intersection + mid = node->plane->dist; + break; + default: + back = front = x * node->plane->normal[0] + y * node->plane->normal[1]; + front += startz * node->plane->normal[2]; + back += endz * node->plane->normal[2]; + side = front < node->plane->dist; + if ((back < node->plane->dist) == side) + { + node = node->children[side]; + goto loc0; + } + // found an intersection + mid = startz + distz * (front - node->plane->dist) / (front - back); + break; + } + + // go down front side + if (node->children[side]->plane && Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid)) + return true; // hit something + else + { + // check for impact on this node + if (node->numsurfaces) + { + unsigned int i; + int dsi, dti, lmwidth, lmheight; + float ds, dt; + msurface_t *surface; + unsigned char *lightmap; + int maps, line3, size3; + float dsfrac; + float dtfrac; + float scale, w, w00, w01, w10, w11; + + surface = model->data_surfaces + node->firstsurface; + for (i = 0;i < node->numsurfaces;i++, surface++) + { + if (!(surface->texture->basematerialflags & MATERIALFLAG_WALL) || !surface->lightmapinfo || !surface->lightmapinfo->samples) + continue; // no lightmaps + + // location we want to sample in the lightmap + ds = ((x * surface->lightmapinfo->texinfo->vecs[0][0] + y * surface->lightmapinfo->texinfo->vecs[0][1] + mid * surface->lightmapinfo->texinfo->vecs[0][2] + surface->lightmapinfo->texinfo->vecs[0][3]) - surface->lightmapinfo->texturemins[0]) * 0.0625f; + dt = ((x * surface->lightmapinfo->texinfo->vecs[1][0] + y * surface->lightmapinfo->texinfo->vecs[1][1] + mid * surface->lightmapinfo->texinfo->vecs[1][2] + surface->lightmapinfo->texinfo->vecs[1][3]) - surface->lightmapinfo->texturemins[1]) * 0.0625f; + + // check the bounds + dsi = (int)ds; + dti = (int)dt; + lmwidth = ((surface->lightmapinfo->extents[0]>>4)+1); + lmheight = ((surface->lightmapinfo->extents[1]>>4)+1); + + // is it in bounds? + if (dsi >= 0 && dsi < lmwidth-1 && dti >= 0 && dti < lmheight-1) + { + // calculate bilinear interpolation factors + // and also multiply by fixedpoint conversion factors + dsfrac = ds - dsi; + dtfrac = dt - dti; + w00 = (1 - dsfrac) * (1 - dtfrac) * (1.0f / 32768.0f); + w01 = ( dsfrac) * (1 - dtfrac) * (1.0f / 32768.0f); + w10 = (1 - dsfrac) * ( dtfrac) * (1.0f / 32768.0f); + w11 = ( dsfrac) * ( dtfrac) * (1.0f / 32768.0f); + + // values for pointer math + line3 = lmwidth * 3; // LordHavoc: *3 for colored lighting + size3 = lmwidth * lmheight * 3; // LordHavoc: *3 for colored lighting + + // look up the pixel + lightmap = surface->lightmapinfo->samples + dti * line3 + dsi*3; // LordHavoc: *3 for colored lighting + + // bilinear filter each lightmap style, and sum them + for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++) + { + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[maps]]; + w = w00 * scale;VectorMA(ambientcolor, w, lightmap , ambientcolor); + w = w01 * scale;VectorMA(ambientcolor, w, lightmap + 3 , ambientcolor); + w = w10 * scale;VectorMA(ambientcolor, w, lightmap + line3 , ambientcolor); + w = w11 * scale;VectorMA(ambientcolor, w, lightmap + line3 + 3, ambientcolor); + lightmap += size3; + } + + return true; // success + } + } + } + + // go down back side + node = node->children[side ^ 1]; + startz = mid; + distz = endz - startz; + goto loc0; + } +} + +static void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal) +{ + // pretend lighting is coming down from above (due to lack of a lightgrid to know primary lighting direction) + VectorSet(diffusenormal, 0, 0, 1); + + if (!model->brushq1.lightdata) + { + VectorSet(ambientcolor, 1, 1, 1); + VectorSet(diffusecolor, 0, 0, 0); + return; + } + + Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536); +} + +static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, double mid[3]) +{ + unsigned int i; + int j; + int k; + const msurface_t *surface; + float normal[3]; + float v0[3]; + float v1[3]; + float edgedir[3]; + float edgenormal[3]; + float p[4]; + float midf; + float t1; + float t2; + VectorCopy(mid, p); + p[3] = 1; + surface = model->data_surfaces + node->firstsurface; + for (i = 0;i < node->numsurfaces;i++, surface++) + { + // skip surfaces whose bounding box does not include the point +// if (!BoxesOverlap(mid, mid, surface->mins, surface->maxs)) +// continue; + // skip faces with contents we don't care about + if (!(t->trace->hitsupercontentsmask & surface->texture->supercontents)) + continue; + // get the surface normal - since it is flat we know any vertex normal will suffice + VectorCopy(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex, normal); + // skip backfaces + if (DotProduct(t->dist, normal) > 0) + continue; + // iterate edges and see if the point is outside one of them + for (j = 0, k = surface->num_vertices - 1;j < surface->num_vertices;k = j, j++) + { + VectorCopy(model->surfmesh.data_vertex3f + 3 * (surface->num_firstvertex + k), v0); + VectorCopy(model->surfmesh.data_vertex3f + 3 * (surface->num_firstvertex + j), v1); + VectorSubtract(v0, v1, edgedir); + CrossProduct(edgedir, normal, edgenormal); + if (DotProduct(edgenormal, p) > DotProduct(edgenormal, v0)) + break; + } + // if the point is outside one of the edges, it is not within the surface + if (j < surface->num_vertices) + continue; + + // we hit a surface, this is the impact point... + VectorCopy(normal, t->trace->plane.normal); + t->trace->plane.dist = DotProduct(normal, p); + + // calculate the true fraction + t1 = DotProduct(t->start, t->trace->plane.normal) - t->trace->plane.dist; + t2 = DotProduct(t->end, t->trace->plane.normal) - t->trace->plane.dist; + midf = t1 / (t1 - t2); + t->trace->realfraction = midf; + + // calculate the return fraction which is nudged off the surface a bit + midf = (t1 - DIST_EPSILON) / (t1 - t2); + t->trace->fraction = bound(0, midf, 1); + + if (collision_prefernudgedfraction.integer) + t->trace->realfraction = t->trace->fraction; + + t->trace->hittexture = surface->texture->currentframe; + t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags; + t->trace->hitsupercontents = t->trace->hittexture->supercontents; + return surface->texture->currentframe; + } + return NULL; +} + +static int Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, const double p1[3], const double p2[3]) +{ + const mplane_t *plane; + double t1, t2; + int side; + double midf, mid[3]; + const mleaf_t *leaf; + + while (node->plane) + { + plane = node->plane; + 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 (t1 < 0) + { + if (t2 < 0) + { + node = node->children[1]; + continue; + } + side = 1; + } + else + { + if (t2 >= 0) + { + node = node->children[0]; + continue; + } + side = 0; + } + + // the line intersects, find intersection point + // LordHavoc: this uses the original trace for maximum accuracy + if (plane->type < 3) + { + t1 = t->start[plane->type] - plane->dist; + t2 = t->end[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, t->start) - plane->dist; + t2 = DotProduct (plane->normal, t->end) - plane->dist; + } + + midf = t1 / (t1 - t2); + VectorMA(t->start, midf, t->dist, mid); + + // recurse both sides, front side first, return if we hit a surface + if (Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side], p1, mid) == HULLCHECKSTATE_DONE) + return HULLCHECKSTATE_DONE; + + // test each surface on the node + Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(t, model, node, mid); + if (t->trace->hittexture) + return HULLCHECKSTATE_DONE; + + // recurse back side + return Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side ^ 1], mid, p2); + } + leaf = (const mleaf_t *)node; + side = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, leaf->contents); + if (!t->trace->startfound) + { + t->trace->startfound = true; + t->trace->startsupercontents |= side; + } + if (side & SUPERCONTENTS_LIQUIDSMASK) + t->trace->inwater = true; + if (side == 0) + t->trace->inopen = true; + if (side & t->trace->hitsupercontentsmask) + { + // if the first leaf is solid, set startsolid + if (t->trace->allsolid) + t->trace->startsolid = true; + return HULLCHECKSTATE_SOLID; + } + else + { + t->trace->allsolid = false; + return HULLCHECKSTATE_EMPTY; + } +} + +static void Mod_Q1BSP_TraceLineAgainstSurfaces(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + RecursiveHullCheckTraceInfo_t rhc; + + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + rhc.trace = trace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 + VectorCopy(start, rhc.start); + VectorCopy(end, rhc.end); + VectorSubtract(rhc.end, rhc.start, rhc.dist); + Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(&rhc, model, model->brush.data_nodes + rhc.hull->firstclipnode, rhc.start, rhc.end); + VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos); +} + +static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend) +{ + int c; + unsigned char *outstart = out; + while (out < outend) + { + if (in == inend) + { + Con_Printf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart)); + return; + } + c = *in++; + if (c) + *out++ = c; + else + { + if (in == inend) + { + Con_Printf("Mod_Q1BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart)); + return; + } + for (c = *in++;c > 0;c--) + { + if (out == outend) + { + Con_Printf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart)); + return; + } + *out++ = 0; + } + } + } +} + +/* +============= +R_Q1BSP_LoadSplitSky + +A sky texture is 256*128, with the right side being a masked overlay +============== +*/ +static void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesperpixel) +{ + int x, y; + int w = width/2; + int h = height; + unsigned int *solidpixels = (unsigned int *)Mem_Alloc(tempmempool, w*h*sizeof(unsigned char[4])); + unsigned int *alphapixels = (unsigned int *)Mem_Alloc(tempmempool, w*h*sizeof(unsigned char[4])); + + // allocate a texture pool if we need it + if (loadmodel->texturepool == NULL && cls.state != ca_dedicated) + loadmodel->texturepool = R_AllocTexturePool(); + + if (bytesperpixel == 4) + { + for (y = 0;y < h;y++) + { + for (x = 0;x < w;x++) + { + solidpixels[y*w+x] = ((unsigned *)src)[y*width+x+w]; + alphapixels[y*w+x] = ((unsigned *)src)[y*width+x]; + } + } + } + else + { + // make an average value for the back to avoid + // a fringe on the top level + int p, r, g, b; + union + { + unsigned int i; + unsigned char b[4]; + } + bgra; + r = g = b = 0; + for (y = 0;y < h;y++) + { + for (x = 0;x < w;x++) + { + p = src[x*width+y+w]; + r += palette_rgb[p][0]; + g += palette_rgb[p][1]; + b += palette_rgb[p][2]; + } + } + bgra.b[2] = r/(w*h); + bgra.b[1] = g/(w*h); + bgra.b[0] = b/(w*h); + bgra.b[3] = 0; + for (y = 0;y < h;y++) + { + for (x = 0;x < w;x++) + { + solidpixels[y*w+x] = palette_bgra_complete[src[y*width+x+w]]; + p = src[y*width+x]; + alphapixels[y*w+x] = p ? palette_bgra_complete[p] : bgra.i; + } + } + } + + loadmodel->brush.solidskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_solidtexture", 0 , (unsigned char *) solidpixels, w, h, vid.sRGB3D); + loadmodel->brush.alphaskyskinframe = R_SkinFrame_LoadInternalBGRA("sky_alphatexture", TEXF_ALPHA, (unsigned char *) alphapixels, w, h, vid.sRGB3D); + Mem_Free(solidpixels); + Mem_Free(alphapixels); +} + +static void Mod_Q1BSP_LoadTextures(sizebuf_t *sb) +{ + int i, j, k, num, max, altmax, mtwidth, mtheight, doffset, incomplete, nummiptex = 0; + skinframe_t *skinframe; + texture_t *tx, *tx2, *anims[10], *altanims[10]; + texture_t backuptex; + unsigned char *data, *mtdata; + const char *s; + char mapname[MAX_QPATH], name[MAX_QPATH]; + unsigned char zeroopaque[4], zerotrans[4]; + sizebuf_t miptexsb; + char vabuf[1024]; + Vector4Set(zeroopaque, 0, 0, 0, 255); + Vector4Set(zerotrans, 0, 0, 0, 128); + + loadmodel->data_textures = NULL; + + // add two slots for notexture walls and notexture liquids + if (sb->cursize) + { + nummiptex = MSG_ReadLittleLong(sb); + loadmodel->num_textures = nummiptex + 2; + loadmodel->num_texturesperskin = loadmodel->num_textures; + } + else + { + loadmodel->num_textures = 2; + loadmodel->num_texturesperskin = loadmodel->num_textures; + } + + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_textures * sizeof(texture_t)); + + // fill out all slots with notexture + if (cls.state != ca_dedicated) + skinframe = R_SkinFrame_LoadMissing(); + else + skinframe = NULL; + for (i = 0, tx = loadmodel->data_textures;i < loadmodel->num_textures;i++, tx++) + { + strlcpy(tx->name, "NO TEXTURE FOUND", sizeof(tx->name)); + tx->width = 16; + tx->height = 16; + if (cls.state != ca_dedicated) + { + tx->numskinframes = 1; + tx->skinframerate = 1; + tx->skinframes[0] = skinframe; + tx->currentskinframe = tx->skinframes[0]; + } + tx->basematerialflags = MATERIALFLAG_WALL; + if (i == loadmodel->num_textures - 1) + { + tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW; + tx->supercontents = mod_q1bsp_texture_water.supercontents; + tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags; + } + else + { + tx->supercontents = mod_q1bsp_texture_solid.supercontents; + tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags; + } + tx->currentframe = tx; + + // clear water settings + tx->reflectmin = 0; + tx->reflectmax = 1; + tx->refractfactor = 1; + Vector4Set(tx->refractcolor4f, 1, 1, 1, 1); + tx->reflectfactor = 1; + Vector4Set(tx->reflectcolor4f, 1, 1, 1, 1); + tx->r_water_wateralpha = 1; + tx->offsetmapping = OFFSETMAPPING_DEFAULT; + tx->offsetscale = 1; + tx->offsetbias = 0; + tx->specularscalemod = 1; + tx->specularpowermod = 1; + tx->transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". + } + + if (!sb->cursize) + { + Con_Printf("%s: no miptex lump to load textures from\n", loadmodel->name); + return; + } + + s = loadmodel->name; + if (!strncasecmp(s, "maps/", 5)) + s += 5; + FS_StripExtension(s, mapname, sizeof(mapname)); + + // just to work around bounds checking when debugging with it (array index out of bounds error thing) + // LordHavoc: mostly rewritten map texture loader + for (i = 0;i < nummiptex;i++) + { + doffset = MSG_ReadLittleLong(sb); + if (r_nosurftextures.integer) + continue; + if (doffset == -1) + { + Con_DPrintf("%s: miptex #%i missing\n", loadmodel->name, i); + continue; + } + + MSG_InitReadBuffer(&miptexsb, sb->data + doffset, sb->cursize - doffset); + + // copy name, but only up to 16 characters + // (the output buffer can hold more than this, but the input buffer is + // only 16) + for (j = 0;j < 16;j++) + name[j] = MSG_ReadByte(&miptexsb); + name[j] = 0; + // pretty up the buffer (replacing any trailing garbage with 0) + for (j = strlen(name);j < 16;j++) + name[j] = 0; + + if (!name[0]) + { + dpsnprintf(name, sizeof(name), "unnamed%i", i); + Con_DPrintf("%s: warning: renaming unnamed texture to %s\n", loadmodel->name, name); + } + + mtwidth = MSG_ReadLittleLong(&miptexsb); + mtheight = MSG_ReadLittleLong(&miptexsb); + mtdata = NULL; + j = MSG_ReadLittleLong(&miptexsb); + if (j) + { + // texture included + if (j < 40 || j + mtwidth * mtheight > miptexsb.cursize) + { + Con_Printf("%s: Texture \"%s\" is corrupt or incomplete\n", loadmodel->name, name); + continue; + } + mtdata = miptexsb.data + j; + } + + if ((mtwidth & 15) || (mtheight & 15)) + Con_DPrintf("%s: warning: texture \"%s\" is not 16 aligned\n", loadmodel->name, name); + + // LordHavoc: force all names to lowercase + for (j = 0;name[j];j++) + if (name[j] >= 'A' && name[j] <= 'Z') + name[j] += 'a' - 'A'; + + // LordHavoc: backup the texture_t because q3 shader loading overwrites it + backuptex = loadmodel->data_textures[i]; + if (name[0] && Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + i, name, false, false, 0)) + continue; + loadmodel->data_textures[i] = backuptex; + + tx = loadmodel->data_textures + i; + strlcpy(tx->name, name, sizeof(tx->name)); + tx->width = mtwidth; + tx->height = mtheight; + + if (tx->name[0] == '*') + { + if (!strncmp(tx->name, "*lava", 5)) + { + tx->supercontents = mod_q1bsp_texture_lava.supercontents; + tx->surfaceflags = mod_q1bsp_texture_lava.surfaceflags; + } + else if (!strncmp(tx->name, "*slime", 6)) + { + tx->supercontents = mod_q1bsp_texture_slime.supercontents; + tx->surfaceflags = mod_q1bsp_texture_slime.surfaceflags; + } + else + { + tx->supercontents = mod_q1bsp_texture_water.supercontents; + tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags; + } + } + else if (!strncmp(tx->name, "sky", 3)) + { + tx->supercontents = mod_q1bsp_texture_sky.supercontents; + tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags; + // for the surface traceline we need to hit this surface as a solid... + tx->supercontents |= SUPERCONTENTS_SOLID; + } + else + { + tx->supercontents = mod_q1bsp_texture_solid.supercontents; + tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags; + } + + if (cls.state != ca_dedicated) + { + // LordHavoc: HL sky textures are entirely different than quake + if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == mtheight * 2) + { + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), false, false, false, NULL); + if (!data) + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), false, false, false, NULL); + if (data && image_width == image_height * 2) + { + R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); + Mem_Free(data); + } + else if (mtdata != NULL) + R_Q1BSP_LoadSplitSky(mtdata, mtwidth, mtheight, 1); + } + else + { + skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + if (!skinframe) + skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + if (skinframe) + tx->offsetmapping = OFFSETMAPPING_DEFAULT; // allow offsetmapping on external textures without a q3 shader + if (!skinframe) + { + // did not find external texture, load it from the bsp or wad3 + if (loadmodel->brush.ishlbsp) + { + // internal texture overrides wad + unsigned char *pixels, *freepixels; + pixels = freepixels = NULL; + if (mtdata) + pixels = W_ConvertWAD3TextureBGRA(&miptexsb); + if (pixels == NULL) + pixels = freepixels = W_GetTextureBGRA(tx->name); + if (pixels != NULL) + { + tx->width = image_width; + tx->height = image_height; + skinframe = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP, pixels, image_width, image_height, true); + } + if (freepixels) + Mem_Free(freepixels); + } + else if (mtdata) // texture included + skinframe = R_SkinFrame_LoadInternalQuake(tx->name, TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP, false, r_fullbrights.integer, mtdata, tx->width, tx->height); + } + // if skinframe is still NULL the "missing" texture will be used + if (skinframe) + tx->skinframes[0] = skinframe; + } + // LordHavoc: some Tenebrae textures get replaced by black + if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae + tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, TEXF_MIPMAP | TEXF_ALPHA, zerotrans, 1, 1, false); + else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae + tx->skinframes[0] = R_SkinFrame_LoadInternalBGRA(tx->name, 0, zeroopaque, 1, 1, false); + } + + tx->basematerialflags = MATERIALFLAG_WALL; + if (tx->name[0] == '*') + { + // LordHavoc: some turbulent textures should not be affected by wateralpha + if (!strncmp(tx->name, "*glassmirror", 12)) // Tenebrae + tx->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_REFLECTION; + else if (!strncmp(tx->name,"*lava",5) + || !strncmp(tx->name,"*teleport",9) + || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture + tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW; + else + tx->basematerialflags |= MATERIALFLAG_WATERSCROLL | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERALPHA | MATERIALFLAG_WATERSHADER; + if (tx->skinframes[0] && tx->skinframes[0]->hasalpha) + tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + } + else if (!strncmp(tx->name, "mirror", 6)) // Tenebrae + { + // replace the texture with black + tx->basematerialflags |= MATERIALFLAG_REFLECTION; + } + else if (!strncmp(tx->name, "sky", 3)) + tx->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + else if (!strcmp(tx->name, "caulk")) + tx->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + else if (tx->skinframes[0] && tx->skinframes[0]->hasalpha) + tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + + // start out with no animation + tx->currentframe = tx; + tx->currentskinframe = tx->skinframes[0]; + tx->currentmaterialflags = tx->basematerialflags; + } + + // sequence the animations + for (i = 0;i < nummiptex;i++) + { + tx = loadmodel->data_textures + i; + if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0) + continue; + if (tx->anim_total[0] || tx->anim_total[1]) + continue; // already sequenced + + // find the number of frames in the animation + memset(anims, 0, sizeof(anims)); + memset(altanims, 0, sizeof(altanims)); + + for (j = i;j < nummiptex;j++) + { + tx2 = loadmodel->data_textures + j; + if (!tx2 || tx2->name[0] != '+' || strcmp(tx2->name+2, tx->name+2)) + continue; + + num = tx2->name[1]; + if (num >= '0' && num <= '9') + anims[num - '0'] = tx2; + else if (num >= 'a' && num <= 'j') + altanims[num - 'a'] = tx2; + else + Con_Printf("Bad animating texture %s\n", tx->name); + } + + max = altmax = 0; + for (j = 0;j < 10;j++) + { + if (anims[j]) + max = j + 1; + if (altanims[j]) + altmax = j + 1; + } + //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax); + + incomplete = false; + for (j = 0;j < max;j++) + { + if (!anims[j]) + { + Con_Printf("Missing frame %i of %s\n", j, tx->name); + incomplete = true; + } + } + for (j = 0;j < altmax;j++) + { + if (!altanims[j]) + { + Con_Printf("Missing altframe %i of %s\n", j, tx->name); + incomplete = true; + } + } + if (incomplete) + continue; + + if (altmax < 1) + { + // if there is no alternate animation, duplicate the primary + // animation into the alternate + altmax = max; + for (k = 0;k < 10;k++) + altanims[k] = anims[k]; + } + + // link together the primary animation + for (j = 0;j < max;j++) + { + tx2 = anims[j]; + tx2->animated = true; + tx2->anim_total[0] = max; + tx2->anim_total[1] = altmax; + for (k = 0;k < 10;k++) + { + tx2->anim_frames[0][k] = anims[k]; + tx2->anim_frames[1][k] = altanims[k]; + } + } + + // if there really is an alternate anim... + if (anims[0] != altanims[0]) + { + // link together the alternate animation + for (j = 0;j < altmax;j++) + { + tx2 = altanims[j]; + tx2->animated = true; + // the primary/alternate are reversed here + tx2->anim_total[0] = altmax; + tx2->anim_total[1] = max; + for (k = 0;k < 10;k++) + { + tx2->anim_frames[0][k] = altanims[k]; + tx2->anim_frames[1][k] = anims[k]; + } + } + } + } +} + +static void Mod_Q1BSP_LoadLighting(sizebuf_t *sb) +{ + int i; + unsigned char *in, *out, *data, d; + char litfilename[MAX_QPATH]; + char dlitfilename[MAX_QPATH]; + fs_offset_t filesize; + if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight + { + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize); + for (i = 0;i < sb->cursize;i++) + loadmodel->brushq1.lightdata[i] = sb->data[i] >>= 1; + } + else // LordHavoc: bsp version 29 (normal white lighting) + { + // LordHavoc: hope is not lost yet, check for a .lit file to load + strlcpy (litfilename, loadmodel->name, sizeof (litfilename)); + FS_StripExtension (litfilename, litfilename, sizeof (litfilename)); + strlcpy (dlitfilename, litfilename, sizeof (dlitfilename)); + strlcat (litfilename, ".lit", sizeof (litfilename)); + strlcat (dlitfilename, ".dlit", sizeof (dlitfilename)); + data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize); + if (data) + { + if (filesize == (fs_offset_t)(8 + sb->cursize * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + { + i = LittleLong(((int *)data)[1]); + if (i == 1) + { + if (developer_loading.integer) + Con_Printf("loaded %s\n", litfilename); + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8); + memcpy(loadmodel->brushq1.lightdata, data + 8, filesize - 8); + Mem_Free(data); + data = (unsigned char*) FS_LoadFile(dlitfilename, tempmempool, false, &filesize); + if (data) + { + if (filesize == (fs_offset_t)(8 + sb->cursize * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + { + i = LittleLong(((int *)data)[1]); + if (i == 1) + { + if (developer_loading.integer) + Con_Printf("loaded %s\n", dlitfilename); + loadmodel->brushq1.nmaplightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8); + memcpy(loadmodel->brushq1.nmaplightdata, data + 8, filesize - 8); + loadmodel->brushq3.deluxemapping_modelspace = false; + loadmodel->brushq3.deluxemapping = true; + } + } + Mem_Free(data); + data = NULL; + } + return; + } + else + Con_Printf("Unknown .lit file version (%d)\n", i); + } + else if (filesize == 8) + Con_Print("Empty .lit file, ignoring\n"); + else + Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", (int) filesize, (int) (8 + sb->cursize * 3)); + if (data) + { + Mem_Free(data); + data = NULL; + } + } + // LordHavoc: oh well, expand the white lighting data + if (!sb->cursize) + return; + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize*3); + in = sb->data; + out = loadmodel->brushq1.lightdata; + for (i = 0;i < sb->cursize;i++) + { + d = *in++; + *out++ = d; + *out++ = d; + *out++ = d; + } + } +} + +static void Mod_Q1BSP_LoadVisibility(sizebuf_t *sb) +{ + loadmodel->brushq1.num_compressedpvs = 0; + loadmodel->brushq1.data_compressedpvs = NULL; + if (!sb->cursize) + return; + loadmodel->brushq1.num_compressedpvs = sb->cursize; + loadmodel->brushq1.data_compressedpvs = (unsigned char *)Mem_Alloc(loadmodel->mempool, sb->cursize); + MSG_ReadBytes(sb, sb->cursize, loadmodel->brushq1.data_compressedpvs); +} + +// used only for HalfLife maps +static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) +{ + char key[128], value[4096]; + int i, j, k; + if (!data) + return; + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] != '{') + return; // error + while (1) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strlcpy(key, com_token + 1, sizeof(key)); + else + strlcpy(key, com_token, sizeof(key)); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + dpsnprintf(value, sizeof(value), "%s", com_token); + if (!strcmp("wad", key)) // for HalfLife maps + { + if (loadmodel->brush.ishlbsp) + { + j = 0; + for (i = 0;i < (int)sizeof(value);i++) + if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':') + break; + if (value[i]) + { + for (;i < (int)sizeof(value);i++) + { + // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'... + if (value[i] == '\\' || value[i] == '/' || value[i] == ':') + j = i+1; + else if (value[i] == ';' || value[i] == 0) + { + k = value[i]; + value[i] = 0; + W_LoadTextureWadFile(&value[j], false); + j = i+1; + if (!k) + break; + } + } + } + } + } + } +} + +static void Mod_Q1BSP_LoadEntities(sizebuf_t *sb) +{ + loadmodel->brush.entities = NULL; + if (!sb->cursize) + return; + loadmodel->brush.entities = (char *)Mem_Alloc(loadmodel->mempool, sb->cursize + 1); + MSG_ReadBytes(sb, sb->cursize, (unsigned char *)loadmodel->brush.entities); + loadmodel->brush.entities[sb->cursize] = 0; + if (loadmodel->brush.ishlbsp) + Mod_Q1BSP_ParseWadsFromEntityLump(loadmodel->brush.entities); +} + + +static void Mod_Q1BSP_LoadVertexes(sizebuf_t *sb) +{ + mvertex_t *out; + int i, count; + size_t structsize = 12; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadVertexes: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + out = (mvertex_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); + + loadmodel->brushq1.vertexes = out; + loadmodel->brushq1.numvertexes = count; + + for ( i=0 ; iposition[0] = MSG_ReadLittleFloat(sb); + out->position[1] = MSG_ReadLittleFloat(sb); + out->position[2] = MSG_ReadLittleFloat(sb); + } +} + +static void Mod_Q1BSP_LoadSubmodels(sizebuf_t *sb, hullinfo_t *hullinfo) +{ + mmodel_t *out; + int i, j, count; + size_t structsize = (48+4*hullinfo->filehulls); + + if (sb->cursize % structsize) + Host_Error ("Mod_Q1BSP_LoadSubmodels: funny lump size in %s", loadmodel->name); + + count = sb->cursize / structsize; + out = (mmodel_t *)Mem_Alloc (loadmodel->mempool, count*sizeof(*out)); + + loadmodel->brushq1.submodels = out; + loadmodel->brush.numsubmodels = count; + + for (i = 0; i < count; i++, out++) + { + // spread out the mins / maxs by a pixel + out->mins[0] = MSG_ReadLittleFloat(sb) - 1; + out->mins[1] = MSG_ReadLittleFloat(sb) - 1; + out->mins[2] = MSG_ReadLittleFloat(sb) - 1; + out->maxs[0] = MSG_ReadLittleFloat(sb) + 1; + out->maxs[1] = MSG_ReadLittleFloat(sb) + 1; + out->maxs[2] = MSG_ReadLittleFloat(sb) + 1; + out->origin[0] = MSG_ReadLittleFloat(sb); + out->origin[1] = MSG_ReadLittleFloat(sb); + out->origin[2] = MSG_ReadLittleFloat(sb); + for (j = 0; j < hullinfo->filehulls; j++) + out->headnode[j] = MSG_ReadLittleLong(sb); + out->visleafs = MSG_ReadLittleLong(sb); + out->firstface = MSG_ReadLittleLong(sb); + out->numfaces = MSG_ReadLittleLong(sb); + } +} + +static void Mod_Q1BSP_LoadEdges(sizebuf_t *sb) +{ + medge_t *out; + int i, count; + size_t structsize = loadmodel->brush.isbsp2 ? 8 : 4; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadEdges: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + out = (medge_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brushq1.edges = out; + loadmodel->brushq1.numedges = count; + + for ( i=0 ; ibrush.isbsp2) + { + out->v[0] = (unsigned int)MSG_ReadLittleLong(sb); + out->v[1] = (unsigned int)MSG_ReadLittleLong(sb); + } + else + { + out->v[0] = (unsigned short)MSG_ReadLittleShort(sb); + out->v[1] = (unsigned short)MSG_ReadLittleShort(sb); + } + if ((int)out->v[0] >= loadmodel->brushq1.numvertexes || (int)out->v[1] >= loadmodel->brushq1.numvertexes) + { + Con_Printf("Mod_Q1BSP_LoadEdges: %s has invalid vertex indices in edge %i (vertices %i %i >= numvertices %i)\n", loadmodel->name, i, out->v[0], out->v[1], loadmodel->brushq1.numvertexes); + if(!loadmodel->brushq1.numvertexes) + Host_Error("Mod_Q1BSP_LoadEdges: %s has edges but no vertexes, cannot fix\n", loadmodel->name); + + out->v[0] = 0; + out->v[1] = 0; + } + } +} + +static void Mod_Q1BSP_LoadTexinfo(sizebuf_t *sb) +{ + mtexinfo_t *out; + int i, j, k, count, miptex; + size_t structsize = 40; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadTexinfo: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + out = (mtexinfo_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brushq1.texinfo = out; + loadmodel->brushq1.numtexinfo = count; + + for (i = 0;i < count;i++, out++) + { + for (k = 0;k < 2;k++) + for (j = 0;j < 4;j++) + out->vecs[k][j] = MSG_ReadLittleFloat(sb); + + miptex = MSG_ReadLittleLong(sb); + out->flags = MSG_ReadLittleLong(sb); + + out->texture = NULL; + if (loadmodel->data_textures) + { + if ((unsigned int) miptex >= (unsigned int) loadmodel->num_textures) + Con_Printf("error in model \"%s\": invalid miptex index %i(of %i)\n", loadmodel->name, miptex, loadmodel->num_textures); + else + out->texture = loadmodel->data_textures + miptex; + } + if (out->flags & TEX_SPECIAL) + { + // if texture chosen is NULL or the shader needs a lightmap, + // force to notexture water shader + if (out->texture == NULL) + out->texture = loadmodel->data_textures + (loadmodel->num_textures - 1); + } + else + { + // if texture chosen is NULL, force to notexture + if (out->texture == NULL) + out->texture = loadmodel->data_textures + (loadmodel->num_textures - 2); + } + } +} + +#if 0 +void BoundPoly(int numverts, float *verts, vec3_t mins, vec3_t maxs) +{ + int i, j; + float *v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + v = verts; + for (i = 0;i < numverts;i++) + { + for (j = 0;j < 3;j++, v++) + { + if (*v < mins[j]) + mins[j] = *v; + if (*v > maxs[j]) + maxs[j] = *v; + } + } +} + +#define MAX_SUBDIVPOLYTRIANGLES 4096 +#define MAX_SUBDIVPOLYVERTS(MAX_SUBDIVPOLYTRIANGLES * 3) + +static int subdivpolyverts, subdivpolytriangles; +static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3]; +static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3]; + +static int subdivpolylookupvert(vec3_t v) +{ + int i; + for (i = 0;i < subdivpolyverts;i++) + if (subdivpolyvert[i][0] == v[0] + && subdivpolyvert[i][1] == v[1] + && subdivpolyvert[i][2] == v[2]) + return i; + if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS) + Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size"); + VectorCopy(v, subdivpolyvert[subdivpolyverts]); + return subdivpolyverts++; +} + +static void SubdividePolygon(int numverts, float *verts) +{ + int i, i1, i2, i3, f, b, c, p; + vec3_t mins, maxs, front[256], back[256]; + float m, *pv, *cv, dist[256], frac; + + if (numverts > 250) + Host_Error("SubdividePolygon: ran out of verts in buffer"); + + BoundPoly(numverts, verts, mins, maxs); + + for (i = 0;i < 3;i++) + { + m = (mins[i] + maxs[i]) * 0.5; + m = r_subdivide_size.value * floor(m/r_subdivide_size.value + 0.5); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + for (cv = verts, c = 0;c < numverts;c++, cv += 3) + dist[c] = cv[i] - m; + + f = b = 0; + for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3) + { + if (dist[p] >= 0) + { + VectorCopy(pv, front[f]); + f++; + } + if (dist[p] <= 0) + { + VectorCopy(pv, back[b]); + b++; + } + if (dist[p] == 0 || dist[c] == 0) + continue; + if ((dist[p] > 0) != (dist[c] > 0) ) + { + // clip point + frac = dist[p] / (dist[p] - dist[c]); + front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]); + front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]); + front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]); + f++; + b++; + } + } + + SubdividePolygon(f, front[0]); + SubdividePolygon(b, back[0]); + return; + } + + i1 = subdivpolylookupvert(verts); + i2 = subdivpolylookupvert(verts + 3); + for (i = 2;i < numverts;i++) + { + if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES) + { + Con_Print("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n"); + return; + } + + i3 = subdivpolylookupvert(verts + i * 3); + subdivpolyindex[subdivpolytriangles][0] = i1; + subdivpolyindex[subdivpolytriangles][1] = i2; + subdivpolyindex[subdivpolytriangles][2] = i3; + i2 = i3; + subdivpolytriangles++; + } +} + +//Breaks a polygon up along axial 64 unit +//boundaries so that turbulent and sky warps +//can be done reasonably. +static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface) +{ + int i, j; + surfvertex_t *v; + surfmesh_t *mesh; + + subdivpolytriangles = 0; + subdivpolyverts = 0; + SubdividePolygon(surface->num_vertices, (surface->mesh->data_vertex3f + 3 * surface->num_firstvertex)); + if (subdivpolytriangles < 1) + Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?"); + + surface->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t)); + mesh->num_vertices = subdivpolyverts; + mesh->num_triangles = subdivpolytriangles; + mesh->vertex = (surfvertex_t *)(mesh + 1); + mesh->index = (int *)(mesh->vertex + mesh->num_vertices); + memset(mesh->vertex, 0, mesh->num_vertices * sizeof(surfvertex_t)); + + for (i = 0;i < mesh->num_triangles;i++) + for (j = 0;j < 3;j++) + mesh->index[i*3+j] = subdivpolyindex[i][j]; + + for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++) + { + VectorCopy(subdivpolyvert[i], v->v); + v->st[0] = DotProduct(v->v, surface->lightmapinfo->texinfo->vecs[0]); + v->st[1] = DotProduct(v->v, surface->lightmapinfo->texinfo->vecs[1]); + } +} +#endif + +extern cvar_t gl_max_lightmapsize; +static void Mod_Q1BSP_LoadFaces(sizebuf_t *sb) +{ + msurface_t *surface; + int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber, lightmapsize, totallightmapsamples, lightmapoffset, texinfoindex; + float texmins[2], texmaxs[2], val; + rtexture_t *lightmaptexture, *deluxemaptexture; + char vabuf[1024]; + size_t structsize = loadmodel->brush.isbsp2 ? 28 : 20; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadFaces: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + loadmodel->data_surfaces = (msurface_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t)); + loadmodel->data_surfaces_lightmapinfo = (msurface_lightmapinfo_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_lightmapinfo_t)); + + loadmodel->num_surfaces = count; + + loadmodel->brushq1.firstrender = true; + loadmodel->brushq1.lightmapupdateflags = (unsigned char *)Mem_Alloc(loadmodel->mempool, count*sizeof(unsigned char)); + + totalverts = 0; + totaltris = 0; + for (surfacenum = 0;surfacenum < count;surfacenum++) + { + if (loadmodel->brush.isbsp2) + numedges = BuffLittleLong(sb->data + structsize * surfacenum + 12); + else + numedges = BuffLittleShort(sb->data + structsize * surfacenum + 8); + totalverts += numedges; + totaltris += numedges - 2; + } + + Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false); + + lightmaptexture = NULL; + deluxemaptexture = r_texture_blanknormalmap; + lightmapnumber = 0; + lightmapsize = bound(256, gl_max_lightmapsize.integer, (int)vid.maxtexturesize_2d); + totallightmapsamples = 0; + + totalverts = 0; + totaltris = 0; + for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++) + { + surface->lightmapinfo = loadmodel->data_surfaces_lightmapinfo + surfacenum; + planenum = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + /*side = */loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + firstedge = MSG_ReadLittleLong(sb); + numedges = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + texinfoindex = loadmodel->brush.isbsp2 ? MSG_ReadLittleLong(sb) : (unsigned short)MSG_ReadLittleShort(sb); + for (i = 0;i < MAXLIGHTMAPS;i++) + surface->lightmapinfo->styles[i] = MSG_ReadByte(sb); + lightmapoffset = MSG_ReadLittleLong(sb); + + // FIXME: validate edges, texinfo, etc? + if ((unsigned int) firstedge > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges) + Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)", firstedge, numedges, loadmodel->brushq1.numsurfedges); + if ((unsigned int) texinfoindex >= (unsigned int) loadmodel->brushq1.numtexinfo) + Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)", texinfoindex, loadmodel->brushq1.numtexinfo); + if ((unsigned int) planenum >= (unsigned int) loadmodel->brush.num_planes) + Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)", planenum, loadmodel->brush.num_planes); + + surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + texinfoindex; + surface->texture = surface->lightmapinfo->texinfo->texture; + + //surface->flags = surface->texture->flags; + //if (LittleShort(in->side)) + // surface->flags |= SURF_PLANEBACK; + //surface->plane = loadmodel->brush.data_planes + planenum; + + surface->num_firstvertex = totalverts; + surface->num_vertices = numedges; + surface->num_firsttriangle = totaltris; + surface->num_triangles = numedges - 2; + totalverts += numedges; + totaltris += numedges - 2; + + // convert edges back to a normal polygon + for (i = 0;i < surface->num_vertices;i++) + { + int lindex = loadmodel->brushq1.surfedges[firstedge + i]; + float s, t; + // note: the q1bsp format does not allow a 0 surfedge (it would have no negative counterpart) + if (lindex >= 0) + VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3); + else + VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3); + s = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]; + t = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]; + (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 0] = s / surface->texture->width; + (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 1] = t / surface->texture->height; + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = 0; + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = 0; + (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = 0; + } + + for (i = 0;i < surface->num_triangles;i++) + { + (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] = 0 + surface->num_firstvertex; + (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] = i + 1 + surface->num_firstvertex; + (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] = i + 2 + surface->num_firstvertex; + } + + // compile additional data about the surface geometry + Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)); + + // generate surface extents information + texmins[0] = texmaxs[0] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]; + texmins[1] = texmaxs[1] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]; + for (i = 1;i < surface->num_vertices;i++) + { + for (j = 0;j < 2;j++) + { + val = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3, surface->lightmapinfo->texinfo->vecs[j]) + surface->lightmapinfo->texinfo->vecs[j][3]; + texmins[j] = min(texmins[j], val); + texmaxs[j] = max(texmaxs[j], val); + } + } + for (i = 0;i < 2;i++) + { + surface->lightmapinfo->texturemins[i] = (int) floor(texmins[i] / 16.0) * 16; + surface->lightmapinfo->extents[i] = (int) ceil(texmaxs[i] / 16.0) * 16 - surface->lightmapinfo->texturemins[i]; + } + + smax = surface->lightmapinfo->extents[0] >> 4; + tmax = surface->lightmapinfo->extents[1] >> 4; + ssize = (surface->lightmapinfo->extents[0] >> 4) + 1; + tsize = (surface->lightmapinfo->extents[1] >> 4) + 1; + + // lighting info + surface->lightmaptexture = NULL; + surface->deluxemaptexture = r_texture_blanknormalmap; + if (lightmapoffset == -1) + { + surface->lightmapinfo->samples = NULL; +#if 1 + // give non-lightmapped water a 1x white lightmap + if (surface->texture->name[0] == '*' && (surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) && ssize <= 256 && tsize <= 256) + { + surface->lightmapinfo->samples = (unsigned char *)Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); + surface->lightmapinfo->styles[0] = 0; + memset(surface->lightmapinfo->samples, 128, ssize * tsize * 3); + } +#endif + } + else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30) + surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + lightmapoffset; + else // LordHavoc: white lighting (bsp version 29) + { + surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (lightmapoffset * 3); + if (loadmodel->brushq1.nmaplightdata) + surface->lightmapinfo->nmapsamples = loadmodel->brushq1.nmaplightdata + (lightmapoffset * 3); + } + + // check if we should apply a lightmap to this + if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples) + { + if (ssize > 256 || tsize > 256) + Host_Error("Bad surface extents"); + + if (lightmapsize < ssize) + lightmapsize = ssize; + if (lightmapsize < tsize) + lightmapsize = tsize; + + totallightmapsamples += ssize*tsize; + + // force lightmap upload on first time seeing the surface + // + // additionally this is used by the later code to see if a + // lightmap is needed on this surface (rather than duplicating the + // logic above) + loadmodel->brushq1.lightmapupdateflags[surfacenum] = true; + loadmodel->lit = true; + } + } + + // small maps (such as ammo boxes especially) don't need big lightmap + // textures, so this code tries to guess a good size based on + // totallightmapsamples (size of the lightmaps lump basically), as well as + // trying to max out the size if there is a lot of lightmap data to store + // additionally, never choose a lightmapsize that is smaller than the + // largest surface encountered (as it would fail) + i = lightmapsize; + for (lightmapsize = 64; (lightmapsize < i) && (lightmapsize < bound(128, gl_max_lightmapsize.integer, (int)vid.maxtexturesize_2d)) && (totallightmapsamples > lightmapsize*lightmapsize); lightmapsize*=2) + ; + + // now that we've decided the lightmap texture size, we can do the rest + if (cls.state != ca_dedicated) + { + int stainmapsize = 0; + mod_alloclightmap_state_t allocState; + + Mod_AllocLightmap_Init(&allocState, lightmapsize, lightmapsize); + for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++) + { + int i, iu, iv, lightmapx = 0, lightmapy = 0; + float u, v, ubase, vbase, uscale, vscale; + + if (!loadmodel->brushq1.lightmapupdateflags[surfacenum]) + continue; + + smax = surface->lightmapinfo->extents[0] >> 4; + tmax = surface->lightmapinfo->extents[1] >> 4; + ssize = (surface->lightmapinfo->extents[0] >> 4) + 1; + tsize = (surface->lightmapinfo->extents[1] >> 4) + 1; + stainmapsize += ssize * tsize * 3; + + if (!lightmaptexture || !Mod_AllocLightmap_Block(&allocState, ssize, tsize, &lightmapx, &lightmapy)) + { + // allocate a texture pool if we need it + if (loadmodel->texturepool == NULL) + loadmodel->texturepool = R_AllocTexturePool(); + // could not find room, make a new lightmap + loadmodel->brushq3.num_mergedlightmaps = lightmapnumber + 1; + loadmodel->brushq3.data_lightmaps = (rtexture_t **)Mem_Realloc(loadmodel->mempool, loadmodel->brushq3.data_lightmaps, loadmodel->brushq3.num_mergedlightmaps * sizeof(loadmodel->brushq3.data_lightmaps[0])); + loadmodel->brushq3.data_deluxemaps = (rtexture_t **)Mem_Realloc(loadmodel->mempool, loadmodel->brushq3.data_deluxemaps, loadmodel->brushq3.num_mergedlightmaps * sizeof(loadmodel->brushq3.data_deluxemaps[0])); + loadmodel->brushq3.data_lightmaps[lightmapnumber] = lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); + if (loadmodel->brushq1.nmaplightdata) + loadmodel->brushq3.data_deluxemaps[lightmapnumber] = deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); + lightmapnumber++; + Mod_AllocLightmap_Reset(&allocState); + Mod_AllocLightmap_Block(&allocState, ssize, tsize, &lightmapx, &lightmapy); + } + surface->lightmaptexture = lightmaptexture; + surface->deluxemaptexture = deluxemaptexture; + surface->lightmapinfo->lightmaporigin[0] = lightmapx; + surface->lightmapinfo->lightmaporigin[1] = lightmapy; + + uscale = 1.0f / (float)lightmapsize; + vscale = 1.0f / (float)lightmapsize; + ubase = lightmapx * uscale; + vbase = lightmapy * vscale; + + for (i = 0;i < surface->num_vertices;i++) + { + u = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]) + 8 - surface->lightmapinfo->texturemins[0]) * (1.0 / 16.0); + v = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0); + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = u * uscale + ubase; + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = v * vscale + vbase; + // LordHavoc: calc lightmap data offset for vertex lighting to use + iu = (int) u; + iv = (int) v; + (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = (bound(0, iv, tmax) * ssize + bound(0, iu, smax)) * 3; + } + } + + if (cl_stainmaps.integer) + { + // allocate stainmaps for permanent marks on walls and clear white + unsigned char *stainsamples = NULL; + stainsamples = (unsigned char *)Mem_Alloc(loadmodel->mempool, stainmapsize); + memset(stainsamples, 255, stainmapsize); + // assign pointers + for (surfacenum = 0, surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, surface++) + { + if (!loadmodel->brushq1.lightmapupdateflags[surfacenum]) + continue; + ssize = (surface->lightmapinfo->extents[0] >> 4) + 1; + tsize = (surface->lightmapinfo->extents[1] >> 4) + 1; + surface->lightmapinfo->stainsamples = stainsamples; + stainsamples += ssize * tsize * 3; + } + } + } + + // generate ushort elements array if possible + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; +} + +static void Mod_Q1BSP_LoadNodes_RecursiveSetParent(mnode_t *node, mnode_t *parent) +{ + //if (node->parent) + // Host_Error("Mod_Q1BSP_LoadNodes_RecursiveSetParent: runaway recursion"); + node->parent = parent; + if (node->plane) + { + // this is a node, recurse to children + Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[0], node); + Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[1], node); + // combine supercontents of children + node->combinedsupercontents = node->children[0]->combinedsupercontents | node->children[1]->combinedsupercontents; + } + else + { + int j; + mleaf_t *leaf = (mleaf_t *)node; + // if this is a leaf, calculate supercontents mask from all collidable + // primitives in the leaf (brushes and collision surfaces) + // also flag if the leaf contains any collision surfaces + leaf->combinedsupercontents = 0; + // combine the supercontents values of all brushes in this leaf + for (j = 0;j < leaf->numleafbrushes;j++) + leaf->combinedsupercontents |= loadmodel->brush.data_brushes[leaf->firstleafbrush[j]].texture->supercontents; + // check if this leaf contains any collision surfaces (q3 patches) + for (j = 0;j < leaf->numleafsurfaces;j++) + { + msurface_t *surface = loadmodel->data_surfaces + leaf->firstleafsurface[j]; + if (surface->num_collisiontriangles) + { + leaf->containscollisionsurfaces = true; + leaf->combinedsupercontents |= surface->texture->supercontents; + } + } + } +} + +static void Mod_Q1BSP_LoadNodes(sizebuf_t *sb) +{ + int i, j, count, p, child[2]; + mnode_t *out; + size_t structsize = loadmodel->brush.isbsp2rmqe ? 32 : (loadmodel->brush.isbsp2 ? 44 : 24); + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadNodes: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + if (count == 0) + Host_Error("Mod_Q1BSP_LoadNodes: missing BSP tree in %s",loadmodel->name); + out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); + + loadmodel->brush.data_nodes = out; + loadmodel->brush.num_nodes = count; + + for ( i=0 ; iplane = loadmodel->brush.data_planes + p; + + if (loadmodel->brush.isbsp2rmqe) + { + child[0] = MSG_ReadLittleLong(sb); + child[1] = MSG_ReadLittleLong(sb); + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); + out->firstsurface = MSG_ReadLittleLong(sb); + out->numsurfaces = MSG_ReadLittleLong(sb); + } + else if (loadmodel->brush.isbsp2) + { + child[0] = MSG_ReadLittleLong(sb); + child[1] = MSG_ReadLittleLong(sb); + out->mins[0] = MSG_ReadLittleFloat(sb); + out->mins[1] = MSG_ReadLittleFloat(sb); + out->mins[2] = MSG_ReadLittleFloat(sb); + out->maxs[0] = MSG_ReadLittleFloat(sb); + out->maxs[1] = MSG_ReadLittleFloat(sb); + out->maxs[2] = MSG_ReadLittleFloat(sb); + out->firstsurface = MSG_ReadLittleLong(sb); + out->numsurfaces = MSG_ReadLittleLong(sb); + } + else + { + child[0] = (unsigned short)MSG_ReadLittleShort(sb); + child[1] = (unsigned short)MSG_ReadLittleShort(sb); + if (child[0] >= count) + child[0] -= 65536; + if (child[1] >= count) + child[1] -= 65536; + + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); + + out->firstsurface = (unsigned short)MSG_ReadLittleShort(sb); + out->numsurfaces = (unsigned short)MSG_ReadLittleShort(sb); + } + + for (j=0 ; j<2 ; j++) + { + // LordHavoc: this code supports broken bsp files produced by + // arguire qbsp which can produce more than 32768 nodes, any value + // below count is assumed to be a node number, any other value is + // assumed to be a leaf number + p = child[j]; + if (p >= 0) + { + if (p < loadmodel->brush.num_nodes) + out->children[j] = loadmodel->brush.data_nodes + p; + else + { + Con_Printf("Mod_Q1BSP_LoadNodes: invalid node index %i (file has only %i nodes)\n", p, loadmodel->brush.num_nodes); + // map it to the solid leaf + out->children[j] = (mnode_t *)loadmodel->brush.data_leafs; + } + } + else + { + // get leaf index as a positive value starting at 0 (-1 becomes 0, -2 becomes 1, etc) + p = -(p+1); + if (p < loadmodel->brush.num_leafs) + out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + p); + else + { + Con_Printf("Mod_Q1BSP_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->brush.num_leafs); + // map it to the solid leaf + out->children[j] = (mnode_t *)loadmodel->brush.data_leafs; + } + } + } + } + + Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL); // sets nodes and leafs +} + +static void Mod_Q1BSP_LoadLeafs(sizebuf_t *sb) +{ + mleaf_t *out; + int i, j, count, p, firstmarksurface, nummarksurfaces; + size_t structsize = loadmodel->brush.isbsp2rmqe ? 32 : (loadmodel->brush.isbsp2 ? 44 : 28); + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadLeafs: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + out = (mleaf_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); + + loadmodel->brush.data_leafs = out; + loadmodel->brush.num_leafs = count; + // get visleafs from the submodel data + loadmodel->brush.num_pvsclusters = loadmodel->brushq1.submodels[0].visleafs; + loadmodel->brush.num_pvsclusterbytes = (loadmodel->brush.num_pvsclusters+7)>>3; + loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_pvsclusters * loadmodel->brush.num_pvsclusterbytes); + memset(loadmodel->brush.data_pvsclusters, 0xFF, loadmodel->brush.num_pvsclusters * loadmodel->brush.num_pvsclusterbytes); + + // FIXME: this function could really benefit from some error checking + for ( i=0 ; icontents = MSG_ReadLittleLong(sb); + + out->clusterindex = i - 1; + if (out->clusterindex >= loadmodel->brush.num_pvsclusters) + out->clusterindex = -1; + + p = MSG_ReadLittleLong(sb); + // ignore visofs errors on leaf 0 (solid) + if (p >= 0 && out->clusterindex >= 0) + { + if (p >= loadmodel->brushq1.num_compressedpvs) + Con_Print("Mod_Q1BSP_LoadLeafs: invalid visofs\n"); + else + Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brush.data_pvsclusters + out->clusterindex * loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brush.num_pvsclusterbytes); + } + + if (loadmodel->brush.isbsp2rmqe) + { + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); + + firstmarksurface = MSG_ReadLittleLong(sb); + nummarksurfaces = MSG_ReadLittleLong(sb); + } + else if (loadmodel->brush.isbsp2) + { + out->mins[0] = MSG_ReadLittleFloat(sb); + out->mins[1] = MSG_ReadLittleFloat(sb); + out->mins[2] = MSG_ReadLittleFloat(sb); + out->maxs[0] = MSG_ReadLittleFloat(sb); + out->maxs[1] = MSG_ReadLittleFloat(sb); + out->maxs[2] = MSG_ReadLittleFloat(sb); + + firstmarksurface = MSG_ReadLittleLong(sb); + nummarksurfaces = MSG_ReadLittleLong(sb); + } + else + { + out->mins[0] = MSG_ReadLittleShort(sb); + out->mins[1] = MSG_ReadLittleShort(sb); + out->mins[2] = MSG_ReadLittleShort(sb); + out->maxs[0] = MSG_ReadLittleShort(sb); + out->maxs[1] = MSG_ReadLittleShort(sb); + out->maxs[2] = MSG_ReadLittleShort(sb); + + firstmarksurface = (unsigned short)MSG_ReadLittleShort(sb); + nummarksurfaces = (unsigned short)MSG_ReadLittleShort(sb); + } + + if (firstmarksurface >= 0 && firstmarksurface + nummarksurfaces <= loadmodel->brush.num_leafsurfaces) + { + out->firstleafsurface = loadmodel->brush.data_leafsurfaces + firstmarksurface; + out->numleafsurfaces = nummarksurfaces; + } + else + { + Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", firstmarksurface, firstmarksurface+nummarksurfaces, 0, loadmodel->brush.num_leafsurfaces); + out->firstleafsurface = NULL; + out->numleafsurfaces = 0; + } + + for (j = 0;j < 4;j++) + out->ambient_sound_level[j] = MSG_ReadByte(sb); + } +} + +static qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void) +{ + int i, j; + mleaf_t *leaf; + const unsigned char *pvs; + // if there's no vis data, assume supported (because everything is visible all the time) + if (!loadmodel->brush.data_pvsclusters) + return true; + // check all liquid leafs to see if they can see into empty leafs, if any + // can we can assume this map supports r_wateralpha + for (i = 0, leaf = loadmodel->brush.data_leafs;i < loadmodel->brush.num_leafs;i++, leaf++) + { + if ((leaf->contents == CONTENTS_WATER || leaf->contents == CONTENTS_SLIME) && leaf->clusterindex >= 0) + { + pvs = loadmodel->brush.data_pvsclusters + leaf->clusterindex * loadmodel->brush.num_pvsclusterbytes; + for (j = 0;j < loadmodel->brush.num_leafs;j++) + if (CHECKPVSBIT(pvs, loadmodel->brush.data_leafs[j].clusterindex) && loadmodel->brush.data_leafs[j].contents == CONTENTS_EMPTY) + return true; + } + } + return false; +} + +static void Mod_Q1BSP_LoadClipnodes(sizebuf_t *sb, hullinfo_t *hullinfo) +{ + mclipnode_t *out; + int i, count; + hull_t *hull; + size_t structsize = loadmodel->brush.isbsp2 ? 12 : 8; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadClipnodes: funny lump size in %s",loadmodel->name); + count = sb->cursize / structsize; + out = (mclipnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); + + loadmodel->brushq1.clipnodes = out; + loadmodel->brushq1.numclipnodes = count; + + for (i = 1; i < MAX_MAP_HULLS; i++) + { + hull = &loadmodel->brushq1.hulls[i]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->brush.data_planes; + hull->clip_mins[0] = hullinfo->hullsizes[i][0][0]; + hull->clip_mins[1] = hullinfo->hullsizes[i][0][1]; + hull->clip_mins[2] = hullinfo->hullsizes[i][0][2]; + hull->clip_maxs[0] = hullinfo->hullsizes[i][1][0]; + hull->clip_maxs[1] = hullinfo->hullsizes[i][1][1]; + hull->clip_maxs[2] = hullinfo->hullsizes[i][1][2]; + VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size); + } + + for (i=0 ; iplanenum = MSG_ReadLittleLong(sb); + if (out->planenum < 0 || out->planenum >= loadmodel->brush.num_planes) + Host_Error("%s: Corrupt clipping hull(out of range planenum)", loadmodel->name); + if (loadmodel->brush.isbsp2) + { + out->children[0] = MSG_ReadLittleLong(sb); + out->children[1] = MSG_ReadLittleLong(sb); + if (out->children[0] >= count) + Host_Error("%s: Corrupt clipping hull (invalid child index)", loadmodel->name); + if (out->children[1] >= count) + Host_Error("%s: Corrupt clipping hull (invalid child index)", loadmodel->name); + } + else + { + // LordHavoc: this code supports arguire qbsp's broken clipnodes indices (more than 32768 clipnodes), values above count are assumed to be contents values + out->children[0] = (unsigned short)MSG_ReadLittleShort(sb); + out->children[1] = (unsigned short)MSG_ReadLittleShort(sb); + if (out->children[0] >= count) + out->children[0] -= 65536; + if (out->children[1] >= count) + out->children[1] -= 65536; + } + } +} + +//Duplicate the drawing hull structure as a clipping hull +static void Mod_Q1BSP_MakeHull0(void) +{ + mnode_t *in; + mclipnode_t *out; + int i; + hull_t *hull; + + hull = &loadmodel->brushq1.hulls[0]; + + in = loadmodel->brush.data_nodes; + out = (mclipnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_nodes * sizeof(*out)); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = loadmodel->brush.num_nodes - 1; + hull->planes = loadmodel->brush.data_planes; + + for (i = 0;i < loadmodel->brush.num_nodes;i++, out++, in++) + { + out->planenum = in->plane - loadmodel->brush.data_planes; + out->children[0] = in->children[0]->plane ? in->children[0] - loadmodel->brush.data_nodes : ((mleaf_t *)in->children[0])->contents; + out->children[1] = in->children[1]->plane ? in->children[1] - loadmodel->brush.data_nodes : ((mleaf_t *)in->children[1])->contents; + } +} + +static void Mod_Q1BSP_LoadLeaffaces(sizebuf_t *sb) +{ + int i, j; + size_t structsize = loadmodel->brush.isbsp2 ? 4 : 2; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadLeaffaces: funny lump size in %s",loadmodel->name); + loadmodel->brush.num_leafsurfaces = sb->cursize / structsize; + loadmodel->brush.data_leafsurfaces = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_leafsurfaces * sizeof(int)); + + if (loadmodel->brush.isbsp2) + { + for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++) + { + j = MSG_ReadLittleLong(sb); + if (j < 0 || j >= loadmodel->num_surfaces) + Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number"); + loadmodel->brush.data_leafsurfaces[i] = j; + } + } + else + { + for (i = 0;i < loadmodel->brush.num_leafsurfaces;i++) + { + j = (unsigned short) MSG_ReadLittleShort(sb); + if (j >= loadmodel->num_surfaces) + Host_Error("Mod_Q1BSP_LoadLeaffaces: bad surface number"); + loadmodel->brush.data_leafsurfaces[i] = j; + } + } +} + +static void Mod_Q1BSP_LoadSurfedges(sizebuf_t *sb) +{ + int i; + size_t structsize = 4; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadSurfedges: funny lump size in %s",loadmodel->name); + loadmodel->brushq1.numsurfedges = sb->cursize / structsize; + loadmodel->brushq1.surfedges = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numsurfedges * sizeof(int)); + + for (i = 0;i < loadmodel->brushq1.numsurfedges;i++) + loadmodel->brushq1.surfedges[i] = MSG_ReadLittleLong(sb); +} + + +static void Mod_Q1BSP_LoadPlanes(sizebuf_t *sb) +{ + int i; + mplane_t *out; + size_t structsize = 20; + + if (sb->cursize % structsize) + Host_Error("Mod_Q1BSP_LoadPlanes: funny lump size in %s", loadmodel->name); + loadmodel->brush.num_planes = sb->cursize / structsize; + loadmodel->brush.data_planes = out = (mplane_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_planes * sizeof(*out)); + + for (i = 0;i < loadmodel->brush.num_planes;i++, out++) + { + out->normal[0] = MSG_ReadLittleFloat(sb); + out->normal[1] = MSG_ReadLittleFloat(sb); + out->normal[2] = MSG_ReadLittleFloat(sb); + out->dist = MSG_ReadLittleFloat(sb); + MSG_ReadLittleLong(sb); // type is not used, we use PlaneClassify + PlaneClassify(out); + } +} + +static void Mod_Q1BSP_LoadMapBrushes(void) +{ +#if 0 +// unfinished + int submodel, numbrushes; + qboolean firstbrush; + char *text, *maptext; + char mapfilename[MAX_QPATH]; + FS_StripExtension (loadmodel->name, mapfilename, sizeof (mapfilename)); + strlcat (mapfilename, ".map", sizeof (mapfilename)); + maptext = (unsigned char*) FS_LoadFile(mapfilename, tempmempool, false, NULL); + if (!maptext) + return; + text = maptext; + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + submodel = 0; + for (;;) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; + if (com_token[0] != '{') + return; // error + // entity + firstbrush = true; + numbrushes = 0; + maxbrushes = 256; + brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t)); + for (;;) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] == '}') + break; // end of entity + if (com_token[0] == '{') + { + // brush + if (firstbrush) + { + if (submodel) + { + if (submodel > loadmodel->brush.numsubmodels) + { + Con_Printf("Mod_Q1BSP_LoadMapBrushes: .map has more submodels than .bsp!\n"); + model = NULL; + } + else + model = loadmodel->brush.submodels[submodel]; + } + else + model = loadmodel; + } + for (;;) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + return; // error + if (com_token[0] == '}') + break; // end of brush + // each brush face should be this format: + // ( x y z ) ( x y z ) ( x y z ) texture scroll_s scroll_t rotateangle scale_s scale_t + // FIXME: support hl .map format + for (pointnum = 0;pointnum < 3;pointnum++) + { + COM_ParseToken_Simple(&data, false, false, true); + for (componentnum = 0;componentnum < 3;componentnum++) + { + COM_ParseToken_Simple(&data, false, false, true); + point[pointnum][componentnum] = atof(com_token); + } + COM_ParseToken_Simple(&data, false, false, true); + } + COM_ParseToken_Simple(&data, false, false, true); + strlcpy(facetexture, com_token, sizeof(facetexture)); + COM_ParseToken_Simple(&data, false, false, true); + //scroll_s = atof(com_token); + COM_ParseToken_Simple(&data, false, false, true); + //scroll_t = atof(com_token); + COM_ParseToken_Simple(&data, false, false, true); + //rotate = atof(com_token); + COM_ParseToken_Simple(&data, false, false, true); + //scale_s = atof(com_token); + COM_ParseToken_Simple(&data, false, false, true); + //scale_t = atof(com_token); + TriangleNormal(point[0], point[1], point[2], planenormal); + VectorNormalizeDouble(planenormal); + planedist = DotProduct(point[0], planenormal); + //ChooseTexturePlane(planenormal, texturevector[0], texturevector[1]); + } + continue; + } + } + } +#endif +} + + +#define MAX_PORTALPOINTS 64 + +typedef struct portal_s +{ + mplane_t plane; + mnode_t *nodes[2]; // [0] = front side of plane + struct portal_s *next[2]; + int numpoints; + double points[3*MAX_PORTALPOINTS]; + struct portal_s *chain; // all portals are linked into a list +} +portal_t; + +static memexpandablearray_t portalarray; + +static void Mod_Q1BSP_RecursiveRecalcNodeBBox(mnode_t *node) +{ + // process only nodes (leafs already had their box calculated) + if (!node->plane) + return; + + // calculate children first + Mod_Q1BSP_RecursiveRecalcNodeBBox(node->children[0]); + Mod_Q1BSP_RecursiveRecalcNodeBBox(node->children[1]); + + // make combined bounding box from children + node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]); + node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]); + node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]); + node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]); + node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]); + node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]); +} + +static void Mod_Q1BSP_FinalizePortals(void) +{ + int i, j, numportals, numpoints, portalindex, portalrange = Mem_ExpandableArray_IndexRange(&portalarray); + portal_t *p; + mportal_t *portal; + mvertex_t *point; + mleaf_t *leaf, *endleaf; + + // tally up portal and point counts and recalculate bounding boxes for all + // leafs (because qbsp is very sloppy) + leaf = loadmodel->brush.data_leafs; + endleaf = leaf + loadmodel->brush.num_leafs; + if (mod_recalculatenodeboxes.integer) + { + for (;leaf < endleaf;leaf++) + { + VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000); + VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000); + } + } + numportals = 0; + numpoints = 0; + for (portalindex = 0;portalindex < portalrange;portalindex++) + { + p = (portal_t*)Mem_ExpandableArray_RecordAtIndex(&portalarray, portalindex); + if (!p) + continue; + // note: this check must match the one below or it will usually corrupt memory + // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides + if (p->numpoints >= 3 && p->nodes[0] != p->nodes[1] && ((mleaf_t *)p->nodes[0])->clusterindex >= 0 && ((mleaf_t *)p->nodes[1])->clusterindex >= 0) + { + numportals += 2; + numpoints += p->numpoints * 2; + } + } + loadmodel->brush.data_portals = (mportal_t *)Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t)); + loadmodel->brush.num_portals = numportals; + loadmodel->brush.data_portalpoints = (mvertex_t *)((unsigned char *) loadmodel->brush.data_portals + numportals * sizeof(mportal_t)); + loadmodel->brush.num_portalpoints = numpoints; + // clear all leaf portal chains + for (i = 0;i < loadmodel->brush.num_leafs;i++) + loadmodel->brush.data_leafs[i].portals = NULL; + // process all portals in the global portal chain, while freeing them + portal = loadmodel->brush.data_portals; + point = loadmodel->brush.data_portalpoints; + for (portalindex = 0;portalindex < portalrange;portalindex++) + { + p = (portal_t*)Mem_ExpandableArray_RecordAtIndex(&portalarray, portalindex); + if (!p) + continue; + if (p->numpoints >= 3 && p->nodes[0] != p->nodes[1]) + { + // note: this check must match the one above or it will usually corrupt memory + // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides + if (((mleaf_t *)p->nodes[0])->clusterindex >= 0 && ((mleaf_t *)p->nodes[1])->clusterindex >= 0) + { + // first make the back to front portal(forward portal) + portal->points = point; + portal->numpoints = p->numpoints; + portal->plane.dist = p->plane.dist; + VectorCopy(p->plane.normal, portal->plane.normal); + portal->here = (mleaf_t *)p->nodes[1]; + portal->past = (mleaf_t *)p->nodes[0]; + // copy points + for (j = 0;j < portal->numpoints;j++) + { + VectorCopy(p->points + j*3, point->position); + point++; + } + BoxFromPoints(portal->mins, portal->maxs, portal->numpoints, portal->points->position); + PlaneClassify(&portal->plane); + + // link into leaf's portal chain + portal->next = portal->here->portals; + portal->here->portals = portal; + + // advance to next portal + portal++; + + // then make the front to back portal(backward portal) + portal->points = point; + portal->numpoints = p->numpoints; + portal->plane.dist = -p->plane.dist; + VectorNegate(p->plane.normal, portal->plane.normal); + portal->here = (mleaf_t *)p->nodes[0]; + portal->past = (mleaf_t *)p->nodes[1]; + // copy points + for (j = portal->numpoints - 1;j >= 0;j--) + { + VectorCopy(p->points + j*3, point->position); + point++; + } + BoxFromPoints(portal->mins, portal->maxs, portal->numpoints, portal->points->position); + PlaneClassify(&portal->plane); + + // link into leaf's portal chain + portal->next = portal->here->portals; + portal->here->portals = portal; + + // advance to next portal + portal++; + } + // add the portal's polygon points to the leaf bounding boxes + if (mod_recalculatenodeboxes.integer) + { + for (i = 0;i < 2;i++) + { + leaf = (mleaf_t *)p->nodes[i]; + for (j = 0;j < p->numpoints;j++) + { + if (leaf->mins[0] > p->points[j*3+0]) leaf->mins[0] = p->points[j*3+0]; + if (leaf->mins[1] > p->points[j*3+1]) leaf->mins[1] = p->points[j*3+1]; + if (leaf->mins[2] > p->points[j*3+2]) leaf->mins[2] = p->points[j*3+2]; + if (leaf->maxs[0] < p->points[j*3+0]) leaf->maxs[0] = p->points[j*3+0]; + if (leaf->maxs[1] < p->points[j*3+1]) leaf->maxs[1] = p->points[j*3+1]; + if (leaf->maxs[2] < p->points[j*3+2]) leaf->maxs[2] = p->points[j*3+2]; + } + } + } + } + } + // now recalculate the node bounding boxes from the leafs + if (mod_recalculatenodeboxes.integer) + Mod_Q1BSP_RecursiveRecalcNodeBBox(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode); +} + +/* +============= +AddPortalToNodes +============= +*/ +static void AddPortalToNodes(portal_t *p, mnode_t *front, mnode_t *back) +{ + if (!front) + Host_Error("AddPortalToNodes: NULL front node"); + if (!back) + Host_Error("AddPortalToNodes: NULL back node"); + if (p->nodes[0] || p->nodes[1]) + Host_Error("AddPortalToNodes: already included"); + // note: front == back is handled gracefully, because leaf 0 is the shared solid leaf, it can often have portals with the same leaf on both sides + + p->nodes[0] = front; + p->next[0] = (portal_t *)front->portals; + front->portals = (mportal_t *)p; + + p->nodes[1] = back; + p->next[1] = (portal_t *)back->portals; + back->portals = (mportal_t *)p; +} + +/* +============= +RemovePortalFromNode +============= +*/ +static void RemovePortalFromNodes(portal_t *portal) +{ + int i; + mnode_t *node; + void **portalpointer; + portal_t *t; + for (i = 0;i < 2;i++) + { + node = portal->nodes[i]; + + portalpointer = (void **) &node->portals; + while (1) + { + t = (portal_t *)*portalpointer; + if (!t) + Host_Error("RemovePortalFromNodes: portal not in leaf"); + + if (t == portal) + { + if (portal->nodes[0] == node) + { + *portalpointer = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == node) + { + *portalpointer = portal->next[1]; + portal->nodes[1] = NULL; + } + else + Host_Error("RemovePortalFromNodes: portal not bounding leaf"); + break; + } + + if (t->nodes[0] == node) + portalpointer = (void **) &t->next[0]; + else if (t->nodes[1] == node) + portalpointer = (void **) &t->next[1]; + else + Host_Error("RemovePortalFromNodes: portal not bounding leaf"); + } + } +} + +#define PORTAL_DIST_EPSILON (1.0 / 32.0) +static double *portalpointsbuffer; +static int portalpointsbufferoffset; +static int portalpointsbuffersize; +static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node) +{ + int i, side; + mnode_t *front, *back, *other_node; + mplane_t clipplane, *plane; + portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp; + int numfrontpoints, numbackpoints; + double *frontpoints, *backpoints; + + // if a leaf, we're done + if (!node->plane) + return; + + // get some space for our clipping operations to use + if (portalpointsbuffersize < portalpointsbufferoffset + 6*MAX_PORTALPOINTS) + { + portalpointsbuffersize = portalpointsbufferoffset * 2; + portalpointsbuffer = (double *)Mem_Realloc(loadmodel->mempool, portalpointsbuffer, portalpointsbuffersize * sizeof(*portalpointsbuffer)); + } + frontpoints = portalpointsbuffer + portalpointsbufferoffset; + portalpointsbufferoffset += 3*MAX_PORTALPOINTS; + backpoints = portalpointsbuffer + portalpointsbufferoffset; + portalpointsbufferoffset += 3*MAX_PORTALPOINTS; + + plane = node->plane; + + front = node->children[0]; + back = node->children[1]; + if (front == back) + Host_Error("Mod_Q1BSP_RecursiveNodePortals: corrupt node hierarchy"); + + // create the new portal by generating a polygon for the node plane, + // and clipping it by all of the other portals(which came from nodes above this one) + nodeportal = (portal_t *)Mem_ExpandableArray_AllocRecord(&portalarray); + nodeportal->plane = *plane; + + // TODO: calculate node bounding boxes during recursion and calculate a maximum plane size accordingly to improve precision (as most maps do not need 1 billion unit plane polygons) + PolygonD_QuadForPlane(nodeportal->points, nodeportal->plane.normal[0], nodeportal->plane.normal[1], nodeportal->plane.normal[2], nodeportal->plane.dist, 1024.0*1024.0*1024.0); + nodeportal->numpoints = 4; + // side = 0; // shut up compiler warning -> should be no longer needed, Host_Error is declared noreturn now + for (portal = (portal_t *)node->portals;portal;portal = portal->next[side]) + { + clipplane = portal->plane; + if (portal->nodes[0] == portal->nodes[1]) + Host_Error("Mod_Q1BSP_RecursiveNodePortals: portal has same node on both sides(1)"); + if (portal->nodes[0] == node) + side = 0; + else if (portal->nodes[1] == node) + { + clipplane.dist = -clipplane.dist; + VectorNegate(clipplane.normal, clipplane.normal); + side = 1; + } + else + { + Host_Error("Mod_Q1BSP_RecursiveNodePortals: mislinked portal"); + side = 0; // hush warning + } + + for (i = 0;i < nodeportal->numpoints*3;i++) + frontpoints[i] = nodeportal->points[i]; + PolygonD_Divide(nodeportal->numpoints, frontpoints, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, PORTAL_DIST_EPSILON, MAX_PORTALPOINTS, nodeportal->points, &nodeportal->numpoints, 0, NULL, NULL, NULL); + if (nodeportal->numpoints <= 0 || nodeportal->numpoints >= MAX_PORTALPOINTS) + break; + } + + if (nodeportal->numpoints < 3) + { + Con_Print("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal was clipped away\n"); + nodeportal->numpoints = 0; + } + else if (nodeportal->numpoints >= MAX_PORTALPOINTS) + { + Con_Print("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal has too many points\n"); + nodeportal->numpoints = 0; + } + + AddPortalToNodes(nodeportal, front, back); + + // split the portals of this node along this node's plane and assign them to the children of this node + // (migrating the portals downward through the tree) + for (portal = (portal_t *)node->portals;portal;portal = nextportal) + { + if (portal->nodes[0] == portal->nodes[1]) + Host_Error("Mod_Q1BSP_RecursiveNodePortals: portal has same node on both sides(2)"); + if (portal->nodes[0] == node) + side = 0; + else if (portal->nodes[1] == node) + side = 1; + else + { + Host_Error("Mod_Q1BSP_RecursiveNodePortals: mislinked portal"); + side = 0; // hush warning + } + nextportal = portal->next[side]; + if (!portal->numpoints) + continue; + + other_node = portal->nodes[!side]; + RemovePortalFromNodes(portal); + + // cut the portal into two portals, one on each side of the node plane + PolygonD_Divide(portal->numpoints, portal->points, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, PORTAL_DIST_EPSILON, MAX_PORTALPOINTS, frontpoints, &numfrontpoints, MAX_PORTALPOINTS, backpoints, &numbackpoints, NULL); + + if (!numfrontpoints) + { + if (side == 0) + AddPortalToNodes(portal, back, other_node); + else + AddPortalToNodes(portal, other_node, back); + continue; + } + if (!numbackpoints) + { + if (side == 0) + AddPortalToNodes(portal, front, other_node); + else + AddPortalToNodes(portal, other_node, front); + continue; + } + + // the portal is split + splitportal = (portal_t *)Mem_ExpandableArray_AllocRecord(&portalarray); + temp = splitportal->chain; + *splitportal = *portal; + splitportal->chain = temp; + for (i = 0;i < numbackpoints*3;i++) + splitportal->points[i] = backpoints[i]; + splitportal->numpoints = numbackpoints; + for (i = 0;i < numfrontpoints*3;i++) + portal->points[i] = frontpoints[i]; + portal->numpoints = numfrontpoints; + + if (side == 0) + { + AddPortalToNodes(portal, front, other_node); + AddPortalToNodes(splitportal, back, other_node); + } + else + { + AddPortalToNodes(portal, other_node, front); + AddPortalToNodes(splitportal, other_node, back); + } + } + + Mod_Q1BSP_RecursiveNodePortals(front); + Mod_Q1BSP_RecursiveNodePortals(back); + + portalpointsbufferoffset -= 6*MAX_PORTALPOINTS; +} + +static void Mod_Q1BSP_MakePortals(void) +{ + Mem_ExpandableArray_NewArray(&portalarray, loadmodel->mempool, sizeof(portal_t), 1020*1024/sizeof(portal_t)); + portalpointsbufferoffset = 0; + portalpointsbuffersize = 6*MAX_PORTALPOINTS*128; + portalpointsbuffer = (double *)Mem_Alloc(loadmodel->mempool, portalpointsbuffersize * sizeof(*portalpointsbuffer)); + Mod_Q1BSP_RecursiveNodePortals(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode); + Mem_Free(portalpointsbuffer); + portalpointsbuffer = NULL; + portalpointsbufferoffset = 0; + portalpointsbuffersize = 0; + Mod_Q1BSP_FinalizePortals(); + Mem_ExpandableArray_FreeArray(&portalarray); +} + +//Returns PVS data for a given point +//(note: can return NULL) +static unsigned char *Mod_Q1BSP_GetPVS(dp_model_t *model, const vec3_t p) +{ + mnode_t *node; + node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode; + while (node->plane) + node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; + if (((mleaf_t *)node)->clusterindex >= 0) + return model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes; + else + return NULL; +} + +static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(dp_model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbytes, mnode_t *node) +{ + while (node->plane) + { + float d = PlaneDiff(org, node->plane); + if (d > radius) + node = node->children[0]; + else if (d < -radius) + node = node->children[1]; + else + { + // go down both sides + Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, pvsbytes, node->children[0]); + node = node->children[1]; + } + } + // if this leaf is in a cluster, accumulate the pvs bits + if (((mleaf_t *)node)->clusterindex >= 0) + { + int i; + unsigned char *pvs = model->brush.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brush.num_pvsclusterbytes; + for (i = 0;i < pvsbytes;i++) + pvsbuffer[i] |= pvs[i]; + } +} + +//Calculates a PVS that is the inclusive or of all leafs within radius pixels +//of the given point. +static int Mod_Q1BSP_FatPVS(dp_model_t *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qboolean merge) +{ + int bytes = model->brush.num_pvsclusterbytes; + bytes = min(bytes, pvsbufferlength); + if (r_novis.integer || r_trippy.integer || !model->brush.num_pvsclusters || !Mod_Q1BSP_GetPVS(model, org)) + { + memset(pvsbuffer, 0xFF, bytes); + return bytes; + } + if (!merge) + memset(pvsbuffer, 0, bytes); + Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode); + return bytes; +} + +static void Mod_Q1BSP_RoundUpToHullSize(dp_model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs) +{ + vec3_t size; + const hull_t *hull; + + VectorSubtract(inmaxs, inmins, size); + if (cmodel->brush.ishlbsp) + { + if (size[0] < 3) + hull = &cmodel->brushq1.hulls[0]; // 0x0x0 + else if (size[0] <= 32) + { + if (size[2] < 54) // pick the nearest of 36 or 72 + hull = &cmodel->brushq1.hulls[3]; // 32x32x36 + else + hull = &cmodel->brushq1.hulls[1]; // 32x32x72 + } + else + hull = &cmodel->brushq1.hulls[2]; // 64x64x64 + } + else + { + if (size[0] < 3) + hull = &cmodel->brushq1.hulls[0]; // 0x0x0 + else if (size[0] <= 32) + hull = &cmodel->brushq1.hulls[1]; // 32x32x56 + else + hull = &cmodel->brushq1.hulls[2]; // 64x64x88 + } + VectorCopy(inmins, outmins); + VectorAdd(inmins, hull->clip_size, outmaxs); +} + +static int Mod_Q1BSP_CreateShadowMesh(dp_model_t *mod) +{ + int j; + int numshadowmeshtriangles = 0; + msurface_t *surface; + if (cls.state == ca_dedicated) + return 0; + // make a single combined shadow mesh to allow optimized shadow volume creation + + for (j = 0, surface = mod->data_surfaces;j < mod->num_surfaces;j++, surface++) + { + surface->num_firstshadowmeshtriangle = numshadowmeshtriangles; + numshadowmeshtriangles += surface->num_triangles; + } + mod->brush.shadowmesh = Mod_ShadowMesh_Begin(mod->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true); + for (j = 0, surface = mod->data_surfaces;j < mod->num_surfaces;j++, surface++) + if (surface->num_triangles > 0) + Mod_ShadowMesh_AddMesh(mod->mempool, mod->brush.shadowmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + mod->brush.shadowmesh = Mod_ShadowMesh_Finish(mod->mempool, mod->brush.shadowmesh, false, r_enableshadowvolumes.integer != 0, false); + if (mod->brush.shadowmesh && mod->brush.shadowmesh->neighbor3i) + Mod_BuildTriangleNeighbors(mod->brush.shadowmesh->neighbor3i, mod->brush.shadowmesh->element3i, mod->brush.shadowmesh->numtriangles); + + return numshadowmeshtriangles; +} + +void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); + +void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, k; + sizebuf_t lumpsb[HEADER_LUMPS]; + mmodel_t *bm; + float dist, modelyawradius, modelradius; + msurface_t *surface; + hullinfo_t hullinfo; + int totalstylesurfaces, totalstyles, stylecounts[256], remapstyles[256]; + model_brush_lightstyleinfo_t styleinfo[256]; + unsigned char *datapointer; + sizebuf_t sb; + + MSG_InitReadBuffer(&sb, (unsigned char *)buffer, (unsigned char *)bufferend - (unsigned char *)buffer); + + mod->type = mod_brushq1; + + mod->brush.isbsp2 = false; + mod->brush.ishlbsp = false; + i = MSG_ReadLittleLong(&sb); + switch(i) + { + case BSPVERSION: + mod->modeldatatypestring = "Q1BSP"; + break; + case 30: + mod->brush.ishlbsp = true; + mod->modeldatatypestring = "HLBSP"; + break; + case ('2' + 'P' * 256 + 'S' * 65536 + 'B' * 16777216): + mod->brush.isbsp2 = true; + mod->brush.isbsp2rmqe = true; // like bsp2 except leaf/node bounds are 16bit (unexpanded) + mod->modeldatatypestring = "Q1BSP2rmqe"; + break; + case ('B' + 'S' * 256 + 'P' * 65536 + '2' * 16777216): + mod->brush.isbsp2 = true; + mod->modeldatatypestring = "Q1BSP2"; + break; + default: + mod->modeldatatypestring = "Unknown BSP"; + Host_Error("Mod_Q1BSP_Load: %s has wrong version number %i: supported versions are 29 (Quake), 30 (Half-Life), \"BSP2\" or \"2PSB\" (rmqe)", mod->name, i); + return; + } + +// fill in hull info + VectorClear (hullinfo.hullsizes[0][0]); + VectorClear (hullinfo.hullsizes[0][1]); + if (mod->brush.ishlbsp) + { + hullinfo.filehulls = 4; + VectorSet (hullinfo.hullsizes[1][0], -16, -16, -36); + VectorSet (hullinfo.hullsizes[1][1], 16, 16, 36); + VectorSet (hullinfo.hullsizes[2][0], -32, -32, -32); + VectorSet (hullinfo.hullsizes[2][1], 32, 32, 32); + VectorSet (hullinfo.hullsizes[3][0], -16, -16, -18); + VectorSet (hullinfo.hullsizes[3][1], 16, 16, 18); + } + else + { + hullinfo.filehulls = 4; + VectorSet (hullinfo.hullsizes[1][0], -16, -16, -24); + VectorSet (hullinfo.hullsizes[1][1], 16, 16, 32); + VectorSet (hullinfo.hullsizes[2][0], -32, -32, -24); + VectorSet (hullinfo.hullsizes[2][1], 32, 32, 64); + } + +// read lumps + for (i = 0; i < HEADER_LUMPS; i++) + { + int offset = MSG_ReadLittleLong(&sb); + int size = MSG_ReadLittleLong(&sb); + if (offset < 0 || offset + size > sb.cursize) + Host_Error("Mod_Q1BSP_Load: %s has invalid lump %i (offset %i, size %i, file size %i)\n", mod->name, i, offset, size, (int)sb.cursize); + MSG_InitReadBuffer(&lumpsb[i], sb.data + offset, size); + } + + mod->soundfromcenter = true; + mod->TraceBox = Mod_Q1BSP_TraceBox; + mod->TraceLine = Mod_Q1BSP_TraceLine; + mod->TracePoint = Mod_Q1BSP_TracePoint; + mod->PointSuperContents = Mod_Q1BSP_PointSuperContents; + mod->TraceLineAgainstSurfaces = Mod_Q1BSP_TraceLineAgainstSurfaces; + mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight; + mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents; + mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents; + mod->brush.GetPVS = Mod_Q1BSP_GetPVS; + mod->brush.FatPVS = Mod_Q1BSP_FatPVS; + mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS; + mod->brush.BoxTouchingLeafPVS = Mod_Q1BSP_BoxTouchingLeafPVS; + mod->brush.BoxTouchingVisibleLeafs = Mod_Q1BSP_BoxTouchingVisibleLeafs; + mod->brush.FindBoxClusters = Mod_Q1BSP_FindBoxClusters; + mod->brush.LightPoint = Mod_Q1BSP_LightPoint; + mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; + mod->brush.AmbientSoundLevelsForPoint = Mod_Q1BSP_AmbientSoundLevelsForPoint; + mod->brush.RoundUpToHullSize = Mod_Q1BSP_RoundUpToHullSize; + mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf; + mod->Draw = R_Q1BSP_Draw; + mod->DrawDepth = R_Q1BSP_DrawDepth; + mod->DrawDebug = R_Q1BSP_DrawDebug; + mod->DrawPrepass = R_Q1BSP_DrawPrepass; + mod->GetLightInfo = R_Q1BSP_GetLightInfo; + mod->CompileShadowMap = R_Q1BSP_CompileShadowMap; + mod->DrawShadowMap = R_Q1BSP_DrawShadowMap; + mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + mod->DrawLight = R_Q1BSP_DrawLight; + +// load into heap + + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < HEADER_LUMPS;i++) + { + int temp; + if (i == LUMP_ENTITIES) + continue; + temp = Com_BlockChecksum(lumpsb[i].data, lumpsb[i].cursize); + mod->brush.qw_md4sum ^= LittleLong(temp); + if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= LittleLong(temp); + } + + Mod_Q1BSP_LoadEntities(&lumpsb[LUMP_ENTITIES]); + Mod_Q1BSP_LoadVertexes(&lumpsb[LUMP_VERTEXES]); + Mod_Q1BSP_LoadEdges(&lumpsb[LUMP_EDGES]); + Mod_Q1BSP_LoadSurfedges(&lumpsb[LUMP_SURFEDGES]); + Mod_Q1BSP_LoadTextures(&lumpsb[LUMP_TEXTURES]); + Mod_Q1BSP_LoadLighting(&lumpsb[LUMP_LIGHTING]); + Mod_Q1BSP_LoadPlanes(&lumpsb[LUMP_PLANES]); + Mod_Q1BSP_LoadTexinfo(&lumpsb[LUMP_TEXINFO]); + Mod_Q1BSP_LoadFaces(&lumpsb[LUMP_FACES]); + Mod_Q1BSP_LoadLeaffaces(&lumpsb[LUMP_MARKSURFACES]); + Mod_Q1BSP_LoadVisibility(&lumpsb[LUMP_VISIBILITY]); + // load submodels before leafs because they contain the number of vis leafs + Mod_Q1BSP_LoadSubmodels(&lumpsb[LUMP_MODELS], &hullinfo); + Mod_Q1BSP_LoadLeafs(&lumpsb[LUMP_LEAFS]); + Mod_Q1BSP_LoadNodes(&lumpsb[LUMP_NODES]); + Mod_Q1BSP_LoadClipnodes(&lumpsb[LUMP_CLIPNODES], &hullinfo); + + for (i = 0; i < HEADER_LUMPS; i++) + if (lumpsb[i].readcount != lumpsb[i].cursize && i != LUMP_TEXTURES && i != LUMP_LIGHTING) + Host_Error("Lump %i incorrectly loaded (readcount %i, size %i)\n", i, lumpsb[i].readcount, lumpsb[i].cursize); + + // check if the map supports transparent water rendering + loadmodel->brush.supportwateralpha = Mod_Q1BSP_CheckWaterAlphaSupport(); + + if (mod->brushq1.data_compressedpvs) + Mem_Free(mod->brushq1.data_compressedpvs); + mod->brushq1.data_compressedpvs = NULL; + mod->brushq1.num_compressedpvs = 0; + + Mod_Q1BSP_MakeHull0(); + if (mod_bsp_portalize.integer) + Mod_Q1BSP_MakePortals(); + + mod->numframes = 2; // regular and alternate animation + mod->numskins = 1; + + // make a single combined shadow mesh to allow optimized shadow volume creation + Mod_Q1BSP_CreateShadowMesh(loadmodel); + + if (loadmodel->brush.numsubmodels) + loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); + + // LordHavoc: to clear the fog around the original quake submodel code, I + // will explain: + // first of all, some background info on the submodels: + // model 0 is the map model (the world, named maps/e1m1.bsp for example) + // model 1 and higher are submodels (doors and the like, named *1, *2, etc) + // now the weird for loop itself: + // the loop functions in an odd way, on each iteration it sets up the + // current 'mod' model (which despite the confusing code IS the model of + // the number i), at the end of the loop it duplicates the model to become + // the next submodel, and loops back to set up the new submodel. + + // LordHavoc: now the explanation of my sane way (which works identically): + // set up the world model, then on each submodel copy from the world model + // and set up the submodel with the respective model info. + totalstylesurfaces = 0; + totalstyles = 0; + for (i = 0;i < mod->brush.numsubmodels;i++) + { + memset(stylecounts, 0, sizeof(stylecounts)); + for (k = 0;k < mod->brushq1.submodels[i].numfaces;k++) + { + surface = mod->data_surfaces + mod->brushq1.submodels[i].firstface + k; + for (j = 0;j < MAXLIGHTMAPS;j++) + stylecounts[surface->lightmapinfo->styles[j]]++; + } + for (k = 0;k < 255;k++) + { + totalstyles++; + if (stylecounts[k]) + totalstylesurfaces += stylecounts[k]; + } + } + datapointer = (unsigned char *)Mem_Alloc(mod->mempool, mod->num_surfaces * sizeof(int) + totalstyles * sizeof(model_brush_lightstyleinfo_t) + totalstylesurfaces * sizeof(int *)); + for (i = 0;i < mod->brush.numsubmodels;i++) + { + // LordHavoc: this code was originally at the end of this loop, but + // has been transformed to something more readable at the start here. + + if (i > 0) + { + char name[10]; + // duplicate the basic information + dpsnprintf(name, sizeof(name), "*%i", i); + mod = Mod_FindName(name, loadmodel->name); + // copy the base model to this one + *mod = *loadmodel; + // rename the clone back to its proper name + strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = loadmodel; + // textures and memory belong to the main model + mod->texturepool = NULL; + mod->mempool = NULL; + mod->brush.GetPVS = NULL; + mod->brush.FatPVS = NULL; + mod->brush.BoxTouchingPVS = NULL; + mod->brush.BoxTouchingLeafPVS = NULL; + mod->brush.BoxTouchingVisibleLeafs = NULL; + mod->brush.FindBoxClusters = NULL; + mod->brush.LightPoint = NULL; + mod->brush.AmbientSoundLevelsForPoint = NULL; + } + + mod->brush.submodel = i; + + if (loadmodel->brush.submodels) + loadmodel->brush.submodels[i] = mod; + + bm = &mod->brushq1.submodels[i]; + + mod->brushq1.hulls[0].firstclipnode = bm->headnode[0]; + for (j=1 ; jbrushq1.hulls[j].firstclipnode = bm->headnode[j]; + mod->brushq1.hulls[j].lastclipnode = mod->brushq1.numclipnodes - 1; + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + + // set node/leaf parents for this submodel + Mod_Q1BSP_LoadNodes_RecursiveSetParent(mod->brush.data_nodes + mod->brushq1.hulls[0].firstclipnode, NULL); + + // make the model surface list (used by shadowing/lighting) + mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int); + Mod_MakeSortedSurfaces(mod); + + // copy the submodel bounds, then enlarge the yaw and rotated bounds according to radius + // (previously this code measured the radius of the vertices of surfaces in the submodel, but that broke submodels that contain only CLIP brushes, which do not produce surfaces) + VectorCopy(bm->mins, mod->normalmins); + VectorCopy(bm->maxs, mod->normalmaxs); + dist = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0])); + modelyawradius = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1])); + modelyawradius = dist*dist+modelyawradius*modelyawradius; + modelradius = max(fabs(mod->normalmins[2]), fabs(mod->normalmaxs[2])); + modelradius = modelyawradius + modelradius * modelradius; + modelyawradius = sqrt(modelyawradius); + modelradius = sqrt(modelradius); + mod->yawmins[0] = mod->yawmins[1] = -modelyawradius; + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; + + // this gets altered below if sky or water is used + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + + // scan surfaces for sky and water and flag the submodel as possessing these features or not + // build lightstyle lists for quick marking of dirty lightmaps when lightstyles flicker + if (mod->nummodelsurfaces) + { + for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++) + if (surface->texture->basematerialflags & MATERIALFLAG_SKY) + break; + if (j < mod->nummodelsurfaces) + mod->DrawSky = R_Q1BSP_DrawSky; + + for (j = 0, surface = &mod->data_surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surface++) + if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + break; + if (j < mod->nummodelsurfaces) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + + // build lightstyle update chains + // (used to rapidly mark lightmapupdateflags on many surfaces + // when d_lightstylevalue changes) + memset(stylecounts, 0, sizeof(stylecounts)); + for (k = 0;k < mod->nummodelsurfaces;k++) + { + surface = mod->data_surfaces + mod->firstmodelsurface + k; + for (j = 0;j < MAXLIGHTMAPS;j++) + stylecounts[surface->lightmapinfo->styles[j]]++; + } + mod->brushq1.num_lightstyles = 0; + for (k = 0;k < 255;k++) + { + if (stylecounts[k]) + { + styleinfo[mod->brushq1.num_lightstyles].style = k; + styleinfo[mod->brushq1.num_lightstyles].value = 0; + styleinfo[mod->brushq1.num_lightstyles].numsurfaces = 0; + styleinfo[mod->brushq1.num_lightstyles].surfacelist = (int *)datapointer;datapointer += stylecounts[k] * sizeof(int); + remapstyles[k] = mod->brushq1.num_lightstyles; + mod->brushq1.num_lightstyles++; + } + } + for (k = 0;k < mod->nummodelsurfaces;k++) + { + surface = mod->data_surfaces + mod->firstmodelsurface + k; + for (j = 0;j < MAXLIGHTMAPS;j++) + { + if (surface->lightmapinfo->styles[j] != 255) + { + int r = remapstyles[surface->lightmapinfo->styles[j]]; + styleinfo[r].surfacelist[styleinfo[r].numsurfaces++] = mod->firstmodelsurface + k; + } + } + } + mod->brushq1.data_lightstyleinfo = (model_brush_lightstyleinfo_t *)datapointer;datapointer += mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t); + memcpy(mod->brushq1.data_lightstyleinfo, styleinfo, mod->brushq1.num_lightstyles * sizeof(model_brush_lightstyleinfo_t)); + } + else + { + // LordHavoc: empty submodel(lacrima.bsp has such a glitch) + Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadmodel->name); + } + //mod->brushq1.num_visleafs = bm->visleafs; + + // build a Bounding Interval Hierarchy for culling triangles in light rendering + Mod_MakeCollisionBIH(mod, true, &mod->render_bih); + + if (mod_q1bsp_polygoncollisions.integer) + { + mod->collision_bih = mod->render_bih; + // point traces and contents checks still use the bsp tree + mod->TraceLine = Mod_CollisionBIH_TraceLine; + mod->TraceBox = Mod_CollisionBIH_TraceBox; + mod->TraceBrush = Mod_CollisionBIH_TraceBrush; + mod->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLineAgainstSurfaces; + } + + // generate VBOs and other shared data before cloning submodels + if (i == 0) + { + Mod_BuildVBOs(); + Mod_Q1BSP_LoadMapBrushes(); + //Mod_Q1BSP_ProcessLightList(); + } + } + + Con_DPrintf("Stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); +} + +static void Mod_Q2BSP_LoadEntities(lump_t *l) +{ +} + +static void Mod_Q2BSP_LoadPlanes(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadPlanes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadVertices(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadVertices: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadVisibility(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadVisibility: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadNodes(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadNodes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadTexInfo(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadTexInfo: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadFaces(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadFaces: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadLighting(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadLighting: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadLeafs(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadLeafs: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadLeafFaces(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadLeafBrushes(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadEdges(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadEdges: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadSurfEdges(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadSurfEdges: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadBrushes(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadBrushes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadBrushSides(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadBrushSides: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadAreas(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadAreas: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadAreaPortals(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadAreaPortals: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_LoadModels(lump_t *l) +{ +/* + d_t *in; + m_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q2BSP_LoadModels: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel-> = out; + loadmodel->num = count; + + for (i = 0;i < count;i++, in++, out++) + { + } +*/ +} + +static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i; + q2dheader_t *header; + + Host_Error("Mod_Q2BSP_Load: not yet implemented"); + + mod->modeldatatypestring = "Q2BSP"; + + mod->type = mod_brushq2; + + header = (q2dheader_t *)buffer; + + i = LittleLong(header->version); + if (i != Q2BSPVERSION) + Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION); + + mod_base = (unsigned char *)header; + + // swap all the lumps + for (i = 0;i < (int) sizeof(*header) / 4;i++) + ((int *)header)[i] = LittleLong(((int *)header)[i]); + + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < Q2HEADER_LUMPS;i++) + { + if (i == Q2LUMP_ENTITIES) + continue; + mod->brush.qw_md4sum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + if (i == Q2LUMP_VISIBILITY || i == Q2LUMP_LEAFS || i == Q2LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + } + + Mod_Q2BSP_LoadEntities(&header->lumps[Q2LUMP_ENTITIES]); + Mod_Q2BSP_LoadPlanes(&header->lumps[Q2LUMP_PLANES]); + Mod_Q2BSP_LoadVertices(&header->lumps[Q2LUMP_VERTEXES]); + Mod_Q2BSP_LoadVisibility(&header->lumps[Q2LUMP_VISIBILITY]); + Mod_Q2BSP_LoadNodes(&header->lumps[Q2LUMP_NODES]); + Mod_Q2BSP_LoadTexInfo(&header->lumps[Q2LUMP_TEXINFO]); + Mod_Q2BSP_LoadFaces(&header->lumps[Q2LUMP_FACES]); + Mod_Q2BSP_LoadLighting(&header->lumps[Q2LUMP_LIGHTING]); + Mod_Q2BSP_LoadLeafs(&header->lumps[Q2LUMP_LEAFS]); + Mod_Q2BSP_LoadLeafFaces(&header->lumps[Q2LUMP_LEAFFACES]); + Mod_Q2BSP_LoadLeafBrushes(&header->lumps[Q2LUMP_LEAFBRUSHES]); + Mod_Q2BSP_LoadEdges(&header->lumps[Q2LUMP_EDGES]); + Mod_Q2BSP_LoadSurfEdges(&header->lumps[Q2LUMP_SURFEDGES]); + Mod_Q2BSP_LoadBrushes(&header->lumps[Q2LUMP_BRUSHES]); + Mod_Q2BSP_LoadBrushSides(&header->lumps[Q2LUMP_BRUSHSIDES]); + Mod_Q2BSP_LoadAreas(&header->lumps[Q2LUMP_AREAS]); + Mod_Q2BSP_LoadAreaPortals(&header->lumps[Q2LUMP_AREAPORTALS]); + // LordHavoc: must go last because this makes the submodels + Mod_Q2BSP_LoadModels(&header->lumps[Q2LUMP_MODELS]); +} + +static int Mod_Q3BSP_SuperContentsFromNativeContents(dp_model_t *model, int nativecontents); +static int Mod_Q3BSP_NativeContentsFromSuperContents(dp_model_t *model, int supercontents); + +static void Mod_Q3BSP_LoadEntities(lump_t *l) +{ + const char *data; + char key[128], value[MAX_INPUTLINE]; + float v[3]; + loadmodel->brushq3.num_lightgrid_cellsize[0] = 64; + loadmodel->brushq3.num_lightgrid_cellsize[1] = 64; + loadmodel->brushq3.num_lightgrid_cellsize[2] = 128; + if (!l->filelen) + return; + loadmodel->brush.entities = (char *)Mem_Alloc(loadmodel->mempool, l->filelen + 1); + memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen); + loadmodel->brush.entities[l->filelen] = 0; + data = loadmodel->brush.entities; + // some Q3 maps override the lightgrid_cellsize with a worldspawn key + // VorteX: q3map2 FS-R generates tangentspace deluxemaps for q3bsp and sets 'deluxeMaps' key + loadmodel->brushq3.deluxemapping = false; + if (data && COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{') + { + while (1) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strlcpy(key, com_token + 1, sizeof(key)); + else + strlcpy(key, com_token, sizeof(key)); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; // error + strlcpy(value, com_token, sizeof(value)); + if (!strcasecmp("gridsize", key)) // this one is case insensitive to 100% match q3map2 + { +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif +#if 0 + if (sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3 && v[0] != 0 && v[1] != 0 && v[2] != 0) + VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize); +#else + VectorSet(v, 64, 64, 128); + if(sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) != 3) + Con_Printf("Mod_Q3BSP_LoadEntities: funny gridsize \"%s\" in %s, interpreting as \"%f %f %f\" to match q3map2's parsing\n", value, loadmodel->name, v[0], v[1], v[2]); + if (v[0] != 0 && v[1] != 0 && v[2] != 0) + VectorCopy(v, loadmodel->brushq3.num_lightgrid_cellsize); +#endif + } + else if (!strcmp("deluxeMaps", key)) + { + if (!strcmp(com_token, "1")) + { + loadmodel->brushq3.deluxemapping = true; + loadmodel->brushq3.deluxemapping_modelspace = true; + } + else if (!strcmp(com_token, "2")) + { + loadmodel->brushq3.deluxemapping = true; + loadmodel->brushq3.deluxemapping_modelspace = false; + } + } + } + } +} + +static void Mod_Q3BSP_LoadTextures(lump_t *l) +{ + q3dtexture_t *in; + texture_t *out; + int i, count; + + in = (q3dtexture_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (texture_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->data_textures = out; + loadmodel->num_textures = count; + loadmodel->num_texturesperskin = loadmodel->num_textures; + + for (i = 0;i < count;i++) + { + strlcpy (out[i].name, in[i].name, sizeof (out[i].name)); + out[i].surfaceflags = LittleLong(in[i].surfaceflags); + out[i].supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in[i].contents)); + Mod_LoadTextureFromQ3Shader(out + i, out[i].name, true, true, TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS); + // restore the surfaceflags and supercontents + out[i].surfaceflags = LittleLong(in[i].surfaceflags); + out[i].supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in[i].contents)); + } +} + +static void Mod_Q3BSP_LoadPlanes(lump_t *l) +{ + q3dplane_t *in; + mplane_t *out; + int i, count; + + in = (q3dplane_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadPlanes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mplane_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_planes = out; + loadmodel->brush.num_planes = count; + + for (i = 0;i < count;i++, in++, out++) + { + out->normal[0] = LittleFloat(in->normal[0]); + out->normal[1] = LittleFloat(in->normal[1]); + out->normal[2] = LittleFloat(in->normal[2]); + out->dist = LittleFloat(in->dist); + PlaneClassify(out); + } +} + +static void Mod_Q3BSP_LoadBrushSides(lump_t *l) +{ + q3dbrushside_t *in; + q3mbrushside_t *out; + int i, n, count; + + in = (q3dbrushside_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (q3mbrushside_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_brushsides = out; + loadmodel->brush.num_brushsides = count; + + for (i = 0;i < count;i++, in++, out++) + { + n = LittleLong(in->planeindex); + if (n < 0 || n >= loadmodel->brush.num_planes) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)", n, loadmodel->brush.num_planes); + out->plane = loadmodel->brush.data_planes + n; + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->num_textures) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)", n, loadmodel->num_textures); + out->texture = loadmodel->data_textures + n; + } +} + +static void Mod_Q3BSP_LoadBrushSides_IG(lump_t *l) +{ + q3dbrushside_ig_t *in; + q3mbrushside_t *out; + int i, n, count; + + in = (q3dbrushside_ig_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (q3mbrushside_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_brushsides = out; + loadmodel->brush.num_brushsides = count; + + for (i = 0;i < count;i++, in++, out++) + { + n = LittleLong(in->planeindex); + if (n < 0 || n >= loadmodel->brush.num_planes) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)", n, loadmodel->brush.num_planes); + out->plane = loadmodel->brush.data_planes + n; + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->num_textures) + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)", n, loadmodel->num_textures); + out->texture = loadmodel->data_textures + n; + } +} + +static void Mod_Q3BSP_LoadBrushes(lump_t *l) +{ + q3dbrush_t *in; + q3mbrush_t *out; + int i, j, n, c, count, maxplanes, q3surfaceflags; + colplanef_t *planes; + + in = (q3dbrush_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadBrushes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (q3mbrush_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_brushes = out; + loadmodel->brush.num_brushes = count; + + maxplanes = 0; + planes = NULL; + + for (i = 0;i < count;i++, in++, out++) + { + n = LittleLong(in->firstbrushside); + c = LittleLong(in->numbrushsides); + if (n < 0 || n + c > loadmodel->brush.num_brushsides) + Host_Error("Mod_Q3BSP_LoadBrushes: invalid brushside range %i : %i (%i brushsides)", n, n + c, loadmodel->brush.num_brushsides); + out->firstbrushside = loadmodel->brush.data_brushsides + n; + out->numbrushsides = c; + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->num_textures) + Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)", n, loadmodel->num_textures); + out->texture = loadmodel->data_textures + n; + + // make a list of mplane_t structs to construct a colbrush from + if (maxplanes < out->numbrushsides) + { + maxplanes = out->numbrushsides; + if (planes) + Mem_Free(planes); + planes = (colplanef_t *)Mem_Alloc(tempmempool, sizeof(colplanef_t) * maxplanes); + } + q3surfaceflags = 0; + for (j = 0;j < out->numbrushsides;j++) + { + VectorCopy(out->firstbrushside[j].plane->normal, planes[j].normal); + planes[j].dist = out->firstbrushside[j].plane->dist; + planes[j].q3surfaceflags = out->firstbrushside[j].texture->surfaceflags; + planes[j].texture = out->firstbrushside[j].texture; + q3surfaceflags |= planes[j].q3surfaceflags; + } + // make the colbrush from the planes + out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents, q3surfaceflags, out->texture, true); + + // this whole loop can take a while (e.g. on redstarrepublic4) + CL_KeepaliveMessage(false); + } + if (planes) + Mem_Free(planes); +} + +static void Mod_Q3BSP_LoadEffects(lump_t *l) +{ + q3deffect_t *in; + q3deffect_t *out; + int i, n, count; + + in = (q3deffect_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadEffects: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (q3deffect_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brushq3.data_effects = out; + loadmodel->brushq3.num_effects = count; + + for (i = 0;i < count;i++, in++, out++) + { + strlcpy (out->shadername, in->shadername, sizeof (out->shadername)); + n = LittleLong(in->brushindex); + if (n >= loadmodel->brush.num_brushes) + { + Con_Printf("Mod_Q3BSP_LoadEffects: invalid brushindex %i (%i brushes), setting to -1\n", n, loadmodel->brush.num_brushes); + n = -1; + } + out->brushindex = n; + out->unknown = LittleLong(in->unknown); + } +} + +static void Mod_Q3BSP_LoadVertices(lump_t *l) +{ + q3dvertex_t *in; + int i, count; + + in = (q3dvertex_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name); + loadmodel->brushq3.num_vertices = count = l->filelen / sizeof(*in); + loadmodel->brushq3.data_vertex3f = (float *)Mem_Alloc(loadmodel->mempool, count * (sizeof(float) * (3 + 3 + 2 + 2 + 4))); + loadmodel->brushq3.data_normal3f = loadmodel->brushq3.data_vertex3f + count * 3; + loadmodel->brushq3.data_texcoordtexture2f = loadmodel->brushq3.data_normal3f + count * 3; + loadmodel->brushq3.data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordtexture2f + count * 2; + loadmodel->brushq3.data_color4f = loadmodel->brushq3.data_texcoordlightmap2f + count * 2; + + for (i = 0;i < count;i++, in++) + { + loadmodel->brushq3.data_vertex3f[i * 3 + 0] = LittleFloat(in->origin3f[0]); + loadmodel->brushq3.data_vertex3f[i * 3 + 1] = LittleFloat(in->origin3f[1]); + loadmodel->brushq3.data_vertex3f[i * 3 + 2] = LittleFloat(in->origin3f[2]); + loadmodel->brushq3.data_normal3f[i * 3 + 0] = LittleFloat(in->normal3f[0]); + loadmodel->brushq3.data_normal3f[i * 3 + 1] = LittleFloat(in->normal3f[1]); + loadmodel->brushq3.data_normal3f[i * 3 + 2] = LittleFloat(in->normal3f[2]); + loadmodel->brushq3.data_texcoordtexture2f[i * 2 + 0] = LittleFloat(in->texcoord2f[0]); + loadmodel->brushq3.data_texcoordtexture2f[i * 2 + 1] = LittleFloat(in->texcoord2f[1]); + loadmodel->brushq3.data_texcoordlightmap2f[i * 2 + 0] = LittleFloat(in->lightmap2f[0]); + loadmodel->brushq3.data_texcoordlightmap2f[i * 2 + 1] = LittleFloat(in->lightmap2f[1]); + // svector/tvector are calculated later in face loading + if(mod_q3bsp_sRGBlightmaps.integer) + { + // if lightmaps are sRGB, vertex colors are sRGB too, so we need to linearize them + // note: when this is in use, lightmap color 128 is no longer neutral, but "sRGB half power" is + // working like this may be odd, but matches q3map2 -gamma 2.2 + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + // we fix the brightness consistently via lightmapscale + } + else + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = Image_LinearFloatFromsRGB(in->color4ub[0]); + loadmodel->brushq3.data_color4f[i * 4 + 1] = Image_LinearFloatFromsRGB(in->color4ub[1]); + loadmodel->brushq3.data_color4f[i * 4 + 2] = Image_LinearFloatFromsRGB(in->color4ub[2]); + } + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[0]); + loadmodel->brushq3.data_color4f[i * 4 + 1] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[1]); + loadmodel->brushq3.data_color4f[i * 4 + 2] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[2]); + } + else + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + } + } + loadmodel->brushq3.data_color4f[i * 4 + 3] = in->color4ub[3] * (1.0f / 255.0f); + if(in->color4ub[0] != 255 || in->color4ub[1] != 255 || in->color4ub[2] != 255) + loadmodel->lit = true; + } +} + +static void Mod_Q3BSP_LoadTriangles(lump_t *l) +{ + int *in; + int *out; + int i, count; + + in = (int *)(mod_base + l->fileofs); + if (l->filelen % sizeof(int[3])) + Host_Error("Mod_Q3BSP_LoadTriangles: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + + if(!loadmodel->brushq3.num_vertices) + { + if (count) + Con_Printf("Mod_Q3BSP_LoadTriangles: %s has triangles but no vertexes, broken compiler, ignoring problem\n", loadmodel->name); + loadmodel->brushq3.num_triangles = 0; + return; + } + + out = (int *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + loadmodel->brushq3.num_triangles = count / 3; + loadmodel->brushq3.data_element3i = out; + + for (i = 0;i < count;i++, in++, out++) + { + *out = LittleLong(*in); + if (*out < 0 || *out >= loadmodel->brushq3.num_vertices) + { + Con_Printf("Mod_Q3BSP_LoadTriangles: invalid vertexindex %i (%i vertices), setting to 0\n", *out, loadmodel->brushq3.num_vertices); + *out = 0; + } + } +} + +static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) +{ + q3dlightmap_t *input_pointer; + int i; + int j; + int k; + int count; + int powerx; + int powery; + int powerxy; + int powerdxy; + int endlightmap; + int mergegoal; + int lightmapindex; + int realcount; + int realindex; + int mergedwidth; + int mergedheight; + int mergedcolumns; + int mergedrows; + int mergedrowsxcolumns; + int size; + int bytesperpixel; + int rgbmap[3]; + unsigned char *c; + unsigned char *mergedpixels; + unsigned char *mergeddeluxepixels; + unsigned char *mergebuf; + char mapname[MAX_QPATH]; + qboolean external; + unsigned char *inpixels[10000]; // max count q3map2 can output (it uses 4 digits) + char vabuf[1024]; + + // defaults for q3bsp + size = 128; + bytesperpixel = 3; + rgbmap[0] = 2; + rgbmap[1] = 1; + rgbmap[2] = 0; + external = false; + loadmodel->brushq3.lightmapsize = 128; + + if (cls.state == ca_dedicated) + return; + + if(mod_q3bsp_nolightmaps.integer) + { + return; + } + else if(l->filelen) + { + // prefer internal LMs for compatibility (a BSP contains no info on whether external LMs exist) + if (developer_loading.integer) + Con_Printf("Using internal lightmaps\n"); + input_pointer = (q3dlightmap_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*input_pointer)) + Host_Error("Mod_Q3BSP_LoadLightmaps: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*input_pointer); + for(i = 0; i < count; ++i) + inpixels[i] = input_pointer[i].rgb; + } + else + { + // no internal lightmaps + // try external lightmaps + if (developer_loading.integer) + Con_Printf("Using external lightmaps\n"); + FS_StripExtension(loadmodel->name, mapname, sizeof(mapname)); + inpixels[0] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, 0), false, false, false, NULL); + if(!inpixels[0]) + return; + + // using EXTERNAL lightmaps instead + if(image_width != (int) CeilPowerOf2(image_width) || image_width != image_height) + { + Mem_Free(inpixels[0]); + Host_Error("Mod_Q3BSP_LoadLightmaps: invalid external lightmap size in %s",loadmodel->name); + } + + size = image_width; + bytesperpixel = 4; + rgbmap[0] = 0; + rgbmap[1] = 1; + rgbmap[2] = 2; + external = true; + + for(count = 1; ; ++count) + { + inpixels[count] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, count), false, false, false, NULL); + if(!inpixels[count]) + break; // we got all of them + if(image_width != size || image_height != size) + { + Mem_Free(inpixels[count]); + inpixels[count] = NULL; + Con_Printf("Mod_Q3BSP_LoadLightmaps: mismatched lightmap size in %s - external lightmap %s/lm_%04d does not match earlier ones\n", loadmodel->name, mapname, count); + break; + } + } + } + + loadmodel->brushq3.lightmapsize = size; + loadmodel->brushq3.num_originallightmaps = count; + + // now check the surfaces to see if any of them index an odd numbered + // lightmap, if so this is not a deluxemapped bsp file + // + // also check what lightmaps are actually used, because q3map2 sometimes + // (always?) makes an unused one at the end, which + // q3map2 sometimes (or always?) makes a second blank lightmap for no + // reason when only one lightmap is used, which can throw off the + // deluxemapping detection method, so check 2-lightmap bsp's specifically + // to see if the second lightmap is blank, if so it is not deluxemapped. + // VorteX: autodetect only if previous attempt to find "deluxeMaps" key + // in Mod_Q3BSP_LoadEntities was failed + if (!loadmodel->brushq3.deluxemapping) + { + loadmodel->brushq3.deluxemapping = !(count & 1); + loadmodel->brushq3.deluxemapping_modelspace = true; + endlightmap = 0; + if (loadmodel->brushq3.deluxemapping) + { + int facecount = faceslump->filelen / sizeof(q3dface_t); + q3dface_t *faces = (q3dface_t *)(mod_base + faceslump->fileofs); + for (i = 0;i < facecount;i++) + { + j = LittleLong(faces[i].lightmapindex); + if (j >= 0) + { + endlightmap = max(endlightmap, j + 1); + if ((j & 1) || j + 1 >= count) + { + loadmodel->brushq3.deluxemapping = false; + break; + } + } + } + } + + // q3map2 sometimes (or always?) makes a second blank lightmap for no + // reason when only one lightmap is used, which can throw off the + // deluxemapping detection method, so check 2-lightmap bsp's specifically + // to see if the second lightmap is blank, if so it is not deluxemapped. + // + // further research has shown q3map2 sometimes creates a deluxemap and two + // blank lightmaps, which must be handled properly as well + if (endlightmap == 1 && count > 1) + { + c = inpixels[1]; + for (i = 0;i < size*size;i++) + { + if (c[bytesperpixel*i + rgbmap[0]]) + break; + if (c[bytesperpixel*i + rgbmap[1]]) + break; + if (c[bytesperpixel*i + rgbmap[2]]) + break; + } + if (i == size*size) + { + // all pixels in the unused lightmap were black... + loadmodel->brushq3.deluxemapping = false; + } + } + } + + Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not "); + + // figure out what the most reasonable merge power is within limits + + // find the appropriate NxN dimensions to merge to, to avoid wasted space + realcount = count >> (int)loadmodel->brushq3.deluxemapping; + + // figure out how big the merged texture has to be + mergegoal = 128< size && mergegoal * mergegoal / 4 >= size * size * realcount) + mergegoal /= 2; + mergedwidth = mergegoal; + mergedheight = mergegoal; + // choose non-square size (2x1 aspect) if only half the space is used; + // this really only happens when the entire set fits in one texture, if + // there are multiple textures, we don't worry about shrinking the last + // one to fit, because the driver prefers the same texture size on + // consecutive draw calls... + if (mergedwidth * mergedheight / 2 >= size*size*realcount) + mergedheight /= 2; + + loadmodel->brushq3.num_lightmapmergedwidthpower = 0; + loadmodel->brushq3.num_lightmapmergedheightpower = 0; + while (mergedwidth > size<brushq3.num_lightmapmergedwidthpower) + loadmodel->brushq3.num_lightmapmergedwidthpower++; + while (mergedheight > size<brushq3.num_lightmapmergedheightpower) + loadmodel->brushq3.num_lightmapmergedheightpower++; + loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower = loadmodel->brushq3.num_lightmapmergedwidthpower + loadmodel->brushq3.num_lightmapmergedheightpower + (loadmodel->brushq3.deluxemapping ? 1 : 0); + + powerx = loadmodel->brushq3.num_lightmapmergedwidthpower; + powery = loadmodel->brushq3.num_lightmapmergedheightpower; + powerxy = powerx+powery; + powerdxy = loadmodel->brushq3.deluxemapping + powerxy; + + mergedcolumns = 1 << powerx; + mergedrows = 1 << powery; + mergedrowsxcolumns = 1 << powerxy; + + loadmodel->brushq3.num_mergedlightmaps = (realcount + (1 << powerxy) - 1) >> powerxy; + loadmodel->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + if (loadmodel->brushq3.deluxemapping) + loadmodel->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + + // allocate a texture pool if we need it + if (loadmodel->texturepool == NULL && cls.state != ca_dedicated) + loadmodel->texturepool = R_AllocTexturePool(); + + mergedpixels = (unsigned char *) Mem_Alloc(tempmempool, mergedwidth * mergedheight * 4); + mergeddeluxepixels = loadmodel->brushq3.deluxemapping ? (unsigned char *) Mem_Alloc(tempmempool, mergedwidth * mergedheight * 4) : NULL; + for (i = 0;i < count;i++) + { + // figure out which merged lightmap texture this fits into + realindex = i >> (int)loadmodel->brushq3.deluxemapping; + lightmapindex = i >> powerdxy; + + // choose the destination address + mergebuf = (loadmodel->brushq3.deluxemapping && (i & 1)) ? mergeddeluxepixels : mergedpixels; + mergebuf += 4 * (realindex & (mergedcolumns-1))*size + 4 * ((realindex >> powerx) & (mergedrows-1))*mergedwidth*size; + if ((i & 1) == 0 || !loadmodel->brushq3.deluxemapping) + Con_DPrintf("copying original lightmap %i (%ix%i) to %i (at %i,%i)\n", i, size, size, lightmapindex, (realindex & (mergedcolumns-1))*size, ((realindex >> powerx) & (mergedrows-1))*size); + + // convert pixels from RGB or BGRA while copying them into the destination rectangle + for (j = 0;j < size;j++) + for (k = 0;k < size;k++) + { + mergebuf[(j*mergedwidth+k)*4+0] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[0]]; + mergebuf[(j*mergedwidth+k)*4+1] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[1]]; + mergebuf[(j*mergedwidth+k)*4+2] = inpixels[i][(j*size+k)*bytesperpixel+rgbmap[2]]; + mergebuf[(j*mergedwidth+k)*4+3] = 255; + } + + // upload texture if this was the last tile being written to the texture + if (((realindex + 1) & (mergedrowsxcolumns - 1)) == 0 || (realindex + 1) == realcount) + { + if (loadmodel->brushq3.deluxemapping && (i & 1)) + loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%04i", lightmapindex), mergedwidth, mergedheight, mergeddeluxepixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + else + { + if(mod_q3bsp_sRGBlightmaps.integer) + { + textype_t t; + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + t = TEXTYPE_BGRA; // in stupid fallback mode, we upload lightmaps in sRGB form and just fix their brightness + // we fix the brightness consistently via lightmapscale + } + else + t = TEXTYPE_SRGB_BGRA; // normally, we upload lightmaps in sRGB form (possibly downconverted to linear) + loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, t, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + Image_MakesRGBColorsFromLinear_Lightmap(mergedpixels, mergedpixels, mergedwidth * mergedheight); + loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + } + } + } + } + + if (mergeddeluxepixels) + Mem_Free(mergeddeluxepixels); + Mem_Free(mergedpixels); + if(external) + { + for(i = 0; i < count; ++i) + Mem_Free(inpixels[i]); + } +} + +static void Mod_Q3BSP_BuildBBoxes(const int *element3i, int num_triangles, const float *vertex3f, float **collisionbbox6f, int *collisionstride, int stride) +{ + int j, k, cnt, tri; + float *mins, *maxs; + const float *vert; + *collisionstride = stride; + if(stride > 0) + { + cnt = (num_triangles + stride - 1) / stride; + *collisionbbox6f = (float *) Mem_Alloc(loadmodel->mempool, sizeof(float[6]) * cnt); + for(j = 0; j < cnt; ++j) + { + mins = &((*collisionbbox6f)[6 * j + 0]); + maxs = &((*collisionbbox6f)[6 * j + 3]); + for(k = 0; k < stride; ++k) + { + tri = j * stride + k; + if(tri >= num_triangles) + break; + vert = &(vertex3f[element3i[3 * tri + 0] * 3]); + if(!k || vert[0] < mins[0]) mins[0] = vert[0]; + if(!k || vert[1] < mins[1]) mins[1] = vert[1]; + if(!k || vert[2] < mins[2]) mins[2] = vert[2]; + if(!k || vert[0] > maxs[0]) maxs[0] = vert[0]; + if(!k || vert[1] > maxs[1]) maxs[1] = vert[1]; + if(!k || vert[2] > maxs[2]) maxs[2] = vert[2]; + vert = &(vertex3f[element3i[3 * tri + 1] * 3]); + if(vert[0] < mins[0]) mins[0] = vert[0]; + if(vert[1] < mins[1]) mins[1] = vert[1]; + if(vert[2] < mins[2]) mins[2] = vert[2]; + if(vert[0] > maxs[0]) maxs[0] = vert[0]; + if(vert[1] > maxs[1]) maxs[1] = vert[1]; + if(vert[2] > maxs[2]) maxs[2] = vert[2]; + vert = &(vertex3f[element3i[3 * tri + 2] * 3]); + if(vert[0] < mins[0]) mins[0] = vert[0]; + if(vert[1] < mins[1]) mins[1] = vert[1]; + if(vert[2] < mins[2]) mins[2] = vert[2]; + if(vert[0] > maxs[0]) maxs[0] = vert[0]; + if(vert[1] > maxs[1]) maxs[1] = vert[1]; + if(vert[2] > maxs[2]) maxs[2] = vert[2]; + } + } + } + else + *collisionbbox6f = NULL; +} + +typedef struct patchtess_s +{ + patchinfo_t info; + + // Auxiliary data used only by patch loading code in Mod_Q3BSP_LoadFaces + int surface_id; + float lodgroup[6]; + float *originalvertex3f; +} patchtess_t; + +#define PATCHTESS_SAME_LODGROUP(a,b) \ + ( \ + (a).lodgroup[0] == (b).lodgroup[0] && \ + (a).lodgroup[1] == (b).lodgroup[1] && \ + (a).lodgroup[2] == (b).lodgroup[2] && \ + (a).lodgroup[3] == (b).lodgroup[3] && \ + (a).lodgroup[4] == (b).lodgroup[4] && \ + (a).lodgroup[5] == (b).lodgroup[5] \ + ) + +static void Mod_Q3BSP_LoadFaces(lump_t *l) +{ + q3dface_t *in, *oldin; + msurface_t *out, *oldout; + int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshvertices, meshtriangles, collisionvertices, collisiontriangles, numvertices, numtriangles, cxtess, cytess; + float lightmaptcbase[2], lightmaptcscale[2]; + //int *originalelement3i; + //int *originalneighbor3i; + float *originalvertex3f; + //float *originalsvector3f; + //float *originaltvector3f; + float *originalnormal3f; + float *originalcolor4f; + float *originaltexcoordtexture2f; + float *originaltexcoordlightmap2f; + float *surfacecollisionvertex3f; + int *surfacecollisionelement3i; + float *v; + patchtess_t *patchtess = NULL; + int patchtesscount = 0; + qboolean again; + + in = (q3dface_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadFaces: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (msurface_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->data_surfaces = out; + loadmodel->num_surfaces = count; + + if(count > 0) + patchtess = (patchtess_t*) Mem_Alloc(tempmempool, count * sizeof(*patchtess)); + + i = 0; + oldi = i; + oldin = in; + oldout = out; + meshvertices = 0; + meshtriangles = 0; + for (;i < count;i++, in++, out++) + { + // check face type first + type = LittleLong(in->type); + if (type != Q3FACETYPE_FLAT + && type != Q3FACETYPE_PATCH + && type != Q3FACETYPE_MESH + && type != Q3FACETYPE_FLARE) + { + Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type); + continue; + } + + n = LittleLong(in->textureindex); + if (n < 0 || n >= loadmodel->num_textures) + { + Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->num_textures); + continue; + } + out->texture = loadmodel->data_textures + n; + n = LittleLong(in->effectindex); + if (n < -1 || n >= loadmodel->brushq3.num_effects) + { + if (developer_extra.integer) + Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects); + n = -1; + } + if (n == -1) + out->effect = NULL; + else + out->effect = loadmodel->brushq3.data_effects + n; + + if (cls.state != ca_dedicated) + { + out->lightmaptexture = NULL; + out->deluxemaptexture = r_texture_blanknormalmap; + n = LittleLong(in->lightmapindex); + if (n < 0) + n = -1; + else if (n >= loadmodel->brushq3.num_originallightmaps) + { + if(loadmodel->brushq3.num_originallightmaps != 0) + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_originallightmaps); + n = -1; + } + else + { + out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower]; + if (loadmodel->brushq3.deluxemapping) + out->deluxemaptexture = loadmodel->brushq3.data_deluxemaps[n >> loadmodel->brushq3.num_lightmapmergedwidthheightdeluxepower]; + loadmodel->lit = true; + } + } + + firstvertex = LittleLong(in->firstvertex); + numvertices = LittleLong(in->numvertices); + firstelement = LittleLong(in->firstelement); + numtriangles = LittleLong(in->numelements) / 3; + if (numtriangles * 3 != LittleLong(in->numelements)) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements)); + continue; + } + if (firstvertex < 0 || firstvertex + numvertices > loadmodel->brushq3.num_vertices) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + numvertices, loadmodel->brushq3.num_vertices); + continue; + } + if (firstelement < 0 || firstelement + numtriangles * 3 > loadmodel->brushq3.num_triangles * 3) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + numtriangles * 3, loadmodel->brushq3.num_triangles * 3); + continue; + } + switch(type) + { + case Q3FACETYPE_FLAT: + case Q3FACETYPE_MESH: + // no processing necessary + break; + case Q3FACETYPE_PATCH: + patchsize[0] = LittleLong(in->specific.patch.patchsize[0]); + patchsize[1] = LittleLong(in->specific.patch.patchsize[1]); + if (numvertices != (patchsize[0] * patchsize[1]) || patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer)) + { + Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]); + continue; + } + originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3; + + // convert patch to Q3FACETYPE_MESH + xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value); + ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value); + // bound to user settings + xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer); + ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer); + // bound to sanity settings + xtess = bound(0, xtess, 1024); + ytess = bound(0, ytess, 1024); + + // lower quality collision patches! Same procedure as before, but different cvars + // convert patch to Q3FACETYPE_MESH + cxtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value); + cytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value); + // bound to user settings + cxtess = bound(r_subdivisions_collision_mintess.integer, cxtess, r_subdivisions_collision_maxtess.integer); + cytess = bound(r_subdivisions_collision_mintess.integer, cytess, r_subdivisions_collision_maxtess.integer); + // bound to sanity settings + cxtess = bound(0, cxtess, 1024); + cytess = bound(0, cytess, 1024); + + // store it for the LOD grouping step + patchtess[patchtesscount].info.xsize = patchsize[0]; + patchtess[patchtesscount].info.ysize = patchsize[1]; + patchtess[patchtesscount].info.lods[PATCH_LOD_VISUAL].xtess = xtess; + patchtess[patchtesscount].info.lods[PATCH_LOD_VISUAL].ytess = ytess; + patchtess[patchtesscount].info.lods[PATCH_LOD_COLLISION].xtess = cxtess; + patchtess[patchtesscount].info.lods[PATCH_LOD_COLLISION].ytess = cytess; + + patchtess[patchtesscount].surface_id = i; + patchtess[patchtesscount].lodgroup[0] = LittleFloat(in->specific.patch.mins[0]); + patchtess[patchtesscount].lodgroup[1] = LittleFloat(in->specific.patch.mins[1]); + patchtess[patchtesscount].lodgroup[2] = LittleFloat(in->specific.patch.mins[2]); + patchtess[patchtesscount].lodgroup[3] = LittleFloat(in->specific.patch.maxs[0]); + patchtess[patchtesscount].lodgroup[4] = LittleFloat(in->specific.patch.maxs[1]); + patchtess[patchtesscount].lodgroup[5] = LittleFloat(in->specific.patch.maxs[2]); + patchtess[patchtesscount].originalvertex3f = originalvertex3f; + ++patchtesscount; + break; + case Q3FACETYPE_FLARE: + if (developer_extra.integer) + Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name); + // don't render it + continue; + } + out->num_vertices = numvertices; + out->num_triangles = numtriangles; + meshvertices += out->num_vertices; + meshtriangles += out->num_triangles; + } + + // Fix patches tesselations so that they make no seams + do + { + again = false; + for(i = 0; i < patchtesscount; ++i) + { + for(j = i+1; j < patchtesscount; ++j) + { + if (!PATCHTESS_SAME_LODGROUP(patchtess[i], patchtess[j])) + continue; + + if (Q3PatchAdjustTesselation(3, &patchtess[i].info, patchtess[i].originalvertex3f, &patchtess[j].info, patchtess[j].originalvertex3f) ) + again = true; + } + } + } + while (again); + + // Calculate resulting number of triangles + collisionvertices = 0; + collisiontriangles = 0; + for(i = 0; i < patchtesscount; ++i) + { + finalwidth = Q3PatchDimForTess(patchtess[i].info.xsize, patchtess[i].info.lods[PATCH_LOD_VISUAL].xtess); + finalheight = Q3PatchDimForTess(patchtess[i].info.ysize,patchtess[i].info.lods[PATCH_LOD_VISUAL].ytess); + numvertices = finalwidth * finalheight; + numtriangles = (finalwidth - 1) * (finalheight - 1) * 2; + + oldout[patchtess[i].surface_id].num_vertices = numvertices; + oldout[patchtess[i].surface_id].num_triangles = numtriangles; + meshvertices += oldout[patchtess[i].surface_id].num_vertices; + meshtriangles += oldout[patchtess[i].surface_id].num_triangles; + + finalwidth = Q3PatchDimForTess(patchtess[i].info.xsize, patchtess[i].info.lods[PATCH_LOD_COLLISION].xtess); + finalheight = Q3PatchDimForTess(patchtess[i].info.ysize,patchtess[i].info.lods[PATCH_LOD_COLLISION].ytess); + numvertices = finalwidth * finalheight; + numtriangles = (finalwidth - 1) * (finalheight - 1) * 2; + + oldout[patchtess[i].surface_id].num_collisionvertices = numvertices; + oldout[patchtess[i].surface_id].num_collisiontriangles = numtriangles; + collisionvertices += oldout[patchtess[i].surface_id].num_collisionvertices; + collisiontriangles += oldout[patchtess[i].surface_id].num_collisiontriangles; + } + + i = oldi; + in = oldin; + out = oldout; + Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, true, false); + if (collisiontriangles) + { + loadmodel->brush.data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, collisionvertices * sizeof(float[3])); + loadmodel->brush.data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, collisiontriangles * sizeof(int[3])); + } + meshvertices = 0; + meshtriangles = 0; + collisionvertices = 0; + collisiontriangles = 0; + for (;i < count && meshvertices + out->num_vertices <= loadmodel->surfmesh.num_vertices;i++, in++, out++) + { + if (out->num_vertices < 3 || out->num_triangles < 1) + continue; + + type = LittleLong(in->type); + firstvertex = LittleLong(in->firstvertex); + firstelement = LittleLong(in->firstelement); + out->num_firstvertex = meshvertices; + out->num_firsttriangle = meshtriangles; + out->num_firstcollisiontriangle = collisiontriangles; + switch(type) + { + case Q3FACETYPE_FLAT: + case Q3FACETYPE_MESH: + // no processing necessary, except for lightmap merging + for (j = 0;j < out->num_vertices;j++) + { + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 0]; + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 1]; + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 2]; + (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 0]; + (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 1]; + (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 2]; + (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 0]; + (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 1]; + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 0]; + (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 1]; + (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 0] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 0]; + (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 1] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 1]; + (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 2] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 2]; + (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 3] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 3]; + } + for (j = 0;j < out->num_triangles*3;j++) + (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = loadmodel->brushq3.data_element3i[firstelement + j] + out->num_firstvertex; + break; + case Q3FACETYPE_PATCH: + patchsize[0] = LittleLong(in->specific.patch.patchsize[0]); + patchsize[1] = LittleLong(in->specific.patch.patchsize[1]); + originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3; + originalnormal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3; + originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2; + originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2; + originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4; + + xtess = ytess = cxtess = cytess = -1; + for(j = 0; j < patchtesscount; ++j) + if(patchtess[j].surface_id == i) + { + xtess = patchtess[j].info.lods[PATCH_LOD_VISUAL].xtess; + ytess = patchtess[j].info.lods[PATCH_LOD_VISUAL].ytess; + cxtess = patchtess[j].info.lods[PATCH_LOD_COLLISION].xtess; + cytess = patchtess[j].info.lods[PATCH_LOD_COLLISION].ytess; + break; + } + if(xtess == -1) + { + Con_Printf("ERROR: patch %d isn't preprocessed?!?\n", i); + xtess = ytess = cxtess = cytess = 0; + } + + finalwidth = Q3PatchDimForTess(patchsize[0],xtess); //((patchsize[0] - 1) * xtess) + 1; + finalheight = Q3PatchDimForTess(patchsize[1],ytess); //((patchsize[1] - 1) * ytess) + 1; + finalvertices = finalwidth * finalheight; + oldnumtriangles = finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2; + type = Q3FACETYPE_MESH; + // generate geometry + // (note: normals are skipped because they get recalculated) + Q3PatchTesselateFloat(3, sizeof(float[3]), (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess); + Q3PatchTesselateFloat(3, sizeof(float[3]), (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalnormal3f, xtess, ytess); + Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess); + Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess); + Q3PatchTesselateFloat(4, sizeof(float[4]), (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess); + Q3PatchTriangleElements((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex); + + out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), loadmodel->surfmesh.data_vertex3f); + + if (developer_extra.integer) + { + if (out->num_triangles < finaltriangles) + Con_DPrintf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles); + else + Con_DPrintf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles); + } + // q3map does not put in collision brushes for curves... ugh + // build the lower quality collision geometry + finalwidth = Q3PatchDimForTess(patchsize[0],cxtess); //((patchsize[0] - 1) * cxtess) + 1; + finalheight = Q3PatchDimForTess(patchsize[1],cytess); //((patchsize[1] - 1) * cytess) + 1; + finalvertices = finalwidth * finalheight; + oldnumtriangles2 = finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2; + + // legacy collision geometry implementation + out->deprecatedq3data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices); + out->deprecatedq3data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles); + out->num_collisionvertices = finalvertices; + out->num_collisiontriangles = finaltriangles; + Q3PatchTesselateFloat(3, sizeof(float[3]), out->deprecatedq3data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, cxtess, cytess); + Q3PatchTriangleElements(out->deprecatedq3data_collisionelement3i, finalwidth, finalheight, 0); + + //Mod_SnapVertices(3, out->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), 0.25); + Mod_SnapVertices(3, finalvertices, out->deprecatedq3data_collisionvertex3f, 1); + + out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(finaltriangles, out->deprecatedq3data_collisionelement3i, out->deprecatedq3data_collisionelement3i, out->deprecatedq3data_collisionvertex3f); + + // now optimize the collision mesh by finding triangle bboxes... + Mod_Q3BSP_BuildBBoxes(out->deprecatedq3data_collisionelement3i, out->num_collisiontriangles, out->deprecatedq3data_collisionvertex3f, &out->deprecatedq3data_collisionbbox6f, &out->deprecatedq3num_collisionbboxstride, mod_q3bsp_curves_collisions_stride.integer); + Mod_Q3BSP_BuildBBoxes(loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle, out->num_triangles, loadmodel->surfmesh.data_vertex3f, &out->deprecatedq3data_bbox6f, &out->deprecatedq3num_bboxstride, mod_q3bsp_curves_stride.integer); + + // store collision geometry for BIH collision tree + surfacecollisionvertex3f = loadmodel->brush.data_collisionvertex3f + collisionvertices * 3; + surfacecollisionelement3i = loadmodel->brush.data_collisionelement3i + collisiontriangles * 3; + Q3PatchTesselateFloat(3, sizeof(float[3]), surfacecollisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, cxtess, cytess); + Q3PatchTriangleElements(surfacecollisionelement3i, finalwidth, finalheight, collisionvertices); + Mod_SnapVertices(3, finalvertices, surfacecollisionvertex3f, 1); +#if 1 + // remove this once the legacy code is removed + { + int nc = out->num_collisiontriangles; +#endif + out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(finaltriangles, surfacecollisionelement3i, surfacecollisionelement3i, loadmodel->brush.data_collisionvertex3f); +#if 1 + if(nc != out->num_collisiontriangles) + { + Con_Printf("number of collision triangles differs between BIH and BSP. FAIL.\n"); + } + } +#endif + + if (developer_extra.integer) + Con_DPrintf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles); + + collisionvertices += finalvertices; + collisiontriangles += out->num_collisiontriangles; + break; + default: + break; + } + meshvertices += out->num_vertices; + meshtriangles += out->num_triangles; + for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++) + if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices) + invalidelements++; + if (invalidelements) + { + Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3); + for (j = 0;j < out->num_triangles * 3;j++) + { + Con_Printf(" %i", (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] - out->num_firstvertex); + if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices) + (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = out->num_firstvertex; + } + Con_Print("\n"); + } + // calculate a bounding box + VectorClear(out->mins); + VectorClear(out->maxs); + if (out->num_vertices) + { + if (cls.state != ca_dedicated && out->lightmaptexture) + { + // figure out which part of the merged lightmap this fits into + int lightmapindex = LittleLong(in->lightmapindex) >> (loadmodel->brushq3.deluxemapping ? 1 : 0); + int mergewidth = R_TextureWidth(out->lightmaptexture) / loadmodel->brushq3.lightmapsize; + int mergeheight = R_TextureHeight(out->lightmaptexture) / loadmodel->brushq3.lightmapsize; + lightmapindex &= mergewidth * mergeheight - 1; + lightmaptcscale[0] = 1.0f / mergewidth; + lightmaptcscale[1] = 1.0f / mergeheight; + lightmaptcbase[0] = (lightmapindex % mergewidth) * lightmaptcscale[0]; + lightmaptcbase[1] = (lightmapindex / mergewidth) * lightmaptcscale[1]; + // modify the lightmap texcoords to match this region of the merged lightmap + for (j = 0, v = loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex;j < out->num_vertices;j++, v += 2) + { + v[0] = v[0] * lightmaptcscale[0] + lightmaptcbase[0]; + v[1] = v[1] * lightmaptcscale[1] + lightmaptcbase[1]; + } + } + VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->mins); + VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->maxs); + for (j = 1, v = (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex) + 3;j < out->num_vertices;j++, v += 3) + { + out->mins[0] = min(out->mins[0], v[0]); + out->maxs[0] = max(out->maxs[0], v[0]); + out->mins[1] = min(out->mins[1], v[1]); + out->maxs[1] = max(out->maxs[1], v[1]); + out->mins[2] = min(out->mins[2], v[2]); + out->maxs[2] = max(out->maxs[2], v[2]); + } + out->mins[0] -= 1.0f; + out->mins[1] -= 1.0f; + out->mins[2] -= 1.0f; + out->maxs[0] += 1.0f; + out->maxs[1] += 1.0f; + out->maxs[2] += 1.0f; + } + // set lightmap styles for consistency with q1bsp + //out->lightmapinfo->styles[0] = 0; + //out->lightmapinfo->styles[1] = 255; + //out->lightmapinfo->styles[2] = 255; + //out->lightmapinfo->styles[3] = 255; + } + + i = oldi; + out = oldout; + for (;i < count;i++, out++) + { + if(out->num_vertices && out->num_triangles) + continue; + if(out->num_vertices == 0) + { + Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s) has no vertices, ignoring\n", i, out->texture ? out->texture->name : "(none)"); + if(out->num_triangles == 0) + Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s) has no triangles, ignoring\n", i, out->texture ? out->texture->name : "(none)"); + } + else if(out->num_triangles == 0) + Con_Printf("Mod_Q3BSP_LoadFaces: surface %d (texture %s, near %f %f %f) has no triangles, ignoring\n", i, out->texture ? out->texture->name : "(none)", + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[0 * 3 + 0], + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[1 * 3 + 0], + (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[2 * 3 + 0]); + } + + // for per pixel lighting + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + + // generate ushort elements array if possible + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + + // free the no longer needed vertex data + loadmodel->brushq3.num_vertices = 0; + if (loadmodel->brushq3.data_vertex3f) + Mem_Free(loadmodel->brushq3.data_vertex3f); + loadmodel->brushq3.data_vertex3f = NULL; + loadmodel->brushq3.data_normal3f = NULL; + loadmodel->brushq3.data_texcoordtexture2f = NULL; + loadmodel->brushq3.data_texcoordlightmap2f = NULL; + loadmodel->brushq3.data_color4f = NULL; + // free the no longer needed triangle data + loadmodel->brushq3.num_triangles = 0; + if (loadmodel->brushq3.data_element3i) + Mem_Free(loadmodel->brushq3.data_element3i); + loadmodel->brushq3.data_element3i = NULL; + + if(patchtess) + Mem_Free(patchtess); +} + +static void Mod_Q3BSP_LoadModels(lump_t *l) +{ + q3dmodel_t *in; + q3dmodel_t *out; + int i, j, n, c, count; + + in = (q3dmodel_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadModels: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (q3dmodel_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brushq3.data_models = out; + loadmodel->brushq3.num_models = count; + + for (i = 0;i < count;i++, in++, out++) + { + for (j = 0;j < 3;j++) + { + out->mins[j] = LittleFloat(in->mins[j]); + out->maxs[j] = LittleFloat(in->maxs[j]); + } + n = LittleLong(in->firstface); + c = LittleLong(in->numfaces); + if (n < 0 || n + c > loadmodel->num_surfaces) + Host_Error("Mod_Q3BSP_LoadModels: invalid face range %i : %i (%i faces)", n, n + c, loadmodel->num_surfaces); + out->firstface = n; + out->numfaces = c; + n = LittleLong(in->firstbrush); + c = LittleLong(in->numbrushes); + if (n < 0 || n + c > loadmodel->brush.num_brushes) + Host_Error("Mod_Q3BSP_LoadModels: invalid brush range %i : %i (%i brushes)", n, n + c, loadmodel->brush.num_brushes); + out->firstbrush = n; + out->numbrushes = c; + } +} + +static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l) +{ + int *in; + int *out; + int i, n, count; + + in = (int *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (int *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_leafbrushes = out; + loadmodel->brush.num_leafbrushes = count; + + for (i = 0;i < count;i++, in++, out++) + { + n = LittleLong(*in); + if (n < 0 || n >= loadmodel->brush.num_brushes) + Host_Error("Mod_Q3BSP_LoadLeafBrushes: invalid brush index %i (%i brushes)", n, loadmodel->brush.num_brushes); + *out = n; + } +} + +static void Mod_Q3BSP_LoadLeafFaces(lump_t *l) +{ + int *in; + int *out; + int i, n, count; + + in = (int *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (int *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_leafsurfaces = out; + loadmodel->brush.num_leafsurfaces = count; + + for (i = 0;i < count;i++, in++, out++) + { + n = LittleLong(*in); + if (n < 0 || n >= loadmodel->num_surfaces) + Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)", n, loadmodel->num_surfaces); + *out = n; + } +} + +static void Mod_Q3BSP_LoadLeafs(lump_t *l) +{ + q3dleaf_t *in; + mleaf_t *out; + int i, j, n, c, count; + + in = (q3dleaf_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadLeafs: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mleaf_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_leafs = out; + loadmodel->brush.num_leafs = count; + + for (i = 0;i < count;i++, in++, out++) + { + out->parent = NULL; + out->plane = NULL; + out->clusterindex = LittleLong(in->clusterindex); + out->areaindex = LittleLong(in->areaindex); + for (j = 0;j < 3;j++) + { + // yes the mins/maxs are ints + out->mins[j] = LittleLong(in->mins[j]) - 1; + out->maxs[j] = LittleLong(in->maxs[j]) + 1; + } + n = LittleLong(in->firstleafface); + c = LittleLong(in->numleaffaces); + if (n < 0 || n + c > loadmodel->brush.num_leafsurfaces) + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafsurface range %i : %i (%i leafsurfaces)", n, n + c, loadmodel->brush.num_leafsurfaces); + out->firstleafsurface = loadmodel->brush.data_leafsurfaces + n; + out->numleafsurfaces = c; + n = LittleLong(in->firstleafbrush); + c = LittleLong(in->numleafbrushes); + if (n < 0 || n + c > loadmodel->brush.num_leafbrushes) + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)", n, n + c, loadmodel->brush.num_leafbrushes); + out->firstleafbrush = loadmodel->brush.data_leafbrushes + n; + out->numleafbrushes = c; + } +} + +static void Mod_Q3BSP_LoadNodes(lump_t *l) +{ + q3dnode_t *in; + mnode_t *out; + int i, j, n, count; + + in = (q3dnode_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + if (count == 0) + Host_Error("Mod_Q3BSP_LoadNodes: missing BSP tree in %s",loadmodel->name); + out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + + loadmodel->brush.data_nodes = out; + loadmodel->brush.num_nodes = count; + + for (i = 0;i < count;i++, in++, out++) + { + out->parent = NULL; + n = LittleLong(in->planeindex); + if (n < 0 || n >= loadmodel->brush.num_planes) + Host_Error("Mod_Q3BSP_LoadNodes: invalid planeindex %i (%i planes)", n, loadmodel->brush.num_planes); + out->plane = loadmodel->brush.data_planes + n; + for (j = 0;j < 2;j++) + { + n = LittleLong(in->childrenindex[j]); + if (n >= 0) + { + if (n >= loadmodel->brush.num_nodes) + Host_Error("Mod_Q3BSP_LoadNodes: invalid child node index %i (%i nodes)", n, loadmodel->brush.num_nodes); + out->children[j] = loadmodel->brush.data_nodes + n; + } + else + { + n = -1 - n; + if (n >= loadmodel->brush.num_leafs) + Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)", n, loadmodel->brush.num_leafs); + out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + n); + } + } + for (j = 0;j < 3;j++) + { + // yes the mins/maxs are ints + out->mins[j] = LittleLong(in->mins[j]) - 1; + out->maxs[j] = LittleLong(in->maxs[j]) + 1; + } + } + + // set the parent pointers + Mod_Q1BSP_LoadNodes_RecursiveSetParent(loadmodel->brush.data_nodes, NULL); +} + +static void Mod_Q3BSP_LoadLightGrid(lump_t *l) +{ + q3dlightgrid_t *in; + q3dlightgrid_t *out; + int count; + int i; + + in = (q3dlightgrid_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name); + loadmodel->brushq3.num_lightgrid_scale[0] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[0]; + loadmodel->brushq3.num_lightgrid_scale[1] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[1]; + loadmodel->brushq3.num_lightgrid_scale[2] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[2]; + loadmodel->brushq3.num_lightgrid_imins[0] = (int)ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]); + loadmodel->brushq3.num_lightgrid_imins[1] = (int)ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]); + loadmodel->brushq3.num_lightgrid_imins[2] = (int)ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]); + loadmodel->brushq3.num_lightgrid_imaxs[0] = (int)floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]); + loadmodel->brushq3.num_lightgrid_imaxs[1] = (int)floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]); + loadmodel->brushq3.num_lightgrid_imaxs[2] = (int)floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]); + loadmodel->brushq3.num_lightgrid_isize[0] = loadmodel->brushq3.num_lightgrid_imaxs[0] - loadmodel->brushq3.num_lightgrid_imins[0] + 1; + loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1; + loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1; + count = loadmodel->brushq3.num_lightgrid_isize[0] * loadmodel->brushq3.num_lightgrid_isize[1] * loadmodel->brushq3.num_lightgrid_isize[2]; + Matrix4x4_CreateScale3(&loadmodel->brushq3.num_lightgrid_indexfromworld, loadmodel->brushq3.num_lightgrid_scale[0], loadmodel->brushq3.num_lightgrid_scale[1], loadmodel->brushq3.num_lightgrid_scale[2]); + Matrix4x4_ConcatTranslate(&loadmodel->brushq3.num_lightgrid_indexfromworld, -loadmodel->brushq3.num_lightgrid_imins[0] * loadmodel->brushq3.num_lightgrid_cellsize[0], -loadmodel->brushq3.num_lightgrid_imins[1] * loadmodel->brushq3.num_lightgrid_cellsize[1], -loadmodel->brushq3.num_lightgrid_imins[2] * loadmodel->brushq3.num_lightgrid_cellsize[2]); + + // if lump is empty there is nothing to load, we can deal with that in the LightPoint code + if (l->filelen) + { + if (l->filelen < count * (int)sizeof(*in)) + { + Con_Printf("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, (int)(count * sizeof(*in)), loadmodel->brushq3.num_lightgrid_isize[0], loadmodel->brushq3.num_lightgrid_isize[1], loadmodel->brushq3.num_lightgrid_isize[2]); + return; // ignore the grid if we cannot understand it + } + if (l->filelen != count * (int)sizeof(*in)) + Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", (int)(count * sizeof(*in)), l->filelen); + out = (q3dlightgrid_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); + loadmodel->brushq3.data_lightgrid = out; + loadmodel->brushq3.num_lightgrid = count; + // no swapping or validation necessary + memcpy(out, in, count * (int)sizeof(*out)); + + if(mod_q3bsp_sRGBlightmaps.integer) + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + // we fix the brightness consistently via lightmapscale + } + else + { + for(i = 0; i < count; ++i) + { + out[i].ambientrgb[0] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[0]) * 255.0f + 0.5f); + out[i].ambientrgb[1] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[1]) * 255.0f + 0.5f); + out[i].ambientrgb[2] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[2]) * 255.0f + 0.5f); + out[i].diffusergb[0] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[0]) * 255.0f + 0.5f); + out[i].diffusergb[1] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[1]) * 255.0f + 0.5f); + out[i].diffusergb[2] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[2]) * 255.0f + 0.5f); + } + } + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + for(i = 0; i < count; ++i) + { + out[i].ambientrgb[0] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[0]) * 255.0f + 0.5f); + out[i].ambientrgb[1] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[1]) * 255.0f + 0.5f); + out[i].ambientrgb[2] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[2]) * 255.0f + 0.5f); + out[i].diffusergb[0] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[0]) * 255.0f + 0.5f); + out[i].diffusergb[1] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[1]) * 255.0f + 0.5f); + out[i].diffusergb[2] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[2]) * 255.0f + 0.5f); + } + } + else + { + // all is good + } + } + } +} + +static void Mod_Q3BSP_LoadPVS(lump_t *l) +{ + q3dpvs_t *in; + int totalchains; + + if (l->filelen == 0) + { + int i; + // unvised maps often have cluster indices even without pvs, so check + // leafs to find real number of clusters + loadmodel->brush.num_pvsclusters = 1; + for (i = 0;i < loadmodel->brush.num_leafs;i++) + loadmodel->brush.num_pvsclusters = max(loadmodel->brush.num_pvsclusters, loadmodel->brush.data_leafs[i].clusterindex + 1); + + // create clusters + loadmodel->brush.num_pvsclusterbytes = (loadmodel->brush.num_pvsclusters + 7) / 8; + totalchains = loadmodel->brush.num_pvsclusterbytes * loadmodel->brush.num_pvsclusters; + loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, totalchains); + memset(loadmodel->brush.data_pvsclusters, 0xFF, totalchains); + return; + } + + in = (q3dpvs_t *)(mod_base + l->fileofs); + if (l->filelen < 9) + Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name); + + loadmodel->brush.num_pvsclusters = LittleLong(in->numclusters); + loadmodel->brush.num_pvsclusterbytes = LittleLong(in->chainlength); + if (loadmodel->brush.num_pvsclusterbytes < ((loadmodel->brush.num_pvsclusters + 7) / 8)) + Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8", loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.num_pvsclusters); + totalchains = loadmodel->brush.num_pvsclusterbytes * loadmodel->brush.num_pvsclusters; + if (l->filelen < totalchains + (int)sizeof(*in)) + Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)", loadmodel->brush.num_pvsclusters, loadmodel->brush.num_pvsclusterbytes, (int)(totalchains + sizeof(*in)), l->filelen); + + loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, totalchains); + memcpy(loadmodel->brush.data_pvsclusters, (unsigned char *)(in + 1), totalchains); +} + +static void Mod_Q3BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal) +{ + int i, j, k, index[3]; + float transformed[3], blend1, blend2, blend, stylescale = 1; + q3dlightgrid_t *a, *s; + + // scale lighting by lightstyle[0] so that darkmode in dpmod works properly + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + // LordHavoc: FIXME: is this true? + stylescale = 1; // added while render + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + stylescale = r_refdef.scene.rtlightstylevalue[0]; + break; + } + + if (!model->brushq3.num_lightgrid) + { + ambientcolor[0] = stylescale; + ambientcolor[1] = stylescale; + ambientcolor[2] = stylescale; + return; + } + + Matrix4x4_Transform(&model->brushq3.num_lightgrid_indexfromworld, p, transformed); + //Matrix4x4_Print(&model->brushq3.num_lightgrid_indexfromworld); + //Con_Printf("%f %f %f transformed %f %f %f clamped ", p[0], p[1], p[2], transformed[0], transformed[1], transformed[2]); + transformed[0] = bound(0, transformed[0], model->brushq3.num_lightgrid_isize[0] - 1); + transformed[1] = bound(0, transformed[1], model->brushq3.num_lightgrid_isize[1] - 1); + transformed[2] = bound(0, transformed[2], model->brushq3.num_lightgrid_isize[2] - 1); + index[0] = (int)floor(transformed[0]); + index[1] = (int)floor(transformed[1]); + index[2] = (int)floor(transformed[2]); + //Con_Printf("%f %f %f index %i %i %i:\n", transformed[0], transformed[1], transformed[2], index[0], index[1], index[2]); + + // now lerp the values + VectorClear(diffusenormal); + a = &model->brushq3.data_lightgrid[(index[2] * model->brushq3.num_lightgrid_isize[1] + index[1]) * model->brushq3.num_lightgrid_isize[0] + index[0]]; + for (k = 0;k < 2;k++) + { + blend1 = (k ? (transformed[2] - index[2]) : (1 - (transformed[2] - index[2]))); + if (blend1 < 0.001f || index[2] + k >= model->brushq3.num_lightgrid_isize[2]) + continue; + for (j = 0;j < 2;j++) + { + blend2 = blend1 * (j ? (transformed[1] - index[1]) : (1 - (transformed[1] - index[1]))); + if (blend2 < 0.001f || index[1] + j >= model->brushq3.num_lightgrid_isize[1]) + continue; + for (i = 0;i < 2;i++) + { + blend = blend2 * (i ? (transformed[0] - index[0]) : (1 - (transformed[0] - index[0]))) * stylescale; + if (blend < 0.001f || index[0] + i >= model->brushq3.num_lightgrid_isize[0]) + continue; + s = a + (k * model->brushq3.num_lightgrid_isize[1] + j) * model->brushq3.num_lightgrid_isize[0] + i; + VectorMA(ambientcolor, blend * (1.0f / 128.0f), s->ambientrgb, ambientcolor); + VectorMA(diffusecolor, blend * (1.0f / 128.0f), s->diffusergb, diffusecolor); + // this uses the mod_md3_sin table because the values are + // already in the 0-255 range, the 64+ bias fetches a cosine + // instead of a sine value + diffusenormal[0] += blend * (mod_md3_sin[64 + s->diffuseyaw] * mod_md3_sin[s->diffusepitch]); + diffusenormal[1] += blend * (mod_md3_sin[ s->diffuseyaw] * mod_md3_sin[s->diffusepitch]); + diffusenormal[2] += blend * (mod_md3_sin[64 + s->diffusepitch]); + //Con_Printf("blend %f: ambient %i %i %i, diffuse %i %i %i, diffusepitch %i diffuseyaw %i (%f %f, normal %f %f %f)\n", blend, s->ambientrgb[0], s->ambientrgb[1], s->ambientrgb[2], s->diffusergb[0], s->diffusergb[1], s->diffusergb[2], s->diffusepitch, s->diffuseyaw, pitch, yaw, (cos(yaw) * cospitch), (sin(yaw) * cospitch), (-sin(pitch))); + } + } + } + + // normalize the light direction before turning + VectorNormalize(diffusenormal); + //Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]); +} + +static int Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3]) +{ + double t1, t2; + double midf, mid[3]; + int ret, side; + + // check for empty + while (node->plane) + { + // find the point distances + mplane_t *plane = node->plane; + 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 (t1 < 0) + { + if (t2 < 0) + { + node = node->children[1]; + continue; + } + side = 1; + } + else + { + if (t2 >= 0) + { + node = node->children[0]; + continue; + } + side = 0; + } + + midf = t1 / (t1 - t2); + VectorLerp(p1, midf, p2, mid); + + // recurse both sides, front side first + // return 2 if empty is followed by solid (hit something) + // do not return 2 if both are solid or both empty, + // or if start is solid and end is empty + // as these degenerate cases usually indicate the eye is in solid and + // should see the target point anyway + ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid); + if (ret != 0) + return ret; + ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2); + if (ret != 1) + return ret; + return 2; + } + return ((mleaf_t *)node)->clusterindex < 0; +} + +static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end) +{ + if (model->brush.submodel || mod_q3bsp_tracelineofsight_brushes.integer) + { + trace_t trace; + model->TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK); + return trace.fraction == 1; + } + else + { + double tracestart[3], traceend[3]; + VectorCopy(start, tracestart); + VectorCopy(end, traceend); + return !Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend); + } +} + +void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask) +{ + const bih_t *bih; + const bih_leaf_t *leaf; + const bih_node_t *node; + const colbrushf_t *brush; + int axis; + int nodenum; + int nodestackpos = 0; + int nodestack[1024]; + + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + + bih = &model->collision_bih; + if(!bih->nodes) + return; + + nodenum = bih->rootnode; + nodestack[nodestackpos++] = nodenum; + while (nodestackpos) + { + nodenum = nodestack[--nodestackpos]; + node = bih->nodes + nodenum; +#if 1 + if (!BoxesOverlap(start, start, node->mins, node->maxs)) + continue; +#endif + if (node->type <= BIH_SPLITZ && nodestackpos+2 <= 1024) + { + axis = node->type - BIH_SPLITX; + if (start[axis] >= node->frontmin) + nodestack[nodestackpos++] = node->front; + if (start[axis] <= node->backmax) + nodestack[nodestackpos++] = node->back; + } + else if (node->type == BIH_UNORDERED) + { + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = bih->leafs + node->children[axis]; +#if 1 + if (!BoxesOverlap(start, start, leaf->mins, leaf->maxs)) + continue; +#endif + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TracePointBrushFloat(trace, start, brush); + break; + case BIH_COLLISIONTRIANGLE: + // collision triangle - skipped because they have no volume + break; + case BIH_RENDERTRIANGLE: + // render triangle - skipped because they have no volume + break; + } + } + } + } +} + +static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, const bih_t *bih) +{ + const bih_leaf_t *leaf; + const bih_node_t *node; + const colbrushf_t *brush; + const int *e; + const texture_t *texture; + vec3_t nodebigmins, nodebigmaxs, nodestart, nodeend, sweepnodemins, sweepnodemaxs; + vec_t d1, d2, d3, d4, f, nodestackline[1024][6]; + int axis, nodenum, nodestackpos = 0, nodestack[1024]; + + if(!bih->nodes) + return; + + if (VectorCompare(start, end)) + { + Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + return; + } + + nodenum = bih->rootnode; + + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + + // push first node + nodestackline[nodestackpos][0] = start[0]; + nodestackline[nodestackpos][1] = start[1]; + nodestackline[nodestackpos][2] = start[2]; + nodestackline[nodestackpos][3] = end[0]; + nodestackline[nodestackpos][4] = end[1]; + nodestackline[nodestackpos][5] = end[2]; + nodestack[nodestackpos++] = nodenum; + while (nodestackpos) + { + nodenum = nodestack[--nodestackpos]; + node = bih->nodes + nodenum; + VectorCopy(nodestackline[nodestackpos], nodestart); + VectorCopy(nodestackline[nodestackpos] + 3, nodeend); + sweepnodemins[0] = min(nodestart[0], nodeend[0]); sweepnodemins[1] = min(nodestart[1], nodeend[1]); sweepnodemins[2] = min(nodestart[2], nodeend[2]); sweepnodemaxs[0] = max(nodestart[0], nodeend[0]); sweepnodemaxs[1] = max(nodestart[1], nodeend[1]); sweepnodemaxs[2] = max(nodestart[2], nodeend[2]); + if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, node->mins, node->maxs)) + continue; + if (node->type <= BIH_SPLITZ && nodestackpos+2 <= 1024) + { + // recurse children of the split + axis = node->type - BIH_SPLITX; + d1 = node->backmax - nodestart[axis]; + d2 = node->backmax - nodeend[axis]; + d3 = nodestart[axis] - node->frontmin; + d4 = nodeend[axis] - node->frontmin; + switch((d1 < 0) | ((d2 < 0) << 1) | ((d3 < 0) << 2) | ((d4 < 0) << 3)) + { + case 0: /* >>>> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 1: /* <>>> */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 2: /* ><>> */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 3: /* <<>> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 4: /* >><> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 5: /* <><> */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 6: /* ><<> */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 7: /* <<<> */ f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 8: /* >>>< */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 9: /* <>>< */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 10: /* ><>< */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 11: /* <<>< */ f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 12: /* >><< */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 13: /* <><< */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 14: /* ><<< */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 15: /* <<<< */ break; + } + } + else if (node->type == BIH_UNORDERED) + { + // calculate sweep bounds for this node + // copy node bounds into local variables + VectorCopy(node->mins, nodebigmins); + VectorCopy(node->maxs, nodebigmaxs); + // clip line to this node bounds + axis = 0; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + axis = 1; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + axis = 2; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + // some of the line intersected the enlarged node box + // calculate sweep bounds for this node + sweepnodemins[0] = min(nodestart[0], nodeend[0]); sweepnodemins[1] = min(nodestart[1], nodeend[1]); sweepnodemins[2] = min(nodestart[2], nodeend[2]); sweepnodemaxs[0] = max(nodestart[0], nodeend[0]); sweepnodemaxs[1] = max(nodestart[1], nodeend[1]); sweepnodemaxs[2] = max(nodestart[2], nodeend[2]); + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = bih->leafs + node->children[axis]; + if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, leaf->mins, leaf->maxs)) + continue; + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TraceLineBrushFloat(trace, start, end, brush, brush); + break; + case BIH_COLLISIONTRIANGLE: + if (!mod_q3bsp_curves_collisions.integer) + continue; + e = model->brush.data_collisionelement3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceLineTriangleFloat(trace, start, end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + case BIH_RENDERTRIANGLE: + e = model->surfmesh.data_element3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceLineTriangleFloat(trace, start, end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + } + } + } + } +} + +void Mod_CollisionBIH_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + if (VectorCompare(start, end)) + { + Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + return; + } + Mod_CollisionBIH_TraceLineShared(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, &model->collision_bih); +} + +void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *thisbrush_start, colbrushf_t *thisbrush_end, int hitsupercontentsmask) +{ + const bih_t *bih; + const bih_leaf_t *leaf; + const bih_node_t *node; + const colbrushf_t *brush; + const int *e; + const texture_t *texture; + vec3_t start, end, startmins, startmaxs, endmins, endmaxs, mins, maxs; + vec3_t nodebigmins, nodebigmaxs, nodestart, nodeend, sweepnodemins, sweepnodemaxs; + vec_t d1, d2, d3, d4, f, nodestackline[1024][6]; + int axis, nodenum, nodestackpos = 0, nodestack[1024]; + + if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(thisbrush_start->mins, thisbrush_start->maxs) && VectorCompare(thisbrush_end->mins, thisbrush_end->maxs)) + { + if (VectorCompare(thisbrush_start->mins, thisbrush_end->mins)) + Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, thisbrush_start->mins, hitsupercontentsmask); + else + Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, thisbrush_start->mins, thisbrush_end->mins, hitsupercontentsmask); + return; + } + + bih = &model->collision_bih; + if(!bih->nodes) + return; + nodenum = bih->rootnode; + + // box trace, performed as brush trace + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + + // calculate tracebox-like parameters for efficient culling + VectorMAM(0.5f, thisbrush_start->mins, 0.5f, thisbrush_start->maxs, start); + VectorMAM(0.5f, thisbrush_end->mins, 0.5f, thisbrush_end->maxs, end); + VectorSubtract(thisbrush_start->mins, start, startmins); + VectorSubtract(thisbrush_start->maxs, start, startmaxs); + VectorSubtract(thisbrush_end->mins, end, endmins); + VectorSubtract(thisbrush_end->maxs, end, endmaxs); + mins[0] = min(startmins[0], endmins[0]); + mins[1] = min(startmins[1], endmins[1]); + mins[2] = min(startmins[2], endmins[2]); + maxs[0] = max(startmaxs[0], endmaxs[0]); + maxs[1] = max(startmaxs[1], endmaxs[1]); + maxs[2] = max(startmaxs[2], endmaxs[2]); + + // push first node + nodestackline[nodestackpos][0] = start[0]; + nodestackline[nodestackpos][1] = start[1]; + nodestackline[nodestackpos][2] = start[2]; + nodestackline[nodestackpos][3] = end[0]; + nodestackline[nodestackpos][4] = end[1]; + nodestackline[nodestackpos][5] = end[2]; + nodestack[nodestackpos++] = nodenum; + while (nodestackpos) + { + nodenum = nodestack[--nodestackpos]; + node = bih->nodes + nodenum; + VectorCopy(nodestackline[nodestackpos], nodestart); + VectorCopy(nodestackline[nodestackpos] + 3, nodeend); + sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0]; sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1]; sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2]; sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0]; sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1]; sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2]; + if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, node->mins, node->maxs)) + continue; + if (node->type <= BIH_SPLITZ && nodestackpos+2 <= 1024) + { + // recurse children of the split + axis = node->type - BIH_SPLITX; + d1 = node->backmax - nodestart[axis] - mins[axis]; + d2 = node->backmax - nodeend[axis] - mins[axis]; + d3 = nodestart[axis] - node->frontmin + maxs[axis]; + d4 = nodeend[axis] - node->frontmin + maxs[axis]; + switch((d1 < 0) | ((d2 < 0) << 1) | ((d3 < 0) << 2) | ((d4 < 0) << 3)) + { + case 0: /* >>>> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 1: /* <>>> */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 2: /* ><>> */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 3: /* <<>> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 4: /* >><> */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 5: /* <><> */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 6: /* ><<> */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 7: /* <<<> */ f = d3 / (d3 - d4); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 8: /* >>>< */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 9: /* <>>< */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 10: /* ><>< */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 11: /* <<>< */ f = d3 / (d3 - d4); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->front; break; + case 12: /* >><< */ VectorCopy(nodestart, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 13: /* <><< */ f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos]); VectorCopy( nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 14: /* ><<< */ f = d1 / (d1 - d2); VectorCopy(nodestart, nodestackline[nodestackpos]); VectorLerp(nodestart, f, nodeend, nodestackline[nodestackpos] + 3); nodestack[nodestackpos++] = node->back; break; + case 15: /* <<<< */ break; + } + } + else if (node->type == BIH_UNORDERED) + { + // calculate sweep bounds for this node + // copy node bounds into local variables and expand to get Minkowski Sum of the two shapes + VectorSubtract(node->mins, maxs, nodebigmins); + VectorSubtract(node->maxs, mins, nodebigmaxs); + // clip line to this node bounds + axis = 0; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + axis = 1; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + axis = 2; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } + // some of the line intersected the enlarged node box + // calculate sweep bounds for this node + sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0]; sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1]; sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2]; sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0]; sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1]; sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2]; + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = bih->leafs + node->children[axis]; + if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, leaf->mins, leaf->maxs)) + continue; + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush); + break; + case BIH_COLLISIONTRIANGLE: + if (!mod_q3bsp_curves_collisions.integer) + continue; + e = model->brush.data_collisionelement3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + case BIH_RENDERTRIANGLE: + e = model->surfmesh.data_element3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + } + } + } + } +} + +void Mod_CollisionBIH_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) +{ + colboxbrushf_t thisbrush_start, thisbrush_end; + vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; + + // box trace, performed as brush trace + VectorAdd(start, boxmins, boxstartmins); + VectorAdd(start, boxmaxs, boxstartmaxs); + VectorAdd(end, boxmins, boxendmins); + VectorAdd(end, boxmaxs, boxendmaxs); + Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL); + Mod_CollisionBIH_TraceBrush(model, frameblend, skeleton, trace, &thisbrush_start.brush, &thisbrush_end.brush, hitsupercontentsmask); +} + + +static int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point) +{ + trace_t trace; + Mod_CollisionBIH_TracePoint(model, NULL, NULL, &trace, point, 0); + return trace.startsupercontents; +} + +void Mod_CollisionBIH_TracePoint_Mesh(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask) +{ +#if 0 + // broken - needs to be modified to count front faces and backfaces to figure out if it is in solid + vec3_t end; + int hitsupercontents; + VectorSet(end, start[0], start[1], model->normalmins[2]); +#endif + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; +#if 0 + Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + hitsupercontents = trace->hitsupercontents; + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + trace->startsupercontents = hitsupercontents; +#endif +} + +int Mod_CollisionBIH_PointSuperContents_Mesh(struct model_s *model, int frame, const vec3_t start) +{ +#if 0 + // broken - needs to be modified to count front faces and backfaces to figure out if it is in solid + trace_t trace; + vec3_t end; + VectorSet(end, start[0], start[1], model->normalmins[2]); + memset(&trace, 0, sizeof(trace)); + trace.fraction = 1; + trace.realfraction = 1; + trace.hitsupercontentsmask = 0; + Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + return trace.hitsupercontents; +#else + return 0; +#endif +} + +static void Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace_t *trace, dp_model_t *model, mnode_t *node, const vec3_t point, int markframe) +{ + int i; + mleaf_t *leaf; + colbrushf_t *brush; + // find which leaf the point is in + while (node->plane) + node = node->children[(node->plane->type < 3 ? point[node->plane->type] : DotProduct(point, node->plane->normal)) < node->plane->dist]; + // point trace the brushes + leaf = (mleaf_t *)node; + for (i = 0;i < leaf->numleafbrushes;i++) + { + brush = model->brush.data_brushes[leaf->firstleafbrush[i]].colbrushf; + if (brush && brush->markframe != markframe && BoxesOverlap(point, point, brush->mins, brush->maxs)) + { + brush->markframe = markframe; + Collision_TracePointBrushFloat(trace, point, brush); + } + } + // can't do point traces on curves (they have no thickness) +} + +static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, dp_model_t *model, mnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs) +{ + int i, startside, endside; + float dist1, dist2, midfrac, mid[3], nodesegmentmins[3], nodesegmentmaxs[3]; + mleaf_t *leaf; + msurface_t *surface; + mplane_t *plane; + colbrushf_t *brush; + // walk the tree until we hit a leaf, recursing for any split cases + while (node->plane) + { +#if 0 + if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs)) + return; + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[0], start, end, startfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); + node = node->children[1]; +#else + // abort if this part of the bsp tree can not be hit by this trace +// if (!(node->combinedsupercontents & trace->hitsupercontentsmask)) +// return; + plane = node->plane; + // axial planes are much more common than non-axial, so an optimized + // axial case pays off here + if (plane->type < 3) + { + dist1 = start[plane->type] - plane->dist; + dist2 = end[plane->type] - plane->dist; + } + else + { + dist1 = DotProduct(start, plane->normal) - plane->dist; + dist2 = DotProduct(end, plane->normal) - plane->dist; + } + startside = dist1 < 0; + endside = dist2 < 0; + if (startside == endside) + { + // most of the time the line fragment is on one side of the plane + node = node->children[startside]; + } + else + { + // line crosses node plane, split the line + dist1 = PlaneDiff(linestart, plane); + dist2 = PlaneDiff(lineend, plane); + midfrac = dist1 / (dist1 - dist2); + VectorLerp(linestart, midfrac, lineend, mid); + // take the near side first + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); + // if we found an impact on the front side, don't waste time + // exploring the far side + if (midfrac <= trace->realfraction) + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); + return; + } +#endif + } + // abort if this part of the bsp tree can not be hit by this trace +// if (!(node->combinedsupercontents & trace->hitsupercontentsmask)) +// return; + // hit a leaf + nodesegmentmins[0] = min(start[0], end[0]) - 1; + nodesegmentmins[1] = min(start[1], end[1]) - 1; + nodesegmentmins[2] = min(start[2], end[2]) - 1; + nodesegmentmaxs[0] = max(start[0], end[0]) + 1; + nodesegmentmaxs[1] = max(start[1], end[1]) + 1; + nodesegmentmaxs[2] = max(start[2], end[2]) + 1; + // line trace the brushes + leaf = (mleaf_t *)node; +#if 0 + if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) + return; +#endif + for (i = 0;i < leaf->numleafbrushes;i++) + { + brush = model->brush.data_brushes[leaf->firstleafbrush[i]].colbrushf; + if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs)) + { + brush->markframe = markframe; + Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush); + } + } + // can't do point traces on curves (they have no thickness) + if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end)) + { + // line trace the curves + for (i = 0;i < leaf->numleafsurfaces;i++) + { + surface = model->data_surfaces + leaf->firstleafsurface[i]; + if (surface->num_collisiontriangles && surface->deprecatedq3collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs)) + { + surface->deprecatedq3collisionmarkframe = markframe; + Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->deprecatedq3data_collisionelement3i, surface->deprecatedq3data_collisionvertex3f, surface->deprecatedq3num_collisionbboxstride, surface->deprecatedq3data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs); + } + } + } +} + +static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, dp_model_t *model, mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs) +{ + int i; + int sides; + mleaf_t *leaf; + colbrushf_t *brush; + msurface_t *surface; + mplane_t *plane; + float nodesegmentmins[3], nodesegmentmaxs[3]; + // walk the tree until we hit a leaf, recursing for any split cases + while (node->plane) + { +#if 0 + if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs)) + return; + Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); + node = node->children[1]; +#else + // abort if this part of the bsp tree can not be hit by this trace +// if (!(node->combinedsupercontents & trace->hitsupercontentsmask)) +// return; + plane = node->plane; + // axial planes are much more common than non-axial, so an optimized + // axial case pays off here + if (plane->type < 3) + { + // this is an axial plane, compare bounding box directly to it and + // recurse sides accordingly + // recurse down node sides + // use an inlined axial BoxOnPlaneSide to slightly reduce overhead + //sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, plane); + //sides = ((segmentmaxs[plane->type] >= plane->dist) | ((segmentmins[plane->type] < plane->dist) << 1)); + sides = ((segmentmaxs[plane->type] >= plane->dist) + ((segmentmins[plane->type] < plane->dist) * 2)); + } + else + { + // this is a non-axial plane, so check if the start and end boxes + // are both on one side of the plane to handle 'diagonal' cases + sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, plane); + } + if (sides == 3) + { + // segment crosses plane + Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); + sides = 2; + } + // if sides == 0 then the trace itself is bogus (Not A Number values), + // in this case we simply pretend the trace hit nothing + if (sides == 0) + return; // ERROR: NAN bounding box! + // take whichever side the segment box is on + node = node->children[sides - 1]; +#endif + } + // abort if this part of the bsp tree can not be hit by this trace +// if (!(node->combinedsupercontents & trace->hitsupercontentsmask)) +// return; + nodesegmentmins[0] = max(segmentmins[0], node->mins[0] - 1); + nodesegmentmins[1] = max(segmentmins[1], node->mins[1] - 1); + nodesegmentmins[2] = max(segmentmins[2], node->mins[2] - 1); + nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0] + 1); + nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1] + 1); + nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2] + 1); + // hit a leaf + leaf = (mleaf_t *)node; +#if 0 + if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) + return; +#endif + for (i = 0;i < leaf->numleafbrushes;i++) + { + brush = model->brush.data_brushes[leaf->firstleafbrush[i]].colbrushf; + if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs)) + { + brush->markframe = markframe; + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush); + } + } + if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer) + { + for (i = 0;i < leaf->numleafsurfaces;i++) + { + surface = model->data_surfaces + leaf->firstleafsurface[i]; + if (surface->num_collisiontriangles && surface->deprecatedq3collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs)) + { + surface->deprecatedq3collisionmarkframe = markframe; + Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->deprecatedq3data_collisionelement3i, surface->deprecatedq3data_collisionvertex3f, surface->deprecatedq3num_collisionbboxstride, surface->deprecatedq3data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs); + } + } + } +} + + +static int markframe = 0; + +static void Mod_Q3BSP_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask) +{ + int i; + q3mbrush_t *brush; + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + if (mod_collision_bih.integer) + Mod_CollisionBIH_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + else if (model->brush.submodel) + { + for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) + if (brush->colbrushf) + Collision_TracePointBrushFloat(trace, start, brush->colbrushf); + } + else + Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, ++markframe); +} + +static void Mod_Q3BSP_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + int i; + float segmentmins[3], segmentmaxs[3]; + msurface_t *surface; + q3mbrush_t *brush; + + if (VectorCompare(start, end)) + { + Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask); + return; + } + + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + segmentmins[0] = min(start[0], end[0]) - 1; + segmentmins[1] = min(start[1], end[1]) - 1; + segmentmins[2] = min(start[2], end[2]) - 1; + segmentmaxs[0] = max(start[0], end[0]) + 1; + segmentmaxs[1] = max(start[1], end[1]) + 1; + segmentmaxs[2] = max(start[2], end[2]) + 1; + if (mod_collision_bih.integer) + Mod_CollisionBIH_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + else if (model->brush.submodel) + { + for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) + if (brush->colbrushf && BoxesOverlap(segmentmins, segmentmaxs, brush->colbrushf->mins, brush->colbrushf->maxs)) + Collision_TraceLineBrushFloat(trace, start, end, brush->colbrushf, brush->colbrushf); + if (mod_q3bsp_curves_collisions.integer) + for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++) + if (surface->num_collisiontriangles && BoxesOverlap(segmentmins, segmentmaxs, surface->mins, surface->maxs)) + Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->deprecatedq3data_collisionelement3i, surface->deprecatedq3data_collisionvertex3f, surface->deprecatedq3num_collisionbboxstride, surface->deprecatedq3data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs); + } + else + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs); +} + +static void Mod_Q3BSP_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *start, colbrushf_t *end, int hitsupercontentsmask) +{ + float segmentmins[3], segmentmaxs[3]; + int i; + msurface_t *surface; + q3mbrush_t *brush; + + if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(start->mins, start->maxs) && VectorCompare(end->mins, end->maxs)) + { + if (VectorCompare(start->mins, end->mins)) + Mod_Q3BSP_TracePoint(model, frameblend, skeleton, trace, start->mins, hitsupercontentsmask); + else + Mod_Q3BSP_TraceLine(model, frameblend, skeleton, trace, start->mins, end->mins, hitsupercontentsmask); + return; + } + + // box trace, performed as brush trace + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + segmentmins[0] = min(start->mins[0], end->mins[0]); + segmentmins[1] = min(start->mins[1], end->mins[1]); + segmentmins[2] = min(start->mins[2], end->mins[2]); + segmentmaxs[0] = max(start->maxs[0], end->maxs[0]); + segmentmaxs[1] = max(start->maxs[1], end->maxs[1]); + segmentmaxs[2] = max(start->maxs[2], end->maxs[2]); + if (mod_collision_bih.integer) + Mod_CollisionBIH_TraceBrush(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask); + else if (model->brush.submodel) + { + for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) + if (brush->colbrushf && BoxesOverlap(segmentmins, segmentmaxs, brush->colbrushf->mins, brush->colbrushf->maxs)) + Collision_TraceBrushBrushFloat(trace, start, end, brush->colbrushf, brush->colbrushf); + if (mod_q3bsp_curves_collisions.integer) + for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++) + if (surface->num_collisiontriangles && BoxesOverlap(segmentmins, segmentmaxs, surface->mins, surface->maxs)) + Collision_TraceBrushTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->deprecatedq3data_collisionelement3i, surface->deprecatedq3data_collisionvertex3f, surface->deprecatedq3num_collisionbboxstride, surface->deprecatedq3data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs); + } + else + Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, ++markframe, segmentmins, segmentmaxs); +} + +static void Mod_Q3BSP_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) +{ + colboxbrushf_t thisbrush_start, thisbrush_end; + vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; + + // box trace, performed as brush trace + VectorAdd(start, boxmins, boxstartmins); + VectorAdd(start, boxmaxs, boxstartmaxs); + VectorAdd(end, boxmins, boxendmins); + VectorAdd(end, boxmaxs, boxendmaxs); + Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL); + Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL); + Mod_Q3BSP_TraceBrush(model, frameblend, skeleton, trace, &thisbrush_start.brush, &thisbrush_end.brush, hitsupercontentsmask); +} + +static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const vec3_t point) +{ + int i; + int supercontents = 0; + q3mbrush_t *brush; + if (mod_collision_bih.integer) + { + supercontents = Mod_CollisionBIH_PointSuperContents(model, frame, point); + } + // test if the point is inside each brush + else if (model->brush.submodel) + { + // submodels are effectively one leaf + for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) + if (brush->colbrushf && Collision_PointInsideBrushFloat(point, brush->colbrushf)) + supercontents |= brush->colbrushf->supercontents; + } + else + { + mnode_t *node = model->brush.data_nodes; + mleaf_t *leaf; + // find which leaf the point is in + while (node->plane) + node = node->children[(node->plane->type < 3 ? point[node->plane->type] : DotProduct(point, node->plane->normal)) < node->plane->dist]; + leaf = (mleaf_t *)node; + // now check the brushes in the leaf + for (i = 0;i < leaf->numleafbrushes;i++) + { + brush = model->brush.data_brushes + leaf->firstleafbrush[i]; + if (brush->colbrushf && Collision_PointInsideBrushFloat(point, brush->colbrushf)) + supercontents |= brush->colbrushf->supercontents; + } + } + return supercontents; +} + +void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + Mod_CollisionBIH_TraceLineShared(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, &model->render_bih); +} + + +bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t *out) +{ + int j; + int bihnumleafs; + int bihmaxnodes; + int brushindex; + int triangleindex; + int bihleafindex; + int nummodelbrushes = model->nummodelbrushes; + int nummodelsurfaces = model->nummodelsurfaces; + const int *e; + const int *collisionelement3i; + const float *collisionvertex3f; + const int *renderelement3i; + const float *rendervertex3f; + bih_leaf_t *bihleafs; + bih_node_t *bihnodes; + int *temp_leafsort; + int *temp_leafsortscratch; + const msurface_t *surface; + const q3mbrush_t *brush; + + // find out how many BIH leaf nodes we need + bihnumleafs = 0; + if (userendersurfaces) + { + for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++) + bihnumleafs += surface->num_triangles; + } + else + { + for (brushindex = 0, brush = model->brush.data_brushes + brushindex+model->firstmodelbrush;brushindex < nummodelbrushes;brushindex++, brush++) + if (brush->colbrushf) + bihnumleafs++; + for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++) + { + if (surface->texture->basematerialflags & MATERIALFLAG_MESHCOLLISIONS) + bihnumleafs += surface->num_triangles + surface->num_collisiontriangles; + else + bihnumleafs += surface->num_collisiontriangles; + } + } + + if (!bihnumleafs) + return NULL; + + // allocate the memory for the BIH leaf nodes + bihleafs = (bih_leaf_t *)Mem_Alloc(loadmodel->mempool, sizeof(bih_leaf_t) * bihnumleafs); + + // now populate the BIH leaf nodes + bihleafindex = 0; + + // add render surfaces + renderelement3i = model->surfmesh.data_element3i; + rendervertex3f = model->surfmesh.data_vertex3f; + for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++) + { + for (triangleindex = 0, e = renderelement3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3) + { + if (!userendersurfaces && !(surface->texture->basematerialflags & MATERIALFLAG_MESHCOLLISIONS)) + continue; + bihleafs[bihleafindex].type = BIH_RENDERTRIANGLE; + bihleafs[bihleafindex].textureindex = surface->texture - model->data_textures; + bihleafs[bihleafindex].surfaceindex = surface - model->data_surfaces; + bihleafs[bihleafindex].itemindex = triangleindex+surface->num_firsttriangle; + bihleafs[bihleafindex].mins[0] = min(rendervertex3f[3*e[0]+0], min(rendervertex3f[3*e[1]+0], rendervertex3f[3*e[2]+0])) - 1; + bihleafs[bihleafindex].mins[1] = min(rendervertex3f[3*e[0]+1], min(rendervertex3f[3*e[1]+1], rendervertex3f[3*e[2]+1])) - 1; + bihleafs[bihleafindex].mins[2] = min(rendervertex3f[3*e[0]+2], min(rendervertex3f[3*e[1]+2], rendervertex3f[3*e[2]+2])) - 1; + bihleafs[bihleafindex].maxs[0] = max(rendervertex3f[3*e[0]+0], max(rendervertex3f[3*e[1]+0], rendervertex3f[3*e[2]+0])) + 1; + bihleafs[bihleafindex].maxs[1] = max(rendervertex3f[3*e[0]+1], max(rendervertex3f[3*e[1]+1], rendervertex3f[3*e[2]+1])) + 1; + bihleafs[bihleafindex].maxs[2] = max(rendervertex3f[3*e[0]+2], max(rendervertex3f[3*e[1]+2], rendervertex3f[3*e[2]+2])) + 1; + bihleafindex++; + } + } + + if (!userendersurfaces) + { + // add collision brushes + for (brushindex = 0, brush = model->brush.data_brushes + brushindex+model->firstmodelbrush;brushindex < nummodelbrushes;brushindex++, brush++) + { + if (!brush->colbrushf) + continue; + bihleafs[bihleafindex].type = BIH_BRUSH; + bihleafs[bihleafindex].textureindex = brush->texture - model->data_textures; + bihleafs[bihleafindex].surfaceindex = -1; + bihleafs[bihleafindex].itemindex = brushindex+model->firstmodelbrush; + VectorCopy(brush->colbrushf->mins, bihleafs[bihleafindex].mins); + VectorCopy(brush->colbrushf->maxs, bihleafs[bihleafindex].maxs); + bihleafindex++; + } + + // add collision surfaces + collisionelement3i = model->brush.data_collisionelement3i; + collisionvertex3f = model->brush.data_collisionvertex3f; + for (j = 0, surface = model->data_surfaces + model->firstmodelsurface;j < nummodelsurfaces;j++, surface++) + { + for (triangleindex = 0, e = collisionelement3i + 3*surface->num_firstcollisiontriangle;triangleindex < surface->num_collisiontriangles;triangleindex++, e += 3) + { + bihleafs[bihleafindex].type = BIH_COLLISIONTRIANGLE; + bihleafs[bihleafindex].textureindex = surface->texture - model->data_textures; + bihleafs[bihleafindex].surfaceindex = surface - model->data_surfaces; + bihleafs[bihleafindex].itemindex = triangleindex+surface->num_firstcollisiontriangle; + bihleafs[bihleafindex].mins[0] = min(collisionvertex3f[3*e[0]+0], min(collisionvertex3f[3*e[1]+0], collisionvertex3f[3*e[2]+0])) - 1; + bihleafs[bihleafindex].mins[1] = min(collisionvertex3f[3*e[0]+1], min(collisionvertex3f[3*e[1]+1], collisionvertex3f[3*e[2]+1])) - 1; + bihleafs[bihleafindex].mins[2] = min(collisionvertex3f[3*e[0]+2], min(collisionvertex3f[3*e[1]+2], collisionvertex3f[3*e[2]+2])) - 1; + bihleafs[bihleafindex].maxs[0] = max(collisionvertex3f[3*e[0]+0], max(collisionvertex3f[3*e[1]+0], collisionvertex3f[3*e[2]+0])) + 1; + bihleafs[bihleafindex].maxs[1] = max(collisionvertex3f[3*e[0]+1], max(collisionvertex3f[3*e[1]+1], collisionvertex3f[3*e[2]+1])) + 1; + bihleafs[bihleafindex].maxs[2] = max(collisionvertex3f[3*e[0]+2], max(collisionvertex3f[3*e[1]+2], collisionvertex3f[3*e[2]+2])) + 1; + bihleafindex++; + } + } + } + + // allocate buffers for the produced and temporary data + bihmaxnodes = bihnumleafs + 1; + bihnodes = (bih_node_t *)Mem_Alloc(loadmodel->mempool, sizeof(bih_node_t) * bihmaxnodes); + temp_leafsort = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int) * bihnumleafs * 2); + temp_leafsortscratch = temp_leafsort + bihnumleafs; + + // now build it + BIH_Build(out, bihnumleafs, bihleafs, bihmaxnodes, bihnodes, temp_leafsort, temp_leafsortscratch); + + // we're done with the temporary data + Mem_Free(temp_leafsort); + + // resize the BIH nodes array if it over-allocated + if (out->maxnodes > out->numnodes) + { + out->maxnodes = out->numnodes; + out->nodes = (bih_node_t *)Mem_Realloc(loadmodel->mempool, out->nodes, out->numnodes * sizeof(bih_node_t)); + } + + return out; +} + +static int Mod_Q3BSP_SuperContentsFromNativeContents(dp_model_t *model, int nativecontents) +{ + int supercontents = 0; + if (nativecontents & CONTENTSQ3_SOLID) + supercontents |= SUPERCONTENTS_SOLID; + if (nativecontents & CONTENTSQ3_WATER) + supercontents |= SUPERCONTENTS_WATER; + if (nativecontents & CONTENTSQ3_SLIME) + supercontents |= SUPERCONTENTS_SLIME; + if (nativecontents & CONTENTSQ3_LAVA) + supercontents |= SUPERCONTENTS_LAVA; + if (nativecontents & CONTENTSQ3_BODY) + supercontents |= SUPERCONTENTS_BODY; + if (nativecontents & CONTENTSQ3_CORPSE) + supercontents |= SUPERCONTENTS_CORPSE; + if (nativecontents & CONTENTSQ3_NODROP) + supercontents |= SUPERCONTENTS_NODROP; + if (nativecontents & CONTENTSQ3_PLAYERCLIP) + supercontents |= SUPERCONTENTS_PLAYERCLIP; + if (nativecontents & CONTENTSQ3_MONSTERCLIP) + supercontents |= SUPERCONTENTS_MONSTERCLIP; + if (nativecontents & CONTENTSQ3_DONOTENTER) + supercontents |= SUPERCONTENTS_DONOTENTER; + if (nativecontents & CONTENTSQ3_BOTCLIP) + supercontents |= SUPERCONTENTS_BOTCLIP; + if (!(nativecontents & CONTENTSQ3_TRANSLUCENT)) + supercontents |= SUPERCONTENTS_OPAQUE; + return supercontents; +} + +static int Mod_Q3BSP_NativeContentsFromSuperContents(dp_model_t *model, int supercontents) +{ + int nativecontents = 0; + if (supercontents & SUPERCONTENTS_SOLID) + nativecontents |= CONTENTSQ3_SOLID; + if (supercontents & SUPERCONTENTS_WATER) + nativecontents |= CONTENTSQ3_WATER; + if (supercontents & SUPERCONTENTS_SLIME) + nativecontents |= CONTENTSQ3_SLIME; + if (supercontents & SUPERCONTENTS_LAVA) + nativecontents |= CONTENTSQ3_LAVA; + if (supercontents & SUPERCONTENTS_BODY) + nativecontents |= CONTENTSQ3_BODY; + if (supercontents & SUPERCONTENTS_CORPSE) + nativecontents |= CONTENTSQ3_CORPSE; + if (supercontents & SUPERCONTENTS_NODROP) + nativecontents |= CONTENTSQ3_NODROP; + if (supercontents & SUPERCONTENTS_PLAYERCLIP) + nativecontents |= CONTENTSQ3_PLAYERCLIP; + if (supercontents & SUPERCONTENTS_MONSTERCLIP) + nativecontents |= CONTENTSQ3_MONSTERCLIP; + if (supercontents & SUPERCONTENTS_DONOTENTER) + nativecontents |= CONTENTSQ3_DONOTENTER; + if (supercontents & SUPERCONTENTS_BOTCLIP) + nativecontents |= CONTENTSQ3_BOTCLIP; + if (!(supercontents & SUPERCONTENTS_OPAQUE)) + nativecontents |= CONTENTSQ3_TRANSLUCENT; + return nativecontents; +} + +static void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node) +{ + int numleafs; + while (node->plane) + { + Mod_Q3BSP_RecursiveFindNumLeafs(node->children[0]); + node = node->children[1]; + } + numleafs = ((mleaf_t *)node - loadmodel->brush.data_leafs) + 1; + if (loadmodel->brush.num_leafs < numleafs) + loadmodel->brush.num_leafs = numleafs; +} + +static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, j, lumps; + q3dheader_t *header; + float corner[3], yawradius, modelradius; + + mod->modeldatatypestring = "Q3BSP"; + + mod->type = mod_brushq3; + mod->numframes = 2; // although alternate textures are not supported it is annoying to complain about no such frame 1 + mod->numskins = 1; + + header = (q3dheader_t *)buffer; + if((char *) bufferend < (char *) buffer + sizeof(q3dheader_t)) + Host_Error("Mod_Q3BSP_Load: %s is smaller than its header", mod->name); + + i = LittleLong(header->version); + if (i != Q3BSPVERSION && i != Q3BSPVERSION_IG && i != Q3BSPVERSION_LIVE) + Host_Error("Mod_Q3BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q3BSPVERSION); + + mod->soundfromcenter = true; + mod->TraceBox = Mod_Q3BSP_TraceBox; + mod->TraceBrush = Mod_Q3BSP_TraceBrush; + mod->TraceLine = Mod_Q3BSP_TraceLine; + mod->TracePoint = Mod_Q3BSP_TracePoint; + mod->PointSuperContents = Mod_Q3BSP_PointSuperContents; + mod->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine; + mod->brush.TraceLineOfSight = Mod_Q3BSP_TraceLineOfSight; + mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents; + mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents; + mod->brush.GetPVS = Mod_Q1BSP_GetPVS; + mod->brush.FatPVS = Mod_Q1BSP_FatPVS; + mod->brush.BoxTouchingPVS = Mod_Q1BSP_BoxTouchingPVS; + mod->brush.BoxTouchingLeafPVS = Mod_Q1BSP_BoxTouchingLeafPVS; + mod->brush.BoxTouchingVisibleLeafs = Mod_Q1BSP_BoxTouchingVisibleLeafs; + mod->brush.FindBoxClusters = Mod_Q1BSP_FindBoxClusters; + mod->brush.LightPoint = Mod_Q3BSP_LightPoint; + mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; + mod->brush.AmbientSoundLevelsForPoint = NULL; + mod->brush.RoundUpToHullSize = NULL; + mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf; + mod->Draw = R_Q1BSP_Draw; + mod->DrawDepth = R_Q1BSP_DrawDepth; + mod->DrawDebug = R_Q1BSP_DrawDebug; + mod->DrawPrepass = R_Q1BSP_DrawPrepass; + mod->GetLightInfo = R_Q1BSP_GetLightInfo; + mod->CompileShadowMap = R_Q1BSP_CompileShadowMap; + mod->DrawShadowMap = R_Q1BSP_DrawShadowMap; + mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + mod->DrawLight = R_Q1BSP_DrawLight; + + mod_base = (unsigned char *)header; + + // swap all the lumps + header->ident = LittleLong(header->ident); + header->version = LittleLong(header->version); + lumps = (header->version == Q3BSPVERSION_LIVE) ? Q3HEADER_LUMPS_LIVE : Q3HEADER_LUMPS; + for (i = 0;i < lumps;i++) + { + j = (header->lumps[i].fileofs = LittleLong(header->lumps[i].fileofs)); + if((char *) bufferend < (char *) buffer + j) + Host_Error("Mod_Q3BSP_Load: %s has a lump that starts outside the file!", mod->name); + j += (header->lumps[i].filelen = LittleLong(header->lumps[i].filelen)); + if((char *) bufferend < (char *) buffer + j) + Host_Error("Mod_Q3BSP_Load: %s has a lump that ends outside the file!", mod->name); + } + /* + * NO, do NOT clear them! + * they contain actual data referenced by other stuff. + * Instead, before using the advertisements lump, check header->versio + * again! + * Sorry, but otherwise it breaks memory of the first lump. + for (i = lumps;i < Q3HEADER_LUMPS_MAX;i++) + { + header->lumps[i].fileofs = 0; + header->lumps[i].filelen = 0; + } + */ + + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < lumps;i++) + { + if (i == Q3LUMP_ENTITIES) + continue; + mod->brush.qw_md4sum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + if (i == Q3LUMP_PVS || i == Q3LUMP_LEAFS || i == Q3LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + + // all this checksumming can take a while, so let's send keepalives here too + CL_KeepaliveMessage(false); + } + + Mod_Q3BSP_LoadEntities(&header->lumps[Q3LUMP_ENTITIES]); + Mod_Q3BSP_LoadTextures(&header->lumps[Q3LUMP_TEXTURES]); + Mod_Q3BSP_LoadPlanes(&header->lumps[Q3LUMP_PLANES]); + if (header->version == Q3BSPVERSION_IG) + Mod_Q3BSP_LoadBrushSides_IG(&header->lumps[Q3LUMP_BRUSHSIDES]); + else + Mod_Q3BSP_LoadBrushSides(&header->lumps[Q3LUMP_BRUSHSIDES]); + Mod_Q3BSP_LoadBrushes(&header->lumps[Q3LUMP_BRUSHES]); + Mod_Q3BSP_LoadEffects(&header->lumps[Q3LUMP_EFFECTS]); + Mod_Q3BSP_LoadVertices(&header->lumps[Q3LUMP_VERTICES]); + Mod_Q3BSP_LoadTriangles(&header->lumps[Q3LUMP_TRIANGLES]); + Mod_Q3BSP_LoadLightmaps(&header->lumps[Q3LUMP_LIGHTMAPS], &header->lumps[Q3LUMP_FACES]); + Mod_Q3BSP_LoadFaces(&header->lumps[Q3LUMP_FACES]); + Mod_Q3BSP_LoadModels(&header->lumps[Q3LUMP_MODELS]); + Mod_Q3BSP_LoadLeafBrushes(&header->lumps[Q3LUMP_LEAFBRUSHES]); + Mod_Q3BSP_LoadLeafFaces(&header->lumps[Q3LUMP_LEAFFACES]); + Mod_Q3BSP_LoadLeafs(&header->lumps[Q3LUMP_LEAFS]); + Mod_Q3BSP_LoadNodes(&header->lumps[Q3LUMP_NODES]); + Mod_Q3BSP_LoadLightGrid(&header->lumps[Q3LUMP_LIGHTGRID]); + Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]); + loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models; + + // the MakePortals code works fine on the q3bsp data as well + if (mod_bsp_portalize.integer) + Mod_Q1BSP_MakePortals(); + + // FIXME: shader alpha should replace r_wateralpha support in q3bsp + loadmodel->brush.supportwateralpha = true; + + // make a single combined shadow mesh to allow optimized shadow volume creation + Mod_Q1BSP_CreateShadowMesh(loadmodel); + + loadmodel->brush.num_leafs = 0; + Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes); + + if (loadmodel->brush.numsubmodels) + loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); + + mod = loadmodel; + for (i = 0;i < loadmodel->brush.numsubmodels;i++) + { + if (i > 0) + { + char name[10]; + // duplicate the basic information + dpsnprintf(name, sizeof(name), "*%i", i); + mod = Mod_FindName(name, loadmodel->name); + // copy the base model to this one + *mod = *loadmodel; + // rename the clone back to its proper name + strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = loadmodel; + // textures and memory belong to the main model + mod->texturepool = NULL; + mod->mempool = NULL; + mod->brush.GetPVS = NULL; + mod->brush.FatPVS = NULL; + mod->brush.BoxTouchingPVS = NULL; + mod->brush.BoxTouchingLeafPVS = NULL; + mod->brush.BoxTouchingVisibleLeafs = NULL; + mod->brush.FindBoxClusters = NULL; + mod->brush.LightPoint = NULL; + mod->brush.AmbientSoundLevelsForPoint = NULL; + } + mod->brush.submodel = i; + if (loadmodel->brush.submodels) + loadmodel->brush.submodels[i] = mod; + + // make the model surface list (used by shadowing/lighting) + mod->firstmodelsurface = mod->brushq3.data_models[i].firstface; + mod->nummodelsurfaces = mod->brushq3.data_models[i].numfaces; + mod->firstmodelbrush = mod->brushq3.data_models[i].firstbrush; + mod->nummodelbrushes = mod->brushq3.data_models[i].numbrushes; + mod->sortedmodelsurfaces = (int *)Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces)); + Mod_MakeSortedSurfaces(mod); + + VectorCopy(mod->brushq3.data_models[i].mins, mod->normalmins); + VectorCopy(mod->brushq3.data_models[i].maxs, mod->normalmaxs); + // enlarge the bounding box to enclose all geometry of this model, + // because q3map2 sometimes lies (mostly to affect the lightgrid), + // which can in turn mess up the farclip (as well as culling when + // outside the level - an unimportant concern) + + //printf("Editing model %d... BEFORE re-bounding: %f %f %f - %f %f %f\n", i, mod->normalmins[0], mod->normalmins[1], mod->normalmins[2], mod->normalmaxs[0], mod->normalmaxs[1], mod->normalmaxs[2]); + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + const float *v = mod->surfmesh.data_vertex3f + 3 * surface->num_firstvertex; + int k; + if (!surface->num_vertices) + continue; + for (k = 0;k < surface->num_vertices;k++, v += 3) + { + mod->normalmins[0] = min(mod->normalmins[0], v[0]); + mod->normalmins[1] = min(mod->normalmins[1], v[1]); + mod->normalmins[2] = min(mod->normalmins[2], v[2]); + mod->normalmaxs[0] = max(mod->normalmaxs[0], v[0]); + mod->normalmaxs[1] = max(mod->normalmaxs[1], v[1]); + mod->normalmaxs[2] = max(mod->normalmaxs[2], v[2]); + } + } + //printf("Editing model %d... AFTER re-bounding: %f %f %f - %f %f %f\n", i, mod->normalmins[0], mod->normalmins[1], mod->normalmins[2], mod->normalmaxs[0], mod->normalmaxs[1], mod->normalmaxs[2]); + corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0])); + corner[1] = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1])); + corner[2] = max(fabs(mod->normalmins[2]), fabs(mod->normalmaxs[2])); + modelradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]+corner[2]*corner[2]); + yawradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]); + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->yawmaxs[0] = mod->yawmaxs[1] = yawradius; + mod->yawmins[0] = mod->yawmins[1] = -yawradius; + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; + + // this gets altered below if sky or water is used + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + + for (j = 0;j < mod->nummodelsurfaces;j++) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY) + break; + if (j < mod->nummodelsurfaces) + mod->DrawSky = R_Q1BSP_DrawSky; + + for (j = 0;j < mod->nummodelsurfaces;j++) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + break; + if (j < mod->nummodelsurfaces) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + + Mod_MakeCollisionBIH(mod, false, &mod->collision_bih); + Mod_MakeCollisionBIH(mod, true, &mod->render_bih); + + // generate VBOs and other shared data before cloning submodels + if (i == 0) + Mod_BuildVBOs(); + } + + if (mod_q3bsp_sRGBlightmaps.integer) + { + if (vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + // actually we do in sRGB fallback with sRGB lightmaps: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) + // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) + // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 + // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) + //loadmodel->lightmapscale *= 0.679942f; // fixes neutral level + } + else // if this is NOT set, regular rendering looks right by this requirement anyway + { + /* + // we want color 1 to do the same as without sRGB + // so, we want to map 1 to Image_LinearFloatFromsRGBFloat(2) instead of to 2 + loadmodel->lightmapscale *= 2.476923f; // fixes max level + */ + + // neutral level 0.5 gets uploaded as sRGB and becomes Image_LinearFloatFromsRGBFloat(0.5) + // we need to undo that + loadmodel->lightmapscale *= 2.336f; // fixes neutral level + } + } + + Con_DPrintf("Stats for q3bsp model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); +} + +void Mod_IBSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i = LittleLong(((int *)buffer)[1]); + if (i == Q3BSPVERSION || i == Q3BSPVERSION_IG || i == Q3BSPVERSION_LIVE) + Mod_Q3BSP_Load(mod,buffer, bufferend); + else if (i == Q2BSPVERSION) + Mod_Q2BSP_Load(mod,buffer, bufferend); + else + Host_Error("Mod_IBSP_Load: unknown/unsupported version %i", i); +} + +void Mod_MAP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + Host_Error("Mod_MAP_Load: not yet implemented"); +} + +typedef struct objvertex_s +{ + int nextindex; + int submodelindex; + int textureindex; + float v[3]; + float vt[2]; + float vn[3]; +} +objvertex_t; + +static unsigned char nobsp_pvs[1] = {1}; + +void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + const char *textbase = (char *)buffer, *text = textbase; + char *s; + char *argv[512]; + char line[1024]; + char materialname[MAX_QPATH]; + int i, j, l, numvertices, firstvertex, firsttriangle, elementindex, vertexindex, surfacevertices, surfacetriangles, surfaceelements, submodelindex = 0; + int index1, index2, index3; + objvertex_t vfirst, vprev, vcurrent; + int argc; + int linelen; + int numtriangles = 0; + int maxtriangles = 0; + objvertex_t *vertices = NULL; + int linenumber = 0; + int maxtextures = 0, numtextures = 0, textureindex = 0; + int maxv = 0, numv = 1; + int maxvt = 0, numvt = 1; + int maxvn = 0, numvn = 1; + char *texturenames = NULL; + float dist, modelradius, modelyawradius, yawradius; + float *v = NULL; + float *vt = NULL; + float *vn = NULL; + float mins[3]; + float maxs[3]; + float corner[3]; + objvertex_t *thisvertex = NULL; + int vertexhashindex; + int *vertexhashtable = NULL; + objvertex_t *vertexhashdata = NULL; + objvertex_t *vdata = NULL; + int vertexhashsize = 0; + int vertexhashcount = 0; + skinfile_t *skinfiles = NULL; + unsigned char *data = NULL; + int *submodelfirstsurface; + msurface_t *surface; + msurface_t *tempsurfaces; + + memset(&vfirst, 0, sizeof(vfirst)); + memset(&vprev, 0, sizeof(vprev)); + memset(&vcurrent, 0, sizeof(vcurrent)); + + dpsnprintf(materialname, sizeof(materialname), "%s", loadmodel->name); + + loadmodel->modeldatatypestring = "OBJ"; + + loadmodel->type = mod_obj; + loadmodel->soundfromcenter = true; + loadmodel->TraceBox = Mod_CollisionBIH_TraceBox; + loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; + loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; + loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine; + loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; + loadmodel->brush.TraceLineOfSight = NULL; + loadmodel->brush.SuperContentsFromNativeContents = NULL; + loadmodel->brush.NativeContentsFromSuperContents = NULL; + loadmodel->brush.GetPVS = NULL; + loadmodel->brush.FatPVS = NULL; + loadmodel->brush.BoxTouchingPVS = NULL; + loadmodel->brush.BoxTouchingLeafPVS = NULL; + loadmodel->brush.BoxTouchingVisibleLeafs = NULL; + loadmodel->brush.FindBoxClusters = NULL; + loadmodel->brush.LightPoint = NULL; + loadmodel->brush.FindNonSolidLocation = NULL; + loadmodel->brush.AmbientSoundLevelsForPoint = NULL; + loadmodel->brush.RoundUpToHullSize = NULL; + loadmodel->brush.PointInLeaf = NULL; + loadmodel->Draw = R_Q1BSP_Draw; + loadmodel->DrawDepth = R_Q1BSP_DrawDepth; + loadmodel->DrawDebug = R_Q1BSP_DrawDebug; + loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass; + loadmodel->GetLightInfo = R_Q1BSP_GetLightInfo; + loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap; + loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap; + loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume; + loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + loadmodel->DrawLight = R_Q1BSP_DrawLight; + + skinfiles = Mod_LoadSkinFiles(); + if (loadmodel->numskins < 1) + loadmodel->numskins = 1; + + // make skinscenes for the skins (no groups) + loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins); + for (i = 0;i < loadmodel->numskins;i++) + { + loadmodel->skinscenes[i].firstframe = i; + loadmodel->skinscenes[i].framecount = 1; + loadmodel->skinscenes[i].loop = true; + loadmodel->skinscenes[i].framerate = 10; + } + + VectorClear(mins); + VectorClear(maxs); + + // we always have model 0, i.e. the first "submodel" + loadmodel->brush.numsubmodels = 1; + + // parse the OBJ text now + for(;;) + { + static char emptyarg[1] = ""; + if (!*text) + break; + linenumber++; + linelen = 0; + for (linelen = 0;text[linelen] && text[linelen] != '\r' && text[linelen] != '\n';linelen++) + line[linelen] = text[linelen]; + line[linelen] = 0; + for (argc = 0;argc < 4;argc++) + argv[argc] = emptyarg; + argc = 0; + s = line; + while (*s == ' ' || *s == '\t') + s++; + while (*s) + { + argv[argc++] = s; + while (*s > ' ') + s++; + if (!*s) + break; + *s++ = 0; + while (*s == ' ' || *s == '\t') + s++; + } + text += linelen; + if (*text == '\r') + text++; + if (*text == '\n') + text++; + if (!argc) + continue; + if (argv[0][0] == '#') + continue; + if (!strcmp(argv[0], "v")) + { + if (maxv <= numv) + { + maxv = max(maxv * 2, 1024); + v = (float *)Mem_Realloc(tempmempool, v, maxv * sizeof(float[3])); + } + if(mod_obj_orientation.integer) + { + v[numv*3+0] = atof(argv[1]); + v[numv*3+2] = atof(argv[2]); + v[numv*3+1] = atof(argv[3]); + } + else + { + v[numv*3+0] = atof(argv[1]); + v[numv*3+1] = atof(argv[2]); + v[numv*3+2] = atof(argv[3]); + } + numv++; + } + else if (!strcmp(argv[0], "vt")) + { + if (maxvt <= numvt) + { + maxvt = max(maxvt * 2, 1024); + vt = (float *)Mem_Realloc(tempmempool, vt, maxvt * sizeof(float[2])); + } + vt[numvt*2+0] = atof(argv[1]); + vt[numvt*2+1] = 1-atof(argv[2]); + numvt++; + } + else if (!strcmp(argv[0], "vn")) + { + if (maxvn <= numvn) + { + maxvn = max(maxvn * 2, 1024); + vn = (float *)Mem_Realloc(tempmempool, vn, maxvn * sizeof(float[3])); + } + if(mod_obj_orientation.integer) + { + vn[numvn*3+0] = atof(argv[1]); + vn[numvn*3+2] = atof(argv[2]); + vn[numvn*3+1] = atof(argv[3]); + } + else + { + vn[numvn*3+0] = atof(argv[1]); + vn[numvn*3+1] = atof(argv[2]); + vn[numvn*3+2] = atof(argv[3]); + } + numvn++; + } + else if (!strcmp(argv[0], "f")) + { + if (!numtextures) + { + if (maxtextures <= numtextures) + { + maxtextures = max(maxtextures * 2, 256); + texturenames = (char *)Mem_Realloc(loadmodel->mempool, texturenames, maxtextures * MAX_QPATH); + } + textureindex = numtextures++; + strlcpy(texturenames + textureindex*MAX_QPATH, loadmodel->name, MAX_QPATH); + } + for (j = 1;j < argc;j++) + { + index1 = atoi(argv[j]); + while(argv[j][0] && argv[j][0] != '/') + argv[j]++; + if (argv[j][0]) + argv[j]++; + index2 = atoi(argv[j]); + while(argv[j][0] && argv[j][0] != '/') + argv[j]++; + if (argv[j][0]) + argv[j]++; + index3 = atoi(argv[j]); + // negative refers to a recent vertex + // zero means not specified + // positive means an absolute vertex index + if (index1 < 0) + index1 = numv - index1; + if (index2 < 0) + index2 = numvt - index2; + if (index3 < 0) + index3 = numvn - index3; + vcurrent.nextindex = -1; + vcurrent.textureindex = textureindex; + vcurrent.submodelindex = submodelindex; + if (v && index1 >= 0 && index1 < numv) + VectorCopy(v + 3*index1, vcurrent.v); + if (vt && index2 >= 0 && index2 < numvt) + Vector2Copy(vt + 2*index2, vcurrent.vt); + if (vn && index3 >= 0 && index3 < numvn) + VectorCopy(vn + 3*index3, vcurrent.vn); + if (numtriangles == 0) + { + VectorCopy(vcurrent.v, mins); + VectorCopy(vcurrent.v, maxs); + } + else + { + mins[0] = min(mins[0], vcurrent.v[0]); + mins[1] = min(mins[1], vcurrent.v[1]); + mins[2] = min(mins[2], vcurrent.v[2]); + maxs[0] = max(maxs[0], vcurrent.v[0]); + maxs[1] = max(maxs[1], vcurrent.v[1]); + maxs[2] = max(maxs[2], vcurrent.v[2]); + } + if (j == 1) + vfirst = vcurrent; + else if (j >= 3) + { + if (maxtriangles <= numtriangles) + { + maxtriangles = max(maxtriangles * 2, 32768); + vertices = (objvertex_t*)Mem_Realloc(loadmodel->mempool, vertices, maxtriangles * sizeof(objvertex_t[3])); + } + if(mod_obj_orientation.integer) + { + vertices[numtriangles*3+0] = vfirst; + vertices[numtriangles*3+1] = vprev; + vertices[numtriangles*3+2] = vcurrent; + } + else + { + vertices[numtriangles*3+0] = vfirst; + vertices[numtriangles*3+2] = vprev; + vertices[numtriangles*3+1] = vcurrent; + } + numtriangles++; + } + vprev = vcurrent; + } + } + else if (!strcmp(argv[0], "o") || !strcmp(argv[0], "g")) + { + submodelindex = atof(argv[1]); + loadmodel->brush.numsubmodels = max(submodelindex + 1, loadmodel->brush.numsubmodels); + } + else if (!strcmp(argv[0], "usemtl")) + { + for (i = 0;i < numtextures;i++) + if (!strcmp(texturenames+i*MAX_QPATH, argv[1])) + break; + if (i < numtextures) + textureindex = i; + else + { + if (maxtextures <= numtextures) + { + maxtextures = max(maxtextures * 2, 256); + texturenames = (char *)Mem_Realloc(loadmodel->mempool, texturenames, maxtextures * MAX_QPATH); + } + textureindex = numtextures++; + strlcpy(texturenames + textureindex*MAX_QPATH, argv[1], MAX_QPATH); + } + } + } + + // now that we have the OBJ data loaded as-is, we can convert it + + // copy the model bounds, then enlarge the yaw and rotated bounds according to radius + VectorCopy(mins, loadmodel->normalmins); + VectorCopy(maxs, loadmodel->normalmaxs); + dist = max(fabs(loadmodel->normalmins[0]), fabs(loadmodel->normalmaxs[0])); + modelyawradius = max(fabs(loadmodel->normalmins[1]), fabs(loadmodel->normalmaxs[1])); + modelyawradius = dist*dist+modelyawradius*modelyawradius; + modelradius = max(fabs(loadmodel->normalmins[2]), fabs(loadmodel->normalmaxs[2])); + modelradius = modelyawradius + modelradius * modelradius; + modelyawradius = sqrt(modelyawradius); + modelradius = sqrt(modelradius); + loadmodel->yawmins[0] = loadmodel->yawmins[1] = -modelyawradius; + loadmodel->yawmins[2] = loadmodel->normalmins[2]; + loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = modelyawradius; + loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2]; + loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -modelradius; + loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = modelradius; + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; + + // allocate storage for triangles + loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, numtriangles * sizeof(int[3])); + // allocate vertex hash structures to build an optimal vertex subset + vertexhashsize = numtriangles*2; + vertexhashtable = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int) * vertexhashsize); + memset(vertexhashtable, 0xFF, sizeof(int) * vertexhashsize); + vertexhashdata = (objvertex_t *)Mem_Alloc(loadmodel->mempool, sizeof(*vertexhashdata) * numtriangles*3); + vertexhashcount = 0; + + // gather surface stats for assigning vertex/triangle ranges + firstvertex = 0; + firsttriangle = 0; + elementindex = 0; + loadmodel->num_surfaces = 0; + // allocate storage for the worst case number of surfaces, later we resize + tempsurfaces = (msurface_t *)Mem_Alloc(loadmodel->mempool, numtextures * loadmodel->brush.numsubmodels * sizeof(msurface_t)); + submodelfirstsurface = (int *)Mem_Alloc(loadmodel->mempool, (loadmodel->brush.numsubmodels+1) * sizeof(int)); + surface = tempsurfaces; + for (submodelindex = 0;submodelindex < loadmodel->brush.numsubmodels;submodelindex++) + { + submodelfirstsurface[submodelindex] = loadmodel->num_surfaces; + for (textureindex = 0;textureindex < numtextures;textureindex++) + { + for (vertexindex = 0;vertexindex < numtriangles*3;vertexindex++) + { + thisvertex = vertices + vertexindex; + if (thisvertex->submodelindex == submodelindex && thisvertex->textureindex == textureindex) + break; + } + // skip the surface creation if there are no triangles for it + if (vertexindex == numtriangles*3) + continue; + // create a surface for these vertices + surfacevertices = 0; + surfaceelements = 0; + // we hack in a texture index in the surface to be fixed up later... + surface->texture = (texture_t *)((size_t)textureindex); + // calculate bounds as we go + VectorCopy(thisvertex->v, surface->mins); + VectorCopy(thisvertex->v, surface->maxs); + for (;vertexindex < numtriangles*3;vertexindex++) + { + thisvertex = vertices + vertexindex; + if (thisvertex->submodelindex != submodelindex) + continue; + if (thisvertex->textureindex != textureindex) + continue; + // add vertex to surface bounds + surface->mins[0] = min(surface->mins[0], thisvertex->v[0]); + surface->mins[1] = min(surface->mins[1], thisvertex->v[1]); + surface->mins[2] = min(surface->mins[2], thisvertex->v[2]); + surface->maxs[0] = max(surface->maxs[0], thisvertex->v[0]); + surface->maxs[1] = max(surface->maxs[1], thisvertex->v[1]); + surface->maxs[2] = max(surface->maxs[2], thisvertex->v[2]); + // add the vertex if it is not found in the merged set, and + // get its index (triangle element) for the surface + vertexhashindex = (unsigned int)(thisvertex->v[0] * 3571 + thisvertex->v[0] * 1777 + thisvertex->v[0] * 457) % (unsigned int)vertexhashsize; + for (i = vertexhashtable[vertexhashindex];i >= 0;i = vertexhashdata[i].nextindex) + { + vdata = vertexhashdata + i; + if (vdata->submodelindex == thisvertex->submodelindex && vdata->textureindex == thisvertex->textureindex && VectorCompare(thisvertex->v, vdata->v) && VectorCompare(thisvertex->vn, vdata->vn) && Vector2Compare(thisvertex->vt, vdata->vt)) + break; + } + if (i < 0) + { + i = vertexhashcount++; + vdata = vertexhashdata + i; + *vdata = *thisvertex; + vdata->nextindex = vertexhashtable[vertexhashindex]; + vertexhashtable[vertexhashindex] = i; + surfacevertices++; + } + loadmodel->surfmesh.data_element3i[elementindex++] = i; + surfaceelements++; + } + surfacetriangles = surfaceelements / 3; + surface->num_vertices = surfacevertices; + surface->num_triangles = surfacetriangles; + surface->num_firstvertex = firstvertex; + surface->num_firsttriangle = firsttriangle; + firstvertex += surface->num_vertices; + firsttriangle += surface->num_triangles; + surface++; + loadmodel->num_surfaces++; + } + } + submodelfirstsurface[submodelindex] = loadmodel->num_surfaces; + numvertices = firstvertex; + loadmodel->data_surfaces = (msurface_t *)Mem_Realloc(loadmodel->mempool, tempsurfaces, loadmodel->num_surfaces * sizeof(msurface_t)); + tempsurfaces = NULL; + + // allocate storage for final mesh data + loadmodel->num_textures = numtextures * loadmodel->numskins; + loadmodel->num_texturesperskin = numtextures; + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? numtriangles * sizeof(int[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); + loadmodel->brush.submodels = (dp_model_t **)data;data += loadmodel->brush.numsubmodels * sizeof(dp_model_t *); + loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); + loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); + loadmodel->surfmesh.num_vertices = numvertices; + loadmodel->surfmesh.num_triangles = numtriangles; + if (r_enableshadowvolumes.integer) + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += numtriangles * sizeof(int[3]); + loadmodel->surfmesh.data_vertex3f = (float *)data;data += numvertices * sizeof(float[3]); + loadmodel->surfmesh.data_svector3f = (float *)data;data += numvertices * sizeof(float[3]); + loadmodel->surfmesh.data_tvector3f = (float *)data;data += numvertices * sizeof(float[3]); + loadmodel->surfmesh.data_normal3f = (float *)data;data += numvertices * sizeof(float[3]); + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data;data += numvertices * sizeof(float[2]); + if (loadmodel->surfmesh.num_vertices <= 65536) + loadmodel->surfmesh.data_element3s = (unsigned short *)data;data += loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]); + + for (j = 0;j < loadmodel->surfmesh.num_vertices;j++) + { + VectorCopy(vertexhashdata[j].v, loadmodel->surfmesh.data_vertex3f + 3*j); + VectorCopy(vertexhashdata[j].vn, loadmodel->surfmesh.data_normal3f + 3*j); + Vector2Copy(vertexhashdata[j].vt, loadmodel->surfmesh.data_texcoordtexture2f + 2*j); + } + + // load the textures + for (textureindex = 0;textureindex < numtextures;textureindex++) + Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures + textureindex, skinfiles, texturenames + textureindex*MAX_QPATH, texturenames + textureindex*MAX_QPATH); + Mod_FreeSkinFiles(skinfiles); + + // set the surface textures to their real values now that we loaded them... + for (i = 0;i < loadmodel->num_surfaces;i++) + loadmodel->data_surfaces[i].texture = loadmodel->data_textures + (size_t)loadmodel->data_surfaces[i].texture; + + // free data + Mem_Free(vertices); + Mem_Free(texturenames); + Mem_Free(v); + Mem_Free(vt); + Mem_Free(vn); + Mem_Free(vertexhashtable); + Mem_Free(vertexhashdata); + + // make a single combined shadow mesh to allow optimized shadow volume creation + Mod_Q1BSP_CreateShadowMesh(loadmodel); + + // compute all the mesh information that was not loaded from the file + if (loadmodel->surfmesh.data_element3s) + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, loadmodel->surfmesh.num_vertices, __FILE__, __LINE__); + // generate normals if the file did not have them + if (!VectorLength2(loadmodel->surfmesh.data_normal3f)) + Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); + Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + + // if this is a worldmodel and has no BSP tree, create a fake one for the purpose + loadmodel->brush.num_visleafs = 1; + loadmodel->brush.num_leafs = 1; + loadmodel->brush.num_nodes = 0; + loadmodel->brush.num_leafsurfaces = loadmodel->num_surfaces; + loadmodel->brush.data_leafs = (mleaf_t *)Mem_Alloc(loadmodel->mempool, loadmodel->brush.num_leafs * sizeof(mleaf_t)); + loadmodel->brush.data_nodes = (mnode_t *)loadmodel->brush.data_leafs; + loadmodel->brush.num_pvsclusters = 1; + loadmodel->brush.num_pvsclusterbytes = 1; + loadmodel->brush.data_pvsclusters = nobsp_pvs; + //if (loadmodel->num_nodes) loadmodel->data_nodes = (mnode_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_nodes * sizeof(mnode_t)); + //loadmodel->data_leafsurfaces = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->num_leafsurfaces * sizeof(int)); + loadmodel->brush.data_leafsurfaces = loadmodel->sortedmodelsurfaces; + VectorCopy(loadmodel->normalmins, loadmodel->brush.data_leafs->mins); + VectorCopy(loadmodel->normalmaxs, loadmodel->brush.data_leafs->maxs); + loadmodel->brush.data_leafs->combinedsupercontents = 0; // FIXME? + loadmodel->brush.data_leafs->clusterindex = 0; + loadmodel->brush.data_leafs->areaindex = 0; + loadmodel->brush.data_leafs->numleafsurfaces = loadmodel->brush.num_leafsurfaces; + loadmodel->brush.data_leafs->firstleafsurface = loadmodel->brush.data_leafsurfaces; + loadmodel->brush.data_leafs->numleafbrushes = 0; + loadmodel->brush.data_leafs->firstleafbrush = NULL; + loadmodel->brush.supportwateralpha = true; + + if (loadmodel->brush.numsubmodels) + loadmodel->brush.submodels = (dp_model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); + + mod = loadmodel; + for (i = 0;i < loadmodel->brush.numsubmodels;i++) + { + if (i > 0) + { + char name[10]; + // duplicate the basic information + dpsnprintf(name, sizeof(name), "*%i", i); + mod = Mod_FindName(name, loadmodel->name); + // copy the base model to this one + *mod = *loadmodel; + // rename the clone back to its proper name + strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = loadmodel; + // textures and memory belong to the main model + mod->texturepool = NULL; + mod->mempool = NULL; + mod->brush.GetPVS = NULL; + mod->brush.FatPVS = NULL; + mod->brush.BoxTouchingPVS = NULL; + mod->brush.BoxTouchingLeafPVS = NULL; + mod->brush.BoxTouchingVisibleLeafs = NULL; + mod->brush.FindBoxClusters = NULL; + mod->brush.LightPoint = NULL; + mod->brush.AmbientSoundLevelsForPoint = NULL; + } + mod->brush.submodel = i; + if (loadmodel->brush.submodels) + loadmodel->brush.submodels[i] = mod; + + // make the model surface list (used by shadowing/lighting) + mod->firstmodelsurface = submodelfirstsurface[i]; + mod->nummodelsurfaces = submodelfirstsurface[i+1] - submodelfirstsurface[i]; + mod->firstmodelbrush = 0; + mod->nummodelbrushes = 0; + mod->sortedmodelsurfaces = loadmodel->sortedmodelsurfaces + mod->firstmodelsurface; + Mod_MakeSortedSurfaces(mod); + + VectorClear(mod->normalmins); + VectorClear(mod->normalmaxs); + l = false; + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + const float *v = mod->surfmesh.data_vertex3f + 3 * surface->num_firstvertex; + int k; + if (!surface->num_vertices) + continue; + if (!l) + { + l = true; + VectorCopy(v, mod->normalmins); + VectorCopy(v, mod->normalmaxs); + } + for (k = 0;k < surface->num_vertices;k++, v += 3) + { + mod->normalmins[0] = min(mod->normalmins[0], v[0]); + mod->normalmins[1] = min(mod->normalmins[1], v[1]); + mod->normalmins[2] = min(mod->normalmins[2], v[2]); + mod->normalmaxs[0] = max(mod->normalmaxs[0], v[0]); + mod->normalmaxs[1] = max(mod->normalmaxs[1], v[1]); + mod->normalmaxs[2] = max(mod->normalmaxs[2], v[2]); + } + } + corner[0] = max(fabs(mod->normalmins[0]), fabs(mod->normalmaxs[0])); + corner[1] = max(fabs(mod->normalmins[1]), fabs(mod->normalmaxs[1])); + corner[2] = max(fabs(mod->normalmins[2]), fabs(mod->normalmaxs[2])); + modelradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]+corner[2]*corner[2]); + yawradius = sqrt(corner[0]*corner[0]+corner[1]*corner[1]); + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->yawmaxs[0] = mod->yawmaxs[1] = yawradius; + mod->yawmins[0] = mod->yawmins[1] = -yawradius; + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; + + // this gets altered below if sky or water is used + mod->DrawSky = NULL; + mod->DrawAddWaterPlanes = NULL; + + for (j = 0;j < mod->nummodelsurfaces;j++) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & MATERIALFLAG_SKY) + break; + if (j < mod->nummodelsurfaces) + mod->DrawSky = R_Q1BSP_DrawSky; + + for (j = 0;j < mod->nummodelsurfaces;j++) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)) + break; + if (j < mod->nummodelsurfaces) + mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; + + Mod_MakeCollisionBIH(mod, true, &mod->collision_bih); + mod->render_bih = mod->collision_bih; + + // generate VBOs and other shared data before cloning submodels + if (i == 0) + Mod_BuildVBOs(); + } + mod = loadmodel; + Mem_Free(submodelfirstsurface); + + Con_DPrintf("Stats for obj model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); +} diff --git a/app/jni/model_brush.h b/app/jni/model_brush.h new file mode 100644 index 0000000..1621b49 --- /dev/null +++ b/app/jni/model_brush.h @@ -0,0 +1,716 @@ +/* +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_BRUSH_H +#define MODEL_BRUSH_H + +/* +============================================================================== + +BRUSH MODELS + +============================================================================== +*/ + + + +// +// in memory representation +// +typedef struct mvertex_s +{ + vec3_t position; +} +mvertex_t; + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + + +// plane_t structure +typedef struct mplane_s +{ + vec3_t normal; + float dist; + // for texture axis selection and fast side tests + int type; // set by PlaneClassify() + int signbits; // set by PlaneClassify() +} +mplane_t; + +#define SHADERSTAGE_SKY 0 +#define SHADERSTAGE_NORMAL 1 +#define SHADERSTAGE_COUNT 2 + +//#define SURF_PLANEBACK 2 + +// indicates that all triangles of the surface should be added to the BIH collision system +#define MATERIALFLAG_MESHCOLLISIONS 1 +// use alpha blend on this material +#define MATERIALFLAG_ALPHA 2 +// use additive blend on this material +#define MATERIALFLAG_ADD 4 +// turn off depth test on this material +#define MATERIALFLAG_NODEPTHTEST 8 +// multiply alpha by r_wateralpha cvar +#define MATERIALFLAG_WATERALPHA 16 +// draw with no lighting +#define MATERIALFLAG_FULLBRIGHT 32 +// drawn as a normal surface (alternative to SKY) +#define MATERIALFLAG_WALL 64 +// this surface shows the sky in its place, alternative to WALL +// skipped if transparent +#define MATERIALFLAG_SKY 128 +// swirling water effect (used with MATERIALFLAG_WALL) +#define MATERIALFLAG_WATERSCROLL 256 +// skips drawing the surface +#define MATERIALFLAG_NODRAW 512 +// probably used only on q1bsp water +#define MATERIALFLAG_LIGHTBOTHSIDES 1024 +// use alpha test on this material +#define MATERIALFLAG_ALPHATEST 2048 +// treat this material as a blended transparency (as opposed to an alpha test +// transparency), this causes special fog behavior, and disables glDepthMask +#define MATERIALFLAG_BLENDED 4096 +// render using a custom blendfunc +#define MATERIALFLAG_CUSTOMBLEND 8192 +// do not cast shadows from this material +#define MATERIALFLAG_NOSHADOW 16384 +// render using vertex alpha (q3bsp) as texture blend parameter between foreground (normal) skinframe and background skinframe +#define MATERIALFLAG_VERTEXTEXTUREBLEND 32768 +// disables GL_CULL_FACE on this texture (making it double sided) +#define MATERIALFLAG_NOCULLFACE 65536 +// render with a very short depth range (like 10% of normal), this causes entities to appear infront of most of the scene +#define MATERIALFLAG_SHORTDEPTHRANGE 131072 +// render water, comprising refraction and reflection (note: this is always opaque, the shader does the alpha effect) +#define MATERIALFLAG_WATERSHADER 262144 +// render refraction (note: this is just a way to distort the background, otherwise useless) +#define MATERIALFLAG_REFRACTION 524288 +// render reflection +#define MATERIALFLAG_REFLECTION 1048576 +// use model lighting on this material (q1bsp lightmap sampling or q3bsp lightgrid, implies FULLBRIGHT is false) +#define MATERIALFLAG_MODELLIGHT 4194304 +// add directional model lighting to this material (q3bsp lightgrid only) +#define MATERIALFLAG_MODELLIGHT_DIRECTIONAL 8388608 +// causes RSurf_GetCurrentTexture to leave alone certain fields +#define MATERIALFLAG_CUSTOMSURFACE 16777216 +// causes MATERIALFLAG_BLENDED to render a depth pass before rendering, hiding backfaces and other hidden geometry +#define MATERIALFLAG_TRANSDEPTH 33554432 +// like refraction, but doesn't distort etc. +#define MATERIALFLAG_CAMERA 67108864 +// disable rtlight on surface, use R_LightPoint instead +#define MATERIALFLAG_NORTLIGHT 134217728 +// alphagen vertex +#define MATERIALFLAG_ALPHAGEN_VERTEX 268435456 +// combined mask of all attributes that require depth sorted rendering +#define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) +// combined mask of all attributes that cause some sort of transparency +#define MATERIALFLAGMASK_TRANSLUCENT (MATERIALFLAG_WATERALPHA | MATERIALFLAG_SKY | MATERIALFLAG_NODRAW | MATERIALFLAG_ALPHATEST | MATERIALFLAG_BLENDED | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION) + +typedef struct medge_s +{ + unsigned int v[2]; +} +medge_t; + +struct entity_render_s; +struct texture_s; +struct msurface_s; + +typedef struct mnode_s +{ + //this part shared between node and leaf + mplane_t *plane; // != NULL + struct mnode_s *parent; + struct mportal_s *portals; + // for bounding box culling + vec3_t mins; + vec3_t maxs; + // supercontents from all brushes inside this node or leaf + int combinedsupercontents; + + // this part unique to node + struct mnode_s *children[2]; + + // q1bsp specific + unsigned int firstsurface; + unsigned int numsurfaces; +} +mnode_t; + +typedef struct mleaf_s +{ + //this part shared between node and leaf + mplane_t *plane; // == NULL + struct mnode_s *parent; + struct mportal_s *portals; + // for bounding box culling + vec3_t mins; + vec3_t maxs; + // supercontents from all brushes inside this node or leaf + int combinedsupercontents; + + // this part unique to leaf + // common + int clusterindex; // -1 is not in pvs, >= 0 is pvs bit number + int areaindex; // q3bsp + int containscollisionsurfaces; // indicates whether the leafsurfaces contains q3 patches + int numleafsurfaces; + int *firstleafsurface; + int numleafbrushes; // q3bsp + int *firstleafbrush; // q3bsp + unsigned char ambient_sound_level[NUM_AMBIENTS]; // q1bsp + int contents; // q1bsp: // TODO: remove (only used temporarily during loading when making collision hull 0) + int portalmarkid; // q1bsp // used by see-polygon-through-portals visibility checker +} +mleaf_t; + +typedef struct mclipnode_s +{ + int planenum; + int children[2]; // negative numbers are contents +} mclipnode_t; + +typedef struct hull_s +{ + mclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; + vec3_t clip_size; +} +hull_t; + +typedef struct mportal_s +{ + struct mportal_s *next; // the next portal on this leaf + mleaf_t *here; // the leaf this portal is on + mleaf_t *past; // the leaf through this portal (infront) + int numpoints; + mvertex_t *points; + vec3_t mins, maxs; // culling + mplane_t plane; +} +mportal_t; + +typedef struct svbspmesh_s +{ + struct svbspmesh_s *next; + int numverts, maxverts; + int numtriangles, maxtriangles; + float *verts; + int *elements; +} +svbspmesh_t; + +// Q2 bsp stuff + +#define Q2BSPVERSION 38 + +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits + +//============================================================================= + +#define Q2LUMP_ENTITIES 0 +#define Q2LUMP_PLANES 1 +#define Q2LUMP_VERTEXES 2 +#define Q2LUMP_VISIBILITY 3 +#define Q2LUMP_NODES 4 +#define Q2LUMP_TEXINFO 5 +#define Q2LUMP_FACES 6 +#define Q2LUMP_LIGHTING 7 +#define Q2LUMP_LEAFS 8 +#define Q2LUMP_LEAFFACES 9 +#define Q2LUMP_LEAFBRUSHES 10 +#define Q2LUMP_EDGES 11 +#define Q2LUMP_SURFEDGES 12 +#define Q2LUMP_MODELS 13 +#define Q2LUMP_BRUSHES 14 +#define Q2LUMP_BRUSHSIDES 15 +#define Q2LUMP_POP 16 +#define Q2LUMP_AREAS 17 +#define Q2LUMP_AREAPORTALS 18 +#define Q2HEADER_LUMPS 19 + +typedef struct q2dheader_s +{ + int ident; + int version; + lump_t lumps[Q2HEADER_LUMPS]; +} q2dheader_t; + +typedef struct q2dmodel_s +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} q2dmodel_t; + +// planes (x&~1) and (x&~1)+1 are always opposites + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define Q2CONTENTS_SOLID 1 // an eye is never valid in a solid +#define Q2CONTENTS_WINDOW 2 // translucent, but not watery +#define Q2CONTENTS_AUX 4 +#define Q2CONTENTS_LAVA 8 +#define Q2CONTENTS_SLIME 16 +#define Q2CONTENTS_WATER 32 +#define Q2CONTENTS_MIST 64 +#define Q2LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes + +#define Q2CONTENTS_AREAPORTAL 0x8000 + +#define Q2CONTENTS_PLAYERCLIP 0x10000 +#define Q2CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define Q2CONTENTS_CURRENT_0 0x40000 +#define Q2CONTENTS_CURRENT_90 0x80000 +#define Q2CONTENTS_CURRENT_180 0x100000 +#define Q2CONTENTS_CURRENT_270 0x200000 +#define Q2CONTENTS_CURRENT_UP 0x400000 +#define Q2CONTENTS_CURRENT_DOWN 0x800000 + +#define Q2CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define Q2CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define Q2CONTENTS_DEADMONSTER 0x4000000 +#define Q2CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define Q2CONTENTS_LADDER 0x20000000 + + + +#define Q2SURF_LIGHT 0x1 // value will hold the light strength + +#define Q2SURF_SLICK 0x2 // effects game physics + +#define Q2SURF_SKY 0x4 // don't draw, but add to skybox +#define Q2SURF_WARP 0x8 // turbulent water warp +#define Q2SURF_TRANS33 0x10 +#define Q2SURF_TRANS66 0x20 +#define Q2SURF_FLOWING 0x40 // scroll towards angle +#define Q2SURF_NODRAW 0x80 // don't bother referencing the texture + + + + +typedef struct q2dnode_s +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} q2dnode_t; + + +typedef struct q2texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} q2texinfo_t; + +typedef struct q2dleaf_s +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} q2dleaf_t; + +typedef struct q2dbrushside_s +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} q2dbrushside_t; + +typedef struct q2dbrush_s +{ + int firstside; + int numsides; + int contents; +} q2dbrush_t; + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define Q2DVIS_PVS 0 +#define Q2DVIS_PHS 1 +typedef struct q2dvis_s +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} q2dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct q2dareaportal_s +{ + int portalnum; + int otherarea; +} q2dareaportal_t; + +typedef struct q2darea_s +{ + int numareaportals; + int firstareaportal; +} q2darea_t; + + +//Q3 bsp stuff + +#define Q3BSPVERSION 46 +#define Q3BSPVERSION_LIVE 47 +#define Q3BSPVERSION_IG 48 + +#define Q3LUMP_ENTITIES 0 // entities to spawn (used by server and client) +#define Q3LUMP_TEXTURES 1 // textures used (used by faces) +#define Q3LUMP_PLANES 2 // planes used (used by bsp nodes) +#define Q3LUMP_NODES 3 // bsp nodes (used by bsp nodes, bsp leafs, rendering, collisions) +#define Q3LUMP_LEAFS 4 // bsp leafs (used by bsp nodes) +#define Q3LUMP_LEAFFACES 5 // array of ints indexing faces (used by leafs) +#define Q3LUMP_LEAFBRUSHES 6 // array of ints indexing brushes (used by leafs) +#define Q3LUMP_MODELS 7 // models (used by rendering, collisions) +#define Q3LUMP_BRUSHES 8 // brushes (used by effects, collisions) +#define Q3LUMP_BRUSHSIDES 9 // brush faces (used by brushes) +#define Q3LUMP_VERTICES 10 // mesh vertices (used by faces) +#define Q3LUMP_TRIANGLES 11 // mesh triangles (used by faces) +#define Q3LUMP_EFFECTS 12 // fog (used by faces) +#define Q3LUMP_FACES 13 // surfaces (used by leafs) +#define Q3LUMP_LIGHTMAPS 14 // lightmap textures (used by faces) +#define Q3LUMP_LIGHTGRID 15 // lighting as a voxel grid (used by rendering) +#define Q3LUMP_PVS 16 // potentially visible set; bit[clusters][clusters] (used by rendering) +#define Q3HEADER_LUMPS 17 +#define Q3LUMP_ADVERTISEMENTS 17 // quake live stuff written by zeroradiant's q3map2 (ignored by DP) +#define Q3HEADER_LUMPS_LIVE 18 +#define Q3HEADER_LUMPS_MAX 18 + +typedef struct q3dheader_s +{ + int ident; + int version; + lump_t lumps[Q3HEADER_LUMPS_MAX]; +} q3dheader_t; + +typedef struct q3dtexture_s +{ + char name[Q3PATHLENGTH]; + int surfaceflags; + int contents; +} +q3dtexture_t; + +// note: planes are paired, the pair of planes with i and i ^ 1 are opposites. +typedef struct q3dplane_s +{ + float normal[3]; + float dist; +} +q3dplane_t; + +typedef struct q3dnode_s +{ + int planeindex; + int childrenindex[2]; + int mins[3]; + int maxs[3]; +} +q3dnode_t; + +typedef struct q3dleaf_s +{ + int clusterindex; // pvs index + int areaindex; // area index + int mins[3]; + int maxs[3]; + int firstleafface; + int numleaffaces; + int firstleafbrush; + int numleafbrushes; +} +q3dleaf_t; + +typedef struct q3dmodel_s +{ + float mins[3]; + float maxs[3]; + int firstface; + int numfaces; + int firstbrush; + int numbrushes; +} +q3dmodel_t; + +typedef struct q3dbrush_s +{ + int firstbrushside; + int numbrushsides; + int textureindex; +} +q3dbrush_t; + +typedef struct q3dbrushside_s +{ + int planeindex; + int textureindex; +} +q3dbrushside_t; + +typedef struct q3dbrushside_ig_s +{ + int planeindex; + int textureindex; + int surfaceflags; +} +q3dbrushside_ig_t; + +typedef struct q3dvertex_s +{ + float origin3f[3]; + float texcoord2f[2]; + float lightmap2f[2]; + float normal3f[3]; + unsigned char color4ub[4]; +} +q3dvertex_t; + +typedef struct q3dmeshvertex_s +{ + int offset; // first vertex index of mesh +} +q3dmeshvertex_t; + +typedef struct q3deffect_s +{ + char shadername[Q3PATHLENGTH]; + int brushindex; + int unknown; // I read this is always 5 except in q3dm8 which has one effect with -1 +} +q3deffect_t; + +#define Q3FACETYPE_FLAT 1 // common +#define Q3FACETYPE_PATCH 2 // common +#define Q3FACETYPE_MESH 3 // common +#define Q3FACETYPE_FLARE 4 // rare (is this ever used?) + +typedef struct q3dface_s +{ + int textureindex; + int effectindex; // -1 if none + int type; // Q3FACETYPE + int firstvertex; + int numvertices; + int firstelement; + int numelements; + int lightmapindex; // -1 if none + int lightmap_base[2]; + int lightmap_size[2]; + union + { + struct + { + // corrupt or don't care + int blah[14]; + } + unknown; + struct + { + // Q3FACETYPE_FLAT + // mesh is a collection of triangles on a plane, renderable as a mesh (NOT a polygon) + float lightmap_origin[3]; + float lightmap_vectors[2][3]; + float normal[3]; + int unused1[2]; + } + flat; + struct + { + // Q3FACETYPE_PATCH + // patch renders as a bezier mesh, with adjustable tesselation + // level (optionally based on LOD using the bbox and polygon + // count to choose a tesselation level) + // note: multiple patches may have the same bbox to cause them to + // be LOD adjusted together as a group + int unused1[3]; + float mins[3]; // LOD bbox + float maxs[3]; // LOD bbox + int unused2[3]; + int patchsize[2]; // dimensions of vertex grid + } + patch; + struct + { + // Q3FACETYPE_MESH + // mesh renders as simply a triangle mesh + int unused1[3]; + float mins[3]; + float maxs[3]; + int unused2[5]; + } + mesh; + struct + { + // Q3FACETYPE_FLARE + // flare renders as a simple sprite at origin, no geometry + // exists, nor does it have a radius, a cvar controls the radius + // and another cvar controls distance fade + // (they were not used in Q3 I'm told) + float origin[3]; + int unused1[11]; + } + flare; + } + specific; +} +q3dface_t; + +typedef struct q3dlightmap_s +{ + unsigned char rgb[128*128*3]; +} +q3dlightmap_t; + +typedef struct q3dlightgrid_s +{ + unsigned char ambientrgb[3]; + unsigned char diffusergb[3]; + unsigned char diffusepitch; + unsigned char diffuseyaw; +} +q3dlightgrid_t; + +typedef struct q3dpvs_s +{ + int numclusters; + int chainlength; + // unsigned char chains[]; + // containing bits in 0-7 order (not 7-0 order), + // pvschains[mycluster * chainlength + (thatcluster >> 3)] & (1 << (thatcluster & 7)) +} +q3dpvs_t; + +// surfaceflags from bsp +#define Q3SURFACEFLAG_NODAMAGE 1 +#define Q3SURFACEFLAG_SLICK 2 +#define Q3SURFACEFLAG_SKY 4 +#define Q3SURFACEFLAG_LADDER 8 // has no surfaceparm +#define Q3SURFACEFLAG_NOIMPACT 16 +#define Q3SURFACEFLAG_NOMARKS 32 +#define Q3SURFACEFLAG_FLESH 64 // has no surfaceparm +#define Q3SURFACEFLAG_NODRAW 128 +#define Q3SURFACEFLAG_HINT 256 +#define Q3SURFACEFLAG_SKIP 512 // has no surfaceparm +#define Q3SURFACEFLAG_NOLIGHTMAP 1024 +#define Q3SURFACEFLAG_POINTLIGHT 2048 +#define Q3SURFACEFLAG_METALSTEPS 4096 +#define Q3SURFACEFLAG_NOSTEPS 8192 // has no surfaceparm +#define Q3SURFACEFLAG_NONSOLID 16384 +#define Q3SURFACEFLAG_LIGHTFILTER 32768 +#define Q3SURFACEFLAG_ALPHASHADOW 65536 +#define Q3SURFACEFLAG_NODLIGHT 131072 +#define Q3SURFACEFLAG_DUST 262144 + +// surfaceparms from shaders +#define Q3SURFACEPARM_ALPHASHADOW 1 +#define Q3SURFACEPARM_AREAPORTAL 2 +#define Q3SURFACEPARM_CLUSTERPORTAL 4 +#define Q3SURFACEPARM_DETAIL 8 +#define Q3SURFACEPARM_DONOTENTER 16 +#define Q3SURFACEPARM_FOG 32 +#define Q3SURFACEPARM_LAVA 64 +#define Q3SURFACEPARM_LIGHTFILTER 128 +#define Q3SURFACEPARM_METALSTEPS 256 +#define Q3SURFACEPARM_NODAMAGE 512 +#define Q3SURFACEPARM_NODLIGHT 1024 +#define Q3SURFACEPARM_NODRAW 2048 +#define Q3SURFACEPARM_NODROP 4096 +#define Q3SURFACEPARM_NOIMPACT 8192 +#define Q3SURFACEPARM_NOLIGHTMAP 16384 +#define Q3SURFACEPARM_NOMARKS 32768 +#define Q3SURFACEPARM_NOMIPMAPS 65536 +#define Q3SURFACEPARM_NONSOLID 131072 +#define Q3SURFACEPARM_ORIGIN 262144 +#define Q3SURFACEPARM_PLAYERCLIP 524288 +#define Q3SURFACEPARM_SKY 1048576 +#define Q3SURFACEPARM_SLICK 2097152 +#define Q3SURFACEPARM_SLIME 4194304 +#define Q3SURFACEPARM_STRUCTURAL 8388608 +#define Q3SURFACEPARM_TRANS 16777216 +#define Q3SURFACEPARM_WATER 33554432 +#define Q3SURFACEPARM_POINTLIGHT 67108864 +#define Q3SURFACEPARM_HINT 134217728 +#define Q3SURFACEPARM_DUST 268435456 +#define Q3SURFACEPARM_BOTCLIP 536870912 +#define Q3SURFACEPARM_LIGHTGRID 1073741824 +#define Q3SURFACEPARM_ANTIPORTAL 2147483648u + +typedef struct q3mbrush_s +{ + struct colbrushf_s *colbrushf; + int numbrushsides; + struct q3mbrushside_s *firstbrushside; + struct texture_s *texture; +} +q3mbrush_t; + +typedef struct q3mbrushside_s +{ + struct mplane_s *plane; + struct texture_s *texture; +} +q3mbrushside_t; + +// the first cast is to shut up a stupid warning by clang, the second cast is to make both sides have the same type +#define CHECKPVSBIT(pvs,b) ((b) >= 0 ? (unsigned char) ((pvs)[(b) >> 3] & (1 << ((b) & 7))) : (unsigned char) false) +#define SETPVSBIT(pvs,b) (void) ((b) >= 0 ? (unsigned char) ((pvs)[(b) >> 3] |= (1 << ((b) & 7))) : (unsigned char) false) +#define CLEARPVSBIT(pvs,b) (void) ((b) >= 0 ? (unsigned char) ((pvs)[(b) >> 3] &= ~(1 << ((b) & 7))) : (unsigned char) false) + +#endif + diff --git a/app/jni/model_dpmodel.h b/app/jni/model_dpmodel.h new file mode 100644 index 0000000..52ad0ce --- /dev/null +++ b/app/jni/model_dpmodel.h @@ -0,0 +1,123 @@ + +#ifndef MODEL_DPMODEL_H +#define MODEL_DPMODEL_H + +/* +type 2 model (hierarchical skeletal pose) +within this specification, int is assumed to be 32bit, float is assumed to be 32bit, char is assumed to be 8bit, text is assumed to be an array of chars with NULL termination +all values are big endian (also known as network byte ordering), NOT x86 little endian +general notes: +a pose is a 3x4 matrix (rotation matrix, and translate vector) +parent bones must always be lower in number than their children, models will be rejected if this is not obeyed (can be fixed by modelling utilities) +utility notes: +if a hard edge is desired (faceted lighting, or a jump to another set of skin coordinates), vertices must be duplicated +ability to visually edit groupids of triangles is highly recommended +bones should be markable as 'attach' somehow (up to the utility) and thus protected from culling of unused resources +frame 0 is always the base pose (the one the skeleton was built for) +game notes: +the loader should be very thorough about error checking, all vertex and bone indices should be validated, etc +the gamecode can look up bone numbers by name using a builtin function, for use in attachment situations (the client should have the same model as the host of the gamecode in question - that is to say if the server gamecode is setting the bone number, the client and server must have vaguely compatible models so the client understands, and if the client gamecode is setting the bone number, the server could have a completely different model with no harm done) +the triangle groupid values are up to the gamecode, it is recommended that gamecode process this in an object-oriented fashion (I.E. bullet hits entity, call that entity's function for getting properties of that groupid) +frame 0 should be usable, not skipped +speed optimizations for the saver to do: +remove all unused data (unused bones, vertices, etc, be sure to check if bones are used for attachments however) +sort triangles into strips +sort vertices according to first use in a triangle (caching benefits) after sorting triangles +speed optimizations for the loader to do: +if the model only has one frame, process it at load time to create a simple static vertex mesh to render (this is a hassle, but it is rewarding to optimize all such models) +rendering process: +1*. one or two poses are looked up by number +2*. boneposes (matrices) are interpolated, building bone matrix array +3. bones are parsed sequentially, each bone's matrix is transformed by it's parent bone (which can be -1; the model to world matrix) +4. meshs are parsed sequentially, as follows: + 1. vertices are parsed sequentially and may be influenced by more than one bone (the results of the 3x4 matrix transform will be added together - weighting is already built into these) + 2. shader is looked up and called, passing vertex buffer (temporary) and triangle indices (which are stored in the mesh) +5. rendering is complete +* - these stages can be replaced with completely dynamic animation instead of pose animations. +*/ +// header for the entire file +typedef struct dpmheader_s +{ + char id[16]; // "DARKPLACESMODEL\0", length 16 + unsigned int type; // 2 (hierarchical skeletal pose) + unsigned int filesize; // size of entire model file + float mins[3], maxs[3], yawradius, allradius; // for clipping uses + // these offsets are relative to the file + unsigned int num_bones; + unsigned int num_meshs; + unsigned int num_frames; + unsigned int ofs_bones; // dpmbone_t bone[num_bones]; + unsigned int ofs_meshs; // dpmmesh_t mesh[num_meshs]; + unsigned int ofs_frames; // dpmframe_t frame[num_frames]; +} +dpmheader_t; +// there may be more than one of these +typedef struct dpmmesh_s +{ + // these offsets are relative to the file + char shadername[32]; // name of the shader to use + unsigned int num_verts; + unsigned int num_tris; + unsigned int ofs_verts; // dpmvertex_t vert[numvertices]; // see vertex struct + unsigned int ofs_texcoords; // float texcoords[numvertices][2]; + unsigned int ofs_indices; // unsigned int indices[numtris*3]; // designed for glDrawElements (each triangle is 3 unsigned int indices) + unsigned int ofs_groupids; // unsigned int groupids[numtris]; // the meaning of these values is entirely up to the gamecode and modeler +} +dpmmesh_t; +// if set on a bone, it must be protected from removal +#define DPMBONEFLAG_ATTACHMENT 1 +// one per bone +typedef struct dpmbone_s +{ + // name examples: upperleftarm leftfinger1 leftfinger2 hand, etc + char name[32]; + // parent bone number + signed int parent; + // flags for the bone + unsigned int flags; +} +dpmbone_t; +// a bonepose matrix is intended to be used like this: +// (n = output vertex, v = input vertex, m = matrix, f = influence) +// n[0] = v[0] * m[0][0] + v[1] * m[0][1] + v[2] * m[0][2] + f * m[0][3]; +// n[1] = v[0] * m[1][0] + v[1] * m[1][1] + v[2] * m[1][2] + f * m[1][3]; +// n[2] = v[0] * m[2][0] + v[1] * m[2][1] + v[2] * m[2][2] + f * m[2][3]; +typedef struct dpmbonepose_s +{ + float matrix[3][4]; +} +dpmbonepose_t; +// immediately followed by bone positions for the frame +typedef struct dpmframe_s +{ + // name examples: idle_1 idle_2 idle_3 shoot_1 shoot_2 shoot_3, etc + char name[32]; + float mins[3], maxs[3], yawradius, allradius; + int ofs_bonepositions; // dpmbonepose_t bonepositions[bones]; +} +dpmframe_t; +// one or more of these per vertex +typedef struct dpmbonevert_s +{ + // this pairing of origin and influence is intentional + // (in SSE or 3DNow! assembly it can be done as a quad vector op + // (or two dual vector ops) very easily) + float origin[3]; // vertex location (these blend) + float influence; // influence fraction (these must add up to 1) + // this pairing of normal and bonenum is intentional + // (in SSE or 3DNow! assembly it can be done as a quad vector op + // (or two dual vector ops) very easily, the bonenum is ignored) + float normal[3]; // surface normal (these blend) + unsigned int bonenum; // number of the bone +} +dpmbonevert_t; +// variable size, parsed sequentially +typedef struct dpmvertex_s +{ + unsigned int numbones; + // immediately followed by 1 or more dpmbonevert_t structures +} +dpmvertex_t; + +#endif + diff --git a/app/jni/model_iqm.h b/app/jni/model_iqm.h new file mode 100644 index 0000000..1dbb940 --- /dev/null +++ b/app/jni/model_iqm.h @@ -0,0 +1,127 @@ +#ifndef __MODEL_IQM_H__ +#define __MODEL_IQM_H__ + +typedef struct iqmheader_s +{ + char id[16]; + unsigned int version; + unsigned int filesize; + unsigned int flags; + unsigned int num_text, ofs_text; + unsigned int num_meshes, ofs_meshes; + unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays; + unsigned int num_triangles, ofs_triangles, ofs_neighbors; + unsigned int num_joints, ofs_joints; + unsigned int num_poses, ofs_poses; + unsigned int num_anims, ofs_anims; + unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds; + unsigned int num_comment, ofs_comment; + unsigned int num_extensions, ofs_extensions; +} +iqmheader_t; + +typedef struct iqmmesh_s +{ + unsigned int name; + unsigned int material; + unsigned int first_vertex, num_vertexes; + unsigned int first_triangle, num_triangles; +} +iqmmesh_t; + +#define IQM_POSITION 0 +#define IQM_TEXCOORD 1 +#define IQM_NORMAL 2 +#define IQM_TANGENT 3 +#define IQM_BLENDINDEXES 4 +#define IQM_BLENDWEIGHTS 5 +#define IQM_COLOR 6 +#define IQM_CUSTOM 0x10 + +#define IQM_BYTE 0 +#define IQM_UBYTE 1 +#define IQM_SHORT 2 +#define IQM_USHORT 3 +#define IQM_INT 4 +#define IQM_UINT 5 +#define IQM_HALF 6 +#define IQM_FLOAT 7 +#define IQM_DOUBLE 8 + +// animflags +#define IQM_LOOP 1 + +typedef struct iqmtriangle_s +{ + unsigned int vertex[3]; +} +iqmtriangle_t; + +typedef struct iqmjoint1_s +{ + unsigned int name; + signed int parent; + float origin[3], rotation[3], scale[3]; +} +iqmjoint1_t; + +typedef struct iqmjoint_s +{ + unsigned int name; + signed int parent; + float origin[3], rotation[4], scale[3]; +} +iqmjoint_t; + +typedef struct iqmpose1_s +{ + signed int parent; + unsigned int channelmask; + float channeloffset[9], channelscale[9]; +} +iqmpose1_t; + +typedef struct iqmpose_s +{ + signed int parent; + unsigned int channelmask; + float channeloffset[10], channelscale[10]; +} +iqmpose_t; + +typedef struct iqmanim_s +{ + unsigned int name; + unsigned int first_frame, num_frames; + float framerate; + unsigned int flags; +} +iqmanim_t; + +typedef struct iqmvertexarray_s +{ + unsigned int type; + unsigned int flags; + unsigned int format; + unsigned int size; + unsigned int offset; +} +iqmvertexarray_t; + +typedef struct iqmextension_s +{ + unsigned int name; + unsigned int num_data, ofs_data; + unsigned int ofs_extensions; // pointer to next extension +} +iqmextension_t; + +typedef struct iqmbounds_s +{ + float mins[3], maxs[3]; + float xyradius, radius; +} +iqmbounds_t; + +#endif + diff --git a/app/jni/model_psk.h b/app/jni/model_psk.h new file mode 100644 index 0000000..480386f --- /dev/null +++ b/app/jni/model_psk.h @@ -0,0 +1,117 @@ + +#ifndef MODEL_PSK_H +#define MODEL_PSK_H + +typedef struct pskchunk_s +{ + // id is one of the following: + // .psk: + // ACTRHEAD (recordsize = 0, numrecords = 0) + // PNTS0000 (recordsize = 12, pskpnts_t) + // VTXW0000 (recordsize = 16, pskvtxw_t) + // FACE0000 (recordsize = 12, pskface_t) + // MATT0000 (recordsize = 88, pskmatt_t) + // REFSKELT (recordsize = 120, pskboneinfo_t) + // RAWWEIGHTS (recordsize = 12, pskrawweights_t) + // .psa: + // ANIMHEAD (recordsize = 0, numrecords = 0) + // BONENAMES (recordsize = 120, pskboneinfo_t) + // ANIMINFO (recordsize = 168, pskaniminfo_t) + // ANIMKEYS (recordsize = 32, pskanimkeys_t) + char id[20]; + // in .psk always 0x1e83b9 + // in .psa always 0x2e + int version; + int recordsize; + int numrecords; +} +pskchunk_t; + +typedef struct pskpnts_s +{ + float origin[3]; +} +pskpnts_t; + +typedef struct pskvtxw_s +{ + unsigned short pntsindex; // index into PNTS0000 chunk + unsigned char unknown1[2]; // seems to be garbage + float texcoord[2]; + unsigned char mattindex; // index into MATT0000 chunk + unsigned char unknown2; // always 0? + unsigned char unknown3[2]; // seems to be garbage +} +pskvtxw_t; + +typedef struct pskface_s +{ + unsigned short vtxwindex[3]; // triangle + unsigned char mattindex; // index into MATT0000 chunk + unsigned char unknown; // seems to be garbage + unsigned int group; // faces seem to be grouped, possibly for smoothing? +} +pskface_t; + +typedef struct pskmatt_s +{ + char name[64]; + int unknown[6]; // observed 0 0 0 0 5 0 +} +pskmatt_t; + +typedef struct pskpose_s +{ + float quat[4]; + float origin[3]; + float unknown; // probably a float, always seems to be 0 + float size[3]; +} +pskpose_t; + +typedef struct pskboneinfo_s +{ + char name[64]; + int unknown1; + int numchildren; + int parent; // root bones have 0 here + pskpose_t basepose; +} +pskboneinfo_t; + +typedef struct pskrawweights_s +{ + float weight; + int pntsindex; + int boneindex; +} +pskrawweights_t; + +typedef struct pskaniminfo_s +{ + char name[64]; + char group[64]; + int numbones; + int unknown1; + int unknown2; + int unknown3; + float unknown4; + float playtime; // not really needed + float fps; // frames per second + int unknown5; + int firstframe; + int numframes; + // firstanimkeys = (firstframe + frameindex) * numbones +} +pskaniminfo_t; + +typedef struct pskanimkeys_s +{ + float origin[3]; + float quat[4]; + float frametime; +} +pskanimkeys_t; + +#endif + diff --git a/app/jni/model_shared.c b/app/jni/model_shared.c new file mode 100644 index 0000000..5c87e3d --- /dev/null +++ b/app/jni/model_shared.c @@ -0,0 +1,4474 @@ +/* +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 "image.h" +#include "r_shadow.h" +#include "polygon.h" + +cvar_t r_enableshadowvolumes = {CVAR_SAVE, "r_enableshadowvolumes", "1", "Enables use of Stencil Shadow Volume shadowing methods, saves some memory if turned off"}; +cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"}; +cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"}; +cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"}; +cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"}; +cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"}; +cvar_t mod_generatelightmaps_lightmapsamples = {CVAR_SAVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"}; +cvar_t mod_generatelightmaps_vertexsamples = {CVAR_SAVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"}; +cvar_t mod_generatelightmaps_gridsamples = {CVAR_SAVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"}; +cvar_t mod_generatelightmaps_lightmapradius = {CVAR_SAVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"}; +cvar_t mod_generatelightmaps_vertexradius = {CVAR_SAVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"}; +cvar_t mod_generatelightmaps_gridradius = {CVAR_SAVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"}; + +dp_model_t *loadmodel; + +static mempool_t *mod_mempool; +static memexpandablearray_t models; + +static mempool_t* q3shaders_mem; +typedef struct q3shader_hash_entry_s +{ + q3shaderinfo_t shader; + struct q3shader_hash_entry_s* chain; +} q3shader_hash_entry_t; +#define Q3SHADER_HASH_SIZE 1021 +typedef struct q3shader_data_s +{ + memexpandablearray_t hash_entries; + q3shader_hash_entry_t hash[Q3SHADER_HASH_SIZE]; + memexpandablearray_t char_ptrs; +} q3shader_data_t; +static q3shader_data_t* q3shader_data; + +static void mod_start(void) +{ + int i, count; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + + SCR_PushLoadingScreen(false, "Loading models", 1.0); + count = 0; + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + if (mod->used) + ++count; + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + if (mod->used) + { + SCR_PushLoadingScreen(true, mod->name, 1.0 / count); + Mod_LoadModel(mod, true, false); + SCR_PopLoadingScreen(false); + } + SCR_PopLoadingScreen(false); +} + +static void mod_shutdown(void) +{ + int i; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool)) + Mod_UnloadModel(mod); + + Mod_FreeQ3Shaders(); + Mod_Skeletal_FreeBuffers(); +} + +static void mod_newmap(void) +{ + msurface_t *surface; + int i, j, k, surfacenum, ssize, tsize; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + + for (i = 0;i < nummodels;i++) + { + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool) + { + for (j = 0;j < mod->num_textures && mod->data_textures;j++) + { + for (k = 0;k < mod->data_textures[j].numskinframes;k++) + R_SkinFrame_MarkUsed(mod->data_textures[j].skinframes[k]); + for (k = 0;k < mod->data_textures[j].backgroundnumskinframes;k++) + R_SkinFrame_MarkUsed(mod->data_textures[j].backgroundskinframes[k]); + } + if (mod->brush.solidskyskinframe) + R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe); + if (mod->brush.alphaskyskinframe) + R_SkinFrame_MarkUsed(mod->brush.alphaskyskinframe); + } + } + + if (!cl_stainmaps_clearonload.integer) + return; + + for (i = 0;i < nummodels;i++) + { + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces) + { + for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++) + { + if (surface->lightmapinfo && surface->lightmapinfo->stainsamples) + { + ssize = (surface->lightmapinfo->extents[0] >> 4) + 1; + tsize = (surface->lightmapinfo->extents[1] >> 4) + 1; + memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3); + mod->brushq1.lightmapupdateflags[surfacenum] = true; + } + } + } + } +} + +/* +=============== +Mod_Init +=============== +*/ +static void Mod_Print(void); +static void Mod_Precache (void); +static void Mod_Decompile_f(void); +static void Mod_GenerateLightmaps_f(void); +void Mod_Init (void) +{ + mod_mempool = Mem_AllocPool("modelinfo", 0, NULL); + Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16); + + Mod_BrushInit(); + Mod_AliasInit(); + Mod_SpriteInit(); + + Cvar_RegisterVariable(&r_enableshadowvolumes); + Cvar_RegisterVariable(&r_mipskins); + Cvar_RegisterVariable(&r_mipnormalmaps); + Cvar_RegisterVariable(&mod_generatelightmaps_unitspersample); + Cvar_RegisterVariable(&mod_generatelightmaps_borderpixels); + Cvar_RegisterVariable(&mod_generatelightmaps_texturesize); + + Cvar_RegisterVariable(&mod_generatelightmaps_lightmapsamples); + Cvar_RegisterVariable(&mod_generatelightmaps_vertexsamples); + Cvar_RegisterVariable(&mod_generatelightmaps_gridsamples); + Cvar_RegisterVariable(&mod_generatelightmaps_lightmapradius); + Cvar_RegisterVariable(&mod_generatelightmaps_vertexradius); + Cvar_RegisterVariable(&mod_generatelightmaps_gridradius); + + Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models"); + Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model"); + Cmd_AddCommand ("modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes"); + Cmd_AddCommand ("mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel"); +} + +void Mod_RenderInit(void) +{ + R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL); +} + +void Mod_UnloadModel (dp_model_t *mod) +{ + char name[MAX_QPATH]; + qboolean used; + dp_model_t *parentmodel; + + if (developer_loading.integer) + Con_Printf("unloading model %s\n", mod->name); + + strlcpy(name, mod->name, sizeof(name)); + parentmodel = mod->brush.parentmodel; + used = mod->used; + if (mod->mempool) + { + if (mod->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer); + mod->surfmesh.data_element3i_indexbuffer = NULL; + if (mod->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer); + mod->surfmesh.data_element3s_indexbuffer = NULL; + if (mod->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer); + mod->surfmesh.vbo_vertexbuffer = NULL; + } + // free textures/memory attached to the model + R_FreeTexturePool(&mod->texturepool); + Mem_FreePool(&mod->mempool); + // clear the struct to make it available + memset(mod, 0, sizeof(dp_model_t)); + // restore the fields we want to preserve + strlcpy(mod->name, name, sizeof(mod->name)); + mod->brush.parentmodel = parentmodel; + mod->used = used; + mod->loaded = false; +} + +static void R_Model_Null_Draw(entity_render_t *ent) +{ + return; +} + + +typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass); + +static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass) +{ + const char *bufptr; + int start, len; + float fps; + unsigned int i; + qboolean loop; + char name[64]; + + bufptr = buf; + i = 0; + while(bufptr) + { + // an anim scene! + + // REQUIRED: fetch start + COM_ParseToken_Simple(&bufptr, true, false, true); + if (!bufptr) + break; // end of file + if (!strcmp(com_token, "\n")) + continue; // empty line + start = atoi(com_token); + + // REQUIRED: fetch length + COM_ParseToken_Simple(&bufptr, true, false, true); + if (!bufptr || !strcmp(com_token, "\n")) + { + Con_Printf("framegroups file: missing number of frames\n"); + continue; + } + len = atoi(com_token); + + // OPTIONAL args start + COM_ParseToken_Simple(&bufptr, true, false, true); + + // OPTIONAL: fetch fps + fps = 20; + if (bufptr && strcmp(com_token, "\n")) + { + fps = atof(com_token); + COM_ParseToken_Simple(&bufptr, true, false, true); + } + + // OPTIONAL: fetch loopflag + loop = true; + if (bufptr && strcmp(com_token, "\n")) + { + loop = (atoi(com_token) != 0); + COM_ParseToken_Simple(&bufptr, true, false, true); + } + + // OPTIONAL: fetch name + name[0] = 0; + if (bufptr && strcmp(com_token, "\n")) + { + strlcpy(name, com_token, sizeof(name)); + COM_ParseToken_Simple(&bufptr, true, false, true); + } + + // OPTIONAL: remaining unsupported tokens (eat them) + while (bufptr && strcmp(com_token, "\n")) + COM_ParseToken_Simple(&bufptr, true, false, true); + + //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name); + + if(cb) + cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass); + ++i; + } + + return i; +} + +static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass) +{ + dp_model_t *mod = (dp_model_t *) pass; + animscene_t *anim = &mod->animscenes[i]; + if(name) + strlcpy(anim->name, name, sizeof(anim[i].name)); + else + dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i); + anim->firstframe = bound(0, start, mod->num_poses - 1); + anim->framecount = bound(1, len, mod->num_poses - anim->firstframe); + anim->framerate = max(1, fps); + anim->loop = !!loop; + //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop); +} + +static void Mod_FrameGroupify(dp_model_t *mod, const char *buf) +{ + unsigned int cnt; + + // 0. count + cnt = Mod_FrameGroupify_ParseGroups(buf, NULL, NULL); + if(!cnt) + { + Con_Printf("no scene found in framegroups file, aborting\n"); + return; + } + mod->numframes = cnt; + + // 1. reallocate + // (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay) + mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes); + + // 2. parse + Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod); +} + +static void Mod_FindPotentialDeforms(dp_model_t *mod) +{ + int i, j; + texture_t *texture; + mod->wantnormals = false; + mod->wanttangents = false; + for (i = 0;i < mod->num_textures;i++) + { + texture = mod->data_textures + i; + if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT) + mod->wantnormals = true; + for (j = 0;j < Q3MAXDEFORMS;j++) + { + if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE) + { + mod->wanttangents = true; + mod->wantnormals = true; + break; + } + if (texture->deforms[j].deform != Q3DEFORM_NONE) + mod->wantnormals = true; + } + } +} + +/* +================== +Mod_LoadModel + +Loads a model +================== +*/ +dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk) +{ + int num; + unsigned int crc; + void *buf; + fs_offset_t filesize = 0; + char vabuf[1024]; + + mod->used = true; + + if (mod->name[0] == '*') // submodel + return mod; + + if (!strcmp(mod->name, "null")) + { + if(mod->loaded) + return mod; + + if (mod->loaded || mod->mempool) + Mod_UnloadModel(mod); + + if (developer_loading.integer) + Con_Printf("loading model %s\n", mod->name); + + mod->used = true; + mod->crc = (unsigned int)-1; + mod->loaded = false; + + VectorClear(mod->normalmins); + VectorClear(mod->normalmaxs); + VectorClear(mod->yawmins); + VectorClear(mod->yawmaxs); + VectorClear(mod->rotatedmins); + VectorClear(mod->rotatedmaxs); + + mod->modeldatatypestring = "null"; + mod->type = mod_null; + mod->Draw = R_Model_Null_Draw; + mod->numframes = 2; + mod->numskins = 1; + + // no fatal errors occurred, so this model is ready to use. + mod->loaded = true; + + return mod; + } + + crc = 0; + buf = NULL; + + // even if the model is loaded it still may need reloading... + + // if it is not loaded or checkdisk is true we need to calculate the crc + if (!mod->loaded || checkdisk) + { + if (checkdisk && mod->loaded) + Con_DPrintf("checking model %s\n", mod->name); + buf = FS_LoadFile (mod->name, tempmempool, false, &filesize); + if (buf) + { + crc = CRC_Block((unsigned char *)buf, filesize); + // we need to reload the model if the crc does not match + if (mod->crc != crc) + mod->loaded = false; + } + } + + // if the model is already loaded and checks passed, just return + if (mod->loaded) + { + if (buf) + Mem_Free(buf); + return mod; + } + + if (developer_loading.integer) + Con_Printf("loading model %s\n", mod->name); + + SCR_PushLoadingScreen(true, mod->name, 1); + + // LordHavoc: unload the existing model in this slot (if there is one) + if (mod->loaded || mod->mempool) + Mod_UnloadModel(mod); + + // load the model + mod->used = true; + mod->crc = crc; + // errors can prevent the corresponding mod->loaded = true; + mod->loaded = false; + + // default lightmap scale + mod->lightmapscale = 1; + + // default model radius and bounding box (mainly for missing models) + mod->radius = 16; + VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius); + VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius); + VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius); + VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius); + VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius); + VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius); + + if (!q3shaders_mem) + { + // load q3 shaders for the first time, or after a level change + Mod_LoadQ3Shaders(); + } + + if (buf) + { + char *bufend = (char *)buf + filesize; + + // all models use memory, so allocate a memory pool + mod->mempool = Mem_AllocPool(mod->name, 0, NULL); + + num = LittleLong(*((int *)buf)); + // call the apropriate loader + loadmodel = mod; + if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend); + else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend); + else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend); + else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend); + else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend); + else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend); + else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend); + else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend); + else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend); + else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); + Mem_Free(buf); + + Mod_FindPotentialDeforms(mod); + + buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize); + if(buf) + { + Mod_FrameGroupify(mod, (const char *)buf); + Mem_Free(buf); + } + + Mod_BuildVBOs(); + } + else if (crash) + { + // LordHavoc: Sys_Error was *ANNOYING* + Con_Printf ("Mod_LoadModel: %s not found\n", mod->name); + } + + // no fatal errors occurred, so this model is ready to use. + mod->loaded = true; + + SCR_PopLoadingScreen(false); + + return mod; +} + +void Mod_ClearUsed(void) +{ + int i; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0]) + mod->used = false; +} + +void Mod_PurgeUnused(void) +{ + int i; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + for (i = 0;i < nummodels;i++) + { + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used) + { + Mod_UnloadModel(mod); + Mem_ExpandableArray_FreeRecord(&models, mod); + } + } +} + +/* +================== +Mod_FindName + +================== +*/ +dp_model_t *Mod_FindName(const char *name, const char *parentname) +{ + int i; + int nummodels; + dp_model_t *mod; + + if (!parentname) + parentname = ""; + + // if we're not dedicatd, the renderer calls will crash without video + Host_StartVideo(); + + nummodels = Mem_ExpandableArray_IndexRange(&models); + + if (!name[0]) + Host_Error ("Mod_ForName: empty name"); + + // search the currently loaded models + for (i = 0;i < nummodels;i++) + { + if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname)))) + { + mod->used = true; + return mod; + } + } + + // no match found, create a new one + mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models); + strlcpy(mod->name, name, sizeof(mod->name)); + if (parentname[0]) + mod->brush.parentmodel = Mod_FindName(parentname, NULL); + else + mod->brush.parentmodel = NULL; + mod->loaded = false; + mod->used = true; + return mod; +} + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname) +{ + dp_model_t *model; + model = Mod_FindName(name, parentname); + if (!model->loaded || checkdisk) + Mod_LoadModel(model, crash, checkdisk); + return model; +} + +/* +================== +Mod_Reload + +Reloads all models if they have changed +================== +*/ +void Mod_Reload(void) +{ + int i, count; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + + SCR_PushLoadingScreen(false, "Reloading models", 1.0); + count = 0; + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) + ++count; + for (i = 0;i < nummodels;i++) + if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used) + { + SCR_PushLoadingScreen(true, mod->name, 1.0 / count); + Mod_LoadModel(mod, true, true); + SCR_PopLoadingScreen(false); + } + SCR_PopLoadingScreen(false); +} + +unsigned char *mod_base; + + +//============================================================================= + +/* +================ +Mod_Print +================ +*/ +static void Mod_Print(void) +{ + int i; + int nummodels = Mem_ExpandableArray_IndexRange(&models); + dp_model_t *mod; + + Con_Print("Loaded models:\n"); + for (i = 0;i < nummodels;i++) + { + if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*') + { + if (mod->brush.numsubmodels) + Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels); + else + Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name); + } + } +} + +/* +================ +Mod_Precache +================ +*/ +static void Mod_Precache(void) +{ + if (Cmd_Argc() == 2) + Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL); + else + Con_Print("usage: modelprecache \n"); +} + +int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices) +{ + int i, count; + unsigned char *used; + used = (unsigned char *)Mem_Alloc(tempmempool, numvertices); + memset(used, 0, numvertices); + for (i = 0;i < numelements;i++) + used[elements[i]] = 1; + for (i = 0, count = 0;i < numvertices;i++) + remapvertices[i] = used[i] ? count++ : -1; + Mem_Free(used); + return count; +} + +#if 1 +// fast way, using an edge hash +#define TRIANGLEEDGEHASH 8192 +void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles) +{ + int i, j, p, e1, e2, *n, hashindex, count, match; + const int *e; + typedef struct edgehashentry_s + { + struct edgehashentry_s *next; + int triangle; + int element[2]; + } + edgehashentry_t; + static edgehashentry_t **edgehash; + edgehashentry_t *edgehashentries, *hash; + if (!numtriangles) + return; + edgehash = (edgehashentry_t **)Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash)); + // if there are too many triangles for the stack array, allocate larger buffer + edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t)); + // find neighboring triangles + for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3) + { + for (j = 0, p = 2;j < 3;p = j, j++) + { + e1 = e[p]; + e2 = e[j]; + // this hash index works for both forward and backward edges + hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH; + hash = edgehashentries + i * 3 + j; + hash->next = edgehash[hashindex]; + edgehash[hashindex] = hash; + hash->triangle = i; + hash->element[0] = e1; + hash->element[1] = e2; + } + } + for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3) + { + for (j = 0, p = 2;j < 3;p = j, j++) + { + e1 = e[p]; + e2 = e[j]; + // this hash index works for both forward and backward edges + hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH; + count = 0; + match = -1; + for (hash = edgehash[hashindex];hash;hash = hash->next) + { + if (hash->element[0] == e2 && hash->element[1] == e1) + { + if (hash->triangle != i) + match = hash->triangle; + count++; + } + else if ((hash->element[0] == e1 && hash->element[1] == e2)) + count++; + } + // detect edges shared by three triangles and make them seams + if (count > 2) + match = -1; + n[p] = match; + } + + // also send a keepalive here (this can take a while too!) + CL_KeepaliveMessage(false); + } + // free the allocated buffer + Mem_Free(edgehashentries); + Mem_Free(edgehash); +} +#else +// very slow but simple way +static int Mod_FindTriangleWithEdge(const int *elements, int numtriangles, int start, int end, int ignore) +{ + int i, match, count; + count = 0; + match = -1; + for (i = 0;i < numtriangles;i++, elements += 3) + { + if ((elements[0] == start && elements[1] == end) + || (elements[1] == start && elements[2] == end) + || (elements[2] == start && elements[0] == end)) + { + if (i != ignore) + match = i; + count++; + } + else if ((elements[1] == start && elements[0] == end) + || (elements[2] == start && elements[1] == end) + || (elements[0] == start && elements[2] == end)) + count++; + } + // detect edges shared by three triangles and make them seams + if (count > 2) + match = -1; + return match; +} + +void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles) +{ + int i, *n; + const int *e; + for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3) + { + n[0] = Mod_FindTriangleWithEdge(elements, numtriangles, e[1], e[0], i); + n[1] = Mod_FindTriangleWithEdge(elements, numtriangles, e[2], e[1], i); + n[2] = Mod_FindTriangleWithEdge(elements, numtriangles, e[0], e[2], i); + } +} +#endif + +void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline) +{ + int i, warned = false, endvertex = firstvertex + numverts; + for (i = 0;i < numtriangles * 3;i++) + { + if (elements[i] < firstvertex || elements[i] >= endvertex) + { + if (!warned) + { + warned = true; + Con_Printf("Mod_ValidateElements: out of bounds elements detected at %s:%d\n", filename, fileline); + } + elements[i] = firstvertex; + } + } +} + +// warning: this is an expensive function! +void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting) +{ + int i, j; + const int *element; + float *vectorNormal; + float areaNormal[3]; + // clear the vectors + memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3])); + // process each vertex of each triangle and accumulate the results + // use area-averaging, to make triangles with a big area have a bigger + // weighting on the vertex normal than triangles with a small area + // to do so, just add the 'normals' together (the bigger the area + // the greater the length of the normal is + element = elements; + for (i = 0; i < numtriangles; i++, element += 3) + { + TriangleNormal( + vertex3f + element[0] * 3, + vertex3f + element[1] * 3, + vertex3f + element[2] * 3, + areaNormal + ); + + if (!areaweighting) + VectorNormalize(areaNormal); + + for (j = 0;j < 3;j++) + { + vectorNormal = normal3f + element[j] * 3; + vectorNormal[0] += areaNormal[0]; + vectorNormal[1] += areaNormal[1]; + vectorNormal[2] += areaNormal[2]; + } + } + // and just normalize the accumulated vertex normal in the end + vectorNormal = normal3f + 3 * firstvertex; + for (i = 0; i < numvertices; i++, vectorNormal += 3) + VectorNormalize(vectorNormal); +} + +#if 0 +static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f) +{ + float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; + // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles + // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates + + // 6 multiply, 9 subtract + VectorSubtract(v1, v0, v10); + VectorSubtract(v2, v0, v20); + normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1]; + normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2]; + normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0]; + // 12 multiply, 10 subtract + tc10[1] = tc1[1] - tc0[1]; + tc20[1] = tc2[1] - tc0[1]; + svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0]; + svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1]; + svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2]; + tc10[0] = tc1[0] - tc0[0]; + tc20[0] = tc2[0] - tc0[0]; + tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0]; + tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1]; + tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2]; + // 12 multiply, 4 add, 6 subtract + f = DotProduct(svector3f, normal3f); + svector3f[0] -= f * normal3f[0]; + svector3f[1] -= f * normal3f[1]; + svector3f[2] -= f * normal3f[2]; + f = DotProduct(tvector3f, normal3f); + tvector3f[0] -= f * normal3f[0]; + tvector3f[1] -= f * normal3f[1]; + tvector3f[2] -= f * normal3f[2]; + // if texture is mapped the wrong way (counterclockwise), the tangents + // have to be flipped, this is detected by calculating a normal from the + // two tangents, and seeing if it is opposite the surface normal + // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates + CrossProduct(tvector3f, svector3f, tangentcross); + if (DotProduct(tangentcross, normal3f) < 0) + { + VectorNegate(svector3f, svector3f); + VectorNegate(tvector3f, tvector3f); + } +} +#endif + +// warning: this is a very expensive function! +void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting) +{ + int i, tnum; + float sdir[3], tdir[3], normal[3], *sv, *tv; + const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n; + float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2]; + const int *e; + // clear the vectors + memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3])); + memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3])); + // process each vertex of each triangle and accumulate the results + for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3) + { + v0 = vertex3f + e[0] * 3; + v1 = vertex3f + e[1] * 3; + v2 = vertex3f + e[2] * 3; + tc0 = texcoord2f + e[0] * 2; + tc1 = texcoord2f + e[1] * 2; + tc2 = texcoord2f + e[2] * 2; + + // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles + // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates + + // calculate the edge directions and surface normal + // 6 multiply, 9 subtract + VectorSubtract(v1, v0, v10); + VectorSubtract(v2, v0, v20); + normal[0] = v20[1] * v10[2] - v20[2] * v10[1]; + normal[1] = v20[2] * v10[0] - v20[0] * v10[2]; + normal[2] = v20[0] * v10[1] - v20[1] * v10[0]; + + // calculate the tangents + // 12 multiply, 10 subtract + tc10[1] = tc1[1] - tc0[1]; + tc20[1] = tc2[1] - tc0[1]; + sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0]; + sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1]; + sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2]; + tc10[0] = tc1[0] - tc0[0]; + tc20[0] = tc2[0] - tc0[0]; + tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0]; + tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1]; + tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2]; + + // if texture is mapped the wrong way (counterclockwise), the tangents + // have to be flipped, this is detected by calculating a normal from the + // two tangents, and seeing if it is opposite the surface normal + // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates + CrossProduct(tdir, sdir, tangentcross); + if (DotProduct(tangentcross, normal) < 0) + { + VectorNegate(sdir, sdir); + VectorNegate(tdir, tdir); + } + + if (!areaweighting) + { + VectorNormalize(sdir); + VectorNormalize(tdir); + } + for (i = 0;i < 3;i++) + { + VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3); + VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3); + } + } + // make the tangents completely perpendicular to the surface normal, and + // then normalize them + // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies + for (i = 0, sv = svector3f + 3 * firstvertex, tv = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, sv += 3, tv += 3, n += 3) + { + f = -DotProduct(sv, n); + VectorMA(sv, f, n, sv); + VectorNormalize(sv); + f = -DotProduct(tv, n); + VectorMA(tv, f, n, tv); + VectorNormalize(tv); + } +} + +void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors) +{ + unsigned char *data; + data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * (3 + (neighbors ? 3 : 0)) * sizeof(int) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0)); + loadmodel->surfmesh.num_vertices = numvertices; + loadmodel->surfmesh.num_triangles = numtriangles; + if (loadmodel->surfmesh.num_vertices) + { + loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices; + loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices; + loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices; + loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices; + loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices; + loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices; + if (vertexcolors) + loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices; + if (lightmapoffsets) + loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices; + } + if (loadmodel->surfmesh.num_triangles) + { + loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles; + if (neighbors) + loadmodel->surfmesh.data_neighbor3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles; + if (loadmodel->surfmesh.num_vertices <= 65536) + loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles; + } +} + +shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable) +{ + shadowmesh_t *newmesh; + unsigned char *data; + int size; + size = sizeof(shadowmesh_t); + size += maxverts * sizeof(float[3]); + if (light) + size += maxverts * sizeof(float[11]); + size += maxtriangles * sizeof(int[3]); + if (maxverts <= 65536) + size += maxtriangles * sizeof(unsigned short[3]); + if (neighbors) + size += maxtriangles * sizeof(int[3]); + if (expandable) + size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t); + data = (unsigned char *)Mem_Alloc(mempool, size); + newmesh = (shadowmesh_t *)data;data += sizeof(*newmesh); + newmesh->map_diffuse = map_diffuse; + newmesh->map_specular = map_specular; + newmesh->map_normal = map_normal; + newmesh->maxverts = maxverts; + newmesh->maxtriangles = maxtriangles; + newmesh->numverts = 0; + newmesh->numtriangles = 0; + memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets)); + memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals)); + + newmesh->vertex3f = (float *)data;data += maxverts * sizeof(float[3]); + if (light) + { + newmesh->svector3f = (float *)data;data += maxverts * sizeof(float[3]); + newmesh->tvector3f = (float *)data;data += maxverts * sizeof(float[3]); + newmesh->normal3f = (float *)data;data += maxverts * sizeof(float[3]); + newmesh->texcoord2f = (float *)data;data += maxverts * sizeof(float[2]); + } + newmesh->element3i = (int *)data;data += maxtriangles * sizeof(int[3]); + if (neighbors) + { + newmesh->neighbor3i = (int *)data;data += maxtriangles * sizeof(int[3]); + } + if (expandable) + { + newmesh->vertexhashtable = (shadowmeshvertexhash_t **)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *); + newmesh->vertexhashentries = (shadowmeshvertexhash_t *)data;data += maxverts * sizeof(shadowmeshvertexhash_t); + } + if (maxverts <= 65536) + newmesh->element3s = (unsigned short *)data;data += maxtriangles * sizeof(unsigned short[3]); + return newmesh; +} + +shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors) +{ + shadowmesh_t *newmesh; + newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, neighbors, false); + newmesh->numverts = oldmesh->numverts; + newmesh->numtriangles = oldmesh->numtriangles; + memcpy(newmesh->sideoffsets, oldmesh->sideoffsets, sizeof(oldmesh->sideoffsets)); + memcpy(newmesh->sidetotals, oldmesh->sidetotals, sizeof(oldmesh->sidetotals)); + + memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3])); + if (newmesh->svector3f && oldmesh->svector3f) + { + memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3])); + memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3])); + memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3])); + memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2])); + } + memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3])); + if (newmesh->neighbor3i && oldmesh->neighbor3i) + memcpy(newmesh->neighbor3i, oldmesh->neighbor3i, oldmesh->numtriangles * sizeof(int[3])); + return newmesh; +} + +int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f) +{ + int hashindex, vnum; + shadowmeshvertexhash_t *hash; + // this uses prime numbers intentionally + hashindex = (unsigned int) (vertex14f[0] * 2003 + vertex14f[1] * 4001 + vertex14f[2] * 7919) % SHADOWMESHVERTEXHASH; + for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next) + { + vnum = (hash - mesh->vertexhashentries); + if ((mesh->vertex3f == NULL || (mesh->vertex3f[vnum * 3 + 0] == vertex14f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex14f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex14f[2])) + && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5])) + && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8])) + && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11])) + && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13]))) + return hash - mesh->vertexhashentries; + } + vnum = mesh->numverts++; + hash = mesh->vertexhashentries + vnum; + hash->next = mesh->vertexhashtable[hashindex]; + mesh->vertexhashtable[hashindex] = hash; + if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];} + if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];} + if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];} + if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];} + if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];} + return vnum; +} + +void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f) +{ + if (mesh->numtriangles == 0) + { + // set the properties on this empty mesh to be more favorable... + // (note: this case only occurs for the first triangle added to a new mesh chain) + mesh->map_diffuse = map_diffuse; + mesh->map_specular = map_specular; + mesh->map_normal = map_normal; + } + while (mesh->map_diffuse != map_diffuse || mesh->map_specular != map_specular || mesh->map_normal != map_normal || mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles) + { + if (mesh->next == NULL) + mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, mesh->neighbor3i != NULL, true); + mesh = mesh->next; + } + mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0); + mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1); + mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2); + mesh->numtriangles++; +} + +void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i) +{ + int i, j, e; + float vbuf[3*14], *v; + memset(vbuf, 0, sizeof(vbuf)); + for (i = 0;i < numtris;i++) + { + for (j = 0, v = vbuf;j < 3;j++, v += 14) + { + e = *element3i++; + if (vertex3f) + { + v[0] = vertex3f[e * 3 + 0]; + v[1] = vertex3f[e * 3 + 1]; + v[2] = vertex3f[e * 3 + 2]; + } + if (svector3f) + { + v[3] = svector3f[e * 3 + 0]; + v[4] = svector3f[e * 3 + 1]; + v[5] = svector3f[e * 3 + 2]; + } + if (tvector3f) + { + v[6] = tvector3f[e * 3 + 0]; + v[7] = tvector3f[e * 3 + 1]; + v[8] = tvector3f[e * 3 + 2]; + } + if (normal3f) + { + v[9] = normal3f[e * 3 + 0]; + v[10] = normal3f[e * 3 + 1]; + v[11] = normal3f[e * 3 + 2]; + } + if (texcoord2f) + { + v[12] = texcoord2f[e * 2 + 0]; + v[13] = texcoord2f[e * 2 + 1]; + } + } + Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf); + } + + // the triangle calculation can take a while, so let's do a keepalive here + CL_KeepaliveMessage(false); +} + +shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable) +{ + // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here + CL_KeepaliveMessage(false); + + return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable); +} + +static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool) +{ + if (!mesh->numverts) + return; + + // build r_vertexmesh_t array + // (compressed interleaved array for D3D) + if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays) + { + int vertexindex; + int numvertices = mesh->numverts; + r_vertexmesh_t *vertexmesh; + mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(mempool, numvertices * sizeof(*mesh->vertexmesh)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + } + } + + // upload short indices as a buffer + if (mesh->element3s && !mesh->element3s_indexbuffer) + mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, false, true); + + // upload int indices as a buffer + if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s) + mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false, false); + + // vertex buffer is several arrays and we put them in the same buffer + // + // is this wise? the texcoordtexture2f array is used with dynamic + // vertex/svector/tvector/normal when rendering animated models, on the + // other hand animated models don't use a lot of vertices anyway... + if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays) + { + size_t size; + unsigned char *mem; + size = 0; + mesh->vbooffset_vertexmesh = size;if (mesh->vertexmesh ) size += mesh->numverts * sizeof(r_vertexmesh_t); + mesh->vbooffset_vertex3f = size;if (mesh->vertex3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_svector3f = size;if (mesh->svector3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_tvector3f = size;if (mesh->tvector3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_normal3f = size;if (mesh->normal3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_texcoord2f = size;if (mesh->texcoord2f ) size += mesh->numverts * sizeof(float[2]); + mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (mesh->vertexmesh ) memcpy(mem + mesh->vbooffset_vertexmesh , mesh->vertexmesh , mesh->numverts * sizeof(r_vertexmesh_t)); + if (mesh->vertex3f ) memcpy(mem + mesh->vbooffset_vertex3f , mesh->vertex3f , mesh->numverts * sizeof(float[3])); + if (mesh->svector3f ) memcpy(mem + mesh->vbooffset_svector3f , mesh->svector3f , mesh->numverts * sizeof(float[3])); + if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3])); + if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3])); + if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2])); + mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false); + Mem_Free(mem); + } +} + +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo) +{ + shadowmesh_t *mesh, *newmesh, *nextmesh; + // reallocate meshs to conserve space + for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh) + { + nextmesh = mesh->next; + if (mesh->numverts >= 3 && mesh->numtriangles >= 1) + { + newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light, neighbors); + newmesh->next = firstmesh; + firstmesh = newmesh; + if (newmesh->element3s) + { + int i; + for (i = 0;i < newmesh->numtriangles*3;i++) + newmesh->element3s[i] = newmesh->element3i[i]; + } + if (createvbo) + Mod_ShadowMesh_CreateVBOs(newmesh, mempool); + } + Mem_Free(mesh); + } + + // this can take a while, so let's do a keepalive here + CL_KeepaliveMessage(false); + + return firstmesh; +} + +void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius) +{ + int i; + shadowmesh_t *mesh; + vec3_t nmins, nmaxs, ncenter, temp; + float nradius2, dist2, *v; + VectorClear(nmins); + VectorClear(nmaxs); + // calculate bbox + for (mesh = firstmesh;mesh;mesh = mesh->next) + { + if (mesh == firstmesh) + { + VectorCopy(mesh->vertex3f, nmins); + VectorCopy(mesh->vertex3f, nmaxs); + } + for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3) + { + if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0]; + if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1]; + if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2]; + } + } + // calculate center and radius + ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f; + ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f; + ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f; + nradius2 = 0; + for (mesh = firstmesh;mesh;mesh = mesh->next) + { + for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3) + { + VectorSubtract(v, ncenter, temp); + dist2 = DotProduct(temp, temp); + if (nradius2 < dist2) + nradius2 = dist2; + } + } + // return data + if (mins) + VectorCopy(nmins, mins); + if (maxs) + VectorCopy(nmaxs, maxs); + if (center) + VectorCopy(ncenter, center); + if (radius) + *radius = sqrt(nradius2); +} + +void Mod_ShadowMesh_Free(shadowmesh_t *mesh) +{ + shadowmesh_t *nextmesh; + for (;mesh;mesh = nextmesh) + { + if (mesh->element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer); + if (mesh->element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer); + if (mesh->vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer); + nextmesh = mesh->next; + Mem_Free(mesh); + } +} + +void Mod_CreateCollisionMesh(dp_model_t *mod) +{ + int k, numcollisionmeshtriangles; + qboolean usesinglecollisionmesh = false; + const msurface_t *surface = NULL; + + mempool_t *mempool = mod->mempool; + if (!mempool && mod->brush.parentmodel) + mempool = mod->brush.parentmodel->mempool; + // make a single combined collision mesh for physics engine use + // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface + numcollisionmeshtriangles = 0; + for (k = 0;k < mod->nummodelsurfaces;k++) + { + surface = mod->data_surfaces + mod->firstmodelsurface + k; + if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh + { + usesinglecollisionmesh = true; + numcollisionmeshtriangles = surface->num_triangles; + break; + } + if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) + continue; + numcollisionmeshtriangles += surface->num_triangles; + } + mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, false, true); + if (usesinglecollisionmesh) + Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + else + { + for (k = 0;k < mod->nummodelsurfaces;k++) + { + surface = mod->data_surfaces + mod->firstmodelsurface + k; + if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID)) + continue; + Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + } + } + mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false, false); +} + +#if 0 +static void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +{ + float v[3], tc[3]; + v[0] = ix; + v[1] = iy; + if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight) + v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f); + else + v[2] = 0; + Matrix4x4_Transform(pixelstepmatrix, v, vertex3f); + Matrix4x4_Transform(pixeltexturestepmatrix, v, tc); + texcoord2f[0] = tc[0]; + texcoord2f[1] = tc[1]; +} + +static void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +{ + float vup[3], vdown[3], vleft[3], vright[3]; + float tcup[3], tcdown[3], tcleft[3], tcright[3]; + float sv[3], tv[3], nl[3]; + Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix); + Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix); + Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix); + Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix); + Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix); + Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f); + Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl); + VectorAdd(svector3f, sv, svector3f); + VectorAdd(tvector3f, tv, tvector3f); + VectorAdd(normal3f, nl, normal3f); + Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl); + VectorAdd(svector3f, sv, svector3f); + VectorAdd(tvector3f, tv, tvector3f); + VectorAdd(normal3f, nl, normal3f); + Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl); + VectorAdd(svector3f, sv, svector3f); + VectorAdd(tvector3f, tv, tvector3f); + VectorAdd(normal3f, nl, normal3f); +} + +static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, int *neighbor3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix) +{ + int x, y, ix, iy, *e; + e = element3i; + for (y = 0;y < height;y++) + { + for (x = 0;x < width;x++) + { + e[0] = (y + 1) * (width + 1) + (x + 0); + e[1] = (y + 0) * (width + 1) + (x + 0); + e[2] = (y + 1) * (width + 1) + (x + 1); + e[3] = (y + 0) * (width + 1) + (x + 0); + e[4] = (y + 0) * (width + 1) + (x + 1); + e[5] = (y + 1) * (width + 1) + (x + 1); + e += 6; + } + } + Mod_BuildTriangleNeighbors(neighbor3i, element3i, width*height*2); + for (y = 0, iy = y1;y < height + 1;y++, iy++) + for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3) + Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix); +} +#endif + +#if 0 +void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y) +{ + float mins[3]; + float maxs[3]; + float chunkwidth = min(stepsize, model->terrain.width - 1 - x); + float chunkheight = min(stepsize, model->terrain.height - 1 - y); + float viewvector[3]; + unsigned int firstvertex; + unsigned int *e; + float *v; + if (chunkwidth < 2 || chunkheight < 2) + return; + VectorSet(mins, model->terrain.mins[0] + x * stepsize * model->terrain.scale[0], model->terrain.mins[1] + y * stepsize * model->terrain.scale[1], model->terrain.mins[2]); + VectorSet(maxs, model->terrain.mins[0] + (x+1) * stepsize * model->terrain.scale[0], model->terrain.mins[1] + (y+1) * stepsize * model->terrain.scale[1], model->terrain.maxs[2]); + viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0]; + viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1]; + viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2]; + if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value) + { + // too close for this stepsize, emit as 4 chunks instead + stepsize /= 2; + Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y); + Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y); + Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize); + Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize); + return; + } + // emit the geometry at stepsize into our vertex buffer / index buffer + // we add two columns and two rows for skirt + outwidth = chunkwidth+2; + outheight = chunkheight+2; + outwidth2 = outwidth-1; + outheight2 = outheight-1; + outwidth3 = outwidth+1; + outheight3 = outheight+1; + firstvertex = numvertices; + e = model->terrain.element3i + numtriangles; + numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2; + v = model->terrain.vertex3f + numvertices; + numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2; + // emit the triangles (note: the skirt is treated as two extra rows and two extra columns) + for (ty = 0;ty < outheight;ty++) + { + for (tx = 0;tx < outwidth;tx++) + { + *e++ = firstvertex + (ty )*outwidth3+(tx ); + *e++ = firstvertex + (ty )*outwidth3+(tx+1); + *e++ = firstvertex + (ty+1)*outwidth3+(tx+1); + *e++ = firstvertex + (ty )*outwidth3+(tx ); + *e++ = firstvertex + (ty+1)*outwidth3+(tx+1); + *e++ = firstvertex + (ty+1)*outwidth3+(tx ); + } + } + // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize) + for (ty = 0;ty <= outheight;ty++) + { + skirtrow = ty == 0 || ty == outheight; + ry = y+bound(1, ty, outheight)*stepsize; + for (tx = 0;tx <= outwidth;tx++) + { + skirt = skirtrow || tx == 0 || tx == outwidth; + rx = x+bound(1, tx, outwidth)*stepsize; + v[0] = rx*scale[0]; + v[1] = ry*scale[1]; + v[2] = heightmap[ry*terrainwidth+rx]*scale[2]; + v += 3; + } + } + // TODO: emit skirt vertices +} + +void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model) +{ + for (y = 0;y < model->terrain.size[1];y += model->terrain. + Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y); + Mod_Terrain_BuildChunk(model, +} +#endif + +static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s) +{ + int offset = 0; + if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always userfunc + { + offset = bound(0, s[4] - '0', 9); + offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT; + s += 4; + if(*s) + ++s; + } + if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN; + if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE; + if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE; + if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH; + if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH; + if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE; + if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE; + Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s); + return offset | Q3WAVEFUNC_NONE; +} + +void Mod_FreeQ3Shaders(void) +{ + Mem_FreePool(&q3shaders_mem); +} + +static void Q3Shader_AddToHash (q3shaderinfo_t* shader) +{ + unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name)); + q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE); + q3shader_hash_entry_t* lastEntry = NULL; + while (entry != NULL) + { + if (strcasecmp (entry->shader.name, shader->name) == 0) + { + // redeclaration + if(shader->dpshaderkill) + { + // killed shader is a redeclarion? we can safely ignore it + return; + } + else if(entry->shader.dpshaderkill) + { + // replace the old shader! + // this will skip the entry allocating part + // below and just replace the shader + break; + } + else + { + unsigned char *start, *end, *start2; + start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START); + end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END); + start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START); + if(memcmp(start, start2, end - start)) + Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name); + else + Con_DPrintf("Shader '%s' already defined\n", shader->name); + return; + } + } + lastEntry = entry; + entry = entry->chain; + } + if (entry == NULL) + { + if (lastEntry->shader.name[0] != 0) + { + /* Add to chain */ + q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*) + Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries); + + while (lastEntry->chain != NULL) lastEntry = lastEntry->chain; + lastEntry->chain = newEntry; + newEntry->chain = NULL; + lastEntry = newEntry; + } + /* else: head of chain, in hash entry array */ + entry = lastEntry; + } + memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t)); +} + +extern cvar_t mod_noshader_default_offsetmapping; +extern cvar_t mod_q3shader_default_offsetmapping; +extern cvar_t mod_q3shader_default_offsetmapping_scale; +extern cvar_t mod_q3shader_default_offsetmapping_bias; +extern cvar_t mod_q3shader_default_polygonoffset; +extern cvar_t mod_q3shader_default_polygonfactor; +extern cvar_t mod_q3shader_force_addalpha; +extern cvar_t mod_q3shader_force_terrain_alphaflag; +void Mod_LoadQ3Shaders(void) +{ + int j; + int fileindex; + fssearch_t *search; + char *f; + const char *text; + q3shaderinfo_t shader; + q3shaderinfo_layer_t *layer; + int numparameters; + char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH]; + char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more + unsigned long custsurfaceflags[256]; + int numcustsurfaceflags; + qboolean dpshaderkill; + + Mod_FreeQ3Shaders(); + + q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL); + q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem, + sizeof (q3shader_data_t)); + Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries, + q3shaders_mem, sizeof (q3shader_hash_entry_t), 256); + Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs, + q3shaders_mem, sizeof (char**), 256); + + // parse custinfoparms.txt + numcustsurfaceflags = 0; + if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL) + { + if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) + Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token); + else + { + while (COM_ParseToken_QuakeC(&text, false)) + if (!strcasecmp(com_token, "}")) + break; + // custom surfaceflags section + if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) + Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token); + else + { + while(COM_ParseToken_QuakeC(&text, false)) + { + if (!strcasecmp(com_token, "}")) + break; + // register surfaceflag + if (numcustsurfaceflags >= 256) + { + Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n"); + break; + } + // name + j = strlen(com_token)+1; + custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j); + strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1); + // value + if (COM_ParseToken_QuakeC(&text, false)) + custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0); + else + custsurfaceflags[numcustsurfaceflags] = 0; + numcustsurfaceflags++; + } + } + } + Mem_Free(f); + } + + // parse shaders + search = FS_Search("scripts/*.shader", true, false); + if (!search) + return; + for (fileindex = 0;fileindex < search->numfilenames;fileindex++) + { + text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL); + if (!f) + continue; + while (COM_ParseToken_QuakeC(&text, false)) + { + memset (&shader, 0, sizeof(shader)); + shader.name[0] = 0; + shader.surfaceparms = 0; + shader.surfaceflags = 0; + shader.textureflags = 0; + shader.numlayers = 0; + shader.lighting = false; + shader.vertexalpha = false; + shader.textureblendalpha = false; + shader.primarylayer = 0; + shader.backgroundlayer = 0; + shader.skyboxname[0] = 0; + shader.deforms[0].deform = Q3DEFORM_NONE; + shader.dpnortlight = false; + shader.dpshadow = false; + shader.dpnoshadow = false; + shader.dpmeshcollisions = false; + shader.dpshaderkill = false; + shader.dpreflectcube[0] = 0; + shader.reflectmin = 0; + shader.reflectmax = 1; + shader.refractfactor = 1; + Vector4Set(shader.refractcolor4f, 1, 1, 1, 1); + shader.reflectfactor = 1; + Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1); + shader.r_water_wateralpha = 1; + shader.r_water_waterscroll[0] = 0; + shader.r_water_waterscroll[1] = 0; + shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value; + shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value; + shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value; + shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value; + shader.transparentsort = TRANSPARENTSORT_DISTANCE; + shader.specularscalemod = 1; + shader.specularpowermod = 1; + shader.rtlightambient = 0; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". + + strlcpy(shader.name, com_token, sizeof(shader.name)); + if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) + { + Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token); + break; + } + while (COM_ParseToken_QuakeC(&text, false)) + { + if (!strcasecmp(com_token, "}")) + break; + if (!strcasecmp(com_token, "{")) + { + static q3shaderinfo_layer_t dummy; + if (shader.numlayers < Q3SHADER_MAXLAYERS) + { + layer = shader.layers + shader.numlayers++; + } + else + { + // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found) + memset(&dummy, 0, sizeof(dummy)); + layer = &dummy; + } + layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY; + layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY; + layer->tcgen.tcgen = Q3TCGEN_TEXTURE; + layer->blendfunc[0] = GL_ONE; + layer->blendfunc[1] = GL_ZERO; + while (COM_ParseToken_QuakeC(&text, false)) + { + if (!strcasecmp(com_token, "}")) + break; + if (!strcasecmp(com_token, "\n")) + continue; + numparameters = 0; + for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++) + { + if (j < TEXTURE_MAXFRAMES + 4) + { + // remap dp_water to dpwater, dp_reflect to dpreflect, etc. + if(j == 0 && !strncasecmp(com_token, "dp_", 3)) + dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); + else + strlcpy(parameter[j], com_token, sizeof(parameter[j])); + numparameters = j + 1; + } + if (!COM_ParseToken_QuakeC(&text, true)) + break; + } + //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++) + // parameter[j][0] = 0; + if (developer_insane.integer) + { + Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1); + for (j = 0;j < numparameters;j++) + Con_DPrintf(" %s", parameter[j]); + Con_DPrint("\n"); + } + if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc")) + { + if (numparameters == 2) + { + if (!strcasecmp(parameter[1], "add")) + { + layer->blendfunc[0] = GL_ONE; + layer->blendfunc[1] = GL_ONE; + } + else if (!strcasecmp(parameter[1], "addalpha")) + { + layer->blendfunc[0] = GL_SRC_ALPHA; + layer->blendfunc[1] = GL_ONE; + } + else if (!strcasecmp(parameter[1], "filter")) + { + layer->blendfunc[0] = GL_DST_COLOR; + layer->blendfunc[1] = GL_ZERO; + } + else if (!strcasecmp(parameter[1], "blend")) + { + layer->blendfunc[0] = GL_SRC_ALPHA; + layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA; + } + } + else if (numparameters == 3) + { + int k; + for (k = 0;k < 2;k++) + { + if (!strcasecmp(parameter[k+1], "GL_ONE")) + layer->blendfunc[k] = GL_ONE; + else if (!strcasecmp(parameter[k+1], "GL_ZERO")) + layer->blendfunc[k] = GL_ZERO; + else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR")) + layer->blendfunc[k] = GL_SRC_COLOR; + else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA")) + layer->blendfunc[k] = GL_SRC_ALPHA; + else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR")) + layer->blendfunc[k] = GL_DST_COLOR; + else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA")) + layer->blendfunc[k] = GL_DST_ALPHA; + else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR")) + layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR; + else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA")) + layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA; + else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR")) + layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR; + else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA")) + layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA; + else + layer->blendfunc[k] = GL_ONE; // default in case of parsing error + } + } + } + if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc")) + layer->alphatest = true; + if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap"))) + { + if (!strcasecmp(parameter[0], "clampmap")) + layer->clampmap = true; + layer->numframes = 1; + layer->framerate = 1; + layer->texturename = (char**)Mem_ExpandableArray_AllocRecord ( + &q3shader_data->char_ptrs); + layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]); + if (!strcasecmp(parameter[1], "$lightmap")) + shader.lighting = true; + } + else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap"))) + { + int i; + layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES); + layer->framerate = atof(parameter[1]); + layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes); + for (i = 0;i < layer->numframes;i++) + layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]); + } + else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen")) + { + int i; + for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++) + layer->rgbgen.parms[i] = atof(parameter[i+2]); + if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY; + else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST; + else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY; + else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX; + else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING; + else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE; + else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY; + else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX; + else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX; + else if (!strcasecmp(parameter[1], "wave")) + { + layer->rgbgen.rgbgen = Q3RGBGEN_WAVE; + layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]); + for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++) + layer->rgbgen.waveparms[i] = atof(parameter[i+3]); + } + else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]); + } + else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen")) + { + int i; + for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++) + layer->alphagen.parms[i] = atof(parameter[i+2]); + if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY; + else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST; + else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY; + else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR; + else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY; + else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX; + else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL; + else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX; + else if (!strcasecmp(parameter[1], "wave")) + { + layer->alphagen.alphagen = Q3ALPHAGEN_WAVE; + layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]); + for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++) + layer->alphagen.waveparms[i] = atof(parameter[i+3]); + } + else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]); + } + else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen"))) + { + int i; + // observed values: tcgen environment + // no other values have been observed in real shaders + for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++) + layer->tcgen.parms[i] = atof(parameter[i+2]); + if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE; + else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE; + else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT; + else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP; + else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR; + else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]); + } + else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod")) + { + int i, tcmodindex; + // observed values: + // tcmod rotate # + // tcmod scale # # + // tcmod scroll # # + // tcmod stretch sin # # # # + // tcmod stretch triangle # # # # + // tcmod transform # # # # # # + // tcmod turb # # # # + // tcmod turb sin # # # # (this is bogus) + // no other values have been observed in real shaders + for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++) + if (!layer->tcmods[tcmodindex].tcmod) + break; + if (tcmodindex < Q3MAXTCMODS) + { + for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++) + layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]); + if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE; + else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE; + else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE; + else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL; + else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE; + else if (!strcasecmp(parameter[1], "stretch")) + { + layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH; + layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]); + for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++) + layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]); + } + else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM; + else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT; + else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]); + } + else + Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]); + } + // break out a level if it was a closing brace (not using the character here to not confuse vim) + if (!strcasecmp(com_token, "}")) + break; + } + if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX) + shader.lighting = true; + if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX) + { + if (layer == shader.layers + 0) + { + // vertex controlled transparency + shader.vertexalpha = true; + } + else + { + // multilayer terrain shader or similar + shader.textureblendalpha = true; + if (mod_q3shader_force_terrain_alphaflag.integer) + shader.layers[0].texflags |= TEXF_ALPHA; + } + } + + if(mod_q3shader_force_addalpha.integer) + { + // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE + // this cvar brings back this behaviour + if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE) + layer->blendfunc[0] = GL_SRC_ALPHA; + } + + layer->texflags = 0; + if (layer->alphatest) + layer->texflags |= TEXF_ALPHA; + switch(layer->blendfunc[0]) + { + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + layer->texflags |= TEXF_ALPHA; + break; + } + switch(layer->blendfunc[1]) + { + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + layer->texflags |= TEXF_ALPHA; + break; + } + if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) + layer->texflags |= TEXF_MIPMAP; + if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP)) + layer->texflags |= TEXF_PICMIP | TEXF_COMPRESS; + if (layer->clampmap) + layer->texflags |= TEXF_CLAMP; + continue; + } + numparameters = 0; + for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++) + { + if (j < TEXTURE_MAXFRAMES + 4) + { + // remap dp_water to dpwater, dp_reflect to dpreflect, etc. + if(j == 0 && !strncasecmp(com_token, "dp_", 3)) + dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]); + else + strlcpy(parameter[j], com_token, sizeof(parameter[j])); + numparameters = j + 1; + } + if (!COM_ParseToken_QuakeC(&text, true)) + break; + } + //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++) + // parameter[j][0] = 0; + if (fileindex == 0 && !strcasecmp(com_token, "}")) + break; + if (developer_insane.integer) + { + Con_DPrintf("%s: ", shader.name); + for (j = 0;j < numparameters;j++) + Con_DPrintf(" %s", parameter[j]); + Con_DPrint("\n"); + } + if (numparameters < 1) + continue; + if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2) + { + if (!strcasecmp(parameter[1], "alphashadow")) + shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW; + else if (!strcasecmp(parameter[1], "areaportal")) + shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL; + else if (!strcasecmp(parameter[1], "botclip")) + shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP; + else if (!strcasecmp(parameter[1], "clusterportal")) + shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL; + else if (!strcasecmp(parameter[1], "detail")) + shader.surfaceparms |= Q3SURFACEPARM_DETAIL; + else if (!strcasecmp(parameter[1], "donotenter")) + shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER; + else if (!strcasecmp(parameter[1], "dust")) + shader.surfaceparms |= Q3SURFACEPARM_DUST; + else if (!strcasecmp(parameter[1], "hint")) + shader.surfaceparms |= Q3SURFACEPARM_HINT; + else if (!strcasecmp(parameter[1], "fog")) + shader.surfaceparms |= Q3SURFACEPARM_FOG; + else if (!strcasecmp(parameter[1], "lava")) + shader.surfaceparms |= Q3SURFACEPARM_LAVA; + else if (!strcasecmp(parameter[1], "lightfilter")) + shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER; + else if (!strcasecmp(parameter[1], "lightgrid")) + shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID; + else if (!strcasecmp(parameter[1], "metalsteps")) + shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS; + else if (!strcasecmp(parameter[1], "nodamage")) + shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE; + else if (!strcasecmp(parameter[1], "nodlight")) + shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT; + else if (!strcasecmp(parameter[1], "nodraw")) + shader.surfaceparms |= Q3SURFACEPARM_NODRAW; + else if (!strcasecmp(parameter[1], "nodrop")) + shader.surfaceparms |= Q3SURFACEPARM_NODROP; + else if (!strcasecmp(parameter[1], "noimpact")) + shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT; + else if (!strcasecmp(parameter[1], "nolightmap")) + shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP; + else if (!strcasecmp(parameter[1], "nomarks")) + shader.surfaceparms |= Q3SURFACEPARM_NOMARKS; + else if (!strcasecmp(parameter[1], "nomipmaps")) + shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS; + else if (!strcasecmp(parameter[1], "nonsolid")) + shader.surfaceparms |= Q3SURFACEPARM_NONSOLID; + else if (!strcasecmp(parameter[1], "origin")) + shader.surfaceparms |= Q3SURFACEPARM_ORIGIN; + else if (!strcasecmp(parameter[1], "playerclip")) + shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP; + else if (!strcasecmp(parameter[1], "sky")) + shader.surfaceparms |= Q3SURFACEPARM_SKY; + else if (!strcasecmp(parameter[1], "slick")) + shader.surfaceparms |= Q3SURFACEPARM_SLICK; + else if (!strcasecmp(parameter[1], "slime")) + shader.surfaceparms |= Q3SURFACEPARM_SLIME; + else if (!strcasecmp(parameter[1], "structural")) + shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL; + else if (!strcasecmp(parameter[1], "trans")) + shader.surfaceparms |= Q3SURFACEPARM_TRANS; + else if (!strcasecmp(parameter[1], "water")) + shader.surfaceparms |= Q3SURFACEPARM_WATER; + else if (!strcasecmp(parameter[1], "pointlight")) + shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT; + else if (!strcasecmp(parameter[1], "antiportal")) + shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL; + else if (!strcasecmp(parameter[1], "skip")) + ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway + else + { + // try custom surfaceparms + for (j = 0; j < numcustsurfaceflags; j++) + { + if (!strcasecmp(custsurfaceparmnames[j], parameter[1])) + { + shader.surfaceflags |= custsurfaceflags[j]; + break; + } + } + // failed all + if (j == numcustsurfaceflags) + Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]); + } + } + else if (!strcasecmp(parameter[0], "dpshadow")) + shader.dpshadow = true; + else if (!strcasecmp(parameter[0], "dpnoshadow")) + shader.dpnoshadow = true; + else if (!strcasecmp(parameter[0], "dpnortlight")) + shader.dpnortlight = true; + else if (!strcasecmp(parameter[0], "dpreflectcube")) + strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube)); + else if (!strcasecmp(parameter[0], "dpmeshcollisions")) + shader.dpmeshcollisions = true; + // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used + else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2) + { + if (Cvar_VariableValue(parameter[1]) == 0.0f) + shader.dpshaderkill = dpshaderkill; + } + // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used + else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2) + { + const char *op = NULL; + if (numparameters >= 3) + op = parameter[2]; + if(!op) + { + if (Cvar_VariableValue(parameter[1]) != 0.0f) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "==")) + { + if (Cvar_VariableValue(parameter[1]) == atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "!=")) + { + if (Cvar_VariableValue(parameter[1]) != atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, ">")) + { + if (Cvar_VariableValue(parameter[1]) > atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "<")) + { + if (Cvar_VariableValue(parameter[1]) < atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, ">=")) + { + if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else if (numparameters >= 4 && !strcmp(op, "<=")) + { + if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3])) + shader.dpshaderkill = dpshaderkill; + } + else + { + Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op); + } + } + else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2) + { + // some q3 skies don't have the sky parm set + shader.surfaceparms |= Q3SURFACEPARM_SKY; + strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); + } + else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2) + { + // some q3 skies don't have the sky parm set + shader.surfaceparms |= Q3SURFACEPARM_SKY; + if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-")) + strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname)); + } + else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2) + { + if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided")) + shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED; + } + else if (!strcasecmp(parameter[0], "nomipmaps")) + shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS; + else if (!strcasecmp(parameter[0], "nopicmip")) + shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP; + else if (!strcasecmp(parameter[0], "polygonoffset")) + shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET; + else if (!strcasecmp(parameter[0], "dppolygonoffset")) + { + shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET; + if(numparameters >= 2) + { + shader.biaspolygonfactor = atof(parameter[1]); + if(numparameters >= 3) + shader.biaspolygonoffset = atof(parameter[2]); + else + shader.biaspolygonoffset = 0; + } + } + else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2) + { + shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT; + if (!strcasecmp(parameter[1], "sky")) + shader.transparentsort = TRANSPARENTSORT_SKY; + else if (!strcasecmp(parameter[1], "distance")) + shader.transparentsort = TRANSPARENTSORT_DISTANCE; + else if (!strcasecmp(parameter[1], "hud")) + shader.transparentsort = TRANSPARENTSORT_HUD; + else + Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]); + } + else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5) + { + shader.textureflags |= Q3TEXTUREFLAG_REFRACTION; + shader.refractfactor = atof(parameter[1]); + Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1); + } + else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6) + { + shader.textureflags |= Q3TEXTUREFLAG_REFLECTION; + shader.reflectfactor = atof(parameter[1]); + Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5])); + } + else if (!strcasecmp(parameter[0], "dpcamera")) + { + shader.textureflags |= Q3TEXTUREFLAG_CAMERA; + } + else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12) + { + shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER; + shader.reflectmin = atof(parameter[1]); + shader.reflectmax = atof(parameter[2]); + shader.refractfactor = atof(parameter[3]); + shader.reflectfactor = atof(parameter[4]); + Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1); + Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1); + shader.r_water_wateralpha = atof(parameter[11]); + } + else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3) + { + shader.r_water_waterscroll[0] = 1/atof(parameter[1]); + shader.r_water_waterscroll[1] = 1/atof(parameter[2]); + } + else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2) + { + shader.specularscalemod = atof(parameter[1]); + } + else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2) + { + shader.specularpowermod = atof(parameter[1]); + } + else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2) + { + shader.rtlightambient = atof(parameter[1]); + } + else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2) + { + if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off")) + shader.offsetmapping = OFFSETMAPPING_OFF; + else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal")) + shader.offsetmapping = OFFSETMAPPING_DEFAULT; + else if (!strcasecmp(parameter[1], "linear")) + shader.offsetmapping = OFFSETMAPPING_LINEAR; + else if (!strcasecmp(parameter[1], "relief")) + shader.offsetmapping = OFFSETMAPPING_RELIEF; + if (numparameters >= 3) + shader.offsetscale = atof(parameter[2]); + if (numparameters >= 5) + { + if(!strcasecmp(parameter[3], "bias")) + shader.offsetbias = atof(parameter[4]); + else if(!strcasecmp(parameter[3], "match")) + shader.offsetbias = 1.0f - atof(parameter[4]); + else if(!strcasecmp(parameter[3], "match8")) + shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f; + else if(!strcasecmp(parameter[3], "match16")) + shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f; + } + } + else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2) + { + int i, deformindex; + for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++) + if (!shader.deforms[deformindex].deform) + break; + if (deformindex < Q3MAXDEFORMS) + { + for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++) + shader.deforms[deformindex].parms[i] = atof(parameter[i+2]); + if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW; + else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE; + else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2; + else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0; + else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1; + else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2; + else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3; + else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4; + else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5; + else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6; + else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7; + else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE; + else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL; + else if (!strcasecmp(parameter[1], "wave" )) + { + shader.deforms[deformindex].deform = Q3DEFORM_WAVE; + shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]); + for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++) + shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]); + } + else if (!strcasecmp(parameter[1], "move" )) + { + shader.deforms[deformindex].deform = Q3DEFORM_MOVE; + shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]); + for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++) + shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]); + } + } + } + } + // hide this shader if a cvar said it should be killed + if (shader.dpshaderkill) + shader.numlayers = 0; + // pick the primary layer to render with + if (shader.numlayers) + { + shader.backgroundlayer = -1; + shader.primarylayer = 0; + // if lightmap comes first this is definitely an ordinary texture + // if the first two layers have the correct blendfuncs and use vertex alpha, it is a blended terrain shader + if ((shader.layers[shader.primarylayer].texturename != NULL) + && !strcasecmp(shader.layers[shader.primarylayer].texturename[0], "$lightmap")) + { + shader.backgroundlayer = -1; + shader.primarylayer = 1; + } + else if (shader.numlayers >= 2 + && shader.layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX + && (shader.layers[0].blendfunc[0] == GL_ONE && shader.layers[0].blendfunc[1] == GL_ZERO && !shader.layers[0].alphatest) + && ((shader.layers[1].blendfunc[0] == GL_SRC_ALPHA && shader.layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) + || (shader.layers[1].blendfunc[0] == GL_ONE && shader.layers[1].blendfunc[1] == GL_ZERO && shader.layers[1].alphatest))) + { + // terrain blending or other effects + shader.backgroundlayer = 0; + shader.primarylayer = 1; + } + } + // fix up multiple reflection types + if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER) + shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA); + + Q3Shader_AddToHash (&shader); + } + Mem_Free(f); + } + FS_FreeSearch(search); + // free custinfoparm values + for (j = 0; j < numcustsurfaceflags; j++) + Mem_Free(custsurfaceparmnames[j]); +} + +q3shaderinfo_t *Mod_LookupQ3Shader(const char *name) +{ + unsigned short hash; + q3shader_hash_entry_t* entry; + if (!q3shaders_mem) + Mod_LoadQ3Shaders(); + hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name)); + entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE); + while (entry != NULL) + { + if (strcasecmp (entry->shader.name, name) == 0) + return &entry->shader; + entry = entry->chain; + } + return NULL; +} + +qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags) +{ + int j; + int texflagsmask, texflagsor; + qboolean success = true; + q3shaderinfo_t *shader; + if (!name) + name = ""; + strlcpy(texture->name, name, sizeof(texture->name)); + shader = name[0] ? Mod_LookupQ3Shader(name) : NULL; + + texflagsmask = ~0; + if(!(defaulttexflags & TEXF_PICMIP)) + texflagsmask &= ~TEXF_PICMIP; + if(!(defaulttexflags & TEXF_COMPRESS)) + texflagsmask &= ~TEXF_COMPRESS; + texflagsor = 0; + if(defaulttexflags & TEXF_ISWORLD) + texflagsor |= TEXF_ISWORLD; + if(defaulttexflags & TEXF_ISSPRITE) + texflagsor |= TEXF_ISSPRITE; + // unless later loaded from the shader + texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF; + texture->offsetscale = 1; + texture->offsetbias = 0; + texture->specularscalemod = 1; + texture->specularpowermod = 1; + texture->rtlightambient = 0; + texture->transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". + + if (shader) + { + if (developer_loading.integer) + Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name); + + // allow disabling of picmip or compression by defaulttexflags + texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor; + + if (shader->surfaceparms & Q3SURFACEPARM_SKY) + { + texture->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + if (shader->skyboxname[0]) + { + // quake3 seems to append a _ to the skybox name, so this must do so as well + dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname); + } + } + else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0) + texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + else + texture->basematerialflags = MATERIALFLAG_WALL; + + if (shader->layers[0].alphatest) + texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW; + if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED) + texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE; + if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET) + { + texture->biaspolygonoffset += shader->biaspolygonoffset; + texture->biaspolygonfactor += shader->biaspolygonfactor; + } + if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION) + texture->basematerialflags |= MATERIALFLAG_REFRACTION; + if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION) + texture->basematerialflags |= MATERIALFLAG_REFLECTION; + if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER) + texture->basematerialflags |= MATERIALFLAG_WATERSHADER; + if (shader->textureflags & Q3TEXTUREFLAG_CAMERA) + texture->basematerialflags |= MATERIALFLAG_CAMERA; + texture->customblendfunc[0] = GL_ONE; + texture->customblendfunc[1] = GL_ZERO; + texture->transparentsort = shader->transparentsort; + if (shader->numlayers > 0) + { + texture->customblendfunc[0] = shader->layers[0].blendfunc[0]; + texture->customblendfunc[1] = shader->layers[0].blendfunc[1]; +/* +Q3 shader blendfuncs actually used in the game (* = supported by DP) +* additive GL_ONE GL_ONE +additive weird GL_ONE GL_SRC_ALPHA +additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA +* alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA +alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA +brighten GL_DST_COLOR GL_ONE +brighten GL_ONE GL_SRC_COLOR +brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA +brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA +* modulate GL_DST_COLOR GL_ZERO +* modulate GL_ZERO GL_SRC_COLOR +modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR +modulate inverse alpha GL_ZERO GL_SRC_ALPHA +modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO +* modulate x2 GL_DST_COLOR GL_SRC_COLOR +* no blend GL_ONE GL_ZERO +nothing GL_ZERO GL_ONE +*/ + // if not opaque, figure out what blendfunc to use + if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO) + { + if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE) + texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE) + texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) + texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + else + texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + } + } + if (!shader->lighting) + texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT; + if (shader->primarylayer >= 0) + { + q3shaderinfo_layer_t* primarylayer = shader->layers + shader->primarylayer; + // copy over many primarylayer parameters + texture->rgbgen = primarylayer->rgbgen; + texture->alphagen = primarylayer->alphagen; + texture->tcgen = primarylayer->tcgen; + memcpy(texture->tcmods, primarylayer->tcmods, sizeof(texture->tcmods)); + // load the textures + texture->numskinframes = primarylayer->numframes; + texture->skinframerate = primarylayer->framerate; + for (j = 0;j < primarylayer->numframes;j++) + { + if(cls.state == ca_dedicated) + { + texture->skinframes[j] = NULL; + } + else if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(primarylayer->texturename[j], (primarylayer->texflags & texflagsmask) | texflagsor, false))) + { + Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for shader ^2\"%s\"\n", loadmodel->name, primarylayer->texturename[j], j, texture->name); + texture->skinframes[j] = R_SkinFrame_LoadMissing(); + } + } + } + if (shader->backgroundlayer >= 0) + { + q3shaderinfo_layer_t* backgroundlayer = shader->layers + shader->backgroundlayer; + // copy over one secondarylayer parameter + memcpy(texture->backgroundtcmods, backgroundlayer->tcmods, sizeof(texture->backgroundtcmods)); + // load the textures + texture->backgroundnumskinframes = backgroundlayer->numframes; + texture->backgroundskinframerate = backgroundlayer->framerate; + for (j = 0;j < backgroundlayer->numframes;j++) + { + if(cls.state == ca_dedicated) + { + texture->skinframes[j] = NULL; + } + else if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(backgroundlayer->texturename[j], (backgroundlayer->texflags & texflagsmask) | texflagsor, false))) + { + Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (background frame %i) for shader ^2\"%s\"\n", loadmodel->name, backgroundlayer->texturename[j], j, texture->name); + texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing(); + } + } + } + if (shader->dpshadow) + texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW; + if (shader->dpnoshadow) + texture->basematerialflags |= MATERIALFLAG_NOSHADOW; + if (shader->dpnortlight) + texture->basematerialflags |= MATERIALFLAG_NORTLIGHT; + if (shader->vertexalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX; + memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms)); + texture->reflectmin = shader->reflectmin; + texture->reflectmax = shader->reflectmax; + texture->refractfactor = shader->refractfactor; + Vector4Copy(shader->refractcolor4f, texture->refractcolor4f); + texture->reflectfactor = shader->reflectfactor; + Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f); + texture->r_water_wateralpha = shader->r_water_wateralpha; + Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll); + texture->offsetmapping = shader->offsetmapping; + texture->offsetscale = shader->offsetscale; + texture->offsetbias = shader->offsetbias; + texture->specularscalemod = shader->specularscalemod; + texture->specularpowermod = shader->specularpowermod; + texture->rtlightambient = shader->rtlightambient; + if (shader->dpreflectcube[0]) + texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube); + + // set up default supercontents (on q3bsp this is overridden by the q3bsp loader) + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ; + if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ; + if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ; + if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ; + + // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ; + // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL; + // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ; + if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ; + if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ; + if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ; + if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ; + // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ; + if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ; + // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ; + if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ; + // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ; + // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ; + // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ; + if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ; + + texture->surfaceflags = shader->surfaceflags; + if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ; + // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL; + // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ; + // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ; + // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ; + // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ; + if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ; + if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ; + if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ; + if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ; + // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ; + if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ; + if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ; + if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ; + // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ; + if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ; + // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ; + if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ; + if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ; + // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ; + // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ; + // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ; + // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ; + if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ; + if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ; + if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ; + // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ; + // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ; + // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ; + + if (shader->dpmeshcollisions) + texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS; + if (shader->dpshaderkill && developer_extra.integer) + Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", loadmodel->name, name); + } + else if (!strcmp(texture->name, "noshader") || !texture->name[0]) + { + if (developer_extra.integer) + Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name); + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + } + else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw")) + { + if (developer_extra.integer) + Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name); + texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SOLID; + } + else + { + if (developer_extra.integer) + Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name); + if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW) + { + texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SOLID; + } + else if (texture->surfaceflags & Q3SURFACEFLAG_SKY) + { + texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW; + texture->supercontents = SUPERCONTENTS_SKY; + } + else + { + texture->basematerialflags |= MATERIALFLAG_WALL; + texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE; + } + texture->numskinframes = 1; + if(cls.state == ca_dedicated) + { + texture->skinframes[0] = NULL; + success = false; + } + else + { + if (fallback) + { + if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false))) + { + if(texture->skinframes[0]->hasalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + } + else + success = false; + } + else + success = false; + if (!success && warnmissing) + Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", loadmodel->name, texture->name); + } + } + // init the animation variables + texture->currentframe = texture; + if (texture->numskinframes < 1) + texture->numskinframes = 1; + if (!texture->skinframes[0]) + texture->skinframes[0] = R_SkinFrame_LoadMissing(); + texture->currentskinframe = texture->skinframes[0]; + texture->backgroundcurrentskinframe = texture->backgroundskinframes[0]; + return success; +} + +skinfile_t *Mod_LoadSkinFiles(void) +{ + int i, words, line, wordsoverflow; + char *text; + const char *data; + skinfile_t *skinfile = NULL, *first = NULL; + skinfileitem_t *skinfileitem; + char word[10][MAX_QPATH]; + char vabuf[1024]; + +/* +sample file: +U_bodyBox,models/players/Legoman/BikerA2.tga +U_RArm,models/players/Legoman/BikerA1.tga +U_LArm,models/players/Legoman/BikerA1.tga +U_armor,common/nodraw +U_sword,common/nodraw +U_shield,common/nodraw +U_homb,common/nodraw +U_backpack,common/nodraw +U_colcha,common/nodraw +tag_head, +tag_weapon, +tag_torso, +*/ + memset(word, 0, sizeof(word)); + for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++) + { + // If it's the first file we parse + if (skinfile == NULL) + { + skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t)); + first = skinfile; + } + else + { + skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t)); + skinfile = skinfile->next; + } + skinfile->next = NULL; + + for(line = 0;;line++) + { + // parse line + if (!COM_ParseToken_QuakeC(&data, true)) + break; + if (!strcmp(com_token, "\n")) + continue; + words = 0; + wordsoverflow = false; + do + { + if (words < 10) + strlcpy(word[words++], com_token, sizeof (word[0])); + else + wordsoverflow = true; + } + while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n")); + if (wordsoverflow) + { + Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: line with too many statements, skipping\n", loadmodel->name, i, line); + continue; + } + // words is always >= 1 + if (!strcmp(word[0], "replace")) + { + if (words == 3) + { + if (developer_loading.integer) + Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]); + skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t)); + skinfileitem->next = skinfile->items; + skinfile->items = skinfileitem; + strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name)); + strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); + } + else + Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: wrong number of parameters to command \"%s\", see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line, word[0]); + } + else if (words >= 2 && !strncmp(word[0], "tag_", 4)) + { + // tag name, like "tag_weapon," + // not used for anything (not even in Quake3) + } + else if (words >= 2 && !strcmp(word[1], ",")) + { + // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga" + if (developer_loading.integer) + Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]); + skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t)); + skinfileitem->next = skinfile->items; + skinfile->items = skinfileitem; + strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name)); + strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement)); + } + else + Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: does not look like tag or mesh specification, or replace command, see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line); + } + Mem_Free(text); + } + if (i) + loadmodel->numskins = i; + return first; +} + +void Mod_FreeSkinFiles(skinfile_t *skinfile) +{ + skinfile_t *next; + skinfileitem_t *skinfileitem, *nextitem; + for (;skinfile;skinfile = next) + { + next = skinfile->next; + for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem) + { + nextitem = skinfileitem->next; + Mem_Free(skinfileitem); + } + Mem_Free(skinfile); + } +} + +int Mod_CountSkinFiles(skinfile_t *skinfile) +{ + int i; + for (i = 0;skinfile;skinfile = skinfile->next, i++); + return i; +} + +void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap) +{ + int i; + double isnap = 1.0 / snap; + for (i = 0;i < numvertices*numcomponents;i++) + vertices[i] = floor(vertices[i]*isnap)*snap; +} + +int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f) +{ + int i, outtriangles; + float edgedir1[3], edgedir2[3], temp[3]; + // a degenerate triangle is one with no width (thickness, surface area) + // these are characterized by having all 3 points colinear (along a line) + // or having two points identical + // the simplest check is to calculate the triangle's area + for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3) + { + // calculate first edge + VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1); + VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2); + CrossProduct(edgedir1, edgedir2, temp); + if (VectorLength2(temp) < 0.001f) + continue; // degenerate triangle (no area) + // valid triangle (has area) + VectorCopy(inelement3i, outelement3i); + outelement3i += 3; + outtriangles++; + } + return outtriangles; +} + +void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer) +{ + int i, e; + int firstvertex, lastvertex; + if (numelements > 0 && elements) + { + firstvertex = lastvertex = elements[0]; + for (i = 1;i < numelements;i++) + { + e = elements[i]; + firstvertex = min(firstvertex, e); + lastvertex = max(lastvertex, e); + } + } + else + firstvertex = lastvertex = 0; + if (firstvertexpointer) + *firstvertexpointer = firstvertex; + if (lastvertexpointer) + *lastvertexpointer = lastvertex; +} + +void Mod_MakeSortedSurfaces(dp_model_t *mod) +{ + // make an optimal set of texture-sorted batches to draw... + int j, t; + int *firstsurfacefortexture; + int *numsurfacesfortexture; + if (!mod->sortedmodelsurfaces) + mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces)); + firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture)); + numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture)); + memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture)); + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + int t = (int)(surface->texture - mod->data_textures); + numsurfacesfortexture[t]++; + } + j = 0; + for (t = 0;t < mod->num_textures;t++) + { + firstsurfacefortexture[t] = j; + j += numsurfacesfortexture[t]; + } + for (j = 0;j < mod->nummodelsurfaces;j++) + { + const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface; + int t = (int)(surface->texture - mod->data_textures); + mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface; + } + Mem_Free(firstsurfacefortexture); + Mem_Free(numsurfacesfortexture); +} + +void Mod_BuildVBOs(void) +{ + if (!loadmodel->surfmesh.num_vertices) + return; + + if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i) + { + int i; + for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++) + { + if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i]) + { + Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]); + loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i]; + } + } + } + + // build r_vertexmesh_t array + // (compressed interleaved array for D3D) + if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays) + { + int vertexindex; + int numvertices = loadmodel->surfmesh.num_vertices; + r_vertexmesh_t *vertexmesh; + loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + if (loadmodel->surfmesh.data_lightmapcolor4f) + Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f); + Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + if (loadmodel->surfmesh.data_texcoordlightmap2f) + Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f); + if (loadmodel->surfmesh.data_skeletalindex4ub) + Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub); + if (loadmodel->surfmesh.data_skeletalweight4ub) + Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub); + } + } + + // upload short indices as a buffer + if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer) + loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, false, true); + + // upload int indices as a buffer + if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s) + loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false, false, false); + + // only build a vbo if one has not already been created (this is important for brush models which load specially) + // vertex buffer is several arrays and we put them in the same buffer + // + // is this wise? the texcoordtexture2f array is used with dynamic + // vertex/svector/tvector/normal when rendering animated models, on the + // other hand animated models don't use a lot of vertices anyway... + if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays) + { + size_t size; + unsigned char *mem; + size = 0; + loadmodel->surfmesh.vbooffset_vertexmesh = size;if (loadmodel->surfmesh.data_vertexmesh ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t); + loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_normal3f = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]); + loadmodel->surfmesh.vbooffset_skeletalindex4ub = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); + loadmodel->surfmesh.vbooffset_skeletalweight4ub = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]); + mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (loadmodel->surfmesh.data_vertexmesh ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh , loadmodel->surfmesh.data_vertexmesh , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t)); + if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); + if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); + if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); + if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3])); + if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2])); + if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2])); + if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4])); + if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])); + if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4])); + loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false); + Mem_Free(mem); + } +} + +extern cvar_t mod_obj_orientation; +static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename) +{ + int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0; + int a, b, c; + const char *texname; + const int *e; + const float *v, *vn, *vt; + size_t l; + size_t outbufferpos = 0; + size_t outbuffermax = 0x100000; + char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer; + const msurface_t *surface; + const int maxtextures = 256; + char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH); + dp_model_t *submodel; + + // construct the mtllib file + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename); + if (l > 0) + outbufferpos += l; + for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++) + { + countsurfaces++; + countvertices += surface->num_vertices; + countfaces += surface->num_triangles; + texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default"; + for (textureindex = 0;textureindex < counttextures;textureindex++) + if (!strcmp(texturenames + textureindex * MAX_QPATH, texname)) + break; + if (textureindex < counttextures) + continue; // already wrote this material entry + if (textureindex >= maxtextures) + continue; // just a precaution + textureindex = counttextures++; + strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH); + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "newmtl %s\nNs 96.078431\nKa 0 0 0\nKd 0.64 0.64 0.64\nKs 0.5 0.5 0.5\nNi 1\nd 1\nillum 2\nmap_Kd %s%s\n\n", texname, texname, strstr(texname, ".tga") ? "" : ".tga"); + if (l > 0) + outbufferpos += l; + } + + // write the mtllib file + FS_WriteFile(mtlfilename, outbuffer, outbufferpos); + + // construct the obj file + outbufferpos = 0; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# model exported from %s by darkplaces engine\n# %i vertices, %i faces, %i surfaces\nmtllib %s\n", originalfilename, countvertices, countfaces, countsurfaces, mtlfilename); + if (l > 0) + outbufferpos += l; + + for (vertexindex = 0, v = model->surfmesh.data_vertex3f, vn = model->surfmesh.data_normal3f, vt = model->surfmesh.data_texcoordtexture2f;vertexindex < model->surfmesh.num_vertices;vertexindex++, v += 3, vn += 3, vt += 2) + { + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1-vt[1]); + if (l > 0) + outbufferpos += l; + } + + for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++) + { + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex); + if (l > 0) + outbufferpos += l; + submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model; + for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++) + { + surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex]; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default"); + if (l > 0) + outbufferpos += l; + for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) + { + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + a = e[0]+1; + b = e[1]+1; + c = e[2]+1; + if(mod_obj_orientation.integer) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c); + else + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b); + if (l > 0) + outbufferpos += l; + } + } + } + + // write the obj file + FS_WriteFile(filename, outbuffer, outbufferpos); + + // clean up + Z_Free(outbuffer); + Z_Free(texturenames); + + // print some stats + Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures); +} + +static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles) +{ + int countnodes = 0, counttriangles = 0, countframes = 0; + int surfaceindex; + int triangleindex; + int transformindex; + int poseindex; + int cornerindex; + const int *e; + size_t l; + size_t outbufferpos = 0; + size_t outbuffermax = 0x100000; + char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer; + const msurface_t *surface; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n"); + if (l > 0) + outbufferpos += l; + for (transformindex = 0;transformindex < model->num_bones;transformindex++) + { + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + countnodes++; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent); + if (l > 0) + outbufferpos += l; + } + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n"); + if (l > 0) + outbufferpos += l; + for (poseindex = 0;poseindex < numposes;poseindex++) + { + countframes++; + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex); + if (l > 0) + outbufferpos += l; + for (transformindex = 0;transformindex < model->num_bones;transformindex++) + { + float angles[3]; + float mtest[4][3]; + matrix4x4_t posematrix; + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + + // strangely the smd angles are for a transposed matrix, so we + // have to generate a transposed matrix, then convert that... + Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex)); + Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]); + AnglesFromVectors(angles, mtest[0], mtest[2], false); + if (angles[0] >= 180) angles[0] -= 360; + if (angles[1] >= 180) angles[1] -= 360; + if (angles[2] >= 180) angles[2] -= 360; + +#if 0 +{ + float a = DEG2RAD(angles[ROLL]); + float b = DEG2RAD(angles[PITCH]); + float c = DEG2RAD(angles[YAW]); + float cy, sy, cp, sp, cr, sr; + float test[4][3]; + // smd matrix construction, for comparing + sy = sin(c); + cy = cos(c); + sp = sin(b); + cp = cos(b); + sr = sin(a); + cr = cos(a); + + test[0][0] = cp*cy; + test[0][1] = cp*sy; + test[0][2] = -sp; + test[1][0] = sr*sp*cy+cr*-sy; + test[1][1] = sr*sp*sy+cr*cy; + test[1][2] = sr*cp; + test[2][0] = (cr*sp*cy+-sr*-sy); + test[2][1] = (cr*sp*sy+-sr*cy); + test[2][2] = cr*cp; + test[3][0] = pose[9]; + test[3][1] = pose[10]; + test[3][2] = pose[11]; +} +#endif + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, mtest[3][0], mtest[3][1], mtest[3][2], DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW])); + if (l > 0) + outbufferpos += l; + } + } + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n"); + if (l > 0) + outbufferpos += l; + if (writetriangles) + { + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n"); + if (l > 0) + outbufferpos += l; + for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++) + { + for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) + { + counttriangles++; + if (outbufferpos >= outbuffermax >> 1) + { + outbuffermax *= 2; + oldbuffer = outbuffer; + outbuffer = (char *) Z_Malloc(outbuffermax); + memcpy(outbuffer, oldbuffer, outbufferpos); + Z_Free(oldbuffer); + } + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp"); + if (l > 0) + outbufferpos += l; + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + const int index = e[2-cornerindex]; + const float *v = model->surfmesh.data_vertex3f + index * 3; + const float *vn = model->surfmesh.data_normal3f + index * 3; + const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2; + const int b = model->surfmesh.blends[index]; + if (b < model->num_bones) + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , b, v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]); + else + { + const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones; + const unsigned char *wi = w->index; + const unsigned char *wf = w->influence; + if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f, wi[3], wf[3]/255.0f); + else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f); + else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f); + else l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]); + } + if (l > 0) + outbufferpos += l; + } + } + } + l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n"); + if (l > 0) + outbufferpos += l; + } + + FS_WriteFile(filename, outbuffer, outbufferpos); + Z_Free(outbuffer); + + Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles); +} + +/* +================ +Mod_Decompile_f + +decompiles a model to editable files +================ +*/ +static void Mod_Decompile_f(void) +{ + int i, j, k, l, first, count; + dp_model_t *mod; + char inname[MAX_QPATH]; + char outname[MAX_QPATH]; + char mtlname[MAX_QPATH]; + char basename[MAX_QPATH]; + char animname[MAX_QPATH]; + char animname2[MAX_QPATH]; + char zymtextbuffer[16384]; + char dpmtextbuffer[16384]; + char framegroupstextbuffer[16384]; + int zymtextsize = 0; + int dpmtextsize = 0; + int framegroupstextsize = 0; + char vabuf[1024]; + + if (Cmd_Argc() != 2) + { + Con_Print("usage: modeldecompile \n"); + return; + } + + strlcpy(inname, Cmd_Argv(1), sizeof(inname)); + FS_StripExtension(inname, basename, sizeof(basename)); + + mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL); + if (!mod) + { + Con_Print("No such model\n"); + return; + } + if (mod->brush.submodel) + { + // if we're decompiling a submodel, be sure to give it a proper name based on its parent + FS_StripExtension(cl.model_name[1], outname, sizeof(outname)); + dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name); + outname[0] = 0; + } + if (!mod->surfmesh.num_triangles) + { + Con_Print("Empty model (or sprite)\n"); + return; + } + + // export OBJ if possible (not on sprites) + if (mod->surfmesh.num_triangles) + { + dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename); + dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename); + Mod_Decompile_OBJ(mod, outname, mtlname, inname); + } + + // export SMD if possible (only for skeletal models) + if (mod->surfmesh.num_triangles && mod->num_bones) + { + dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename); + Mod_Decompile_SMD(mod, outname, 0, 1, true); + l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n"); + if (l > 0) zymtextsize += l; + l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n"); + if (l > 0) dpmtextsize += l; + for (i = 0;i < mod->numframes;i = j) + { + strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); + first = mod->animscenes[i].firstframe; + if (mod->animscenes[i].framecount > 1) + { + // framegroup anim + count = mod->animscenes[i].framecount; + j = i + 1; + } + else + { + // individual frame + // check for additional frames with same name + for (l = 0, k = strlen(animname);animname[l];l++) + if(animname[l] < '0' || animname[l] > '9') + k = l + 1; + if(k > 0 && animname[k-1] == '_') + --k; + animname[k] = 0; + count = mod->num_poses - first; + for (j = i + 1;j < mod->numframes;j++) + { + strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2)); + for (l = 0, k = strlen(animname2);animname2[l];l++) + if(animname2[l] < '0' || animname2[l] > '9') + k = l + 1; + if(k > 0 && animname[k-1] == '_') + --k; + animname2[k] = 0; + if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1) + { + count = mod->animscenes[j].firstframe - first; + break; + } + } + // if it's only one frame, use the original frame name + if (j == i + 1) + strlcpy(animname, mod->animscenes[i].name, sizeof(animname)); + + } + dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname); + Mod_Decompile_SMD(mod, outname, first, count, false); + if (zymtextsize < (int)sizeof(zymtextbuffer) - 100) + { + l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop"); + if (l > 0) zymtextsize += l; + } + if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100) + { + l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop"); + if (l > 0) dpmtextsize += l; + } + if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100) + { + l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname); + if (l > 0) framegroupstextsize += l; + } + } + if (zymtextsize) + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize); + if (dpmtextsize) + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize); + if (framegroupstextsize) + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize); + } +} + +void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height) +{ + int y; + memset(state, 0, sizeof(*state)); + state->width = width; + state->height = height; + state->currentY = 0; + state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows)); + for (y = 0;y < state->height;y++) + { + state->rows[y].currentX = 0; + state->rows[y].rowY = -1; + } +} + +void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state) +{ + int y; + state->currentY = 0; + for (y = 0;y < state->height;y++) + { + state->rows[y].currentX = 0; + state->rows[y].rowY = -1; + } +} + +void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state) +{ + if (state->rows) + Mem_Free(state->rows); + memset(state, 0, sizeof(*state)); +} + +qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy) +{ + mod_alloclightmap_row_t *row; + int y; + + row = state->rows + blockheight; + if ((row->rowY < 0) || (row->currentX + blockwidth > state->width)) + { + if (state->currentY + blockheight <= state->height) + { + // use the current allocation position + row->rowY = state->currentY; + row->currentX = 0; + state->currentY += blockheight; + } + else + { + // find another position + for (y = blockheight;y < state->height;y++) + { + if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width)) + { + row = state->rows + y; + break; + } + } + if (y == state->height) + return false; + } + } + *outy = row->rowY; + *outx = row->currentX; + row->currentX += blockwidth; + + return true; +} + +typedef struct lightmapsample_s +{ + float pos[3]; + float sh1[4][3]; + float *vertex_color; + unsigned char *lm_bgr; + unsigned char *lm_dir; +} +lightmapsample_t; + +typedef struct lightmapvertex_s +{ + int index; + float pos[3]; + float normal[3]; + float texcoordbase[2]; + float texcoordlightmap[2]; + float lightcolor[4]; +} +lightmapvertex_t; + +typedef struct lightmaptriangle_s +{ + int triangleindex; + int surfaceindex; + int lightmapindex; + int axis; + int lmoffset[2]; + int lmsize[2]; + // 2D modelspace coordinates of min corner + // snapped to lightmap grid but not in grid coordinates + float lmbase[2]; + // 2D modelspace to lightmap coordinate scale + float lmscale[2]; + float vertex[3][3]; + float mins[3]; + float maxs[3]; +} +lightmaptriangle_t; + +typedef struct lightmaplight_s +{ + float origin[3]; + float radius; + float iradius; + float radius2; + float color[3]; + svbsp_t svbsp; +} +lightmaplight_t; + +lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles; + +#define MAX_LIGHTMAPSAMPLES 64 +static int mod_generatelightmaps_numoffsets[3]; +static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3]; + +static int mod_generatelightmaps_numlights; +static lightmaplight_t *mod_generatelightmaps_lightinfo; + +extern cvar_t r_shadow_lightattenuationdividebias; +extern cvar_t r_shadow_lightattenuationlinearscale; + +static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir) +{ + int i; + int index; + int result; + float relativepoint[3]; + float color[3]; + float dir[3]; + float dist; + float dist2; + float intensity; + float sample[5*3]; + float lightorigin[3]; + float lightradius; + float lightradius2; + float lightiradius; + float lightcolor[3]; + trace_t trace; + for (i = 0;i < 5*3;i++) + sample[i] = 0.0f; + for (index = 0;;index++) + { + result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor); + if (result < 0) + break; + if (result == 0) + continue; + lightradius2 = lightradius * lightradius; + VectorSubtract(lightorigin, pos, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + lightiradius = 1.0f / lightradius; + dist = sqrt(dist2) * lightiradius; + intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); + if (intensity <= 0.0f) + continue; + if (model && model->TraceLine) + { + model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK); + if (trace.fraction < 1) + continue; + } + // scale down intensity to add to both ambient and diffuse + //intensity *= 0.5f; + VectorNormalize(relativepoint); + VectorScale(lightcolor, intensity, color); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity *= VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } + // calculate the direction we'll use to reduce the sample to a directional light source + VectorCopy(sample + 12, dir); + //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]); + VectorNormalize(dir); + // extract the diffuse color along the chosen direction and scale it + diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]); + diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]); + diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]); + // subtract some of diffuse from ambient + VectorMA(sample, -0.333f, diffuse, ambient); + // store the normalized lightdir + VectorCopy(dir, lightdir); +} + +static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs) +{ + int surfaceindex; + int triangleindex; + const msurface_t *surface; + const float *vertex3f = model->surfmesh.data_vertex3f; + const int *element3i = model->surfmesh.data_element3i; + const int *e; + float v2[3][3]; + for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++) + { + if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs)) + continue; + if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW) + continue; + for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3) + { + VectorCopy(vertex3f + 3*e[0], v2[0]); + VectorCopy(vertex3f + 3*e[1], v2[1]); + VectorCopy(vertex3f + 3*e[2], v2[2]); + SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0); + } + } +} + +static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo) +{ + int maxnodes = 1<<14; + svbsp_node_t *nodes; + float origin[3]; + float mins[3]; + float maxs[3]; + svbsp_t svbsp; + VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius); + VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius); + VectorCopy(lightinfo->origin, origin); + nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); + for (;;) + { + SVBSP_Init(&svbsp, origin, maxnodes, nodes); + Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs); + if (svbsp.ranoutofnodes) + { + maxnodes *= 16; + if (maxnodes > 1<<22) + { + Mem_Free(nodes); + return; + } + Mem_Free(nodes); + nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes)); + } + else + break; + } + if (svbsp.numnodes > 0) + { + svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes)); + memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes)); + lightinfo->svbsp = svbsp; + } + Mem_Free(nodes); +} + +static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model) +{ + int index; + int result; + lightmaplight_t *lightinfo; + float origin[3]; + float radius; + float color[3]; + mod_generatelightmaps_numlights = 0; + for (index = 0;;index++) + { + result = R_Shadow_GetRTLightInfo(index, origin, &radius, color); + if (result < 0) + break; + if (result > 0) + mod_generatelightmaps_numlights++; + } + if (mod_generatelightmaps_numlights > 0) + { + mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo)); + lightinfo = mod_generatelightmaps_lightinfo; + for (index = 0;;index++) + { + result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color); + if (result < 0) + break; + if (result > 0) + lightinfo++; + } + } + for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++) + { + lightinfo->iradius = 1.0f / lightinfo->radius; + lightinfo->radius2 = lightinfo->radius * lightinfo->radius; + // TODO: compute svbsp + Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo); + } +} + +static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model) +{ + int i; + if (mod_generatelightmaps_lightinfo) + { + for (i = 0;i < mod_generatelightmaps_numlights;i++) + if (mod_generatelightmaps_lightinfo[i].svbsp.nodes) + Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes); + Mem_Free(mod_generatelightmaps_lightinfo); + } + mod_generatelightmaps_lightinfo = NULL; + mod_generatelightmaps_numlights = 0; +} + +static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos) +{ + const svbsp_node_t *node; + const svbsp_node_t *nodes = svbsp->nodes; + int num = 0; + while (num >= 0) + { + node = nodes + num; + num = node->children[DotProduct(node->plane, pos) < node->plane[3]]; + } + return num == -1; // true if empty, false if solid (shadowed) +} + +static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets) +{ + int i; + float relativepoint[3]; + float color[3]; + float offsetpos[3]; + float dist; + float dist2; + float intensity; + int offsetindex; + int hits; + int tests; + const lightmaplight_t *lightinfo; + trace_t trace; + for (i = 0;i < 5*3;i++) + sample[i] = 0.0f; + for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++) + { + //R_SampleRTLights(pos, sample, numoffsets, offsets); + VectorSubtract(lightinfo->origin, pos, relativepoint); + // don't accept light from behind a surface, it causes bad shading + if (normal && DotProduct(relativepoint, normal) <= 0) + continue; + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightinfo->radius2) + continue; + dist = sqrt(dist2) * lightinfo->iradius; + intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + if (intensity <= 0) + continue; + if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0) + { + hits = 0; + tests = 1; + if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos)) + hits++; + for (offsetindex = 1;offsetindex < numoffsets;offsetindex++) + { + VectorAdd(pos, offsets + 3*offsetindex, offsetpos); + if (!normal) + { + // for light grid we'd better check visibility of the offset point + cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK); + if (trace.fraction < 1) + VectorLerp(pos, trace.fraction, offsetpos, offsetpos); + } + tests++; + if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos)) + hits++; + } + if (!hits) + continue; + // scale intensity according to how many rays succeeded + // we know one test is valid, half of the rest will fail... + //if (normal && tests > 1) + // intensity *= (tests - 1.0f) / tests; + intensity *= (float)hits / tests; + } + // scale down intensity to add to both ambient and diffuse + //intensity *= 0.5f; + VectorNormalize(relativepoint); + VectorScale(lightinfo->color, intensity, color); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity *= VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } +} + +static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir) +{ + float sample[5*3]; + float color[3]; + float dir[3]; + float f; + Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]); + //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]); + VectorCopy(sample + 12, dir); + VectorNormalize(dir); + //VectorAdd(dir, normal, dir); + //VectorNormalize(dir); + f = DotProduct(dir, normal); + f = max(0, f) * 255.0f; + VectorScale(sample, f, color); + //VectorCopy(normal, dir); + VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f); + lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f); + lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f); + lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f); + lm_bgr[3] = 255; + lm_dir[0] = (unsigned char)dir[2]; + lm_dir[1] = (unsigned char)dir[1]; + lm_dir[2] = (unsigned char)dir[0]; + lm_dir[3] = 255; +} + +static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color) +{ + float sample[5*3]; + Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]); + VectorCopy(sample, vertex_color); +} + +static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s) +{ + float sample[5*3]; + float ambient[3]; + float diffuse[3]; + float dir[3]; + Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]); + // calculate the direction we'll use to reduce the sample to a directional light source + VectorCopy(sample + 12, dir); + //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]); + VectorNormalize(dir); + // extract the diffuse color along the chosen direction and scale it + diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f; + diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f; + diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f; + // scale the ambient from 0-2 to 0-255 and subtract some of diffuse + VectorScale(sample, 127.5f, ambient); + VectorMA(ambient, -0.333f, diffuse, ambient); + // encode to the grid format + s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f); + s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f); + s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f); + s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f); + s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f); + s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f); + if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;} + else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;} + else {s->diffusepitch = (unsigned char)(acos(dir[2]) * (127.5f/M_PI));s->diffuseyaw = (unsigned char)(atan2(dir[1], dir[0]) * (127.5f/M_PI));} +} + +static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model) +{ + float radius[3]; + float temp[3]; + int i, j; + memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets)); + mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer); + mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer); + mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer); + radius[0] = mod_generatelightmaps_lightmapradius.value; + radius[1] = mod_generatelightmaps_vertexradius.value; + radius[2] = mod_generatelightmaps_gridradius.value; + for (i = 0;i < 3;i++) + { + for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++) + { + VectorRandom(temp); + VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]); + } + } +} + +static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model) +{ + msurface_t *surface; + int surfaceindex; + int i; + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + surface->lightmaptexture = NULL; + surface->deluxemaptexture = NULL; + } + if (model->brushq3.data_lightmaps) + { + for (i = 0;i < model->brushq3.num_mergedlightmaps;i++) + if (model->brushq3.data_lightmaps[i]) + R_FreeTexture(model->brushq3.data_lightmaps[i]); + Mem_Free(model->brushq3.data_lightmaps); + model->brushq3.data_lightmaps = NULL; + } + if (model->brushq3.data_deluxemaps) + { + for (i = 0;i < model->brushq3.num_mergedlightmaps;i++) + if (model->brushq3.data_deluxemaps[i]) + R_FreeTexture(model->brushq3.data_deluxemaps[i]); + Mem_Free(model->brushq3.data_deluxemaps); + model->brushq3.data_deluxemaps = NULL; + } +} + +static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) +{ + msurface_t *surface; + int surfaceindex; + int vertexindex; + int outvertexindex; + int i; + const int *e; + surfmesh_t oldsurfmesh; + size_t size; + unsigned char *data; + oldsurfmesh = model->surfmesh; + model->surfmesh.num_triangles = oldsurfmesh.num_triangles; + model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3; + size = 0; + size += model->surfmesh.num_vertices * sizeof(float[3]); + size += model->surfmesh.num_vertices * sizeof(float[3]); + size += model->surfmesh.num_vertices * sizeof(float[3]); + size += model->surfmesh.num_vertices * sizeof(float[3]); + size += model->surfmesh.num_vertices * sizeof(float[2]); + size += model->surfmesh.num_vertices * sizeof(float[2]); + size += model->surfmesh.num_vertices * sizeof(float[4]); + data = (unsigned char *)Mem_Alloc(model->mempool, size); + model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]); + model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]); + model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]); + model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]); + model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]); + model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]); + model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]); + if (model->surfmesh.num_vertices > 65536) + model->surfmesh.data_element3s = NULL; + + if (model->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer); + model->surfmesh.data_element3i_indexbuffer = NULL; + if (model->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer); + model->surfmesh.data_element3s_indexbuffer = NULL; + if (model->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer); + model->surfmesh.vbo_vertexbuffer = 0; + + // convert all triangles to unique vertex data + outvertexindex = 0; + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + surface->num_firstvertex = outvertexindex; + surface->num_vertices = surface->num_triangles*3; + e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3; + for (i = 0;i < surface->num_triangles*3;i++) + { + vertexindex = e[i]; + model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0]; + model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1]; + model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2]; + model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0]; + model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1]; + model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2]; + model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0]; + model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1]; + model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2]; + model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0]; + model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1]; + model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2]; + model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0]; + model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1]; + if (oldsurfmesh.data_texcoordlightmap2f) + { + model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0]; + model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1]; + } + if (oldsurfmesh.data_lightmapcolor4f) + { + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2]; + model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3]; + } + else + Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1); + model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex; + outvertexindex++; + } + } + if (model->surfmesh.data_element3s) + for (i = 0;i < model->surfmesh.num_triangles*3;i++) + model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i]; + + // find and update all submodels to use this new surfmesh data + for (i = 0;i < model->brush.numsubmodels;i++) + model->brush.submodels[i]->surfmesh = model->surfmesh; +} + +static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model) +{ + msurface_t *surface; + int surfaceindex; + int i; + int axis; + float normal[3]; + const int *e; + lightmaptriangle_t *triangle; + // generate lightmap triangle structs + mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t)); + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + e = model->surfmesh.data_element3i + surface->num_firsttriangle*3; + for (i = 0;i < surface->num_triangles;i++) + { + triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i]; + triangle->triangleindex = surface->num_firsttriangle+i; + triangle->surfaceindex = surfaceindex; + VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]); + VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]); + VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]); + // calculate bounds of triangle + triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0])); + triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1])); + triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2])); + triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0])); + triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1])); + triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2])); + // pick an axial projection based on the triangle normal + TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal); + axis = 0; + if (fabs(normal[1]) > fabs(normal[axis])) + axis = 1; + if (fabs(normal[2]) > fabs(normal[axis])) + axis = 2; + triangle->axis = axis; + } + } +} + +static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model) +{ + if (mod_generatelightmaps_lightmaptriangles) + Mem_Free(mod_generatelightmaps_lightmaptriangles); + mod_generatelightmaps_lightmaptriangles = NULL; +} + +float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + +static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model) +{ + msurface_t *surface; + int surfaceindex; + int lightmapindex; + int lightmapnumber; + int i; + int j; + int k; + int x; + int y; + int axis; + int axis1; + int axis2; + int retry; + int pixeloffset; + float trianglenormal[3]; + float samplecenter[3]; + float samplenormal[3]; + float temp[3]; + float lmiscale[2]; + float slopex; + float slopey; + float slopebase; + float lmscalepixels; + float lmmins; + float lmmaxs; + float lm_basescalepixels; + int lm_borderpixels; + int lm_texturesize; + //int lm_maxpixels; + const int *e; + lightmaptriangle_t *triangle; + unsigned char *lightmappixels; + unsigned char *deluxemappixels; + mod_alloclightmap_state_t lmstate; + char vabuf[1024]; + + // generate lightmap projection information for all triangles + if (model->texturepool == NULL) + model->texturepool = R_AllocTexturePool(); + lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value); + lm_borderpixels = mod_generatelightmaps_borderpixels.integer; + lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d); + //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1); + Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize); + lightmapnumber = 0; + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + e = model->surfmesh.data_element3i + surface->num_firsttriangle*3; + lmscalepixels = lm_basescalepixels; + for (retry = 0;retry < 30;retry++) + { + // after a couple failed attempts, degrade quality to make it fit + if (retry > 1) + lmscalepixels *= 0.5f; + for (i = 0;i < surface->num_triangles;i++) + { + triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i]; + triangle->lightmapindex = lightmapnumber; + // calculate lightmap bounds in 3D pixel coordinates, limit size, + // pick two planar axes for projection + // lightmap coordinates here are in pixels + // lightmap projections are snapped to pixel grid explicitly, such + // that two neighboring triangles sharing an edge and projection + // axis will have identical sampl espacing along their shared edge + k = 0; + for (j = 0;j < 3;j++) + { + if (j == triangle->axis) + continue; + lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels; + lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels; + triangle->lmsize[k] = (int)(lmmaxs-lmmins); + triangle->lmbase[k] = lmmins/lmscalepixels; + triangle->lmscale[k] = lmscalepixels; + k++; + } + if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1])) + break; + } + // if all fit in this texture, we're done with this surface + if (i == surface->num_triangles) + break; + // if we haven't maxed out the lightmap size yet, we retry the + // entire surface batch... + if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d)) + { + lm_texturesize *= 2; + surfaceindex = -1; + lightmapnumber = 0; + Mod_AllocLightmap_Free(&lmstate); + Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize); + break; + } + // if we have maxed out the lightmap size, and this triangle does + // not fit in the same texture as the rest of the surface, we have + // to retry the entire surface in a new texture (can only use one) + // with multiple retries, the lightmap quality degrades until it + // fits (or gives up) + if (surfaceindex > 0) + lightmapnumber++; + Mod_AllocLightmap_Reset(&lmstate); + } + } + lightmapnumber++; + Mod_AllocLightmap_Free(&lmstate); + + // now put triangles together into lightmap textures, and do not allow + // triangles of a surface to go into different textures (as that would + // require rewriting the surface list) + model->brushq3.deluxemapping_modelspace = true; + model->brushq3.deluxemapping = true; + model->brushq3.num_mergedlightmaps = lightmapnumber; + model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *)); + lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); + deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4); + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + e = model->surfmesh.data_element3i + surface->num_firsttriangle*3; + for (i = 0;i < surface->num_triangles;i++) + { + triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i]; + TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal); + VectorNormalize(trianglenormal); + VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices + axis = triangle->axis; + axis1 = axis == 0 ? 1 : 0; + axis2 = axis == 2 ? 1 : 2; + lmiscale[0] = 1.0f / triangle->lmscale[0]; + lmiscale[1] = 1.0f / triangle->lmscale[1]; + if (trianglenormal[axis] < 0) + VectorNegate(trianglenormal, trianglenormal); + CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1]; + CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2]; + slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey; + for (j = 0;j < 3;j++) + { + float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2; + t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize; + t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize; +#if 0 + samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0]; + samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1]; + samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase; + Con_Printf("%f:%f %f:%f %f:%f = %f %f\n", triangle->vertex[j][axis1], samplecenter[axis1], triangle->vertex[j][axis2], samplecenter[axis2], triangle->vertex[j][axis], samplecenter[axis], t2f[0], t2f[1]); +#endif + } + +#if 0 + switch (axis) + { + default: + case 0: + forward[0] = 0; + forward[1] = 1.0f / triangle->lmscale[0]; + forward[2] = 0; + left[0] = 0; + left[1] = 0; + left[2] = 1.0f / triangle->lmscale[1]; + up[0] = 1.0f; + up[1] = 0; + up[2] = 0; + origin[0] = 0; + origin[1] = triangle->lmbase[0]; + origin[2] = triangle->lmbase[1]; + break; + case 1: + forward[0] = 1.0f / triangle->lmscale[0]; + forward[1] = 0; + forward[2] = 0; + left[0] = 0; + left[1] = 0; + left[2] = 1.0f / triangle->lmscale[1]; + up[0] = 0; + up[1] = 1.0f; + up[2] = 0; + origin[0] = triangle->lmbase[0]; + origin[1] = 0; + origin[2] = triangle->lmbase[1]; + break; + case 2: + forward[0] = 1.0f / triangle->lmscale[0]; + forward[1] = 0; + forward[2] = 0; + left[0] = 0; + left[1] = 1.0f / triangle->lmscale[1]; + left[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1.0f; + origin[0] = triangle->lmbase[0]; + origin[1] = triangle->lmbase[1]; + origin[2] = 0; + break; + } + Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin); +#endif +#define LM_DIST_EPSILON (1.0f / 32.0f) + for (y = 0;y < triangle->lmsize[1];y++) + { + pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4; + for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4) + { + samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0]; + samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1]; + samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase; + VectorMA(samplecenter, 0.125f, samplenormal, samplecenter); + Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset); + } + } + } + } + + for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++) + { + model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va(vabuf, sizeof(vabuf), "lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL); + model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL); + } + + if (lightmappixels) + Mem_Free(lightmappixels); + if (deluxemappixels) + Mem_Free(deluxemappixels); + + for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++) + { + surface = model->data_surfaces + surfaceindex; + if (!surface->num_triangles) + continue; + lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex; + surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex]; + surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex]; + surface->lightmapinfo = NULL; + } + + model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint; + model->brushq1.lightdata = NULL; + model->brushq1.lightmapupdateflags = NULL; + model->brushq1.firstrender = false; + model->brushq1.num_lightstyles = 0; + model->brushq1.data_lightstyleinfo = NULL; + for (i = 0;i < model->brush.numsubmodels;i++) + { + model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL; + model->brush.submodels[i]->brushq1.firstrender = false; + model->brush.submodels[i]->brushq1.num_lightstyles = 0; + model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL; + } +} + +static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model) +{ + int i; + for (i = 0;i < model->surfmesh.num_vertices;i++) + Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i); +} + +static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model) +{ + int x; + int y; + int z; + int index = 0; + float pos[3]; + for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++) + { + pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2]; + for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++) + { + pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1]; + for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++) + { + pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0]; + Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index); + } + } + } +} + +extern cvar_t mod_q3bsp_nolightmaps; +static void Mod_GenerateLightmaps(dp_model_t *model) +{ + //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t)); + dp_model_t *oldloadmodel = loadmodel; + loadmodel = model; + + Mod_GenerateLightmaps_InitSampleOffsets(model); + Mod_GenerateLightmaps_DestroyLightmaps(model); + Mod_GenerateLightmaps_UnweldTriangles(model); + Mod_GenerateLightmaps_CreateTriangleInformation(model); + Mod_GenerateLightmaps_CreateLights(model); + if(!mod_q3bsp_nolightmaps.integer) + Mod_GenerateLightmaps_CreateLightmaps(model); + Mod_GenerateLightmaps_UpdateVertexColors(model); + Mod_GenerateLightmaps_UpdateLightGrid(model); + Mod_GenerateLightmaps_DestroyLights(model); + Mod_GenerateLightmaps_DestroyTriangleInformation(model); + + loadmodel = oldloadmodel; +} + +static void Mod_GenerateLightmaps_f(void) +{ + if (Cmd_Argc() != 1) + { + Con_Printf("usage: mod_generatelightmaps\n"); + return; + } + if (!cl.worldmodel) + { + Con_Printf("no worldmodel loaded\n"); + return; + } + Mod_GenerateLightmaps(cl.worldmodel); +} diff --git a/app/jni/model_shared.h b/app/jni/model_shared.h new file mode 100644 index 0000000..dd5d5e0 --- /dev/null +++ b/app/jni/model_shared.h @@ -0,0 +1,1241 @@ +/* +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_SHARED_H +#define MODEL_SHARED_H + +typedef enum synctype_e {ST_SYNC=0, ST_RAND } synctype_t; + +/* + +d*_t structures are on-disk representations +m*_t structures are in-memory + +*/ + +typedef enum modtype_e {mod_invalid, mod_brushq1, mod_sprite, mod_alias, mod_brushq2, mod_brushq3, mod_obj, mod_null} modtype_t; + +typedef struct animscene_s +{ + char name[32]; // for viewthing support + int firstframe; + int framecount; + int loop; // true or false + float framerate; +} +animscene_t; + +typedef struct skinframe_s +{ + rtexture_t *stain; // inverse modulate with background (used for decals and such) + rtexture_t *merged; // original texture without glow + rtexture_t *base; // original texture without pants/shirt/glow + rtexture_t *pants; // pants only (in greyscale) + rtexture_t *shirt; // shirt only (in greyscale) + rtexture_t *nmap; // normalmap (bumpmap for dot3) + rtexture_t *gloss; // glossmap (for dot3) + rtexture_t *glow; // glow only (fullbrights) + rtexture_t *fog; // alpha of the base texture (if not opaque) + rtexture_t *reflect; // colored mask for cubemap reflections + // accounting data for hash searches: + // the compare variables are used to identify internal skins from certain + // model formats + // (so that two q1bsp maps with the same texture name for different + // textures do not have any conflicts) + struct skinframe_s *next; // next on hash chain + char basename[MAX_QPATH]; // name of this + int textureflags; // texture flags to use + int comparewidth; + int compareheight; + int comparecrc; + // mark and sweep garbage collection, this value is updated to a new value + // on each level change for the used skinframes, if some are not used they + // are freed + int loadsequence; + // indicates whether this texture has transparent pixels + qboolean hasalpha; + // average texture color, if applicable + float avgcolor[4]; + // for mdl skins, we actually only upload on first use (many are never used, and they are almost never used in both base+pants+shirt and merged modes) + unsigned char *qpixels; + int qwidth; + int qheight; + qboolean qhascolormapping; + qboolean qgeneratebase; + qboolean qgeneratemerged; + qboolean qgeneratenmap; + qboolean qgenerateglow; +} +skinframe_t; + +struct md3vertex_s; +struct trivertx_s; +typedef struct texvecvertex_s +{ + signed char svec[3]; + signed char tvec[3]; +} +texvecvertex_t; + +typedef struct blendweights_s +{ + unsigned char index[4]; + unsigned char influence[4]; +} +blendweights_t; + +typedef struct r_vertexgeneric_s +{ + // 36 bytes + float vertex3f[3]; + float color4f[4]; + float texcoord2f[2]; +} +r_vertexgeneric_t; + +typedef struct r_vertexmesh_s +{ + // 88 bytes + float vertex3f[3]; + float color4f[4]; + float texcoordtexture2f[2]; + float texcoordlightmap2f[2]; + float svector3f[3]; + float tvector3f[3]; + float normal3f[3]; + unsigned char skeletalindex4ub[4]; + unsigned char skeletalweight4ub[4]; +} +r_vertexmesh_t; + +typedef struct r_meshbuffer_s +{ + int bufferobject; // OpenGL + void *devicebuffer; // Direct3D + size_t size; + qboolean isindexbuffer; + qboolean isuniformbuffer; + qboolean isdynamic; + qboolean isindex16; + char name[MAX_QPATH]; +} +r_meshbuffer_t; + +// used for mesh lists in q1bsp/q3bsp map models +// (the surfaces reference portions of these meshes) +typedef struct surfmesh_s +{ + // triangle data in system memory + int num_triangles; // number of triangles in the mesh + int *data_element3i; // int[tris*3] triangles of the mesh, 3 indices into vertex arrays for each + r_meshbuffer_t *data_element3i_indexbuffer; + size_t data_element3i_bufferoffset; + unsigned short *data_element3s; // unsigned short[tris*3] triangles of the mesh in unsigned short format (NULL if num_vertices > 65536) + r_meshbuffer_t *data_element3s_indexbuffer; + size_t data_element3s_bufferoffset; + int *data_neighbor3i; // int[tris*3] neighboring triangle on each edge (-1 if none) + // vertex data in system memory + int num_vertices; // number of vertices in the mesh + float *data_vertex3f; // float[verts*3] vertex locations + float *data_svector3f; // float[verts*3] direction of 'S' (right) texture axis for each vertex + float *data_tvector3f; // float[verts*3] direction of 'T' (down) texture axis for each vertex + float *data_normal3f; // float[verts*3] direction of 'R' (out) texture axis for each vertex + float *data_texcoordtexture2f; // float[verts*2] texcoords for surface texture + float *data_texcoordlightmap2f; // float[verts*2] texcoords for lightmap texture + float *data_lightmapcolor4f; + unsigned char *data_skeletalindex4ub; + unsigned char *data_skeletalweight4ub; + int *data_lightmapoffsets; // index into surface's lightmap samples for vertex lighting + r_vertexmesh_t *data_vertexmesh; // interleaved arrays for D3D + // vertex buffer object (stores geometry in video memory) + r_meshbuffer_t *vbo_vertexbuffer; + int vbooffset_vertex3f; + int vbooffset_svector3f; + int vbooffset_tvector3f; + int vbooffset_normal3f; + int vbooffset_texcoordtexture2f; + int vbooffset_texcoordlightmap2f; + int vbooffset_lightmapcolor4f; + int vbooffset_skeletalindex4ub; + int vbooffset_skeletalweight4ub; + int vbooffset_vertexmesh; + // morph blending, these are zero if model is skeletal or static + int num_morphframes; + struct md3vertex_s *data_morphmd3vertex; + struct trivertx_s *data_morphmdlvertex; + struct texvecvertex_s *data_morphtexvecvertex; + float *data_morphmd2framesize6f; + float num_morphmdlframescale[3]; + float num_morphmdlframetranslate[3]; + // skeletal blending, these are NULL if model is morph or static + struct blendweights_s *data_blendweights; + int num_blends; + unsigned short *blends; + // set if there is some kind of animation on this model + qboolean isanimated; + + // vertex and index buffers for rendering + r_meshbuffer_t *vertexmesh_vertexbuffer; +} +surfmesh_t; + +#define SHADOWMESHVERTEXHASH 1024 +typedef struct shadowmeshvertexhash_s +{ + struct shadowmeshvertexhash_s *next; +} +shadowmeshvertexhash_t; + +typedef struct shadowmesh_s +{ + // next mesh in chain + struct shadowmesh_s *next; + // used for light mesh (NULL on shadow mesh) + rtexture_t *map_diffuse; + rtexture_t *map_specular; + rtexture_t *map_normal; + // buffer sizes + int numverts, maxverts; + int numtriangles, maxtriangles; + // used always + float *vertex3f; + // used for light mesh (NULL on shadow mesh) + float *svector3f; + float *tvector3f; + float *normal3f; + float *texcoord2f; + // used always + int *element3i; + r_meshbuffer_t *element3i_indexbuffer; + int element3i_bufferoffset; + unsigned short *element3s; + r_meshbuffer_t *element3s_indexbuffer; + int element3s_bufferoffset; + // vertex/index buffers for rendering + // (created by Mod_ShadowMesh_Finish if possible) + r_vertexmesh_t *vertexmesh; // usually NULL + // used for shadow mapping cubemap side partitioning + int sideoffsets[6], sidetotals[6]; + // used for shadow mesh (NULL on light mesh) + int *neighbor3i; + // these are NULL after Mod_ShadowMesh_Finish is performed, only used + // while building meshes + shadowmeshvertexhash_t **vertexhashtable, *vertexhashentries; + r_meshbuffer_t *vbo_vertexbuffer; + int vbooffset_vertex3f; + int vbooffset_svector3f; + int vbooffset_tvector3f; + int vbooffset_normal3f; + int vbooffset_texcoord2f; + int vbooffset_vertexmesh; +} +shadowmesh_t; + +// various flags from shaders, used for special effects not otherwise classified +// TODO: support these features more directly +#define Q3TEXTUREFLAG_TWOSIDED 1 +#define Q3TEXTUREFLAG_NOPICMIP 16 +#define Q3TEXTUREFLAG_POLYGONOFFSET 32 +#define Q3TEXTUREFLAG_REFRACTION 256 +#define Q3TEXTUREFLAG_REFLECTION 512 +#define Q3TEXTUREFLAG_WATERSHADER 1024 +#define Q3TEXTUREFLAG_CAMERA 2048 +#define Q3TEXTUREFLAG_TRANSPARENTSORT 4096 + +#define Q3PATHLENGTH 64 +#define TEXTURE_MAXFRAMES 64 +#define Q3WAVEPARMS 4 +#define Q3DEFORM_MAXPARMS 3 +#define Q3SHADER_MAXLAYERS 2 // FIXME support more than that (currently only two are used, so why keep more in RAM?) +#define Q3RGBGEN_MAXPARMS 3 +#define Q3ALPHAGEN_MAXPARMS 1 +#define Q3TCGEN_MAXPARMS 6 +#define Q3TCMOD_MAXPARMS 6 +#define Q3MAXTCMODS 8 +#define Q3MAXDEFORMS 4 + +typedef enum q3wavefunc_e +{ + Q3WAVEFUNC_NONE, + Q3WAVEFUNC_INVERSESAWTOOTH, + Q3WAVEFUNC_NOISE, + Q3WAVEFUNC_SAWTOOTH, + Q3WAVEFUNC_SIN, + Q3WAVEFUNC_SQUARE, + Q3WAVEFUNC_TRIANGLE, + Q3WAVEFUNC_COUNT +} +q3wavefunc_e; +typedef int q3wavefunc_t; +#define Q3WAVEFUNC_USER_COUNT 4 +#define Q3WAVEFUNC_USER_SHIFT 8 // use 8 bits for wave func type + +typedef enum q3deform_e +{ + Q3DEFORM_NONE, + Q3DEFORM_PROJECTIONSHADOW, + Q3DEFORM_AUTOSPRITE, + Q3DEFORM_AUTOSPRITE2, + Q3DEFORM_TEXT0, + Q3DEFORM_TEXT1, + Q3DEFORM_TEXT2, + Q3DEFORM_TEXT3, + Q3DEFORM_TEXT4, + Q3DEFORM_TEXT5, + Q3DEFORM_TEXT6, + Q3DEFORM_TEXT7, + Q3DEFORM_BULGE, + Q3DEFORM_WAVE, + Q3DEFORM_NORMAL, + Q3DEFORM_MOVE, + Q3DEFORM_COUNT +} +q3deform_t; + +typedef enum q3rgbgen_e +{ + Q3RGBGEN_IDENTITY, + Q3RGBGEN_CONST, + Q3RGBGEN_ENTITY, + Q3RGBGEN_EXACTVERTEX, + Q3RGBGEN_IDENTITYLIGHTING, + Q3RGBGEN_LIGHTINGDIFFUSE, + Q3RGBGEN_ONEMINUSENTITY, + Q3RGBGEN_ONEMINUSVERTEX, + Q3RGBGEN_VERTEX, + Q3RGBGEN_WAVE, + Q3RGBGEN_COUNT +} +q3rgbgen_t; + +typedef enum q3alphagen_e +{ + Q3ALPHAGEN_IDENTITY, + Q3ALPHAGEN_CONST, + Q3ALPHAGEN_ENTITY, + Q3ALPHAGEN_LIGHTINGSPECULAR, + Q3ALPHAGEN_ONEMINUSENTITY, + Q3ALPHAGEN_ONEMINUSVERTEX, + Q3ALPHAGEN_PORTAL, + Q3ALPHAGEN_VERTEX, + Q3ALPHAGEN_WAVE, + Q3ALPHAGEN_COUNT +} +q3alphagen_t; + +typedef enum q3tcgen_e +{ + Q3TCGEN_NONE, + Q3TCGEN_TEXTURE, // very common + Q3TCGEN_ENVIRONMENT, // common + Q3TCGEN_LIGHTMAP, + Q3TCGEN_VECTOR, + Q3TCGEN_COUNT +} +q3tcgen_t; + +typedef enum q3tcmod_e +{ + Q3TCMOD_NONE, + Q3TCMOD_ENTITYTRANSLATE, + Q3TCMOD_ROTATE, + Q3TCMOD_SCALE, + Q3TCMOD_SCROLL, + Q3TCMOD_STRETCH, + Q3TCMOD_TRANSFORM, + Q3TCMOD_TURBULENT, + Q3TCMOD_PAGE, + Q3TCMOD_COUNT +} +q3tcmod_t; + +typedef struct q3shaderinfo_layer_rgbgen_s +{ + q3rgbgen_t rgbgen; + float parms[Q3RGBGEN_MAXPARMS]; + q3wavefunc_t wavefunc; + float waveparms[Q3WAVEPARMS]; +} +q3shaderinfo_layer_rgbgen_t; + +typedef struct q3shaderinfo_layer_alphagen_s +{ + q3alphagen_t alphagen; + float parms[Q3ALPHAGEN_MAXPARMS]; + q3wavefunc_t wavefunc; + float waveparms[Q3WAVEPARMS]; +} +q3shaderinfo_layer_alphagen_t; + +typedef struct q3shaderinfo_layer_tcgen_s +{ + q3tcgen_t tcgen; + float parms[Q3TCGEN_MAXPARMS]; +} +q3shaderinfo_layer_tcgen_t; + +typedef struct q3shaderinfo_layer_tcmod_s +{ + q3tcmod_t tcmod; + float parms[Q3TCMOD_MAXPARMS]; + q3wavefunc_t wavefunc; + float waveparms[Q3WAVEPARMS]; +} +q3shaderinfo_layer_tcmod_t; + +typedef struct q3shaderinfo_layer_s +{ + int alphatest; + int clampmap; + float framerate; + int numframes; + int texflags; + char** texturename; + int blendfunc[2]; + q3shaderinfo_layer_rgbgen_t rgbgen; + q3shaderinfo_layer_alphagen_t alphagen; + q3shaderinfo_layer_tcgen_t tcgen; + q3shaderinfo_layer_tcmod_t tcmods[Q3MAXTCMODS]; +} +q3shaderinfo_layer_t; + +typedef struct q3shaderinfo_deform_s +{ + q3deform_t deform; + float parms[Q3DEFORM_MAXPARMS]; + q3wavefunc_t wavefunc; + float waveparms[Q3WAVEPARMS]; +} +q3shaderinfo_deform_t; + +typedef enum dpoffsetmapping_technique_s +{ + OFFSETMAPPING_OFF, // none + OFFSETMAPPING_DEFAULT, // cvar-set + OFFSETMAPPING_LINEAR, // linear + OFFSETMAPPING_RELIEF // relief +}dpoffsetmapping_technique_t; + +typedef enum dptransparentsort_category_e +{ + TRANSPARENTSORT_SKY, + TRANSPARENTSORT_DISTANCE, + TRANSPARENTSORT_HUD, +}dptransparentsortcategory_t; + +typedef struct q3shaderinfo_s +{ + char name[Q3PATHLENGTH]; +#define Q3SHADERINFO_COMPARE_START surfaceparms + int surfaceparms; + int surfaceflags; + int textureflags; + int numlayers; + qboolean lighting; + qboolean vertexalpha; + qboolean textureblendalpha; + int primarylayer, backgroundlayer; + q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS]; + char skyboxname[Q3PATHLENGTH]; + q3shaderinfo_deform_t deforms[Q3MAXDEFORMS]; + + // dp-specific additions: + + // shadow control + qboolean dpnortlight; + qboolean dpshadow; + qboolean dpnoshadow; + + // add collisions to all triangles of the surface + qboolean dpmeshcollisions; + + // kill shader based on cvar checks + qboolean dpshaderkill; + + // fake reflection + char dpreflectcube[Q3PATHLENGTH]; + + // reflection + float reflectmin; // when refraction is used, minimum amount of reflection (when looking straight down) + float reflectmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) + float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies) + vec4_t refractcolor4f; // color tint of refraction (including alpha factor) + float reflectfactor; // amount of reflection distort (1.0 = like the cvar specifies) + vec4_t reflectcolor4f; // color tint of reflection (including alpha factor) + float r_water_wateralpha; // additional wateralpha to apply when r_water is active + float r_water_waterscroll[2]; // water normalmapscrollblend - scale and speed + + // offsetmapping + dpoffsetmapping_technique_t offsetmapping; + float offsetscale; + float offsetbias; // 0 is normal, 1 leads to alpha 0 being neutral and alpha 1 pushing "out" + + // polygonoffset (only used if Q3TEXTUREFLAG_POLYGONOFFSET) + float biaspolygonoffset, biaspolygonfactor; + + // transparent sort category + dptransparentsortcategory_t transparentsort; + + // gloss + float specularscalemod; + float specularpowermod; + + // rtlighting ambient addition + float rtlightambient; +#define Q3SHADERINFO_COMPARE_END rtlightambient +} +q3shaderinfo_t; + +typedef enum texturelayertype_e +{ + TEXTURELAYERTYPE_INVALID, + TEXTURELAYERTYPE_LITTEXTURE, + TEXTURELAYERTYPE_TEXTURE, + TEXTURELAYERTYPE_FOG +} +texturelayertype_t; + +typedef struct texturelayer_s +{ + texturelayertype_t type; + qboolean depthmask; + int blendfunc1; + int blendfunc2; + rtexture_t *texture; + matrix4x4_t texmatrix; + vec4_t color; +} +texturelayer_t; + +typedef struct texture_s +{ + // q1bsp + // name + //char name[16]; + // size + unsigned int width, height; + // SURF_ flags + //unsigned int flags; + + // base material flags + int basematerialflags; + // current material flags (updated each bmodel render) + int currentmaterialflags; + + // PolygonOffset values for rendering this material + // (these are added to the r_refdef values and submodel values) + float biaspolygonfactor; + float biaspolygonoffset; + + // textures to use when rendering this material + skinframe_t *currentskinframe; + int numskinframes; + float skinframerate; + skinframe_t *skinframes[TEXTURE_MAXFRAMES]; + // background layer (for terrain texture blending) + skinframe_t *backgroundcurrentskinframe; + int backgroundnumskinframes; + float backgroundskinframerate; + skinframe_t *backgroundskinframes[TEXTURE_MAXFRAMES]; + + // total frames in sequence and alternate sequence + int anim_total[2]; + // direct pointers to each of the frames in the sequences + // (indexed as [alternate][frame]) + struct texture_s *anim_frames[2][10]; + // set if animated or there is an alternate frame set + // (this is an optimization in the renderer) + int animated; + + // renderer checks if this texture needs updating... + int update_lastrenderframe; + void *update_lastrenderentity; + // the current alpha of this texture (may be affected by r_wateralpha) + float currentalpha; + // the current texture frame in animation + struct texture_s *currentframe; + // current texture transform matrix (used for water scrolling) + matrix4x4_t currenttexmatrix; + matrix4x4_t currentbackgroundtexmatrix; + + // various q3 shader features + q3shaderinfo_layer_rgbgen_t rgbgen; + q3shaderinfo_layer_alphagen_t alphagen; + q3shaderinfo_layer_tcgen_t tcgen; + q3shaderinfo_layer_tcmod_t tcmods[Q3MAXTCMODS]; + q3shaderinfo_layer_tcmod_t backgroundtcmods[Q3MAXTCMODS]; + q3shaderinfo_deform_t deforms[Q3MAXDEFORMS]; + + qboolean colormapping; + rtexture_t *basetexture; // original texture without pants/shirt/glow + rtexture_t *pantstexture; // pants only (in greyscale) + rtexture_t *shirttexture; // shirt only (in greyscale) + rtexture_t *nmaptexture; // normalmap (bumpmap for dot3) + rtexture_t *glosstexture; // glossmap (for dot3) + rtexture_t *glowtexture; // glow only (fullbrights) + rtexture_t *fogtexture; // alpha of the base texture (if not opaque) + rtexture_t *reflectmasktexture; // mask for fake reflections + rtexture_t *reflectcubetexture; // fake reflections cubemap + rtexture_t *backgroundbasetexture; // original texture without pants/shirt/glow + rtexture_t *backgroundnmaptexture; // normalmap (bumpmap for dot3) + rtexture_t *backgroundglosstexture; // glossmap (for dot3) + rtexture_t *backgroundglowtexture; // glow only (fullbrights) + float specularscale; + float specularpower; + // color tint (colormod * currentalpha) used for rtlighting this material + float dlightcolor[3]; + // color tint (colormod * 2) used for lightmapped lighting on this material + // includes alpha as 4th component + // replaces role of gl_Color in GLSL shader + float lightmapcolor[4]; + + // from q3 shaders + int customblendfunc[2]; + + int currentnumlayers; + texturelayer_t currentlayers[16]; + + // q3bsp + char name[64]; + int surfaceflags; + int supercontents; + int textureflags; + + // reflection + float reflectmin; // when refraction is used, minimum amount of reflection (when looking straight down) + float reflectmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) + float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies) + vec4_t refractcolor4f; // color tint of refraction (including alpha factor) + float reflectfactor; // amount of reflection distort (1.0 = like the cvar specifies) + vec4_t reflectcolor4f; // color tint of reflection (including alpha factor) + float r_water_wateralpha; // additional wateralpha to apply when r_water is active + float r_water_waterscroll[2]; // scale and speed + int camera_entity; // entity number for use by cameras + + // offsetmapping + dpoffsetmapping_technique_t offsetmapping; + float offsetscale; + float offsetbias; + + // transparent sort category + dptransparentsortcategory_t transparentsort; + + // gloss + float specularscalemod; + float specularpowermod; + + // diffuse and ambient + float rtlightambient; +} + texture_t; + +typedef struct mtexinfo_s +{ + float vecs[2][4]; + texture_t *texture; + int flags; +} +mtexinfo_t; + +typedef struct msurface_lightmapinfo_s +{ + // texture mapping properties used by this surface + mtexinfo_t *texinfo; // q1bsp + // index into r_refdef.scene.lightstylevalue array, 255 means not used (black) + unsigned char styles[MAXLIGHTMAPS]; // q1bsp + // RGB lighting data [numstyles][height][width][3] + unsigned char *samples; // q1bsp + // RGB normalmap data [numstyles][height][width][3] + unsigned char *nmapsamples; // q1bsp + // stain to apply on lightmap (soot/dirt/blood/whatever) + unsigned char *stainsamples; // q1bsp + int texturemins[2]; // q1bsp + int extents[2]; // q1bsp + int lightmaporigin[2]; // q1bsp +} +msurface_lightmapinfo_t; + +struct q3deffect_s; +typedef struct msurface_s +{ + // bounding box for onscreen checks + vec3_t mins; + vec3_t maxs; + // the texture to use on the surface + texture_t *texture; + // the lightmap texture fragment to use on the rendering mesh + rtexture_t *lightmaptexture; + // the lighting direction texture fragment to use on the rendering mesh + rtexture_t *deluxemaptexture; + // lightmaptexture rebuild information not used in q3bsp + msurface_lightmapinfo_t *lightmapinfo; // q1bsp + // fog volume info in q3bsp + struct q3deffect_s *effect; // q3bsp + // mesh information for collisions (only used by q3bsp curves) + int num_firstcollisiontriangle; + int *deprecatedq3data_collisionelement3i; // q3bsp + float *deprecatedq3data_collisionvertex3f; // q3bsp + float *deprecatedq3data_collisionbbox6f; // collision optimization - contains combined bboxes of every data_collisionstride triangles + float *deprecatedq3data_bbox6f; // collision optimization - contains combined bboxes of every data_collisionstride triangles + + // surfaces own ranges of vertices and triangles in the model->surfmesh + int num_triangles; // number of triangles + int num_firsttriangle; // first triangle + int num_vertices; // number of vertices + int num_firstvertex; // first vertex + + // shadow volume building information + int num_firstshadowmeshtriangle; // index into model->brush.shadowmesh + + // mesh information for collisions (only used by q3bsp curves) + int num_collisiontriangles; // q3bsp + int num_collisionvertices; // q3bsp + int deprecatedq3num_collisionbboxstride; + int deprecatedq3num_bboxstride; + // FIXME: collisionmarkframe should be kept in a separate array + int deprecatedq3collisionmarkframe; // q3bsp // don't collide twice in one trace +} +msurface_t; + +#include "matrixlib.h" +#include "bih.h" + +#include "model_brush.h" +#include "model_sprite.h" +#include "model_alias.h" + +typedef struct model_sprite_s +{ + int sprnum_type; + mspriteframe_t *sprdata_frames; +} +model_sprite_t; + +struct trace_s; + +typedef struct model_brush_lightstyleinfo_s +{ + int style; + int value; + int numsurfaces; + int *surfacelist; +} +model_brush_lightstyleinfo_t; + +typedef struct model_brush_s +{ + // true if this model is a HalfLife .bsp file + qboolean ishlbsp; + // true if this model is a BSP2rmqe .bsp file (expanded 32bit bsp format for rmqe) + qboolean isbsp2rmqe; + // true if this model is a BSP2 .bsp file (expanded 32bit bsp format for DarkPlaces, others?) + qboolean isbsp2; + // string of entity definitions (.map format) + char *entities; + + // if not NULL this is a submodel + struct model_s *parentmodel; + // (this is the number of the submodel, an index into submodels) + int submodel; + + // number of submodels in this map (just used by server to know how many + // submodels to load) + int numsubmodels; + // pointers to each of the submodels + struct model_s **submodels; + + int num_planes; + mplane_t *data_planes; + + int num_nodes; + mnode_t *data_nodes; + + // visible leafs, not counting 0 (solid) + int num_visleafs; + // number of actual leafs (including 0 which is solid) + int num_leafs; + mleaf_t *data_leafs; + + int num_leafbrushes; + int *data_leafbrushes; + + int num_leafsurfaces; + int *data_leafsurfaces; + + int num_portals; + mportal_t *data_portals; + + int num_portalpoints; + mvertex_t *data_portalpoints; + + int num_brushes; + q3mbrush_t *data_brushes; + + int num_brushsides; + q3mbrushside_t *data_brushsides; + + // pvs + int num_pvsclusters; + int num_pvsclusterbytes; + unsigned char *data_pvsclusters; + // example + //pvschain = model->brush.data_pvsclusters + mycluster * model->brush.num_pvsclusterbytes; + //if (pvschain[thatcluster >> 3] & (1 << (thatcluster & 7))) + + // collision geometry for q3 curves + int num_collisionvertices; + int num_collisiontriangles; + float *data_collisionvertex3f; + int *data_collisionelement3i; + + // a mesh containing all shadow casting geometry for the whole model (including submodels), portions of this are referenced by each surface's num_firstshadowmeshtriangle + shadowmesh_t *shadowmesh; + + // a mesh containing all SUPERCONTENTS_SOLID surfaces for this model or submodel, for physics engines to use + shadowmesh_t *collisionmesh; + + // common functions + int (*SuperContentsFromNativeContents)(struct model_s *model, int nativecontents); + int (*NativeContentsFromSuperContents)(struct model_s *model, int supercontents); + unsigned char *(*GetPVS)(struct model_s *model, const vec3_t p); + int (*FatPVS)(struct model_s *model, const vec3_t org, vec_t radius, unsigned char *pvsbuffer, int pvsbufferlength, qboolean merge); + int (*BoxTouchingPVS)(struct model_s *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs); + int (*BoxTouchingLeafPVS)(struct model_s *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs); + int (*BoxTouchingVisibleLeafs)(struct model_s *model, const unsigned char *visibleleafs, const vec3_t mins, const vec3_t maxs); + int (*FindBoxClusters)(struct model_s *model, const vec3_t mins, const vec3_t maxs, int maxclusters, int *clusterlist); + void (*LightPoint)(struct model_s *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal); + void (*FindNonSolidLocation)(struct model_s *model, const vec3_t in, vec3_t out, vec_t radius); + mleaf_t *(*PointInLeaf)(struct model_s *model, const vec3_t p); + // these are actually only found on brushq1, but NULL is handled gracefully + void (*AmbientSoundLevelsForPoint)(struct model_s *model, const vec3_t p, unsigned char *out, int outsize); + void (*RoundUpToHullSize)(struct model_s *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs); + // trace a line of sight through this model (returns false if the line if sight is definitely blocked) + qboolean (*TraceLineOfSight)(struct model_s *model, const vec3_t start, const vec3_t end); + + char skybox[MAX_QPATH]; + + skinframe_t *solidskyskinframe; + skinframe_t *alphaskyskinframe; + + qboolean supportwateralpha; + + // QuakeWorld + int qw_md4sum; + int qw_md4sum2; +} +model_brush_t; + +typedef struct model_brushq1_s +{ + mmodel_t *submodels; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + mclipnode_t *clipnodes; + + hull_t hulls[MAX_MAP_HULLS]; + + int num_compressedpvs; + unsigned char *data_compressedpvs; + + int num_lightdata; + unsigned char *lightdata; + unsigned char *nmaplightdata; // deluxemap file + + // lightmap update chains for light styles + int num_lightstyles; + model_brush_lightstyleinfo_t *data_lightstyleinfo; + + // this contains bytes that are 1 if a surface needs its lightmap rebuilt + unsigned char *lightmapupdateflags; + qboolean firstrender; // causes all surface lightmaps to be loaded in first frame +} +model_brushq1_t; + +/* MSVC can't compile empty structs, so this is commented out for now +typedef struct model_brushq2_s +{ +} +model_brushq2_t; +*/ + +typedef struct model_brushq3_s +{ + int num_models; + q3dmodel_t *data_models; + + // used only during loading - freed after loading! + int num_vertices; + float *data_vertex3f; + float *data_normal3f; + float *data_texcoordtexture2f; + float *data_texcoordlightmap2f; + float *data_color4f; + + // freed after loading! + int num_triangles; + int *data_element3i; + + int num_effects; + q3deffect_t *data_effects; + + // lightmap textures + int num_originallightmaps; + int num_mergedlightmaps; + int num_lightmapmergedwidthpower; + int num_lightmapmergedheightpower; + int num_lightmapmergedwidthheightdeluxepower; + int num_lightmapmerge; + rtexture_t **data_lightmaps; + rtexture_t **data_deluxemaps; + + // voxel light data with directional shading + int num_lightgrid; + q3dlightgrid_t *data_lightgrid; + // size of each cell (may vary by map, typically 64 64 128) + float num_lightgrid_cellsize[3]; + // 1.0 / num_lightgrid_cellsize + float num_lightgrid_scale[3]; + // dimensions of the world model in lightgrid cells + int num_lightgrid_imins[3]; + int num_lightgrid_imaxs[3]; + int num_lightgrid_isize[3]; + // transform modelspace coordinates to lightgrid index + matrix4x4_t num_lightgrid_indexfromworld; + + // true if this q3bsp file has been detected as using deluxemapping + // (lightmap texture pairs, every odd one is never directly refernced, + // and contains lighting normals, not colors) + qboolean deluxemapping; + // true if the detected deluxemaps are the modelspace kind, rather than + // the faster tangentspace kind + qboolean deluxemapping_modelspace; + // size of lightmaps (128 by default, but may be another poweroftwo if + // external lightmaps are used (q3map2 -lightmapsize) + int lightmapsize; +} +model_brushq3_t; + +struct frameblend_s; +struct skeleton_s; + +typedef struct model_s +{ + // name and path of model, for example "progs/player.mdl" + char name[MAX_QPATH]; + // model needs to be loaded if this is false + qboolean loaded; + // set if the model is used in current map, models which are not, are purged + qboolean used; + // CRC of the file this model was loaded from, to reload if changed + unsigned int crc; + // mod_brush, mod_alias, mod_sprite + modtype_t type; + // memory pool for allocations + mempool_t *mempool; + // all models use textures... + rtexturepool_t *texturepool; + // EF_* flags (translated from the model file's different flags layout) + int effects; + // number of QC accessible frame(group)s in the model + int numframes; + // number of QC accessible skin(group)s in the model + int numskins; + // whether to randomize animated framegroups + synctype_t synctype; + // bounding box at angles '0 0 0' + vec3_t normalmins, normalmaxs; + // bounding box if yaw angle is not 0, but pitch and roll are + vec3_t yawmins, yawmaxs; + // bounding box if pitch or roll are used + vec3_t rotatedmins, rotatedmaxs; + // sphere radius, usable at any angles + float radius; + // squared sphere radius for easier comparisons + float radius2; + // skin animation info + animscene_t *skinscenes; // [numskins] + // skin animation info + animscene_t *animscenes; // [numframes] + // range of surface numbers in this (sub)model + int firstmodelsurface; + int nummodelsurfaces; + int *sortedmodelsurfaces; + // range of collision brush numbers in this (sub)model + int firstmodelbrush; + int nummodelbrushes; + // BIH (Bounding Interval Hierarchy) for this (sub)model + bih_t collision_bih; + bih_t render_bih; // if not set, use collision_bih instead for rendering purposes too + // for md3 models + int num_tags; + int num_tagframes; + aliastag_t *data_tags; + // for skeletal models + int num_bones; + aliasbone_t *data_bones; + float num_posescale; // scaling factor from origin in poses7s format (includes divide by 32767) + float num_poseinvscale; // scaling factor to origin in poses7s format (includes multiply by 32767) + int num_poses; + short *data_poses7s; // origin xyz, quat xyzw, unit length, values normalized to +/-32767 range + float *data_baseboneposeinverse; + // textures of this model + int num_textures; + int num_texturesperskin; + texture_t *data_textures; + qboolean wantnormals; + qboolean wanttangents; + // surfaces of this model + int num_surfaces; + msurface_t *data_surfaces; + // optional lightmapinfo data for surface lightmap updates + msurface_lightmapinfo_t *data_surfaces_lightmapinfo; + // all surfaces belong to this mesh + surfmesh_t surfmesh; + // data type of model + const char *modeldatatypestring; + // generates vertex data for a given frameblend + void(*AnimateVertices)(const struct model_s * RESTRICT model, const struct frameblend_s * RESTRICT frameblend, const struct skeleton_s *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f); + // draw the model's sky polygons (only used by brush models) + void(*DrawSky)(struct entity_render_s *ent); + // draw refraction/reflection textures for the model's water polygons (only used by brush models) + void(*DrawAddWaterPlanes)(struct entity_render_s *ent); + // draw the model using lightmap/dlight shading + void(*Draw)(struct entity_render_s *ent); + // draw the model to the depth buffer (no color rendering at all) + void(*DrawDepth)(struct entity_render_s *ent); + // draw any enabled debugging effects on this model (such as showing triangles, normals, collision brushes...) + void(*DrawDebug)(struct entity_render_s *ent); + // draw geometry textures for deferred rendering + void(*DrawPrepass)(struct entity_render_s *ent); + // compile an optimized shadowmap mesh for the model based on light source + void(*CompileShadowMap)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); + // draw depth into a shadowmap + void(*DrawShadowMap)(int side, struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const unsigned char *surfacesides, const vec3_t lightmins, const vec3_t lightmaxs); + // gathers info on which clusters and surfaces are lit by light, as well as calculating a bounding box + void(*GetLightInfo)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs, int numfrustumplanes, const mplane_t *frustumplanes); + // compile a shadow volume for the model based on light source + void(*CompileShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); + // draw a shadow volume for the model based on light source + void(*DrawShadowVolume)(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); + // draw the lighting on a model (through stencil) + void(*DrawLight)(struct entity_render_s *ent, int numsurfaces, const int *surfacelist, const unsigned char *trispvs); + // trace a box against this model + void (*TraceBox)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask); + void (*TraceBrush)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, struct colbrushf_s *start, struct colbrushf_s *end, int hitsupercontentsmask); + // trace a box against this model + void (*TraceLine)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); + // trace a point against this model (like PointSuperContents) + void (*TracePoint)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, const vec3_t start, int hitsupercontentsmask); + // find the supercontents value at a point in this model + int (*PointSuperContents)(struct model_s *model, int frame, const vec3_t point); + // trace a line against geometry in this model and report correct texture (used by r_shadow_bouncegrid) + void (*TraceLineAgainstSurfaces)(struct model_s *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); + // fields belonging to some types of model + model_sprite_t sprite; + model_brush_t brush; + model_brushq1_t brushq1; + /* MSVC can't handle an empty struct, so this is commented out for now + model_brushq2_t brushq2; + */ + model_brushq3_t brushq3; + // flags this model for offseting sounds to the model center (used by brush models) + int soundfromcenter; + + // if set, the model contains light information (lightmap, or vertexlight) + qboolean lit; + float lightmapscale; +} +dp_model_t; + +//============================================================================ + +// model loading +extern dp_model_t *loadmodel; +extern unsigned char *mod_base; +// sky/water subdivision +//extern cvar_t gl_subdivide_size; +// texture fullbrights +extern cvar_t r_fullbrights; +extern cvar_t r_enableshadowvolumes; + +void Mod_Init (void); +void Mod_Reload (void); +dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk); +dp_model_t *Mod_FindName (const char *name, const char *parentname); +dp_model_t *Mod_ForName (const char *name, qboolean crash, qboolean checkdisk, const char *parentname); +void Mod_UnloadModel (dp_model_t *mod); + +void Mod_ClearUsed(void); +void Mod_PurgeUnused(void); +void Mod_RemoveStaleWorldModels(dp_model_t *skip); // only used during loading! + +extern dp_model_t *loadmodel; +extern char loadname[32]; // for hunk tags + +int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices); +void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles); +void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline); +void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting); +void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting); + +void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors); +void Mod_MakeSortedSurfaces(dp_model_t *mod); + +// called specially by brush model loaders before generating submodels +// automatically called after model loader returns +void Mod_BuildVBOs(void); + +shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable); +shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors); +int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f); +void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f); +void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i); +shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable); +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo); +void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius); +void Mod_ShadowMesh_Free(shadowmesh_t *mesh); + +void Mod_CreateCollisionMesh(dp_model_t *mod); + +void Mod_FreeQ3Shaders(void); +void Mod_LoadQ3Shaders(void); +q3shaderinfo_t *Mod_LookupQ3Shader(const char *name); +qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags); + +extern cvar_t r_mipskins; +extern cvar_t r_mipnormalmaps; + +typedef struct skinfileitem_s +{ + struct skinfileitem_s *next; + char name[MAX_QPATH]; + char replacement[MAX_QPATH]; +} +skinfileitem_t; + +typedef struct skinfile_s +{ + struct skinfile_s *next; + skinfileitem_t *items; +} +skinfile_t; + +skinfile_t *Mod_LoadSkinFiles(void); +void Mod_FreeSkinFiles(skinfile_t *skinfile); +int Mod_CountSkinFiles(skinfile_t *skinfile); +void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername); + +void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap); +int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f); +void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer); + +typedef struct mod_alloclightmap_row_s +{ + int rowY; + int currentX; +} +mod_alloclightmap_row_t; + +typedef struct mod_alloclightmap_state_s +{ + int width; + int height; + int currentY; + mod_alloclightmap_row_t *rows; +} +mod_alloclightmap_state_t; + +void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height); +void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state); +void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state); +qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy); + +// bsp models +void Mod_BrushInit(void); +// used for talking to the QuakeC mainly +int Mod_Q1BSP_NativeContentsFromSuperContents(struct model_s *model, int supercontents); +int Mod_Q1BSP_SuperContentsFromNativeContents(struct model_s *model, int nativecontents); + +// a lot of model formats use the Q1BSP code, so here are the prototypes... +struct entity_render_s; +void R_Q1BSP_DrawAddWaterPlanes(struct entity_render_s *ent); +void R_Q1BSP_DrawSky(struct entity_render_s *ent); +void R_Q1BSP_Draw(struct entity_render_s *ent); +void R_Q1BSP_DrawDepth(struct entity_render_s *ent); +void R_Q1BSP_DrawDebug(struct entity_render_s *ent); +void R_Q1BSP_DrawPrepass(struct entity_render_s *ent); +void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs, int numfrustumplanes, const mplane_t *frustumplanes); +void R_Q1BSP_CompileShadowMap(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); +void R_Q1BSP_DrawShadowMap(int side, struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const unsigned char *surfacesides, const vec3_t lightmins, const vec3_t lightmaxs); +void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); +void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); +void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist, const unsigned char *trispvs); + +// Collision optimization using Bounding Interval Hierarchy +void Mod_CollisionBIH_TracePoint(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, int hitsupercontentsmask); +void Mod_CollisionBIH_TraceLine(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); +void Mod_CollisionBIH_TraceBox(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask); +void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, struct colbrushf_s *start, struct colbrushf_s *end, int hitsupercontentsmask); +void Mod_CollisionBIH_TracePoint_Mesh(dp_model_t *model, const struct frameblend_s *frameblend, const skeleton_t *skeleton, struct trace_s *trace, const vec3_t start, int hitsupercontentsmask); +int Mod_CollisionBIH_PointSuperContents_Mesh(struct model_s *model, int frame, const vec3_t point); +bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t *out); + +// alias models +struct frameblend_s; +struct skeleton_s; +void Mod_AliasInit(void); +int Mod_Alias_GetTagMatrix(const dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, int tagindex, matrix4x4_t *outmatrix); +int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname); +int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix); + +void Mod_Skeletal_FreeBuffers(void); + +// sprite models +void Mod_SpriteInit(void); + +// loaders +void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IBSP_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_MAP_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IDSP_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend); +void Mod_INTERQUAKEMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend); + +#endif // MODEL_SHARED_H + diff --git a/app/jni/model_sprite.c b/app/jni/model_sprite.c new file mode 100644 index 0000000..e24c842 --- /dev/null +++ b/app/jni/model_sprite.c @@ -0,0 +1,482 @@ +/* +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 "image.h" + +cvar_t r_mipsprites = {CVAR_SAVE, "r_mipsprites", "1", "mipmaps sprites so they render faster in the distance and do not display noise artifacts"}; +cvar_t r_labelsprites_scale = {CVAR_SAVE, "r_labelsprites_scale", "1", "global scale to apply to label sprites before conversion to HUD coordinates"}; +cvar_t r_labelsprites_roundtopixels = {CVAR_SAVE, "r_labelsprites_roundtopixels", "1", "try to make label sprites sharper by rounding their size to 0.5x or 1x and by rounding their position to whole pixels if possible"}; +cvar_t r_overheadsprites_perspective = {CVAR_SAVE, "r_overheadsprites_perspective", "5", "fake perspective effect for SPR_OVERHEAD sprites"}; +cvar_t r_overheadsprites_pushback = {CVAR_SAVE, "r_overheadsprites_pushback", "15", "how far to pull the SPR_OVERHEAD sprites toward the eye (used to avoid intersections with 3D models)"}; +cvar_t r_overheadsprites_scalex = {CVAR_SAVE, "r_overheadsprites_scalex", "1", "additional scale for overhead sprites for x axis"}; +cvar_t r_overheadsprites_scaley = {CVAR_SAVE, "r_overheadsprites_scaley", "1", "additional scale for overhead sprites for y axis"}; +cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"}; +cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accordingly, 2: Make it a continuous rotation"}; +cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"}; +cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"}; + +/* +=============== +Mod_SpriteInit +=============== +*/ +void Mod_SpriteInit (void) +{ + Cvar_RegisterVariable(&r_mipsprites); + Cvar_RegisterVariable(&r_labelsprites_scale); + Cvar_RegisterVariable(&r_labelsprites_roundtopixels); + Cvar_RegisterVariable(&r_overheadsprites_perspective); + Cvar_RegisterVariable(&r_overheadsprites_pushback); + Cvar_RegisterVariable(&r_overheadsprites_scalex); + Cvar_RegisterVariable(&r_overheadsprites_scaley); + Cvar_RegisterVariable(&r_track_sprites); + Cvar_RegisterVariable(&r_track_sprites_flags); + Cvar_RegisterVariable(&r_track_sprites_scalew); + Cvar_RegisterVariable(&r_track_sprites_scaleh); +} + +static void Mod_SpriteSetupTexture(texture_t *texture, skinframe_t *skinframe, qboolean fullbright, qboolean additive) +{ + if (!skinframe) + skinframe = R_SkinFrame_LoadMissing(); + texture->offsetmapping = OFFSETMAPPING_OFF; + texture->offsetscale = 1; + texture->offsetbias = 0; + texture->specularscalemod = 1; + texture->specularpowermod = 1; + texture->basematerialflags = MATERIALFLAG_WALL; + if (fullbright) + texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT; + if (additive) + texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + else if (skinframe->hasalpha) + texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; + texture->currentmaterialflags = texture->basematerialflags; + texture->numskinframes = 1; + texture->currentskinframe = texture->skinframes[0] = skinframe; + texture->surfaceflags = 0; + texture->supercontents = SUPERCONTENTS_SOLID; + if (!(texture->basematerialflags & MATERIALFLAG_BLENDED)) + texture->supercontents |= SUPERCONTENTS_OPAQUE; + texture->transparentsort = TRANSPARENTSORT_DISTANCE; + // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS + // JUST GREP FOR "specularscalemod = 1". +} + +extern cvar_t gl_texturecompression_sprites; + +static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version, const unsigned int *palette, qboolean additive) +{ + int i, j, groupframes, realframes, x, y, origin[2], width, height; + qboolean fullbright; + dspriteframetype_t *pinframetype; + dspriteframe_t *pinframe; + dspritegroup_t *pingroup; + dspriteinterval_t *pinintervals; + skinframe_t *skinframe; + float modelradius, interval; + char name[MAX_QPATH], fogname[MAX_QPATH]; + const void *startframes; + int texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | ((gl_texturecompression.integer && gl_texturecompression_sprites.integer) ? TEXF_COMPRESS : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_ALPHA | TEXF_CLAMP; + modelradius = 0; + + if (loadmodel->numframes < 1) + Host_Error ("Mod_Sprite_SharedSetup: Invalid # of frames: %d", loadmodel->numframes); + + // LordHavoc: hack to allow sprites to be non-fullbright + fullbright = true; + for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++) + if (loadmodel->name[i] == '!') + fullbright = false; + +// +// load the frames +// + startframes = datapointer; + realframes = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + pinframetype = (dspriteframetype_t *)datapointer; + datapointer += sizeof(dspriteframetype_t); + + if (LittleLong (pinframetype->type) == SPR_SINGLE) + groupframes = 1; + else + { + pingroup = (dspritegroup_t *)datapointer; + datapointer += sizeof(dspritegroup_t); + + groupframes = LittleLong(pingroup->numframes); + + datapointer += sizeof(dspriteinterval_t) * groupframes; + } + + for (j = 0;j < groupframes;j++) + { + pinframe = (dspriteframe_t *)datapointer; + if (version == SPRITE32_VERSION) + datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height) * 4; + else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) + datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height); + } + realframes += groupframes; + } + + loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); + loadmodel->sprite.sprdata_frames = (mspriteframe_t *)Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * realframes); + loadmodel->num_textures = realframes; + loadmodel->num_texturesperskin = 1; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, sizeof(texture_t) * loadmodel->num_textures); + + datapointer = (unsigned char *)startframes; + realframes = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + pinframetype = (dspriteframetype_t *)datapointer; + datapointer += sizeof(dspriteframetype_t); + + if (LittleLong (pinframetype->type) == SPR_SINGLE) + { + groupframes = 1; + interval = 0.1f; + } + else + { + pingroup = (dspritegroup_t *)datapointer; + datapointer += sizeof(dspritegroup_t); + + groupframes = LittleLong(pingroup->numframes); + + pinintervals = (dspriteinterval_t *)datapointer; + datapointer += sizeof(dspriteinterval_t) * groupframes; + + interval = LittleFloat(pinintervals[0].interval); + if (interval < 0.01f) + Host_Error("Mod_Sprite_SharedSetup: invalid interval"); + } + + dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "frame %i", i); + loadmodel->animscenes[i].firstframe = realframes; + loadmodel->animscenes[i].framecount = groupframes; + loadmodel->animscenes[i].framerate = 1.0f / interval; + loadmodel->animscenes[i].loop = true; + + for (j = 0;j < groupframes;j++) + { + pinframe = (dspriteframe_t *)datapointer; + datapointer += sizeof(dspriteframe_t); + + origin[0] = LittleLong (pinframe->origin[0]); + origin[1] = LittleLong (pinframe->origin[1]); + width = LittleLong (pinframe->width); + height = LittleLong (pinframe->height); + + loadmodel->sprite.sprdata_frames[realframes].left = origin[0]; + loadmodel->sprite.sprdata_frames[realframes].right = origin[0] + width; + loadmodel->sprite.sprdata_frames[realframes].up = origin[1]; + loadmodel->sprite.sprdata_frames[realframes].down = origin[1] - height; + + x = (int)max(loadmodel->sprite.sprdata_frames[realframes].left * loadmodel->sprite.sprdata_frames[realframes].left, loadmodel->sprite.sprdata_frames[realframes].right * loadmodel->sprite.sprdata_frames[realframes].right); + y = (int)max(loadmodel->sprite.sprdata_frames[realframes].up * loadmodel->sprite.sprdata_frames[realframes].up, loadmodel->sprite.sprdata_frames[realframes].down * loadmodel->sprite.sprdata_frames[realframes].down); + if (modelradius < x + y) + modelradius = x + y; + + if (cls.state != ca_dedicated) + { + skinframe = NULL; + // note: Nehahra's null.spr has width == 0 and height == 0 + if (width > 0 && height > 0) + { + if (groupframes > 1) + { + dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j); + dpsnprintf (fogname, sizeof(fogname), "%s_%i_%ifog", loadmodel->name, i, j); + } + else + { + dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); + dpsnprintf (fogname, sizeof(fogname), "%s_%ifog", loadmodel->name, i); + } + if (!(skinframe = R_SkinFrame_LoadExternal(name, texflags | TEXF_COMPRESS, false))) + { + unsigned char *pixels = (unsigned char *) Mem_Alloc(loadmodel->mempool, width*height*4); + if (version == SPRITE32_VERSION) + { + for (x = 0;x < width*height;x++) + { + pixels[x*4+2] = datapointer[x*4+0]; + pixels[x*4+1] = datapointer[x*4+1]; + pixels[x*4+0] = datapointer[x*4+2]; + pixels[x*4+3] = datapointer[x*4+3]; + } + } + else //if (version == SPRITEHL_VERSION || version == SPRITE_VERSION) + Image_Copy8bitBGRA(datapointer, pixels, width*height, palette ? palette : palette_bgra_transparent); + skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height, false); + // texflags |= TEXF_COMPRESS; + Mem_Free(pixels); + } + } + if (skinframe == NULL) + skinframe = R_SkinFrame_LoadMissing(); + Mod_SpriteSetupTexture(&loadmodel->data_textures[realframes], skinframe, fullbright, additive); + } + + if (version == SPRITE32_VERSION) + datapointer += width * height * 4; + else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) + datapointer += width * height; + realframes++; + } + } + + modelradius = sqrt(modelradius); + for (i = 0;i < 3;i++) + { + loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius; + loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius; + } + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; +} + +void Mod_IDSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int version; + const unsigned char *datapointer; + + datapointer = (unsigned char *)buffer; + + loadmodel->modeldatatypestring = "SPR1"; + + loadmodel->type = mod_sprite; + + loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Sprite_Draw; + loadmodel->DrawDepth = NULL; + loadmodel->CompileShadowVolume = NULL; + loadmodel->DrawShadowVolume = NULL; + loadmodel->DrawLight = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + + version = LittleLong(((dsprite_t *)buffer)->version); + if (version == SPRITE_VERSION || version == SPRITE32_VERSION) + { + dsprite_t *pinqsprite; + + pinqsprite = (dsprite_t *)datapointer; + datapointer += sizeof(dsprite_t); + + loadmodel->numframes = LittleLong (pinqsprite->numframes); + loadmodel->sprite.sprnum_type = LittleLong (pinqsprite->type); + loadmodel->synctype = (synctype_t)LittleLong (pinqsprite->synctype); + + Mod_Sprite_SharedSetup(datapointer, LittleLong (pinqsprite->version), NULL, false); + } + else if (version == SPRITEHL_VERSION) + { + int i, rendermode; + unsigned char palette[256][4]; + const unsigned char *in; + dspritehl_t *pinhlsprite; + + pinhlsprite = (dspritehl_t *)datapointer; + datapointer += sizeof(dspritehl_t); + + loadmodel->numframes = LittleLong (pinhlsprite->numframes); + loadmodel->sprite.sprnum_type = LittleLong (pinhlsprite->type); + loadmodel->synctype = (synctype_t)LittleLong (pinhlsprite->synctype); + rendermode = pinhlsprite->rendermode; + + in = datapointer; + datapointer += 2; + i = in[0] + in[1] * 256; + if (i != 256) + Host_Error ("Mod_IDSP_Load: unexpected number of palette colors %i (should be 256)", i); + in = datapointer; + datapointer += 768; + switch(rendermode) + { + case SPRHL_OPAQUE: + for (i = 0;i < 256;i++) + { + palette[i][2] = in[i*3+0]; + palette[i][1] = in[i*3+1]; + palette[i][0] = in[i*3+2]; + palette[i][3] = 255; + } + break; + case SPRHL_ADDITIVE: + for (i = 0;i < 256;i++) + { + palette[i][2] = in[i*3+0]; + palette[i][1] = in[i*3+1]; + palette[i][0] = in[i*3+2]; + palette[i][3] = 255; + } + // also passes additive == true to Mod_Sprite_SharedSetup + break; + case SPRHL_INDEXALPHA: + for (i = 0;i < 256;i++) + { + palette[i][2] = in[765]; + palette[i][1] = in[766]; + palette[i][0] = in[767]; + palette[i][3] = i; + in += 3; + } + break; + case SPRHL_ALPHATEST: + for (i = 0;i < 256;i++) + { + palette[i][2] = in[i*3+0]; + palette[i][1] = in[i*3+1]; + palette[i][0] = in[i*3+2]; + palette[i][3] = 255; + } + palette[255][0] = palette[255][1] = palette[255][2] = palette[255][3] = 0; + // should this use alpha test or alpha blend? (currently blend) + break; + default: + Host_Error("Mod_IDSP_Load: unknown texFormat (%i, should be 0, 1, 2, or 3)", i); + return; + } + + Mod_Sprite_SharedSetup(datapointer, LittleLong (pinhlsprite->version), (unsigned int *)(&palette[0][0]), rendermode == SPRHL_ADDITIVE); + } + else + Host_Error("Mod_IDSP_Load: %s has wrong version number (%i). Only %i (quake), %i (HalfLife), and %i (sprite32) supported", + loadmodel->name, version, SPRITE_VERSION, SPRITEHL_VERSION, SPRITE32_VERSION); + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); +} + + +void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend) +{ + int i, version; + qboolean fullbright; + const dsprite2_t *pinqsprite; + skinframe_t *skinframe; + float modelradius; + int texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_COMPRESS | TEXF_ALPHA | TEXF_CLAMP; + + loadmodel->modeldatatypestring = "SPR2"; + + loadmodel->type = mod_sprite; + + loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Sprite_Draw; + loadmodel->DrawDepth = NULL; + loadmodel->CompileShadowVolume = NULL; + loadmodel->DrawShadowVolume = NULL; + loadmodel->DrawLight = NULL; + loadmodel->DrawAddWaterPlanes = NULL; + + pinqsprite = (dsprite2_t *)buffer; + + version = LittleLong(pinqsprite->version); + if (version != SPRITE2_VERSION) + Host_Error("Mod_IDS2_Load: %s has wrong version number (%i should be 2 (quake 2)", loadmodel->name, version); + + loadmodel->numframes = LittleLong (pinqsprite->numframes); + if (loadmodel->numframes < 1) + Host_Error ("Mod_IDS2_Load: Invalid # of frames: %d", loadmodel->numframes); + loadmodel->sprite.sprnum_type = SPR_VP_PARALLEL; + loadmodel->synctype = ST_SYNC; + + // LordHavoc: hack to allow sprites to be non-fullbright + fullbright = true; + for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++) + if (loadmodel->name[i] == '!') + fullbright = false; + + loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); + loadmodel->sprite.sprdata_frames = (mspriteframe_t *)Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * loadmodel->numframes); + loadmodel->num_textures = loadmodel->numframes; + loadmodel->num_texturesperskin = 1; + loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, sizeof(texture_t) * loadmodel->num_textures); + + modelradius = 0; + for (i = 0;i < loadmodel->numframes;i++) + { + int origin[2], x, y, width, height; + const dsprite2frame_t *pinframe; + mspriteframe_t *sprframe; + + dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "frame %i", i); + loadmodel->animscenes[i].firstframe = i; + loadmodel->animscenes[i].framecount = 1; + loadmodel->animscenes[i].framerate = 10; + loadmodel->animscenes[i].loop = true; + + pinframe = &pinqsprite->frames[i]; + + origin[0] = LittleLong (pinframe->origin_x); + origin[1] = LittleLong (pinframe->origin_y); + width = LittleLong (pinframe->width); + height = LittleLong (pinframe->height); + + sprframe = &loadmodel->sprite.sprdata_frames[i]; + + // note that sp2 origin[0] is positive, where as it is negative in + // spr/spr32/hlspr + sprframe->left = -origin[0]; + sprframe->right = -origin[0] + width; + sprframe->up = origin[1]; + sprframe->down = origin[1] - height; + + x = (int)max(sprframe->left * sprframe->left, sprframe->right * sprframe->right); + y = (int)max(sprframe->up * sprframe->up, sprframe->down * sprframe->down); + if (modelradius < x + y) + modelradius = x + y; + } + + if (cls.state != ca_dedicated) + { + for (i = 0;i < loadmodel->numframes;i++) + { + const dsprite2frame_t *pinframe; + pinframe = &pinqsprite->frames[i]; + if (!(skinframe = R_SkinFrame_LoadExternal(pinframe->name, texflags, false))) + { + Con_Printf("Mod_IDS2_Load: failed to load %s", pinframe->name); + skinframe = R_SkinFrame_LoadMissing(); + } + Mod_SpriteSetupTexture(&loadmodel->data_textures[i], skinframe, fullbright, false); + } + } + + modelradius = sqrt(modelradius); + for (i = 0;i < 3;i++) + { + loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius; + loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius; + } + loadmodel->radius = modelradius; + loadmodel->radius2 = modelradius * modelradius; + + loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || (loadmodel->animscenes && loadmodel->animscenes[0].framecount > 1); +} diff --git a/app/jni/model_sprite.h b/app/jni/model_sprite.h new file mode 100644 index 0000000..f6408da --- /dev/null +++ b/app/jni/model_sprite.h @@ -0,0 +1,41 @@ +/* +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_SPRITE_H +#define MODEL_SPRITE_H + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + +#include "spritegn.h" + +// FIXME: shorten these? +typedef struct mspriteframe_s +{ + float up, down, left, right; +} mspriteframe_t; + +#endif + diff --git a/app/jni/model_zymotic.h b/app/jni/model_zymotic.h new file mode 100644 index 0000000..d43f72c --- /dev/null +++ b/app/jni/model_zymotic.h @@ -0,0 +1,68 @@ + +#ifndef MODEL_ZYMOTIC_H +#define MODEL_ZYMOTIC_H + +typedef struct zymlump_s +{ + int start; + int length; +} zymlump_t; + +typedef struct zymtype1header_s +{ + char id[12]; // "ZYMOTICMODEL", length 12, no termination + int type; // 0 (vertex morph) 1 (skeletal pose) or 2 (skeletal scripted) + int filesize; // size of entire model file + float mins[3], maxs[3], radius; // for clipping uses + int numverts; + int numtris; + int numshaders; + int numbones; // this may be zero in the vertex morph format (undecided) + int numscenes; // 0 in skeletal scripted models + +// skeletal pose header + // lump offsets are relative to the file + zymlump_t lump_scenes; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct) + zymlump_t lump_poses; // float pose[numposes][numbones][6]; // animation data + zymlump_t lump_bones; // zymbone_t bone[numbones]; + zymlump_t lump_vertbonecounts; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better) + zymlump_t lump_verts; // zymvertex_t vert[numvertices]; // see vertex struct + zymlump_t lump_texcoords; // float texcoords[numvertices][2]; + zymlump_t lump_render; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices) + zymlump_t lump_shaders; // char shadername[numshaders][32]; // shaders used on this model + zymlump_t lump_trizone; // byte trizone[numtris]; // see trizone explanation +} +zymtype1header_t; + +#define ZYMBONEFLAG_SHARED 1 + +typedef struct zymbone_s +{ + char name[32]; + int flags; + int parent; // parent bone number +} +zymbone_t; + +// normally the scene will loop, if this is set it will stay on the final frame +#define ZYMSCENEFLAG_NOLOOP 1 + +typedef struct zymscene_s +{ + char name[32]; + float mins[3], maxs[3], radius; // for clipping + float framerate; // the scene will animate at this framerate (in frames per second) + int flags; + int start, length; // range of poses +} +zymscene_t; + +typedef struct zymvertex_s +{ + int bonenum; + float origin[3]; +} +zymvertex_t; + +#endif + diff --git a/app/jni/modelgen.h b/app/jni/modelgen.h new file mode 100644 index 0000000..0ddb776 --- /dev/null +++ b/app/jni/modelgen.h @@ -0,0 +1,137 @@ +/* +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. * +// ********************************************************* + +#ifndef MODELGEN_H +#define MODELGEN_H + +#define ALIAS_VERSION 6 + +#define ALIAS_ONSEAM 0x0020 + +typedef enum aliasframetype_e { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t; + +typedef enum aliasskintype_e { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; + +typedef struct mdl_s +{ + 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; + +// TODO: could be shorts + +typedef struct stvert_s +{ + 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 trivertx_s +{ + unsigned char v[3]; + unsigned char lightnormalindex; +} +trivertx_t; + +typedef struct daliasframe_s +{ + 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 daliasgroup_s +{ + int numframes; + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used +} +daliasgroup_t; + +typedef struct daliasskingroup_s +{ + int numskins; +} +daliasskingroup_t; + +typedef struct daliasinterval_s +{ + float interval; +} +daliasinterval_t; + +typedef struct daliasskininterval_s +{ + float interval; +} +daliasskininterval_t; + +typedef struct daliasframetype_s +{ + aliasframetype_t type; +} +daliasframetype_t; + +typedef struct daliasskintype_s +{ + aliasskintype_t type; +} +daliasskintype_t; + +#endif + diff --git a/app/jni/mprogdefs.h b/app/jni/mprogdefs.h new file mode 100644 index 0000000..c7993b7 --- /dev/null +++ b/app/jni/mprogdefs.h @@ -0,0 +1,22 @@ + +#ifndef MPROGDEFS_H +#define MPROGDEFS_H + +/* file generated by qcc, do not modify */ + +/* +typedef struct m_globalvars_s +{ + int pad[28]; + int self; +} m_globalvars_t; + +typedef struct m_entvars_s +{ +} m_entvars_t; + +#define M_PROGHEADER_CRC 10020 + +*/ + +#endif diff --git a/app/jni/mvm_cmds.c b/app/jni/mvm_cmds.c new file mode 100644 index 0000000..9a23640 --- /dev/null +++ b/app/jni/mvm_cmds.c @@ -0,0 +1,1577 @@ +#include "quakedef.h" + +#include "prvm_cmds.h" +#include "clvm_cmds.h" +#include "menu.h" +#include "csprogs.h" + +// TODO check which strings really should be engine strings + +//============================================================================ +// Menu + +const char *vm_m_extensions = +"BX_WAL_SUPPORT " +"DP_CINEMATIC_DPV " +"DP_CSQC_BINDMAPS " +"DP_CRYPTO " +"DP_GFX_FONTS " +"DP_GFX_FONTS_FREETYPE " +"DP_UTF8 " +"DP_FONT_VARIABLEWIDTH " +"DP_MENU_EXTRESPONSEPACKET " +"DP_QC_ASINACOSATANATAN2TAN " +"DP_QC_AUTOCVARS " +"DP_QC_CMD " +"DP_QC_CRC16 " +"DP_QC_CVAR_TYPE " +"DP_QC_CVAR_DESCRIPTION " +"DP_QC_DIGEST " +"DP_QC_DIGEST_SHA256 " +"DP_QC_FINDCHAIN_TOFIELD " +"DP_QC_I18N " +"DP_QC_LOG " +"DP_QC_RENDER_SCENE " +"DP_QC_SPRINTF " +"DP_QC_STRFTIME " +"DP_QC_STRINGBUFFERS " +"DP_QC_STRINGBUFFERS_CVARLIST " +"DP_QC_STRINGBUFFERS_EXT_WIP " +"DP_QC_STRINGCOLORFUNCTIONS " +"DP_QC_STRING_CASE_FUNCTIONS " +"DP_QC_STRREPLACE " +"DP_QC_TOKENIZEBYSEPARATOR " +"DP_QC_TOKENIZE_CONSOLE " +"DP_QC_UNLIMITEDTEMPSTRINGS " +"DP_QC_URI_ESCAPE " +"DP_QC_URI_GET " +"DP_QC_URI_POST " +"DP_QC_WHICHPACK " +"FTE_STRINGS " +; + +/* +========= +VM_M_setmousetarget + +setmousetarget(float target) +========= +*/ +static void VM_M_setmousetarget(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_setmousetarget); + + switch((int)PRVM_G_FLOAT(OFS_PARM0)) + { + case 1: + in_client_mouse = false; + break; + case 2: + in_client_mouse = true; + break; + default: + prog->error_cmd("VM_M_setmousetarget: wrong destination %f !",PRVM_G_FLOAT(OFS_PARM0)); + } +} + +/* +========= +VM_M_getmousetarget + +float getmousetarget +========= +*/ +static void VM_M_getmousetarget(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_M_getmousetarget); + + if(in_client_mouse) + PRVM_G_FLOAT(OFS_RETURN) = 2; + else + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + + + +/* +========= +VM_M_setkeydest + +setkeydest(float dest) +========= +*/ +static void VM_M_setkeydest(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_M_setkeydest); + + switch((int)PRVM_G_FLOAT(OFS_PARM0)) + { + case 0: + // key_game + key_dest = key_game; + break; + case 2: + // key_menu + key_dest = key_menu; + break; + case 3: + // key_menu_grabbed + key_dest = key_menu_grabbed; + break; + case 1: + // key_message + // key_dest = key_message + // break; + default: + prog->error_cmd("VM_M_setkeydest: wrong destination %f !", PRVM_G_FLOAT(OFS_PARM0)); + } +} + +/* +========= +VM_M_getkeydest + +float getkeydest +========= +*/ +static void VM_M_getkeydest(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_M_getkeydest); + + // key_game = 0, key_message = 1, key_menu = 2, key_menu_grabbed = 3, unknown = -1 + switch(key_dest) + { + case key_game: + PRVM_G_FLOAT(OFS_RETURN) = 0; + break; + case key_menu: + PRVM_G_FLOAT(OFS_RETURN) = 2; + break; + case key_menu_grabbed: + PRVM_G_FLOAT(OFS_RETURN) = 3; + break; + case key_message: + // not supported + // PRVM_G_FLOAT(OFS_RETURN) = 1; + // break; + default: + PRVM_G_FLOAT(OFS_RETURN) = -1; + } +} + + +/* +========= +VM_M_getresolution + +vector getresolution(float number) +========= +*/ +static void VM_M_getresolution(prvm_prog_t *prog) +{ + int nr, fs; + VM_SAFEPARMCOUNTRANGE(1, 2, VM_getresolution); + + nr = (int)PRVM_G_FLOAT(OFS_PARM0); + + fs = ((prog->argc <= 1) || ((int)PRVM_G_FLOAT(OFS_PARM1))); + + if(nr < 0 || nr >= (fs ? video_resolutions_count : video_resolutions_hardcoded_count)) + { + PRVM_G_VECTOR(OFS_RETURN)[0] = 0; + PRVM_G_VECTOR(OFS_RETURN)[1] = 0; + PRVM_G_VECTOR(OFS_RETURN)[2] = 0; + } + else + { + video_resolution_t *r = &((fs ? video_resolutions : video_resolutions_hardcoded)[nr]); + PRVM_G_VECTOR(OFS_RETURN)[0] = r->width; + PRVM_G_VECTOR(OFS_RETURN)[1] = r->height; + PRVM_G_VECTOR(OFS_RETURN)[2] = r->pixelheight; + } +} + +static void VM_M_getgamedirinfo(prvm_prog_t *prog) +{ + int nr, item; + VM_SAFEPARMCOUNT(2, VM_getgamedirinfo); + + nr = (int)PRVM_G_FLOAT(OFS_PARM0); + item = (int)PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; + + if(nr >= 0 && nr < fs_all_gamedirs_count) + { + if(item == 0) + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, fs_all_gamedirs[nr].name ); + else if(item == 1) + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, fs_all_gamedirs[nr].description ); + } +} + +/* +========= +VM_M_getserverliststat + +float getserverliststat(float type) +========= +*/ +/* + type: +0 serverlist_viewcount +1 serverlist_totalcount +2 masterquerycount +3 masterreplycount +4 serverquerycount +5 serverreplycount +6 sortfield +7 sortflags +*/ +static void VM_M_getserverliststat(prvm_prog_t *prog) +{ + int type; + VM_SAFEPARMCOUNT ( 1, VM_M_getserverliststat ); + + PRVM_G_FLOAT( OFS_RETURN ) = 0; + + type = (int)PRVM_G_FLOAT( OFS_PARM0 ); + switch(type) + { + case 0: + PRVM_G_FLOAT ( OFS_RETURN ) = serverlist_viewcount; + return; + case 1: + PRVM_G_FLOAT ( OFS_RETURN ) = serverlist_cachecount; + return; + case 2: + PRVM_G_FLOAT ( OFS_RETURN ) = masterquerycount; + return; + case 3: + PRVM_G_FLOAT ( OFS_RETURN ) = masterreplycount; + return; + case 4: + PRVM_G_FLOAT ( OFS_RETURN ) = serverquerycount; + return; + case 5: + PRVM_G_FLOAT ( OFS_RETURN ) = serverreplycount; + return; + case 6: + PRVM_G_FLOAT ( OFS_RETURN ) = serverlist_sortbyfield; + return; + case 7: + PRVM_G_FLOAT ( OFS_RETURN ) = serverlist_sortflags; + return; + default: + VM_Warning(prog, "VM_M_getserverliststat: bad type %i!\n", type ); + } +} + +/* +======================== +VM_M_resetserverlistmasks + +resetserverlistmasks() +======================== +*/ +static void VM_M_resetserverlistmasks(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_M_resetserverlistmasks); + ServerList_ResetMasks(); +} + + +/* +======================== +VM_M_setserverlistmaskstring + +setserverlistmaskstring(float mask, float fld, string str, float op) +0-511 and +512 - 1024 or +======================== +*/ +static void VM_M_setserverlistmaskstring(prvm_prog_t *prog) +{ + const char *str; + int masknr; + serverlist_mask_t *mask; + int field; + + VM_SAFEPARMCOUNT( 4, VM_M_setserverlistmaskstring ); + str = PRVM_G_STRING( OFS_PARM2 ); + + masknr = (int)PRVM_G_FLOAT( OFS_PARM0 ); + if( masknr >= 0 && masknr <= SERVERLIST_ANDMASKCOUNT ) + mask = &serverlist_andmasks[masknr]; + else if( masknr >= 512 && masknr - 512 <= SERVERLIST_ORMASKCOUNT ) + mask = &serverlist_ormasks[masknr - 512 ]; + else + { + VM_Warning(prog, "VM_M_setserverlistmaskstring: invalid mask number %i\n", masknr ); + return; + } + + field = (int) PRVM_G_FLOAT( OFS_PARM1 ); + + switch( field ) { + case SLIF_CNAME: + strlcpy( mask->info.cname, str, sizeof(mask->info.cname) ); + break; + case SLIF_NAME: + strlcpy( mask->info.name, str, sizeof(mask->info.name) ); + break; + case SLIF_QCSTATUS: + strlcpy( mask->info.qcstatus, str, sizeof(mask->info.qcstatus) ); + break; + case SLIF_PLAYERS: + strlcpy( mask->info.players, str, sizeof(mask->info.players) ); + break; + case SLIF_MAP: + strlcpy( mask->info.map, str, sizeof(mask->info.map) ); + break; + case SLIF_MOD: + strlcpy( mask->info.mod, str, sizeof(mask->info.mod) ); + break; + case SLIF_GAME: + strlcpy( mask->info.game, str, sizeof(mask->info.game) ); + break; + default: + VM_Warning(prog, "VM_M_setserverlistmaskstring: Bad field number %i passed!\n", field ); + return; + } + + mask->active = true; + mask->tests[field] = (serverlist_maskop_t)((int)PRVM_G_FLOAT( OFS_PARM3 )); +} + +/* +======================== +VM_M_setserverlistmasknumber + +setserverlistmasknumber(float mask, float fld, float num, float op) + +0-511 and +512 - 1024 or +======================== +*/ +static void VM_M_setserverlistmasknumber(prvm_prog_t *prog) +{ + int number; + serverlist_mask_t *mask; + int masknr; + int field; + VM_SAFEPARMCOUNT( 4, VM_M_setserverlistmasknumber ); + + masknr = (int)PRVM_G_FLOAT( OFS_PARM0 ); + if( masknr >= 0 && masknr <= SERVERLIST_ANDMASKCOUNT ) + mask = &serverlist_andmasks[masknr]; + else if( masknr >= 512 && masknr - 512 <= SERVERLIST_ORMASKCOUNT ) + mask = &serverlist_ormasks[masknr - 512 ]; + else + { + VM_Warning(prog, "VM_M_setserverlistmasknumber: invalid mask number %i\n", masknr ); + return; + } + + number = (int)PRVM_G_FLOAT( OFS_PARM2 ); + field = (int) PRVM_G_FLOAT( OFS_PARM1 ); + + switch( field ) { + case SLIF_MAXPLAYERS: + mask->info.maxplayers = number; + break; + case SLIF_NUMPLAYERS: + mask->info.numplayers = number; + break; + case SLIF_NUMBOTS: + mask->info.numbots = number; + break; + case SLIF_NUMHUMANS: + mask->info.numhumans = number; + break; + case SLIF_PING: + mask->info.ping = number; + break; + case SLIF_PROTOCOL: + mask->info.protocol = number; + break; + case SLIF_FREESLOTS: + mask->info.freeslots = number; + break; + case SLIF_ISFAVORITE: + mask->info.isfavorite = number != 0; + break; + default: + VM_Warning(prog, "VM_M_setserverlistmasknumber: Bad field number %i passed!\n", field ); + return; + } + + mask->active = true; + mask->tests[field] = (serverlist_maskop_t)((int)PRVM_G_FLOAT( OFS_PARM3 )); +} + + +/* +======================== +VM_M_resortserverlist + +resortserverlist +======================== +*/ +static void VM_M_resortserverlist(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_M_resortserverlist); + ServerList_RebuildViewList(); +} + +/* +========= +VM_M_getserverliststring + +string getserverliststring(float field, float hostnr) +========= +*/ +static void VM_M_getserverliststring(prvm_prog_t *prog) +{ + serverlist_entry_t *cache; + int hostnr; + + VM_SAFEPARMCOUNT(2, VM_M_getserverliststring); + + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + + hostnr = (int)PRVM_G_FLOAT(OFS_PARM1); + + if(hostnr < 0 || hostnr >= serverlist_viewcount) + { + Con_Print("VM_M_getserverliststring: bad hostnr passed!\n"); + return; + } + cache = ServerList_GetViewEntry(hostnr); + switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) { + case SLIF_CNAME: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.cname ); + break; + case SLIF_NAME: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.name ); + break; + case SLIF_QCSTATUS: + PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.qcstatus ); + break; + case SLIF_PLAYERS: + PRVM_G_INT (OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.players ); + break; + case SLIF_GAME: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.game ); + break; + case SLIF_MOD: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.mod ); + break; + case SLIF_MAP: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.map ); + break; + // TODO remove this again + case 1024: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->line1 ); + break; + case 1025: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->line2 ); + break; + default: + Con_Print("VM_M_getserverliststring: bad field number passed!\n"); + } +} + +/* +========= +VM_M_getserverlistnumber + +float getserverlistnumber(float field, float hostnr) +========= +*/ +static void VM_M_getserverlistnumber(prvm_prog_t *prog) +{ + serverlist_entry_t *cache; + int hostnr; + + VM_SAFEPARMCOUNT(2, VM_M_getserverliststring); + + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + + hostnr = (int)PRVM_G_FLOAT(OFS_PARM1); + + if(hostnr < 0 || hostnr >= serverlist_viewcount) + { + Con_Print("VM_M_getserverliststring: bad hostnr passed!\n"); + return; + } + cache = ServerList_GetViewEntry(hostnr); + switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) { + case SLIF_MAXPLAYERS: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.maxplayers; + break; + case SLIF_NUMPLAYERS: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.numplayers; + break; + case SLIF_NUMBOTS: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.numbots; + break; + case SLIF_NUMHUMANS: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.numhumans; + break; + case SLIF_FREESLOTS: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.freeslots; + break; + case SLIF_PING: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.ping; + break; + case SLIF_PROTOCOL: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.protocol; + break; + case SLIF_ISFAVORITE: + PRVM_G_FLOAT( OFS_RETURN ) = cache->info.isfavorite; + break; + default: + Con_Print("VM_M_getserverlistnumber: bad field number passed!\n"); + } +} + +/* +======================== +VM_M_setserverlistsort + +setserverlistsort(float field, float flags) +======================== +*/ +static void VM_M_setserverlistsort(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT( 2, VM_M_setserverlistsort ); + + serverlist_sortbyfield = (serverlist_infofield_t)((int)PRVM_G_FLOAT( OFS_PARM0 )); + serverlist_sortflags = (int) PRVM_G_FLOAT( OFS_PARM1 ); +} + +/* +======================== +VM_M_refreshserverlist + +refreshserverlist() +======================== +*/ +static void VM_M_refreshserverlist(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT( 0, VM_M_refreshserverlist ); + ServerList_QueryList(false, true, false, false); +} + +/* +======================== +VM_M_getserverlistindexforkey + +float getserverlistindexforkey(string key) +======================== +*/ +static void VM_M_getserverlistindexforkey(prvm_prog_t *prog) +{ + const char *key; + VM_SAFEPARMCOUNT( 1, VM_M_getserverlistindexforkey ); + + key = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( prog, key ); + + if( !strcmp( key, "cname" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_CNAME; + else if( !strcmp( key, "ping" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_PING; + else if( !strcmp( key, "game" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_GAME; + else if( !strcmp( key, "mod" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_MOD; + else if( !strcmp( key, "map" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_MAP; + else if( !strcmp( key, "name" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_NAME; + else if( !strcmp( key, "qcstatus" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_QCSTATUS; + else if( !strcmp( key, "players" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_PLAYERS; + else if( !strcmp( key, "maxplayers" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_MAXPLAYERS; + else if( !strcmp( key, "numplayers" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_NUMPLAYERS; + else if( !strcmp( key, "numbots" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_NUMBOTS; + else if( !strcmp( key, "numhumans" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_NUMHUMANS; + else if( !strcmp( key, "freeslots" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_FREESLOTS; + else if( !strcmp( key, "protocol" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_PROTOCOL; + else if( !strcmp( key, "isfavorite" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = SLIF_ISFAVORITE; + else + PRVM_G_FLOAT( OFS_RETURN ) = -1; +} + +/* +======================== +VM_M_addwantedserverlistkey + +addwantedserverlistkey(string key) +======================== +*/ +static void VM_M_addwantedserverlistkey(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT( 1, VM_M_addwantedserverlistkey ); +} + +/* +=============================================================================== +MESSAGE WRITING + +used only for client and menu +server uses VM_SV_... + +Write*(* data, float type, float to) + +=============================================================================== +*/ + +#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 + +static sizebuf_t *VM_M_WriteDest (prvm_prog_t *prog) +{ + int dest; + int destclient; + + if(!sv.active) + prog->error_cmd("VM_M_WriteDest: game is not server (%s)", prog->name); + + dest = (int)PRVM_G_FLOAT(OFS_PARM1); + switch (dest) + { + case MSG_BROADCAST: + return &sv.datagram; + + case MSG_ONE: + destclient = (int) PRVM_G_FLOAT(OFS_PARM2); + if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active || !svs.clients[destclient].netconnection) + prog->error_cmd("VM_clientcommand: %s: invalid client !", prog->name); + + return &svs.clients[destclient].netconnection->message; + + case MSG_ALL: + return &sv.reliable_datagram; + + case MSG_INIT: + return &sv.signon; + + default: + prog->error_cmd("WriteDest: bad destination"); + break; + } + + return NULL; +} + +static void VM_M_WriteByte (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteByte); + MSG_WriteByte (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +static void VM_M_WriteChar (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteChar); + MSG_WriteChar (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +static void VM_M_WriteShort (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteShort); + MSG_WriteShort (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +static void VM_M_WriteLong (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteLong); + MSG_WriteLong (VM_M_WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +static void VM_M_WriteAngle (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteAngle); + MSG_WriteAngle (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol); +} + +static void VM_M_WriteCoord (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteCoord); + MSG_WriteCoord (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol); +} + +static void VM_M_WriteString (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteString); + MSG_WriteString (VM_M_WriteDest(prog), PRVM_G_STRING(OFS_PARM0)); +} + +static void VM_M_WriteEntity (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_M_WriteEntity); + MSG_WriteShort (VM_M_WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM0)); +} + +/* +================= +VM_M_copyentity + +copies data from one entity to another + +copyentity(entity src, entity dst) +================= +*/ +static void VM_M_copyentity (prvm_prog_t *prog) +{ + prvm_edict_t *in, *out; + VM_SAFEPARMCOUNT(2,VM_M_copyentity); + in = PRVM_G_EDICT(OFS_PARM0); + out = PRVM_G_EDICT(OFS_PARM1); + memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t)); +} + +//#66 vector() getmousepos (EXT_CSQC) +static void VM_M_getmousepos(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_M_getmousepos); + + if (key_consoleactive || (key_dest != key_menu && key_dest != key_menu_grabbed)) + VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0); + else if (in_client_mouse) + VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0); + else + VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0); +} + +static void VM_M_crypto_getkeyfp(prvm_prog_t *prog) +{ + lhnetaddress_t addr; + const char *s; + char keyfp[FP64_SIZE + 1]; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getkeyfp); + + s = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( prog, s ); + + if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, keyfp, sizeof(keyfp), NULL, 0, NULL)) + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, keyfp ); + else + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; +} +static void VM_M_crypto_getidfp(prvm_prog_t *prog) +{ + lhnetaddress_t addr; + const char *s; + char idfp[FP64_SIZE + 1]; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getidfp); + + s = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( prog, s ); + + if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, idfp, sizeof(idfp), NULL)) + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, idfp ); + else + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; +} +static void VM_M_crypto_getencryptlevel(prvm_prog_t *prog) +{ + lhnetaddress_t addr; + const char *s; + int aeslevel; + char vabuf[1024]; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getencryptlevel); + + s = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( prog, s ); + + if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, NULL, 0, &aeslevel)) + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, aeslevel ? va(vabuf, sizeof(vabuf), "%d AES128", aeslevel) : "0"); + else + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; +} +static void VM_M_crypto_getmykeyfp(prvm_prog_t *prog) +{ + int i; + char keyfp[FP64_SIZE + 1]; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); + + i = PRVM_G_FLOAT( OFS_PARM0 ); + switch(Crypto_RetrieveLocalKey(i, keyfp, sizeof(keyfp), NULL, 0, NULL)) + { + case -1: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, ""); + break; + case 0: + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; + break; + default: + case 1: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, keyfp); + break; + } +} +static void VM_M_crypto_getmyidfp(prvm_prog_t *prog) +{ + int i; + char idfp[FP64_SIZE + 1]; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); + + i = PRVM_G_FLOAT( OFS_PARM0 ); + switch(Crypto_RetrieveLocalKey(i, NULL, 0, idfp, sizeof(idfp), NULL)) + { + case -1: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, ""); + break; + case 0: + PRVM_G_INT( OFS_RETURN ) = OFS_NULL; + break; + default: + case 1: + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, idfp); + break; + } +} +static void VM_M_crypto_getmyidstatus(prvm_prog_t *prog) +{ + int i; + qboolean issigned; + + VM_SAFEPARMCOUNT(1,VM_M_crypto_getmykey); + + i = PRVM_G_FLOAT( OFS_PARM0 ); + switch(Crypto_RetrieveLocalKey(i, NULL, 0, NULL, 0, &issigned)) + { + case -1: + PRVM_G_FLOAT( OFS_RETURN ) = 0; // have no ID there + break; + case 0: + PRVM_G_FLOAT( OFS_RETURN ) = -1; // out of range + break; + default: + case 1: + PRVM_G_FLOAT( OFS_RETURN ) = issigned ? 2 : 1; + break; + } +} + +prvm_builtin_t vm_m_builtins[] = { +NULL, // #0 NULL function (not callable) +VM_checkextension, // #1 +VM_error, // #2 +VM_objerror, // #3 +VM_print, // #4 +VM_bprint, // #5 +VM_sprint, // #6 +VM_centerprint, // #7 +VM_normalize, // #8 +VM_vlen, // #9 +VM_vectoyaw, // #10 +VM_vectoangles, // #11 +VM_random, // #12 +VM_localcmd, // #13 +VM_cvar, // #14 +VM_cvar_set, // #15 +VM_dprint, // #16 +VM_ftos, // #17 +VM_fabs, // #18 +VM_vtos, // #19 +VM_etos, // #20 +VM_stof, // #21 +VM_spawn, // #22 +VM_remove, // #23 +VM_find, // #24 +VM_findfloat, // #25 +VM_findchain, // #26 +VM_findchainfloat, // #27 +VM_precache_file, // #28 +VM_precache_sound, // #29 +VM_coredump, // #30 +VM_traceon, // #31 +VM_traceoff, // #32 +VM_eprint, // #33 +VM_rint, // #34 +VM_floor, // #35 +VM_ceil, // #36 +VM_nextent, // #37 +VM_sin, // #38 +VM_cos, // #39 +VM_sqrt, // #40 +VM_randomvec, // #41 +VM_registercvar, // #42 +VM_min, // #43 +VM_max, // #44 +VM_bound, // #45 +VM_pow, // #46 +VM_M_copyentity, // #47 +VM_fopen, // #48 +VM_fclose, // #49 +VM_fgets, // #50 +VM_fputs, // #51 +VM_strlen, // #52 +VM_strcat, // #53 +VM_substring, // #54 +VM_stov, // #55 +VM_strzone, // #56 +VM_strunzone, // #57 +VM_tokenize, // #58 +VM_argv, // #59 +VM_isserver, // #60 +VM_clientcount, // #61 +VM_clientstate, // #62 +VM_clcommand, // #63 +VM_changelevel, // #64 +VM_localsound, // #65 +VM_M_getmousepos, // #66 +VM_gettime, // #67 +VM_loadfromdata, // #68 +VM_loadfromfile, // #69 +VM_modulo, // #70 +VM_cvar_string, // #71 +VM_crash, // #72 +VM_stackdump, // #73 +VM_search_begin, // #74 +VM_search_end, // #75 +VM_search_getsize, // #76 +VM_search_getfilename, // #77 +VM_chr, // #78 +VM_itof, // #79 +VM_ftoe, // #80 +VM_itof, // #81 isString +VM_altstr_count, // #82 +VM_altstr_prepare, // #83 +VM_altstr_get, // #84 +VM_altstr_set, // #85 +VM_altstr_ins, // #86 +VM_findflags, // #87 +VM_findchainflags, // #88 +VM_cvar_defstring, // #89 +// deactivate support for model rendering in the menu until someone has time to do it right [3/2/2008 Andreas] +#if 0 +VM_CL_setmodel, // #90 void(entity e, string m) setmodel (QUAKE) +VM_CL_precache_model, // #91 void(string s) precache_model (QUAKE) +VM_CL_setorigin, // #92 void(entity e, vector o) setorigin (QUAKE) +#else +NULL, +NULL, +NULL, +#endif +NULL, // #93 +NULL, // #94 +NULL, // #95 +NULL, // #96 +NULL, // #97 +NULL, // #98 +NULL, // #99 +NULL, // #100 +NULL, // #101 +NULL, // #102 +NULL, // #103 +NULL, // #104 +NULL, // #105 +NULL, // #106 +NULL, // #107 +NULL, // #108 +NULL, // #109 +NULL, // #110 +NULL, // #111 +NULL, // #112 +NULL, // #113 +NULL, // #114 +NULL, // #115 +NULL, // #116 +NULL, // #117 +NULL, // #118 +NULL, // #119 +NULL, // #120 +NULL, // #121 +NULL, // #122 +NULL, // #123 +NULL, // #124 +NULL, // #125 +NULL, // #126 +NULL, // #127 +NULL, // #128 +NULL, // #129 +NULL, // #130 +NULL, // #131 +NULL, // #132 +NULL, // #133 +NULL, // #134 +NULL, // #135 +NULL, // #136 +NULL, // #137 +NULL, // #138 +NULL, // #139 +NULL, // #140 +NULL, // #141 +NULL, // #142 +NULL, // #143 +NULL, // #144 +NULL, // #145 +NULL, // #146 +NULL, // #147 +NULL, // #148 +NULL, // #149 +NULL, // #150 +NULL, // #151 +NULL, // #152 +NULL, // #153 +NULL, // #154 +NULL, // #155 +NULL, // #156 +NULL, // #157 +NULL, // #158 +NULL, // #159 +NULL, // #160 +NULL, // #161 +NULL, // #162 +NULL, // #163 +NULL, // #164 +NULL, // #165 +NULL, // #166 +NULL, // #167 +NULL, // #168 +NULL, // #169 +NULL, // #170 +NULL, // #171 +NULL, // #172 +NULL, // #173 +NULL, // #174 +NULL, // #175 +NULL, // #176 +NULL, // #177 +NULL, // #178 +NULL, // #179 +NULL, // #180 +NULL, // #181 +NULL, // #182 +NULL, // #183 +NULL, // #184 +NULL, // #185 +NULL, // #186 +NULL, // #187 +NULL, // #188 +NULL, // #189 +NULL, // #190 +NULL, // #191 +NULL, // #192 +NULL, // #193 +NULL, // #194 +NULL, // #195 +NULL, // #196 +NULL, // #197 +NULL, // #198 +NULL, // #199 +NULL, // #200 +NULL, // #201 +NULL, // #202 +NULL, // #203 +NULL, // #204 +NULL, // #205 +NULL, // #206 +NULL, // #207 +NULL, // #208 +NULL, // #209 +NULL, // #210 +NULL, // #211 +NULL, // #212 +NULL, // #213 +NULL, // #214 +NULL, // #215 +NULL, // #216 +NULL, // #217 +NULL, // #218 +NULL, // #219 +NULL, // #220 +VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS) +VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS) +VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS) +VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS) +VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS) +VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS) +VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS) +VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) +VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +NULL, // #231 +NULL, // #232 +NULL, // #233 +NULL, // #234 +NULL, // #235 +NULL, // #236 +NULL, // #237 +NULL, // #238 +NULL, // #239 +NULL, // #240 +NULL, // #241 +NULL, // #242 +NULL, // #243 +NULL, // #244 +NULL, // #245 +NULL, // #246 +NULL, // #247 +NULL, // #248 +NULL, // #249 +NULL, // #250 +NULL, // #251 +NULL, // #252 +NULL, // #253 +NULL, // #254 +NULL, // #255 +NULL, // #256 +NULL, // #257 +NULL, // #258 +NULL, // #259 +NULL, // #260 +NULL, // #261 +NULL, // #262 +NULL, // #263 +NULL, // #264 +NULL, // #265 +NULL, // #266 +NULL, // #267 +NULL, // #268 +NULL, // #269 +NULL, // #270 +NULL, // #271 +NULL, // #272 +NULL, // #273 +NULL, // #274 +NULL, // #275 +NULL, // #276 +NULL, // #277 +NULL, // #278 +NULL, // #279 +NULL, // #280 +NULL, // #281 +NULL, // #282 +NULL, // #283 +NULL, // #284 +NULL, // #285 +NULL, // #286 +NULL, // #287 +NULL, // #288 +NULL, // #289 +NULL, // #290 +NULL, // #291 +NULL, // #292 +NULL, // #293 +NULL, // #294 +NULL, // #295 +NULL, // #296 +NULL, // #297 +NULL, // #298 +NULL, // #299 +// deactivate support for model rendering in the menu until someone has time to do it right [3/2/2008 Andreas] +#if 0 +// CSQC range #300-#399 +VM_CL_R_ClearScene, // #300 void() clearscene (DP_QC_RENDER_SCENE) +VM_CL_R_AddEntities, // #301 void(float mask) addentities (DP_QC_RENDER_SCENE) +VM_CL_R_AddEntity, // #302 void(entity ent) addentity (DP_QC_RENDER_SCENE) +VM_CL_R_SetView, // #303 float(float property, ...) setproperty (DP_QC_RENDER_SCENE) +VM_CL_R_RenderScene, // #304 void() renderscene (DP_QC_RENDER_SCENE) +VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (DP_QC_RENDER_SCENE) +VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon (DP_QC_RENDER_SCENE) +VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex (DP_QC_RENDER_SCENE) +VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon +NULL/*VM_CL_R_LoadWorldModel*/, // #309 void(string modelname) R_LoadWorldModel +// TODO: rearrange and merge all builtin lists and share as many extensions as possible between all VM instances [1/27/2008 Andreas] +VM_CL_setattachment, // #310 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) (DP_QC_RENDER_SCENE) +VM_CL_gettagindex, // #311 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO) (DP_QC_RENDER_SCENE) +VM_CL_gettaginfo, // #312 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO) (DP_QC_RENDER_SCENE) +#else +// CSQC range #300-#399 +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +NULL, +#endif +NULL, // #313 +NULL, // #314 +NULL, // #315 +NULL, // #316 +NULL, // #317 +NULL, // #318 +NULL, // #319 +NULL, // #320 +NULL, // #321 +NULL, // #322 +NULL, // #323 +NULL, // #324 +NULL, // #325 +NULL, // #326 +NULL, // #327 +NULL, // #328 +NULL, // #329 +NULL, // #330 +NULL, // #331 +NULL, // #332 +NULL, // #333 +NULL, // #334 +NULL, // #335 +NULL, // #336 +NULL, // #337 +NULL, // #338 +NULL, // #339 +VM_keynumtostring, // #340 string keynumtostring(float keynum) +VM_stringtokeynum, // #341 float stringtokeynum(string key) +VM_getkeybind, // #342 string(float keynum[, float bindmap]) getkeybind (EXT_CSQC) +NULL, // #343 +NULL, // #344 +NULL, // #345 +NULL, // #346 +NULL, // #347 +NULL, // #348 +VM_CL_isdemo, // #349 +NULL, // #350 +NULL, // #351 +NULL, // #352 +VM_wasfreed, // #353 float(entity ent) wasfreed +NULL, // #354 +VM_CL_videoplaying, // #355 +VM_findfont, // #356 float(string fontname) loadfont (DP_GFX_FONTS) +VM_loadfont, // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS) +NULL, // #358 +NULL, // #359 +NULL, // #360 +NULL, // #361 +NULL, // #362 +NULL, // #363 +NULL, // #364 +NULL, // #365 +NULL, // #366 +NULL, // #367 +NULL, // #368 +NULL, // #369 +NULL, // #370 +NULL, // #371 +NULL, // #372 +NULL, // #373 +NULL, // #374 +NULL, // #375 +NULL, // #376 +NULL, // #377 +NULL, // #378 +NULL, // #379 +NULL, // #380 +NULL, // #381 +NULL, // #382 +NULL, // #383 +NULL, // #384 +NULL, // #385 +NULL, // #386 +NULL, // #387 +NULL, // #388 +NULL, // #389 +NULL, // #390 +NULL, // #391 +NULL, // #392 +NULL, // #393 +NULL, // #394 +NULL, // #395 +NULL, // #396 +NULL, // #397 +NULL, // #398 +NULL, // #399 +NULL, // #400 +VM_M_WriteByte, // #401 +VM_M_WriteChar, // #402 +VM_M_WriteShort, // #403 +VM_M_WriteLong, // #404 +VM_M_WriteAngle, // #405 +VM_M_WriteCoord, // #406 +VM_M_WriteString, // #407 +VM_M_WriteEntity, // #408 +NULL, // #409 +NULL, // #410 +NULL, // #411 +NULL, // #412 +NULL, // #413 +NULL, // #414 +NULL, // #415 +NULL, // #416 +NULL, // #417 +NULL, // #418 +NULL, // #419 +NULL, // #420 +NULL, // #421 +NULL, // #422 +NULL, // #423 +NULL, // #424 +NULL, // #425 +NULL, // #426 +NULL, // #427 +NULL, // #428 +NULL, // #429 +NULL, // #430 +NULL, // #431 +NULL, // #432 +NULL, // #433 +NULL, // #434 +NULL, // #435 +NULL, // #436 +NULL, // #437 +NULL, // #438 +NULL, // #439 +VM_buf_create, // #440 float() buf_create (DP_QC_STRINGBUFFERS) +VM_buf_del, // #441 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS) +VM_buf_getsize, // #442 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS) +VM_buf_copy, // #443 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS) +VM_buf_sort, // #444 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS) +VM_buf_implode, // #445 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS) +VM_bufstr_get, // #446 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS) +VM_bufstr_set, // #447 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS) +VM_bufstr_add, // #448 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS) +VM_bufstr_free, // #449 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS) +NULL, // #450 +VM_iscachedpic, // #451 draw functions... +VM_precache_pic, // #452 +VM_freepic, // #453 +VM_drawcharacter, // #454 +VM_drawstring, // #455 +VM_drawpic, // #456 +VM_drawfill, // #457 +VM_drawsetcliparea, // #458 +VM_drawresetcliparea, // #459 +VM_getimagesize, // #460 +VM_cin_open, // #461 +VM_cin_close, // #462 +VM_cin_setstate, // #463 +VM_cin_getstate, // #464 +VM_cin_restart, // #465 +VM_drawline, // #466 +VM_drawcolorcodedstring, // #467 +VM_stringwidth, // #468 +VM_drawsubpic, // #469 +VM_drawrotpic, // #470 +VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN) +VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN) +VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN) +VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN) +VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN) +VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS) +VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS) +VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME) +VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR) +VM_strtolower, // #480 string(string s) VM_strtolower : DRESK - Return string as lowercase +VM_strtoupper, // #481 string(string s) VM_strtoupper : DRESK - Return string as uppercase +NULL, // #482 +NULL, // #483 +VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE) +VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE) +NULL, // #486 +VM_gecko_create, // #487 float gecko_create( string name ) +VM_gecko_destroy, // #488 void gecko_destroy( string name ) +VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI ) +VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype ) +VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y ) +VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h ) +VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name ) +VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16) +VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE) +VM_numentityfields, // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA) +VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA) +VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA) +VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA) +VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA) +NULL, // #501 +NULL, // #502 +VM_whichpack, // #503 string(string) whichpack = #503; +NULL, // #504 +NULL, // #505 +NULL, // #506 +NULL, // #507 +NULL, // #508 +NULL, // #509 +VM_uri_escape, // #510 string(string in) uri_escape = #510; +VM_uri_unescape, // #511 string(string in) uri_unescape = #511; +VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT) +VM_uri_get, // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST) +VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE) +VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST) +VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION) +NULL, // #519 +NULL, // #520 +NULL, // #521 +NULL, // #522 +NULL, // #523 +NULL, // #524 +NULL, // #525 +NULL, // #526 +NULL, // #527 +NULL, // #528 +NULL, // #529 +NULL, // #530 +NULL, // #531 +VM_log, // #532 +VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME) +VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME) +VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP) +NULL, // #539 +NULL, // #540 +NULL, // #541 +NULL, // #542 +NULL, // #543 +NULL, // #544 +NULL, // #545 +NULL, // #546 +NULL, // #547 +NULL, // #548 +NULL, // #549 +NULL, // #550 +NULL, // #551 +NULL, // #552 +NULL, // #553 +NULL, // #554 +NULL, // #555 +NULL, // #556 +NULL, // #557 +NULL, // #558 +NULL, // #559 +NULL, // #560 +NULL, // #561 +NULL, // #562 +NULL, // #563 +NULL, // #564 +NULL, // #565 +NULL, // #566 +NULL, // #567 +NULL, // #568 +NULL, // #569 +NULL, // #570 +NULL, // #571 +NULL, // #572 +NULL, // #573 +NULL, // #574 +NULL, // #575 +NULL, // #576 +NULL, // #577 +NULL, // #578 +NULL, // #579 +NULL, // #580 +NULL, // #581 +NULL, // #582 +NULL, // #583 +NULL, // #584 +NULL, // #585 +NULL, // #586 +NULL, // #587 +NULL, // #588 +NULL, // #589 +NULL, // #590 +NULL, // #591 +NULL, // #592 +NULL, // #593 +NULL, // #594 +NULL, // #595 +NULL, // #596 +NULL, // #597 +NULL, // #598 +NULL, // #599 +NULL, // #600 +VM_M_setkeydest, // #601 void setkeydest(float dest) +VM_M_getkeydest, // #602 float getkeydest(void) +VM_M_setmousetarget, // #603 void setmousetarget(float trg) +VM_M_getmousetarget, // #604 float getmousetarget(void) +VM_callfunction, // #605 void callfunction(...) +VM_writetofile, // #606 void writetofile(float fhandle, entity ent) +VM_isfunction, // #607 float isfunction(string function_name) +VM_M_getresolution, // #608 vector getresolution(float number, [float forfullscreen]) +VM_keynumtostring, // #609 string keynumtostring(float keynum) +VM_findkeysforcommand, // #610 string findkeysforcommand(string command[, float bindmap]) +VM_M_getserverliststat, // #611 float gethostcachevalue(float type) +VM_M_getserverliststring, // #612 string gethostcachestring(float type, float hostnr) +VM_parseentitydata, // #613 void parseentitydata(entity ent, string data) +VM_stringtokeynum, // #614 float stringtokeynum(string key) +VM_M_resetserverlistmasks, // #615 void resethostcachemasks(void) +VM_M_setserverlistmaskstring, // #616 void sethostcachemaskstring(float mask, float fld, string str, float op) +VM_M_setserverlistmasknumber, // #617 void sethostcachemasknumber(float mask, float fld, float num, float op) +VM_M_resortserverlist, // #618 void resorthostcache(void) +VM_M_setserverlistsort, // #619 void sethostcachesort(float fld, float descending) +VM_M_refreshserverlist, // #620 void refreshhostcache(void) +VM_M_getserverlistnumber, // #621 float gethostcachenumber(float fld, float hostnr) +VM_M_getserverlistindexforkey,// #622 float gethostcacheindexforkey(string key) +VM_M_addwantedserverlistkey, // #623 void addwantedhostcachekey(string key) +VM_CL_getextresponse, // #624 string getextresponse(void) +VM_netaddress_resolve, // #625 string netaddress_resolve(string, float) +VM_M_getgamedirinfo, // #626 string getgamedirinfo(float n, float prop) +VM_sprintf, // #627 string sprintf(string format, ...) +NULL, // #628 +NULL, // #629 +VM_setkeybind, // #630 float(float key, string bind[, float bindmap]) setkeybind +VM_getbindmaps, // #631 vector(void) getbindmap +VM_setbindmaps, // #632 float(vector bm) setbindmap +VM_M_crypto_getkeyfp, // #633 string(string addr) crypto_getkeyfp +VM_M_crypto_getidfp, // #634 string(string addr) crypto_getidfp +VM_M_crypto_getencryptlevel, // #635 string(string addr) crypto_getencryptlevel +VM_M_crypto_getmykeyfp, // #636 string(float addr) crypto_getmykeyfp +VM_M_crypto_getmyidfp, // #637 string(float addr) crypto_getmyidfp +NULL, // #638 +VM_digest_hex, // #639 +NULL, // #640 +VM_M_crypto_getmyidstatus, // #641 float(float i) crypto_getmyidstatus +NULL +}; + +const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t); + +void MVM_init_cmd(prvm_prog_t *prog) +{ + r_refdef_scene_t *scene; + + VM_Cmd_Init(prog); + VM_Polygons_Reset(prog); + + scene = R_GetScenePointer( RST_MENU ); + + memset (scene, 0, sizeof (*scene)); + + scene->maxtempentities = 128; + scene->tempentities = (entity_render_t*) Mem_Alloc(prog->progs_mempool, sizeof(entity_render_t) * scene->maxtempentities); + + scene->maxentities = MAX_EDICTS + 256 + 512; + scene->entities = (entity_render_t **)Mem_Alloc(prog->progs_mempool, sizeof(entity_render_t *) * scene->maxentities); + + scene->ambient = 32.0f; +} + +void MVM_reset_cmd(prvm_prog_t *prog) +{ + // note: the menu's render entities are automatically freed when the prog's pool is freed + + //VM_Cmd_Init(); + VM_Cmd_Reset(prog); + VM_Polygons_Reset(prog); +} diff --git a/app/jni/netconn.c b/app/jni/netconn.c new file mode 100644 index 0000000..52f931d --- /dev/null +++ b/app/jni/netconn.c @@ -0,0 +1,3766 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. +Copyright (C) 2002 Mathieu Olivier +Copyright (C) 2003 Forest Hale + +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 "thread.h" +#include "lhnet.h" + +#define HAVE_SNPRINTF +#define PREFER_PORTABLE_SNPRINTF +#include "snprintf.h" + +// for secure rcon authentication +#include "hmac.h" +#include "mdfour.h" +#include + +#define QWMASTER_PORT 27000 +#define DPMASTER_PORT 27950 + +// note this defaults on for dedicated servers, off for listen servers +cvar_t sv_public = {0, "sv_public", "0", "1: advertises this server on the master server (so that players can find it in the server browser); 0: allow direct queries only; -1: do not respond to direct queries; -2: do not allow anyone to connect; -3: already block at getchallenge level"}; +cvar_t sv_public_rejectreason = {0, "sv_public_rejectreason", "The server is closing.", "Rejection reason for connects when sv_public is -2"}; +static cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "120", "how often to send heartbeat in seconds (only used if sv_public is 1)"}; +extern cvar_t sv_status_privacy; + +static cvar_t sv_masters [] = +{ + {CVAR_SAVE, "sv_master1", "", "user-chosen master server 1"}, + {CVAR_SAVE, "sv_master2", "", "user-chosen master server 2"}, + {CVAR_SAVE, "sv_master3", "", "user-chosen master server 3"}, + {CVAR_SAVE, "sv_master4", "", "user-chosen master server 4"}, + {0, "sv_masterextra1", "69.59.212.88", "ghdigital.com - default master server 1 (admin: LordHavoc)"}, // admin: LordHavoc + {0, "sv_masterextra2", "64.22.107.125", "dpmaster.deathmask.net - default master server 2 (admin: Willis)"}, // admin: Willis + {0, "sv_masterextra3", "92.62.40.73", "dpmaster.tchr.no - default master server 3 (admin: tChr)"}, // admin: tChr +#ifdef SUPPORTIPV6 + {0, "sv_masterextra4", "[2a03:4000:2:225::51:334d]:27950", "dpmaster.sudo.rm-f.org - default master server 4 (admin: divVerent)"}, // admin: divVerent +#endif + {0, NULL, NULL, NULL} +}; + +static cvar_t sv_qwmasters [] = +{ + {CVAR_SAVE, "sv_qwmaster1", "", "user-chosen qwmaster server 1"}, + {CVAR_SAVE, "sv_qwmaster2", "", "user-chosen qwmaster server 2"}, + {CVAR_SAVE, "sv_qwmaster3", "", "user-chosen qwmaster server 3"}, + {CVAR_SAVE, "sv_qwmaster4", "", "user-chosen qwmaster server 4"}, + {0, "sv_qwmasterextra1", "master.quakeservers.net:27000", "Global master server. (admin: unknown)"}, + {0, "sv_qwmasterextra2", "asgaard.morphos-team.net:27000", "Global master server. (admin: unknown)"}, + {0, "sv_qwmasterextra3", "qwmaster.ocrana.de:27000", "German master server. (admin: unknown)"}, + {0, "sv_qwmasterextra4", "masterserver.exhale.de:27000", "German master server. (admin: unknown)"}, + {0, "sv_qwmasterextra5", "qwmaster.fodquake.net:27000", "Global master server. (admin: unknown)"}, + {0, NULL, NULL, NULL} +}; + +static double nextheartbeattime = 0; + +sizebuf_t cl_message; +sizebuf_t sv_message; +static unsigned char cl_message_buf[NET_MAXMESSAGE]; +static unsigned char sv_message_buf[NET_MAXMESSAGE]; +char cl_readstring[MAX_INPUTLINE]; +char sv_readstring[MAX_INPUTLINE]; + +cvar_t net_messagetimeout = {0, "net_messagetimeout","300", "drops players who have not sent any packets for this many seconds"}; +cvar_t net_connecttimeout = {0, "net_connecttimeout","15", "after requesting a connection, the client must reply within this many seconds or be dropped (cuts down on connect floods). Must be above 10 seconds."}; +cvar_t net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (cuts down on connect floods). Note that this does not include retries from the same IP; these are handled earlier and let in."}; +cvar_t net_challengefloodblockingtimeout = {0, "net_challengefloodblockingtimeout", "0.5", "when a challenge packet is received, it will block all future challenge packets from that IP address for this many seconds (cuts down on challenge floods). DarkPlaces clients retry once per second, so this should be <= 1. Failure here may lead to connect attempts failing."}; +cvar_t net_getstatusfloodblockingtimeout = {0, "net_getstatusfloodblockingtimeout", "1", "when a getstatus packet is received, it will block all future getstatus packets from that IP address for this many seconds (cuts down on getstatus floods). DarkPlaces retries every 4 seconds, and qstat retries once per second, so this should be <= 1. Failure here may lead to server not showing up in the server list."}; +cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED", "server message to show in server browser"}; +cvar_t developer_networking = {0, "developer_networking", "0", "prints all received and sent packets (recommended only for debugging)"}; + +cvar_t cl_netlocalping = {0, "cl_netlocalping","0", "lags local loopback connection by this much ping time (useful to play more fairly on your own server with people with higher pings)"}; +static cvar_t cl_netpacketloss_send = {0, "cl_netpacketloss_send","0", "drops this percentage of outgoing packets, useful for testing network protocol robustness (jerky movement, prediction errors, etc)"}; +static cvar_t cl_netpacketloss_receive = {0, "cl_netpacketloss_receive","0", "drops this percentage of incoming packets, useful for testing network protocol robustness (jerky movement, effects failing to start, sounds failing to play, etc)"}; +static cvar_t net_slist_queriespersecond = {0, "net_slist_queriespersecond", "20", "how many server information requests to send per second"}; +static cvar_t net_slist_queriesperframe = {0, "net_slist_queriesperframe", "4", "maximum number of server information requests to send each rendered frame (guards against low framerates causing problems)"}; +static cvar_t net_slist_timeout = {0, "net_slist_timeout", "4", "how long to listen for a server information response before giving up"}; +static cvar_t net_slist_pause = {0, "net_slist_pause", "0", "when set to 1, the server list won't update until it is set back to 0"}; +static cvar_t net_slist_maxtries = {0, "net_slist_maxtries", "3", "how many times to ask the same server for information (more times gives better ping reports but takes longer)"}; +static cvar_t net_slist_favorites = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "net_slist_favorites", "", "contains a list of IP addresses and ports to always query explicitly"}; +static cvar_t net_tos_dscp = {CVAR_SAVE, "net_tos_dscp", "32", "DiffServ Codepoint for network sockets (may need game restart to apply)"}; +static cvar_t gameversion = {0, "gameversion", "0", "version of game data (mod-specific) to be sent to querying clients"}; +static cvar_t gameversion_min = {0, "gameversion_min", "-1", "minimum version of game data (mod-specific), when client and server gameversion mismatch in the server browser the server is shown as incompatible; if -1, gameversion is used alone"}; +static cvar_t gameversion_max = {0, "gameversion_max", "-1", "maximum version of game data (mod-specific), when client and server gameversion mismatch in the server browser the server is shown as incompatible; if -1, gameversion is used alone"}; +static cvar_t rcon_restricted_password = {CVAR_PRIVATE, "rcon_restricted_password", "", "password to authenticate rcon commands in restricted mode; may be set to a string of the form user1:pass1 user2:pass2 user3:pass3 to allow multiple user accounts - the client then has to specify ONE of these combinations"}; +static cvar_t rcon_restricted_commands = {0, "rcon_restricted_commands", "", "allowed commands for rcon when the restricted mode password was used"}; +static cvar_t rcon_secure_maxdiff = {0, "rcon_secure_maxdiff", "5", "maximum time difference between rcon request and server system clock (to protect against replay attack)"}; +extern cvar_t rcon_secure; +extern cvar_t rcon_secure_challengetimeout; + +double masterquerytime = -1000; +int masterquerycount = 0; +int masterreplycount = 0; +int serverquerycount = 0; +int serverreplycount = 0; + +challenge_t challenge[MAX_CHALLENGES]; + +/// this is only false if there are still servers left to query +static qboolean serverlist_querysleep = true; +static qboolean serverlist_paused = false; +/// this is pushed a second or two ahead of realtime whenever a master server +/// reply is received, to avoid issuing queries while master replies are still +/// flooding in (which would make a mess of the ping times) +static double serverlist_querywaittime = 0; + +static int cl_numsockets; +static lhnetsocket_t *cl_sockets[16]; +static int sv_numsockets; +static lhnetsocket_t *sv_sockets[16]; + +netconn_t *netconn_list = NULL; +mempool_t *netconn_mempool = NULL; +void *netconn_mutex = NULL; + +cvar_t cl_netport = {0, "cl_port", "0", "forces client to use chosen port number if not 0"}; +cvar_t sv_netport = {0, "port", "26000", "server port for players to connect to"}; +cvar_t net_address = {0, "net_address", "", "network address to open ipv4 ports on (if empty, use default interfaces)"}; +cvar_t net_address_ipv6 = {0, "net_address_ipv6", "", "network address to open ipv6 ports on (if empty, use default interfaces)"}; + +char cl_net_extresponse[NET_EXTRESPONSE_MAX][1400]; +int cl_net_extresponse_count = 0; +int cl_net_extresponse_last = 0; + +char sv_net_extresponse[NET_EXTRESPONSE_MAX][1400]; +int sv_net_extresponse_count = 0; +int sv_net_extresponse_last = 0; + +// ServerList interface +serverlist_mask_t serverlist_andmasks[SERVERLIST_ANDMASKCOUNT]; +serverlist_mask_t serverlist_ormasks[SERVERLIST_ORMASKCOUNT]; + +serverlist_infofield_t serverlist_sortbyfield; +int serverlist_sortflags; + +int serverlist_viewcount = 0; +unsigned short serverlist_viewlist[SERVERLIST_VIEWLISTSIZE]; + +int serverlist_maxcachecount = 0; +int serverlist_cachecount = 0; +serverlist_entry_t *serverlist_cache = NULL; + +qboolean serverlist_consoleoutput; + +static int nFavorites = 0; +static lhnetaddress_t favorites[MAX_FAVORITESERVERS]; +static int nFavorites_idfp = 0; +static char favorites_idfp[MAX_FAVORITESERVERS][FP64_SIZE+1]; + +void NetConn_UpdateFavorites(void) +{ + const char *p; + nFavorites = 0; + nFavorites_idfp = 0; + p = net_slist_favorites.string; + while((size_t) nFavorites < sizeof(favorites) / sizeof(*favorites) && COM_ParseToken_Console(&p)) + { + if(com_token[0] != '[' && strlen(com_token) == FP64_SIZE && !strchr(com_token, '.')) + // currently 44 bytes, longest possible IPv6 address: 39 bytes, so this works + // (if v6 address contains port, it must start with '[') + { + strlcpy(favorites_idfp[nFavorites_idfp], com_token, sizeof(favorites_idfp[nFavorites_idfp])); + ++nFavorites_idfp; + } + else + { + if(LHNETADDRESS_FromString(&favorites[nFavorites], com_token, 26000)) + ++nFavorites; + } + } +} + +/// helper function to insert a value into the viewset +/// spare entries will be removed +static void _ServerList_ViewList_Helper_InsertBefore( int index, serverlist_entry_t *entry ) +{ + int i; + if( serverlist_viewcount < SERVERLIST_VIEWLISTSIZE ) { + i = serverlist_viewcount++; + } else { + i = SERVERLIST_VIEWLISTSIZE - 1; + } + + for( ; i > index ; i-- ) + serverlist_viewlist[ i ] = serverlist_viewlist[ i - 1 ]; + + serverlist_viewlist[index] = (int)(entry - serverlist_cache); +} + +/// we suppose serverlist_viewcount to be valid, ie > 0 +static void _ServerList_ViewList_Helper_Remove( int index ) +{ + serverlist_viewcount--; + for( ; index < serverlist_viewcount ; index++ ) + serverlist_viewlist[index] = serverlist_viewlist[index + 1]; +} + +/// \returns true if A should be inserted before B +static qboolean _ServerList_Entry_Compare( serverlist_entry_t *A, serverlist_entry_t *B ) +{ + int result = 0; // > 0 if for numbers A > B and for text if A < B + + if( serverlist_sortflags & SLSF_FAVORITESFIRST ) + { + if(A->info.isfavorite != B->info.isfavorite) + return A->info.isfavorite; + } + + switch( serverlist_sortbyfield ) { + case SLIF_PING: + result = A->info.ping - B->info.ping; + break; + case SLIF_MAXPLAYERS: + result = A->info.maxplayers - B->info.maxplayers; + break; + case SLIF_NUMPLAYERS: + result = A->info.numplayers - B->info.numplayers; + break; + case SLIF_NUMBOTS: + result = A->info.numbots - B->info.numbots; + break; + case SLIF_NUMHUMANS: + result = A->info.numhumans - B->info.numhumans; + break; + case SLIF_FREESLOTS: + result = A->info.freeslots - B->info.freeslots; + break; + case SLIF_PROTOCOL: + result = A->info.protocol - B->info.protocol; + break; + case SLIF_CNAME: + result = strcmp( B->info.cname, A->info.cname ); + break; + case SLIF_GAME: + result = strcasecmp( B->info.game, A->info.game ); + break; + case SLIF_MAP: + result = strcasecmp( B->info.map, A->info.map ); + break; + case SLIF_MOD: + result = strcasecmp( B->info.mod, A->info.mod ); + break; + case SLIF_NAME: + result = strcasecmp( B->info.name, A->info.name ); + break; + case SLIF_QCSTATUS: + result = strcasecmp( B->info.qcstatus, A->info.qcstatus ); // not really THAT useful, though + break; + case SLIF_ISFAVORITE: + result = !!B->info.isfavorite - !!A->info.isfavorite; + break; + default: + Con_DPrint( "_ServerList_Entry_Compare: Bad serverlist_sortbyfield!\n" ); + break; + } + + if (result != 0) + { + if( serverlist_sortflags & SLSF_DESCENDING ) + return result > 0; + else + return result < 0; + } + + // if the chosen sort key is identical, sort by index + // (makes this a stable sort, so that later replies from servers won't + // shuffle the servers around when they have the same ping) + return A < B; +} + +static qboolean _ServerList_CompareInt( int A, serverlist_maskop_t op, int B ) +{ + // This should actually be done with some intermediate and end-of-function return + switch( op ) { + case SLMO_LESS: + return A < B; + case SLMO_LESSEQUAL: + return A <= B; + case SLMO_EQUAL: + return A == B; + case SLMO_GREATER: + return A > B; + case SLMO_NOTEQUAL: + return A != B; + case SLMO_GREATEREQUAL: + case SLMO_CONTAINS: + case SLMO_NOTCONTAIN: + case SLMO_STARTSWITH: + case SLMO_NOTSTARTSWITH: + return A >= B; + default: + Con_DPrint( "_ServerList_CompareInt: Bad op!\n" ); + return false; + } +} + +static qboolean _ServerList_CompareStr( const char *A, serverlist_maskop_t op, const char *B ) +{ + int i; + char bufferA[ 1400 ], bufferB[ 1400 ]; // should be more than enough + COM_StringDecolorize(A, 0, bufferA, sizeof(bufferA), false); + for (i = 0;i < (int)sizeof(bufferA)-1 && bufferA[i];i++) + bufferA[i] = (bufferA[i] >= 'A' && bufferA[i] <= 'Z') ? (bufferA[i] + 'a' - 'A') : bufferA[i]; + bufferA[i] = 0; + for (i = 0;i < (int)sizeof(bufferB)-1 && B[i];i++) + bufferB[i] = (B[i] >= 'A' && B[i] <= 'Z') ? (B[i] + 'a' - 'A') : B[i]; + bufferB[i] = 0; + + // Same here, also using an intermediate & final return would be more appropriate + // A info B mask + switch( op ) { + case SLMO_CONTAINS: + return *bufferB && !!strstr( bufferA, bufferB ); // we want a real bool + case SLMO_NOTCONTAIN: + return !*bufferB || !strstr( bufferA, bufferB ); + case SLMO_STARTSWITH: + //Con_Printf("startsWith: %s %s\n", bufferA, bufferB); + return *bufferB && !memcmp(bufferA, bufferB, strlen(bufferB)); + case SLMO_NOTSTARTSWITH: + return !*bufferB || memcmp(bufferA, bufferB, strlen(bufferB)); + case SLMO_LESS: + return strcmp( bufferA, bufferB ) < 0; + case SLMO_LESSEQUAL: + return strcmp( bufferA, bufferB ) <= 0; + case SLMO_EQUAL: + return strcmp( bufferA, bufferB ) == 0; + case SLMO_GREATER: + return strcmp( bufferA, bufferB ) > 0; + case SLMO_NOTEQUAL: + return strcmp( bufferA, bufferB ) != 0; + case SLMO_GREATEREQUAL: + return strcmp( bufferA, bufferB ) >= 0; + default: + Con_DPrint( "_ServerList_CompareStr: Bad op!\n" ); + return false; + } +} + +static qboolean _ServerList_Entry_Mask( serverlist_mask_t *mask, serverlist_info_t *info ) +{ + if( !_ServerList_CompareInt( info->ping, mask->tests[SLIF_PING], mask->info.ping ) ) + return false; + if( !_ServerList_CompareInt( info->maxplayers, mask->tests[SLIF_MAXPLAYERS], mask->info.maxplayers ) ) + return false; + if( !_ServerList_CompareInt( info->numplayers, mask->tests[SLIF_NUMPLAYERS], mask->info.numplayers ) ) + return false; + if( !_ServerList_CompareInt( info->numbots, mask->tests[SLIF_NUMBOTS], mask->info.numbots ) ) + return false; + if( !_ServerList_CompareInt( info->numhumans, mask->tests[SLIF_NUMHUMANS], mask->info.numhumans ) ) + return false; + if( !_ServerList_CompareInt( info->freeslots, mask->tests[SLIF_FREESLOTS], mask->info.freeslots ) ) + return false; + if( !_ServerList_CompareInt( info->protocol, mask->tests[SLIF_PROTOCOL], mask->info.protocol )) + return false; + if( *mask->info.cname + && !_ServerList_CompareStr( info->cname, mask->tests[SLIF_CNAME], mask->info.cname ) ) + return false; + if( *mask->info.game + && !_ServerList_CompareStr( info->game, mask->tests[SLIF_GAME], mask->info.game ) ) + return false; + if( *mask->info.mod + && !_ServerList_CompareStr( info->mod, mask->tests[SLIF_MOD], mask->info.mod ) ) + return false; + if( *mask->info.map + && !_ServerList_CompareStr( info->map, mask->tests[SLIF_MAP], mask->info.map ) ) + return false; + if( *mask->info.name + && !_ServerList_CompareStr( info->name, mask->tests[SLIF_NAME], mask->info.name ) ) + return false; + if( *mask->info.qcstatus + && !_ServerList_CompareStr( info->qcstatus, mask->tests[SLIF_QCSTATUS], mask->info.qcstatus ) ) + return false; + if( *mask->info.players + && !_ServerList_CompareStr( info->players, mask->tests[SLIF_PLAYERS], mask->info.players ) ) + return false; + if( !_ServerList_CompareInt( info->isfavorite, mask->tests[SLIF_ISFAVORITE], mask->info.isfavorite )) + return false; + return true; +} + +static void ServerList_ViewList_Insert( serverlist_entry_t *entry ) +{ + int start, end, mid, i; + lhnetaddress_t addr; + + // reject incompatible servers + if( + entry->info.gameversion != gameversion.integer + && + !( + gameversion_min.integer >= 0 // min/max range set by user/mod? + && gameversion_max.integer >= 0 + && gameversion_min.integer <= entry->info.gameversion // version of server in min/max range? + && gameversion_max.integer >= entry->info.gameversion + ) + ) + return; + + // refresh the "favorite" status + entry->info.isfavorite = false; + if(LHNETADDRESS_FromString(&addr, entry->info.cname, 26000)) + { + char idfp[FP64_SIZE+1]; + for(i = 0; i < nFavorites; ++i) + { + if(LHNETADDRESS_Compare(&addr, &favorites[i]) == 0) + { + entry->info.isfavorite = true; + break; + } + } + if(Crypto_RetrieveHostKey(&addr, 0, NULL, 0, idfp, sizeof(idfp), NULL)) + { + for(i = 0; i < nFavorites_idfp; ++i) + { + if(!strcmp(idfp, favorites_idfp[i])) + { + entry->info.isfavorite = true; + break; + } + } + } + } + + // FIXME: change this to be more readable (...) + // now check whether it passes through the masks + for( start = 0 ; start < SERVERLIST_ANDMASKCOUNT && serverlist_andmasks[start].active; start++ ) + if( !_ServerList_Entry_Mask( &serverlist_andmasks[start], &entry->info ) ) + return; + + for( start = 0 ; start < SERVERLIST_ORMASKCOUNT && serverlist_ormasks[start].active ; start++ ) + if( _ServerList_Entry_Mask( &serverlist_ormasks[start], &entry->info ) ) + break; + if( start == SERVERLIST_ORMASKCOUNT || (start > 0 && !serverlist_ormasks[start].active) ) + return; + + if( !serverlist_viewcount ) { + _ServerList_ViewList_Helper_InsertBefore( 0, entry ); + return; + } + // ok, insert it, we just need to find out where exactly: + + // two special cases + // check whether to insert it as new first item + if( _ServerList_Entry_Compare( entry, ServerList_GetViewEntry(0) ) ) { + _ServerList_ViewList_Helper_InsertBefore( 0, entry ); + return; + } // check whether to insert it as new last item + else if( !_ServerList_Entry_Compare( entry, ServerList_GetViewEntry(serverlist_viewcount - 1) ) ) { + _ServerList_ViewList_Helper_InsertBefore( serverlist_viewcount, entry ); + return; + } + start = 0; + end = serverlist_viewcount - 1; + while( end > start + 1 ) + { + mid = (start + end) / 2; + // test the item that lies in the middle between start and end + if( _ServerList_Entry_Compare( entry, ServerList_GetViewEntry(mid) ) ) + // the item has to be in the upper half + end = mid; + else + // the item has to be in the lower half + start = mid; + } + _ServerList_ViewList_Helper_InsertBefore( start + 1, entry ); +} + +static void ServerList_ViewList_Remove( serverlist_entry_t *entry ) +{ + int i; + for( i = 0; i < serverlist_viewcount; i++ ) + { + if (ServerList_GetViewEntry(i) == entry) + { + _ServerList_ViewList_Helper_Remove(i); + break; + } + } +} + +void ServerList_RebuildViewList(void) +{ + int i; + + serverlist_viewcount = 0; + for( i = 0 ; i < serverlist_cachecount ; i++ ) { + serverlist_entry_t *entry = &serverlist_cache[i]; + // also display entries that are currently being refreshed [11/8/2007 Black] + if( entry->query == SQS_QUERIED || entry->query == SQS_REFRESHING ) + ServerList_ViewList_Insert( entry ); + } +} + +void ServerList_ResetMasks(void) +{ + int i; + + memset( &serverlist_andmasks, 0, sizeof( serverlist_andmasks ) ); + memset( &serverlist_ormasks, 0, sizeof( serverlist_ormasks ) ); + // numbots needs to be compared to -1 to always succeed + for(i = 0; i < SERVERLIST_ANDMASKCOUNT; ++i) + serverlist_andmasks[i].info.numbots = -1; + for(i = 0; i < SERVERLIST_ORMASKCOUNT; ++i) + serverlist_ormasks[i].info.numbots = -1; +} + +void ServerList_GetPlayerStatistics(int *numplayerspointer, int *maxplayerspointer) +{ + int i; + int numplayers = 0, maxplayers = 0; + for (i = 0;i < serverlist_cachecount;i++) + { + if (serverlist_cache[i].query == SQS_QUERIED) + { + numplayers += serverlist_cache[i].info.numhumans; + maxplayers += serverlist_cache[i].info.maxplayers; + } + } + *numplayerspointer = numplayers; + *maxplayerspointer = maxplayers; +} + +#if 0 +static void _ServerList_Test(void) +{ + int i; + if (serverlist_maxcachecount <= 1024) + { + serverlist_maxcachecount = 1024; + serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount); + } + for( i = 0 ; i < 1024 ; i++ ) { + memset( &serverlist_cache[serverlist_cachecount], 0, sizeof( serverlist_entry_t ) ); + serverlist_cache[serverlist_cachecount].info.ping = 1000 + 1024 - i; + dpsnprintf( serverlist_cache[serverlist_cachecount].info.name, sizeof(serverlist_cache[serverlist_cachecount].info.name), "Black's ServerList Test %i", i ); + serverlist_cache[serverlist_cachecount].finished = true; + dpsnprintf( serverlist_cache[serverlist_cachecount].line1, sizeof(serverlist_cache[serverlist_cachecount].info.line1), "%i %s", serverlist_cache[serverlist_cachecount].info.ping, serverlist_cache[serverlist_cachecount].info.name ); + ServerList_ViewList_Insert( &serverlist_cache[serverlist_cachecount] ); + serverlist_cachecount++; + } +} +#endif + +void ServerList_QueryList(qboolean resetcache, qboolean querydp, qboolean queryqw, qboolean consoleoutput) +{ + masterquerytime = realtime; + masterquerycount = 0; + masterreplycount = 0; + if( resetcache ) { + serverquerycount = 0; + serverreplycount = 0; + serverlist_cachecount = 0; + serverlist_viewcount = 0; + serverlist_maxcachecount = 0; + serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount); + } else { + // refresh all entries + int n; + for( n = 0 ; n < serverlist_cachecount ; n++ ) { + serverlist_entry_t *entry = &serverlist_cache[ n ]; + entry->query = SQS_REFRESHING; + entry->querycounter = 0; + } + } + serverlist_consoleoutput = consoleoutput; + + //_ServerList_Test(); + + NetConn_QueryMasters(querydp, queryqw); +} + +// rest + +int NetConn_Read(lhnetsocket_t *mysocket, void *data, int maxlength, lhnetaddress_t *peeraddress) +{ + int length; + int i; + if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex) + Thread_LockMutex(netconn_mutex); + length = LHNET_Read(mysocket, data, maxlength, peeraddress); + if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex) + Thread_UnlockMutex(netconn_mutex); + if (length == 0) + return 0; + if (cl_netpacketloss_receive.integer) + for (i = 0;i < cl_numsockets;i++) + if (cl_sockets[i] == mysocket && (rand() % 100) < cl_netpacketloss_receive.integer) + return 0; + if (developer_networking.integer) + { + char addressstring[128], addressstring2[128]; + LHNETADDRESS_ToString(LHNET_AddressFromSocket(mysocket), addressstring, sizeof(addressstring), true); + if (length > 0) + { + LHNETADDRESS_ToString(peeraddress, addressstring2, sizeof(addressstring2), true); + Con_Printf("LHNET_Read(%p (%s), %p, %i, %p) = %i from %s:\n", (void *)mysocket, addressstring, (void *)data, maxlength, (void *)peeraddress, length, addressstring2); + Com_HexDumpToConsole((unsigned char *)data, length); + } + else + Con_Printf("LHNET_Read(%p (%s), %p, %i, %p) = %i\n", (void *)mysocket, addressstring, (void *)data, maxlength, (void *)peeraddress, length); + } + return length; +} + +int NetConn_Write(lhnetsocket_t *mysocket, const void *data, int length, const lhnetaddress_t *peeraddress) +{ + int ret; + int i; + if (cl_netpacketloss_send.integer) + for (i = 0;i < cl_numsockets;i++) + if (cl_sockets[i] == mysocket && (rand() % 100) < cl_netpacketloss_send.integer) + return length; + if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex) + Thread_LockMutex(netconn_mutex); + ret = LHNET_Write(mysocket, data, length, peeraddress); + if (mysocket->address.addresstype == LHNETADDRESSTYPE_LOOP && netconn_mutex) + Thread_UnlockMutex(netconn_mutex); + if (developer_networking.integer) + { + char addressstring[128], addressstring2[128]; + LHNETADDRESS_ToString(LHNET_AddressFromSocket(mysocket), addressstring, sizeof(addressstring), true); + LHNETADDRESS_ToString(peeraddress, addressstring2, sizeof(addressstring2), true); + Con_Printf("LHNET_Write(%p (%s), %p, %i, %p (%s)) = %i%s\n", (void *)mysocket, addressstring, (void *)data, length, (void *)peeraddress, addressstring2, length, ret == length ? "" : " (ERROR)"); + Com_HexDumpToConsole((unsigned char *)data, length); + } + return ret; +} + +int NetConn_WriteString(lhnetsocket_t *mysocket, const char *string, const lhnetaddress_t *peeraddress) +{ + // note this does not include the trailing NULL because we add that in the parser + return NetConn_Write(mysocket, string, (int)strlen(string), peeraddress); +} + +qboolean NetConn_CanSend(netconn_t *conn) +{ + conn->outgoing_packetcounter = (conn->outgoing_packetcounter + 1) % NETGRAPH_PACKETS; + conn->outgoing_netgraph[conn->outgoing_packetcounter].time = realtime; + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes = NETGRAPH_NOPACKET; + conn->outgoing_netgraph[conn->outgoing_packetcounter].reliablebytes = NETGRAPH_NOPACKET; + conn->outgoing_netgraph[conn->outgoing_packetcounter].ackbytes = NETGRAPH_NOPACKET; + if (realtime > conn->cleartime) + return true; + else + { + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes = NETGRAPH_CHOKEDPACKET; + return false; + } +} + +int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, qboolean quakesignon_suppressreliables) +{ + int totallen = 0; + unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE]; + unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE]; + + // if this packet was supposedly choked, but we find ourselves sending one + // anyway, make sure the size counting starts at zero + // (this mostly happens on level changes and disconnects and such) + if (conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes == NETGRAPH_CHOKEDPACKET) + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes = NETGRAPH_NOPACKET; + + if (protocol == PROTOCOL_QUAKEWORLD) + { + int packetLen; + qboolean sendreliable; + + // note that it is ok to send empty messages to the qw server, + // otherwise it won't respond to us at all + + sendreliable = false; + // if the remote side dropped the last reliable message, resend it + if (conn->qw.incoming_acknowledged > conn->qw.last_reliable_sequence && conn->qw.incoming_reliable_acknowledged != conn->qw.reliable_sequence) + sendreliable = true; + // if the reliable transmit buffer is empty, copy the current message out + if (!conn->sendMessageLength && conn->message.cursize) + { + memcpy (conn->sendMessage, conn->message.data, conn->message.cursize); + conn->sendMessageLength = conn->message.cursize; + SZ_Clear(&conn->message); // clear the message buffer + conn->qw.reliable_sequence ^= 1; + sendreliable = true; + } + // outgoing unreliable packet number, and outgoing reliable packet number (0 or 1) + StoreLittleLong(sendbuffer, (unsigned int)conn->outgoing_unreliable_sequence | ((unsigned int)sendreliable<<31)); + // last received unreliable packet number, and last received reliable packet number (0 or 1) + StoreLittleLong(sendbuffer + 4, (unsigned int)conn->qw.incoming_sequence | ((unsigned int)conn->qw.incoming_reliable_sequence<<31)); + packetLen = 8; + conn->outgoing_unreliable_sequence++; + // client sends qport in every packet + if (conn == cls.netcon) + { + *((short *)(sendbuffer + 8)) = LittleShort(cls.qw_qport); + packetLen += 2; + // also update cls.qw_outgoing_sequence + cls.qw_outgoing_sequence = conn->outgoing_unreliable_sequence; + } + if (packetLen + (sendreliable ? conn->sendMessageLength : 0) > 1400) + { + Con_Printf ("NetConn_SendUnreliableMessage: reliable message too big %u\n", data->cursize); + return -1; + } + + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes += packetLen + 28; + + // add the reliable message if there is one + if (sendreliable) + { + conn->outgoing_netgraph[conn->outgoing_packetcounter].reliablebytes += conn->sendMessageLength + 28; + memcpy(sendbuffer + packetLen, conn->sendMessage, conn->sendMessageLength); + packetLen += conn->sendMessageLength; + conn->qw.last_reliable_sequence = conn->outgoing_unreliable_sequence; + } + + // add the unreliable message if possible + if (packetLen + data->cursize <= 1400) + { + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes += data->cursize + 28; + memcpy(sendbuffer + packetLen, data->data, data->cursize); + packetLen += data->cursize; + } + + NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress); + + conn->packetsSent++; + conn->unreliableMessagesSent++; + + totallen += packetLen + 28; + } + else + { + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + const void *sendme; + size_t sendmelen; + + // if a reliable message fragment has been lost, send it again + if (conn->sendMessageLength && (realtime - conn->lastSendTime) > 1.0) + { + if (conn->sendMessageLength <= MAX_PACKETFRAGMENT) + { + dataLen = conn->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_PACKETFRAGMENT; + eom = 0; + } + + packetLen = NET_HEADERSIZE + dataLen; + + StoreBigLong(sendbuffer, packetLen | (NETFLAG_DATA | eom)); + StoreBigLong(sendbuffer + 4, conn->nq.sendSequence - 1); + memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen); + + conn->outgoing_netgraph[conn->outgoing_packetcounter].reliablebytes += packetLen + 28; + + sendme = Crypto_EncryptPacket(&conn->crypto, &sendbuffer, packetLen, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer)); + if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen) + { + conn->lastSendTime = realtime; + conn->packetsReSent++; + } + + totallen += sendmelen + 28; + } + + // if we have a new reliable message to send, do so + if (!conn->sendMessageLength && conn->message.cursize && !quakesignon_suppressreliables) + { + if (conn->message.cursize > (int)sizeof(conn->sendMessage)) + { + Con_Printf("NetConn_SendUnreliableMessage: reliable message too big (%u > %u)\n", conn->message.cursize, (int)sizeof(conn->sendMessage)); + conn->message.overflowed = true; + return -1; + } + + if (developer_networking.integer && conn == cls.netcon) + { + Con_Print("client sending reliable message to server:\n"); + SZ_HexDumpToConsole(&conn->message); + } + + memcpy(conn->sendMessage, conn->message.data, conn->message.cursize); + conn->sendMessageLength = conn->message.cursize; + SZ_Clear(&conn->message); + + if (conn->sendMessageLength <= MAX_PACKETFRAGMENT) + { + dataLen = conn->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_PACKETFRAGMENT; + eom = 0; + } + + packetLen = NET_HEADERSIZE + dataLen; + + StoreBigLong(sendbuffer, packetLen | (NETFLAG_DATA | eom)); + StoreBigLong(sendbuffer + 4, conn->nq.sendSequence); + memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen); + + conn->nq.sendSequence++; + + conn->outgoing_netgraph[conn->outgoing_packetcounter].reliablebytes += packetLen + 28; + + sendme = Crypto_EncryptPacket(&conn->crypto, &sendbuffer, packetLen, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer)); + if(sendme) + NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress); + + conn->lastSendTime = realtime; + conn->packetsSent++; + conn->reliableMessagesSent++; + + totallen += sendmelen + 28; + } + + // if we have an unreliable message to send, do so + if (data->cursize) + { + packetLen = NET_HEADERSIZE + data->cursize; + + if (packetLen > (int)sizeof(sendbuffer)) + { + Con_Printf("NetConn_SendUnreliableMessage: message too big %u\n", data->cursize); + return -1; + } + + StoreBigLong(sendbuffer, packetLen | NETFLAG_UNRELIABLE); + StoreBigLong(sendbuffer + 4, conn->outgoing_unreliable_sequence); + memcpy(sendbuffer + NET_HEADERSIZE, data->data, data->cursize); + + conn->outgoing_unreliable_sequence++; + + conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes += packetLen + 28; + + sendme = Crypto_EncryptPacket(&conn->crypto, &sendbuffer, packetLen, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer)); + if(sendme) + NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress); + + conn->packetsSent++; + conn->unreliableMessagesSent++; + + totallen += sendmelen + 28; + } + } + + // delay later packets to obey rate limit + if (conn->cleartime < realtime - 0.1) + conn->cleartime = realtime - 0.1; + conn->cleartime = conn->cleartime + (double)totallen / (double)rate; + if (conn->cleartime < realtime) + conn->cleartime = realtime; + + return 0; +} + +qboolean NetConn_HaveClientPorts(void) +{ + return !!cl_numsockets; +} + +qboolean NetConn_HaveServerPorts(void) +{ + return !!sv_numsockets; +} + +void NetConn_CloseClientPorts(void) +{ + for (;cl_numsockets > 0;cl_numsockets--) + if (cl_sockets[cl_numsockets - 1]) + LHNET_CloseSocket(cl_sockets[cl_numsockets - 1]); +} + +static void NetConn_OpenClientPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport) +{ + lhnetaddress_t address; + lhnetsocket_t *s; + int success; + char addressstring2[1024]; + if (addressstring && addressstring[0]) + success = LHNETADDRESS_FromString(&address, addressstring, defaultport); + else + success = LHNETADDRESS_FromPort(&address, addresstype, defaultport); + if (success) + { + if ((s = LHNET_OpenSocket_Connectionless(&address))) + { + cl_sockets[cl_numsockets++] = s; + LHNETADDRESS_ToString(LHNET_AddressFromSocket(s), addressstring2, sizeof(addressstring2), true); + if (addresstype != LHNETADDRESSTYPE_LOOP) + Con_Printf("Client opened a socket on address %s\n", addressstring2); + } + else + { + LHNETADDRESS_ToString(&address, addressstring2, sizeof(addressstring2), true); + Con_Printf("Client failed to open a socket on address %s\n", addressstring2); + } + } + else + Con_Printf("Client unable to parse address %s\n", addressstring); +} + +void NetConn_OpenClientPorts(void) +{ + int port; + NetConn_CloseClientPorts(); + + SV_LockThreadMutex(); // FIXME recursive? + Crypto_LoadKeys(); // client sockets + SV_UnlockThreadMutex(); + + port = bound(0, cl_netport.integer, 65535); + if (cl_netport.integer != port) + Cvar_SetValueQuick(&cl_netport, port); + if(port == 0) + Con_Printf("Client using an automatically assigned port\n"); + else + Con_Printf("Client using port %i\n", port); + NetConn_OpenClientPort(NULL, LHNETADDRESSTYPE_LOOP, 2); + NetConn_OpenClientPort(net_address.string, LHNETADDRESSTYPE_INET4, port); +#ifdef SUPPORTIPV6 + NetConn_OpenClientPort(net_address_ipv6.string, LHNETADDRESSTYPE_INET6, port); +#endif +} + +void NetConn_CloseServerPorts(void) +{ + for (;sv_numsockets > 0;sv_numsockets--) + if (sv_sockets[sv_numsockets - 1]) + LHNET_CloseSocket(sv_sockets[sv_numsockets - 1]); +} + +static qboolean NetConn_OpenServerPort(const char *addressstring, lhnetaddresstype_t addresstype, int defaultport, int range) +{ + lhnetaddress_t address; + lhnetsocket_t *s; + int port; + char addressstring2[1024]; + int success; + + for (port = defaultport; port <= defaultport + range; port++) + { + if (addressstring && addressstring[0]) + success = LHNETADDRESS_FromString(&address, addressstring, port); + else + success = LHNETADDRESS_FromPort(&address, addresstype, port); + if (success) + { + if ((s = LHNET_OpenSocket_Connectionless(&address))) + { + sv_sockets[sv_numsockets++] = s; + LHNETADDRESS_ToString(LHNET_AddressFromSocket(s), addressstring2, sizeof(addressstring2), true); + if (addresstype != LHNETADDRESSTYPE_LOOP) + Con_Printf("Server listening on address %s\n", addressstring2); + return true; + } + else + { + LHNETADDRESS_ToString(&address, addressstring2, sizeof(addressstring2), true); + Con_Printf("Server failed to open socket on address %s\n", addressstring2); + } + } + else + { + Con_Printf("Server unable to parse address %s\n", addressstring); + // if it cant parse one address, it wont be able to parse another for sure + return false; + } + } + return false; +} + +void NetConn_OpenServerPorts(int opennetports) +{ + int port; + NetConn_CloseServerPorts(); + + SV_LockThreadMutex(); // FIXME recursive? + Crypto_LoadKeys(); // server sockets + SV_UnlockThreadMutex(); + + NetConn_UpdateSockets(); + port = bound(0, sv_netport.integer, 65535); + if (port == 0) + port = 26000; + Con_Printf("Server using port %i\n", port); + if (sv_netport.integer != port) + Cvar_SetValueQuick(&sv_netport, port); + if (cls.state != ca_dedicated) + NetConn_OpenServerPort(NULL, LHNETADDRESSTYPE_LOOP, 1, 1); + if (opennetports) + { +#ifdef SUPPORTIPV6 + qboolean ip4success = NetConn_OpenServerPort(net_address.string, LHNETADDRESSTYPE_INET4, port, 100); + NetConn_OpenServerPort(net_address_ipv6.string, LHNETADDRESSTYPE_INET6, port, ip4success ? 1 : 100); +#else + NetConn_OpenServerPort(net_address.string, LHNETADDRESSTYPE_INET4, port, 100); +#endif + } + if (sv_numsockets == 0) + Host_Error("NetConn_OpenServerPorts: unable to open any ports!"); +} + +lhnetsocket_t *NetConn_ChooseClientSocketForAddress(lhnetaddress_t *address) +{ + int i, a = LHNETADDRESS_GetAddressType(address); + for (i = 0;i < cl_numsockets;i++) + if (cl_sockets[i] && LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])) == a) + return cl_sockets[i]; + return NULL; +} + +lhnetsocket_t *NetConn_ChooseServerSocketForAddress(lhnetaddress_t *address) +{ + int i, a = LHNETADDRESS_GetAddressType(address); + for (i = 0;i < sv_numsockets;i++) + if (sv_sockets[i] && LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(sv_sockets[i])) == a) + return sv_sockets[i]; + return NULL; +} + +netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress) +{ + netconn_t *conn; + conn = (netconn_t *)Mem_Alloc(netconn_mempool, sizeof(*conn)); + conn->mysocket = mysocket; + conn->peeraddress = *peeraddress; + conn->lastMessageTime = realtime; + conn->message.data = conn->messagedata; + conn->message.maxsize = sizeof(conn->messagedata); + conn->message.cursize = 0; + // LordHavoc: (inspired by ProQuake) use a short connect timeout to + // reduce effectiveness of connection request floods + conn->timeout = realtime + net_connecttimeout.value; + LHNETADDRESS_ToString(&conn->peeraddress, conn->address, sizeof(conn->address), true); + conn->next = netconn_list; + netconn_list = conn; + return conn; +} + +void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength); +void NetConn_Close(netconn_t *conn) +{ + netconn_t *c; + // remove connection from list + + // allow the client to reconnect immediately + NetConn_ClearFlood(&(conn->peeraddress), sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0])); + + if (conn == netconn_list) + netconn_list = conn->next; + else + { + for (c = netconn_list;c;c = c->next) + { + if (c->next == conn) + { + c->next = conn->next; + break; + } + } + // not found in list, we'll avoid crashing here... + if (!c) + return; + } + // free connection + Mem_Free(conn); +} + +static int clientport = -1; +static int clientport2 = -1; +static int hostport = -1; +void NetConn_UpdateSockets(void) +{ + int i, j; + + // TODO add logic to automatically close sockets if needed + LHNET_DefaultDSCP(net_tos_dscp.integer); + + if (cls.state != ca_dedicated) + { + if (clientport2 != cl_netport.integer) + { + clientport2 = cl_netport.integer; + if (cls.state == ca_connected) + Con_Print("Changing \"cl_port\" will not take effect until you reconnect.\n"); + } + if (cls.state == ca_disconnected && clientport != clientport2) + { + clientport = clientport2; + NetConn_CloseClientPorts(); + } + if (cl_numsockets == 0) + NetConn_OpenClientPorts(); + } + + if (hostport != sv_netport.integer) + { + hostport = sv_netport.integer; + if (sv.active) + Con_Print("Changing \"port\" will not take effect until \"map\" command is executed.\n"); + } + + for (j = 0;j < MAX_RCONS;j++) + { + i = (cls.rcon_ringpos + j + 1) % MAX_RCONS; + if(cls.rcon_commands[i][0]) + { + if(realtime > cls.rcon_timeout[i]) + { + char s[128]; + LHNETADDRESS_ToString(&cls.rcon_addresses[i], s, sizeof(s), true); + Con_Printf("rcon to %s (for command %s) failed: challenge request timed out\n", s, cls.rcon_commands[i]); + cls.rcon_commands[i][0] = 0; + --cls.rcon_trying; + break; + } + } + } +} + +static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, size_t length, protocolversion_t protocol, double newtimeout) +{ + int originallength = length; + unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE]; + unsigned char cryptosendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE]; + unsigned char cryptoreadbuffer[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE]; + if (length < 8) + return 0; + + if (protocol == PROTOCOL_QUAKEWORLD) + { + int sequence, sequence_ack; + int reliable_ack, reliable_message; + int count; + //int qport; + + sequence = LittleLong(*((int *)(data + 0))); + sequence_ack = LittleLong(*((int *)(data + 4))); + data += 8; + length -= 8; + + if (conn != cls.netcon) + { + // server only + if (length < 2) + return 0; + // TODO: use qport to identify that this client really is who they say they are? (and elsewhere in the code to identify the connection without a port match?) + //qport = LittleShort(*((int *)(data + 8))); + data += 2; + length -= 2; + } + + conn->packetsReceived++; + reliable_message = (sequence >> 31) & 1; + reliable_ack = (sequence_ack >> 31) & 1; + sequence &= ~(1<<31); + sequence_ack &= ~(1<<31); + if (sequence <= conn->qw.incoming_sequence) + { + //Con_DPrint("Got a stale datagram\n"); + return 0; + } + count = sequence - (conn->qw.incoming_sequence + 1); + if (count > 0) + { + conn->droppedDatagrams += count; + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_netgraph[conn->incoming_packetcounter].time = realtime; + conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = NETGRAPH_LOSTPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes = NETGRAPH_NOPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes = NETGRAPH_NOPACKET; + } + } + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_netgraph[conn->incoming_packetcounter].time = realtime; + conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = originallength + 28; + conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes = NETGRAPH_NOPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes = NETGRAPH_NOPACKET; + if (reliable_ack == conn->qw.reliable_sequence) + { + // received, now we will be able to send another reliable message + conn->sendMessageLength = 0; + conn->reliableMessagesReceived++; + } + conn->qw.incoming_sequence = sequence; + if (conn == cls.netcon) + cls.qw_incoming_sequence = conn->qw.incoming_sequence; + conn->qw.incoming_acknowledged = sequence_ack; + conn->qw.incoming_reliable_acknowledged = reliable_ack; + if (reliable_message) + conn->qw.incoming_reliable_sequence ^= 1; + conn->lastMessageTime = realtime; + conn->timeout = realtime + newtimeout; + conn->unreliableMessagesReceived++; + if (conn == cls.netcon) + { + SZ_Clear(&cl_message); + SZ_Write(&cl_message, data, length); + MSG_BeginReading(&cl_message); + } + else + { + SZ_Clear(&sv_message); + SZ_Write(&sv_message, data, length); + MSG_BeginReading(&sv_message); + } + return 2; + } + else + { + unsigned int count; + unsigned int flags; + unsigned int sequence; + size_t qlength; + const void *sendme; + size_t sendmelen; + + originallength = length; + data = (const unsigned char *) Crypto_DecryptPacket(&conn->crypto, data, length, cryptoreadbuffer, &length, sizeof(cryptoreadbuffer)); + if(!data) + return 0; + if(length < 8) + return 0; + + qlength = (unsigned int)BuffBigLong(data); + flags = qlength & ~NETFLAG_LENGTH_MASK; + qlength &= NETFLAG_LENGTH_MASK; + // control packets were already handled + if (!(flags & NETFLAG_CTL) && qlength == length) + { + sequence = BuffBigLong(data + 4); + conn->packetsReceived++; + data += 8; + length -= 8; + if (flags & NETFLAG_UNRELIABLE) + { + if (sequence >= conn->nq.unreliableReceiveSequence) + { + if (sequence > conn->nq.unreliableReceiveSequence) + { + count = sequence - conn->nq.unreliableReceiveSequence; + conn->droppedDatagrams += count; + //Con_DPrintf("Dropped %u datagram(s)\n", count); + while (count--) + { + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_netgraph[conn->incoming_packetcounter].time = realtime; + conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = NETGRAPH_LOSTPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes = NETGRAPH_NOPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes = NETGRAPH_NOPACKET; + } + } + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_netgraph[conn->incoming_packetcounter].time = realtime; + conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = originallength + 28; + conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes = NETGRAPH_NOPACKET; + conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes = NETGRAPH_NOPACKET; + conn->nq.unreliableReceiveSequence = sequence + 1; + conn->lastMessageTime = realtime; + conn->timeout = realtime + newtimeout; + conn->unreliableMessagesReceived++; + if (length > 0) + { + if (conn == cls.netcon) + { + SZ_Clear(&cl_message); + SZ_Write(&cl_message, data, length); + MSG_BeginReading(&cl_message); + } + else + { + SZ_Clear(&sv_message); + SZ_Write(&sv_message, data, length); + MSG_BeginReading(&sv_message); + } + return 2; + } + } + //else + // Con_DPrint("Got a stale datagram\n"); + return 1; + } + else if (flags & NETFLAG_ACK) + { + conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes += originallength + 28; + if (sequence == (conn->nq.sendSequence - 1)) + { + if (sequence == conn->nq.ackSequence) + { + conn->nq.ackSequence++; + if (conn->nq.ackSequence != conn->nq.sendSequence) + Con_DPrint("ack sequencing error\n"); + conn->lastMessageTime = realtime; + conn->timeout = realtime + newtimeout; + if (conn->sendMessageLength > MAX_PACKETFRAGMENT) + { + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + + conn->sendMessageLength -= MAX_PACKETFRAGMENT; + memmove(conn->sendMessage, conn->sendMessage+MAX_PACKETFRAGMENT, conn->sendMessageLength); + + if (conn->sendMessageLength <= MAX_PACKETFRAGMENT) + { + dataLen = conn->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_PACKETFRAGMENT; + eom = 0; + } + + packetLen = NET_HEADERSIZE + dataLen; + + StoreBigLong(sendbuffer, packetLen | (NETFLAG_DATA | eom)); + StoreBigLong(sendbuffer + 4, conn->nq.sendSequence); + memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen); + + conn->nq.sendSequence++; + + sendme = Crypto_EncryptPacket(&conn->crypto, &sendbuffer, packetLen, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer)); + if (sendme && NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress) == (int)sendmelen) + { + conn->lastSendTime = realtime; + conn->packetsSent++; + } + } + else + conn->sendMessageLength = 0; + } + //else + // Con_DPrint("Duplicate ACK received\n"); + } + //else + // Con_DPrint("Stale ACK received\n"); + return 1; + } + else if (flags & NETFLAG_DATA) + { + unsigned char temppacket[8]; + conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes += originallength + 28; + conn->outgoing_netgraph[conn->outgoing_packetcounter].ackbytes += 8 + 28; + StoreBigLong(temppacket, 8 | NETFLAG_ACK); + StoreBigLong(temppacket + 4, sequence); + sendme = Crypto_EncryptPacket(&conn->crypto, temppacket, 8, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer)); + if(sendme) + NetConn_Write(conn->mysocket, sendme, sendmelen, &conn->peeraddress); + if (sequence == conn->nq.receiveSequence) + { + conn->lastMessageTime = realtime; + conn->timeout = realtime + newtimeout; + conn->nq.receiveSequence++; + if( conn->receiveMessageLength + length <= (int)sizeof( conn->receiveMessage ) ) { + memcpy(conn->receiveMessage + conn->receiveMessageLength, data, length); + conn->receiveMessageLength += length; + } else { + Con_Printf( "Reliable message (seq: %i) too big for message buffer!\n" + "Dropping the message!\n", sequence ); + conn->receiveMessageLength = 0; + return 1; + } + if (flags & NETFLAG_EOM) + { + conn->reliableMessagesReceived++; + length = conn->receiveMessageLength; + conn->receiveMessageLength = 0; + if (length > 0) + { + if (conn == cls.netcon) + { + SZ_Clear(&cl_message); + SZ_Write(&cl_message, conn->receiveMessage, length); + MSG_BeginReading(&cl_message); + } + else + { + SZ_Clear(&sv_message); + SZ_Write(&sv_message, conn->receiveMessage, length); + MSG_BeginReading(&sv_message); + } + return 2; + } + } + } + else + conn->receivedDuplicateCount++; + return 1; + } + } + } + return 0; +} + +static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, protocolversion_t initialprotocol) +{ + crypto_t *crypto; + cls.connect_trying = false; + M_Update_Return_Reason(""); + // the connection request succeeded, stop current connection and set up a new connection + CL_Disconnect(); + // if we're connecting to a remote server, shut down any local server + if (LHNETADDRESS_GetAddressType(peeraddress) != LHNETADDRESSTYPE_LOOP && sv.active) + { + SV_LockThreadMutex(); + Host_ShutdownServer (); + SV_UnlockThreadMutex(); + } + // allocate a net connection to keep track of things + cls.netcon = NetConn_Open(mysocket, peeraddress); + crypto = &cls.crypto; + if(crypto && crypto->authenticated) + { + Crypto_ServerFinishInstance(&cls.netcon->crypto, crypto); + Con_Printf("%s connection to %s has been established: server is %s@%.*s, I am %.*s@%.*s\n", + crypto->use_aes ? "Encrypted" : "Authenticated", + cls.netcon->address, + crypto->server_idfp[0] ? crypto->server_idfp : "-", + crypto_keyfp_recommended_length, crypto->server_keyfp[0] ? crypto->server_keyfp : "-", + crypto_keyfp_recommended_length, crypto->client_idfp[0] ? crypto->client_idfp : "-", + crypto_keyfp_recommended_length, crypto->client_keyfp[0] ? crypto->client_keyfp : "-" + ); + } + Con_Printf("Connection accepted to %s\n", cls.netcon->address); + key_dest = key_game; + m_state = m_none; + cls.demonum = -1; // not in the demo loop now + cls.state = ca_connected; + cls.signon = 0; // need all the signon messages before playing + cls.protocol = initialprotocol; + // reset move sequence numbering on this new connection + cls.servermovesequence = 0; + if (cls.protocol == PROTOCOL_QUAKEWORLD) + Cmd_ForwardStringToServer("new"); + if (cls.protocol == PROTOCOL_QUAKE) + { + // write a keepalive (clc_nop) as it seems to greatly improve the + // chances of connecting to a netquake server + sizebuf_t msg; + unsigned char buf[4]; + memset(&msg, 0, sizeof(msg)); + msg.data = buf; + msg.maxsize = sizeof(buf); + MSG_WriteChar(&msg, clc_nop); + NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false); + } +} + +int NetConn_IsLocalGame(void) +{ + if (cls.state == ca_connected && sv.active && cl.maxclients == 1) + return true; + return false; +} + +static int NetConn_ClientParsePacket_ServerList_ProcessReply(const char *addressstring) +{ + int n; + int pingtime; + serverlist_entry_t *entry = NULL; + + // search the cache for this server and update it + for (n = 0;n < serverlist_cachecount;n++) { + entry = &serverlist_cache[ n ]; + if (!strcmp(addressstring, entry->info.cname)) + break; + } + + if (n == serverlist_cachecount) + { + // LAN search doesnt require an answer from the master server so we wont + // know the ping nor will it be initialized already... + + // find a slot + if (serverlist_cachecount == SERVERLIST_TOTALSIZE) + return -1; + + if (serverlist_maxcachecount <= serverlist_cachecount) + { + serverlist_maxcachecount += 64; + serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount); + } + entry = &serverlist_cache[n]; + + memset(entry, 0, sizeof(*entry)); + // store the data the engine cares about (address and ping) + strlcpy(entry->info.cname, addressstring, sizeof(entry->info.cname)); + entry->info.ping = 100000; + entry->querytime = realtime; + // if not in the slist menu we should print the server to console + if (serverlist_consoleoutput) + Con_Printf("querying %s\n", addressstring); + ++serverlist_cachecount; + } + // if this is the first reply from this server, count it as having replied + pingtime = (int)((realtime - entry->querytime) * 1000.0 + 0.5); + pingtime = bound(0, pingtime, 9999); + if (entry->query == SQS_REFRESHING) { + entry->info.ping = pingtime; + entry->query = SQS_QUERIED; + } else { + // convert to unsigned to catch the -1 + // I still dont like this but its better than the old 10000 magic ping number - as in easier to type and read :( [11/8/2007 Black] + entry->info.ping = min((unsigned) entry->info.ping, (unsigned) pingtime); + serverreplycount++; + } + + // other server info is updated by the caller + return n; +} + +static void NetConn_ClientParsePacket_ServerList_UpdateCache(int n) +{ + serverlist_entry_t *entry = &serverlist_cache[n]; + serverlist_info_t *info = &entry->info; + // update description strings for engine menu and console output + dpsnprintf(entry->line1, sizeof(serverlist_cache[n].line1), "^%c%5d^7 ^%c%3u^7/%3u %-65.65s", info->ping >= 300 ? '1' : (info->ping >= 200 ? '3' : '7'), (int)info->ping, ((info->numhumans > 0 && info->numhumans < info->maxplayers) ? (info->numhumans >= 4 ? '7' : '3') : '1'), info->numplayers, info->maxplayers, info->name); + dpsnprintf(entry->line2, sizeof(serverlist_cache[n].line2), "^4%-21.21s %-19.19s ^%c%-17.17s^4 %-20.20s", info->cname, info->game, + ( + info->gameversion != gameversion.integer + && + !( + gameversion_min.integer >= 0 // min/max range set by user/mod? + && gameversion_max.integer >= 0 + && gameversion_min.integer <= info->gameversion // version of server in min/max range? + && gameversion_max.integer >= info->gameversion + ) + ) ? '1' : '4', + info->mod, info->map); + if (entry->query == SQS_QUERIED) + { + if(!serverlist_paused) + ServerList_ViewList_Remove(entry); + } + // if not in the slist menu we should print the server to console (if wanted) + else if( serverlist_consoleoutput ) + Con_Printf("%s\n%s\n", serverlist_cache[n].line1, serverlist_cache[n].line2); + // and finally, update the view set + if(!serverlist_paused) + ServerList_ViewList_Insert( entry ); + // update the entry's state + serverlist_cache[n].query = SQS_QUERIED; +} + +// returns true, if it's sensible to continue the processing +static qboolean NetConn_ClientParsePacket_ServerList_PrepareQuery( int protocol, const char *ipstring, qboolean isfavorite ) { + int n; + serverlist_entry_t *entry; + + // ignore the rest of the message if the serverlist is full + if( serverlist_cachecount == SERVERLIST_TOTALSIZE ) + return false; + // also ignore it if we have already queried it (other master server response) + for( n = 0 ; n < serverlist_cachecount ; n++ ) + if( !strcmp( ipstring, serverlist_cache[ n ].info.cname ) ) + break; + + if( n < serverlist_cachecount ) { + // the entry has already been queried once or + return true; + } + + if (serverlist_maxcachecount <= n) + { + serverlist_maxcachecount += 64; + serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount); + } + + entry = &serverlist_cache[n]; + + memset(entry, 0, sizeof(*entry)); + entry->protocol = protocol; + // store the data the engine cares about (address and ping) + strlcpy (entry->info.cname, ipstring, sizeof(entry->info.cname)); + + entry->info.isfavorite = isfavorite; + + // no, then reset the ping right away + entry->info.ping = -1; + // we also want to increase the serverlist_cachecount then + serverlist_cachecount++; + serverquerycount++; + + entry->query = SQS_QUERYING; + + return true; +} + +static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *senderaddress, const unsigned char *data, int length, qboolean isextended) +{ + masterreplycount++; + if (serverlist_consoleoutput) + Con_Printf("received DarkPlaces %sserver list...\n", isextended ? "extended " : ""); + while (length >= 7) + { + char ipstring [128]; + + // IPv4 address + if (data[0] == '\\') + { + unsigned short port = data[5] * 256 + data[6]; + + if (port != 0 && (data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || data[4] != 0xFF)) + dpsnprintf (ipstring, sizeof (ipstring), "%u.%u.%u.%u:%hu", data[1], data[2], data[3], data[4], port); + + // move on to next address in packet + data += 7; + length -= 7; + } + // IPv6 address + else if (data[0] == '/' && isextended && length >= 19) + { + unsigned short port = data[17] * 256 + data[18]; + + if (port != 0) + { +#ifdef WHY_JUST_WHY + const char *ifname; + char ifnamebuf[16]; + + /// \TODO: make some basic checks of the IP address (broadcast, ...) + + ifname = LHNETADDRESS_GetInterfaceName(senderaddress, ifnamebuf, sizeof(ifnamebuf)); + if (ifname != NULL) + { + dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x%%%s]:%hu", + (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8], + (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16], + ifname, port); + } + else +#endif + { + dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x]:%hu", + (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8], + (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16], + port); + } + } + + // move on to next address in packet + data += 19; + length -= 19; + } + else + { + Con_Print("Error while parsing the server list\n"); + break; + } + + if (serverlist_consoleoutput && developer_networking.integer) + Con_Printf("Requesting info from DarkPlaces server %s\n", ipstring); + + if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_DARKPLACES7, ipstring, false ) ) { + break; + } + + } + + // begin or resume serverlist queries + serverlist_querysleep = false; + serverlist_querywaittime = realtime + 3; +} + +static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress) +{ + qboolean fromserver; + int ret, c; + const char *s; + char *string, addressstring2[128], ipstring[32]; + char stringbuf[16384]; + char senddata[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE]; + size_t sendlength; + char infostringvalue[MAX_INPUTLINE]; + char vabuf[1024]; + + // quakeworld ingame packet + fromserver = cls.netcon && mysocket == cls.netcon->mysocket && !LHNETADDRESS_Compare(&cls.netcon->peeraddress, peeraddress); + + // convert the address to a string incase we need it + LHNETADDRESS_ToString(peeraddress, addressstring2, sizeof(addressstring2), true); + + if (length >= 5 && data[0] == 255 && data[1] == 255 && data[2] == 255 && data[3] == 255) + { + // received a command string - strip off the packaging and put it + // into our string buffer with NULL termination + data += 4; + length -= 4; + length = min(length, (int)sizeof(stringbuf) - 1); + memcpy(stringbuf, data, length); + stringbuf[length] = 0; + string = stringbuf; + + if (developer_networking.integer) + { + Con_Printf("NetConn_ClientParsePacket: %s sent us a command:\n", addressstring2); + Com_HexDumpToConsole(data, length); + } + + sendlength = sizeof(senddata) - 4; + switch(Crypto_ClientParsePacket(string, length, senddata+4, &sendlength, peeraddress)) + { + case CRYPTO_NOMATCH: + // nothing to do + break; + case CRYPTO_MATCH: + if(sendlength) + { + memcpy(senddata, "\377\377\377\377", 4); + NetConn_Write(mysocket, senddata, sendlength+4, peeraddress); + } + break; + case CRYPTO_DISCARD: + if(sendlength) + { + memcpy(senddata, "\377\377\377\377", 4); + NetConn_Write(mysocket, senddata, sendlength+4, peeraddress); + } + return true; + break; + case CRYPTO_REPLACE: + string = senddata+4; + length = sendlength; + break; + } + + if (length >= 10 && !memcmp(string, "challenge ", 10) && cls.rcon_trying) + { + int i = 0, j; + for (j = 0;j < MAX_RCONS;j++) + { + // note: this value from i is used outside the loop too... + i = (cls.rcon_ringpos + j) % MAX_RCONS; + if(cls.rcon_commands[i][0]) + if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[i])) + break; + } + if (j < MAX_RCONS) + { + char buf[1500]; + char argbuf[1500]; + const char *e; + int n; + dpsnprintf(argbuf, sizeof(argbuf), "%s %s", string + 10, cls.rcon_commands[i]); + memcpy(buf, "\377\377\377\377srcon HMAC-MD4 CHALLENGE ", 29); + + e = strchr(rcon_password.string, ' '); + n = e ? e-rcon_password.string : (int)strlen(rcon_password.string); + + if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 29), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, n)) + { + int k; + buf[45] = ' '; + strlcpy(buf + 46, argbuf, sizeof(buf) - 46); + NetConn_Write(mysocket, buf, 46 + strlen(buf + 46), peeraddress); + cls.rcon_commands[i][0] = 0; + --cls.rcon_trying; + + for (k = 0;k < MAX_RCONS;k++) + if(cls.rcon_commands[k][0]) + if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[k])) + break; + if(k < MAX_RCONS) + { + int l; + NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", peeraddress); + // extend the timeout on other requests as we asked for a challenge + for (l = 0;l < MAX_RCONS;l++) + if(cls.rcon_commands[l][0]) + if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[l])) + cls.rcon_timeout[l] = realtime + rcon_secure_challengetimeout.value; + } + + return true; // we used up the challenge, so we can't use this oen for connecting now anyway + } + } + } + if (length >= 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying) + { + // darkplaces or quake3 + char protocolnames[1400]; + Protocol_Names(protocolnames, sizeof(protocolnames)); + Con_DPrintf("\"%s\" received, sending connect request back to %s\n", string, addressstring2); + M_Update_Return_Reason("Got challenge response"); + // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command) + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2); + // TODO: add userinfo stuff here instead of using NQ commands? + NetConn_WriteString(mysocket, portable_va(vabuf, sizeof(vabuf), "\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s%s\\challenge\\%s", protocolnames, cls.connect_userinfo, string + 10), peeraddress); + return true; + } + if (length == 6 && !memcmp(string, "accept", 6) && cls.connect_trying) + { + // darkplaces or quake3 + M_Update_Return_Reason("Accepted"); + NetConn_ConnectionEstablished(mysocket, peeraddress, PROTOCOL_DARKPLACES3); + return true; + } + if (length > 7 && !memcmp(string, "reject ", 7) && cls.connect_trying) + { + char rejectreason[128]; + cls.connect_trying = false; + string += 7; + length = min(length - 7, (int)sizeof(rejectreason) - 1); + memcpy(rejectreason, string, length); + rejectreason[length] = 0; + M_Update_Return_Reason(rejectreason); + return true; + } + if (length >= 15 && !memcmp(string, "statusResponse\x0A", 15)) + { + serverlist_info_t *info; + char *p; + int n; + + string += 15; + // search the cache for this server and update it + n = NetConn_ClientParsePacket_ServerList_ProcessReply(addressstring2); + if (n < 0) + return true; + + info = &serverlist_cache[n].info; + info->game[0] = 0; + info->mod[0] = 0; + info->map[0] = 0; + info->name[0] = 0; + info->qcstatus[0] = 0; + info->players[0] = 0; + info->protocol = -1; + info->numplayers = 0; + info->numbots = -1; + info->maxplayers = 0; + info->gameversion = 0; + + p = strchr(string, '\n'); + if(p) + { + *p = 0; // cut off the string there + ++p; + } + else + Con_Printf("statusResponse without players block?\n"); + + if ((s = InfoString_GetValue(string, "gamename" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->game, s, sizeof (info->game)); + if ((s = InfoString_GetValue(string, "modname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod )); + if ((s = InfoString_GetValue(string, "mapname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map )); + if ((s = InfoString_GetValue(string, "hostname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name)); + if ((s = InfoString_GetValue(string, "protocol" , infostringvalue, sizeof(infostringvalue))) != NULL) info->protocol = atoi(s); + if ((s = InfoString_GetValue(string, "clients" , infostringvalue, sizeof(infostringvalue))) != NULL) info->numplayers = atoi(s); + if ((s = InfoString_GetValue(string, "bots" , infostringvalue, sizeof(infostringvalue))) != NULL) info->numbots = atoi(s); + if ((s = InfoString_GetValue(string, "sv_maxclients", infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s); + if ((s = InfoString_GetValue(string, "gameversion" , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s); + if ((s = InfoString_GetValue(string, "qcstatus" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus)); + if (p != NULL) strlcpy(info->players, p, sizeof(info->players)); + info->numhumans = info->numplayers - max(0, info->numbots); + info->freeslots = info->maxplayers - info->numplayers; + + NetConn_ClientParsePacket_ServerList_UpdateCache(n); + + return true; + } + if (length >= 13 && !memcmp(string, "infoResponse\x0A", 13)) + { + serverlist_info_t *info; + int n; + + string += 13; + // search the cache for this server and update it + n = NetConn_ClientParsePacket_ServerList_ProcessReply(addressstring2); + if (n < 0) + return true; + + info = &serverlist_cache[n].info; + info->game[0] = 0; + info->mod[0] = 0; + info->map[0] = 0; + info->name[0] = 0; + info->qcstatus[0] = 0; + info->players[0] = 0; + info->protocol = -1; + info->numplayers = 0; + info->numbots = -1; + info->maxplayers = 0; + info->gameversion = 0; + + if ((s = InfoString_GetValue(string, "gamename" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->game, s, sizeof (info->game)); + if ((s = InfoString_GetValue(string, "modname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod )); + if ((s = InfoString_GetValue(string, "mapname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map )); + if ((s = InfoString_GetValue(string, "hostname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name)); + if ((s = InfoString_GetValue(string, "protocol" , infostringvalue, sizeof(infostringvalue))) != NULL) info->protocol = atoi(s); + if ((s = InfoString_GetValue(string, "clients" , infostringvalue, sizeof(infostringvalue))) != NULL) info->numplayers = atoi(s); + if ((s = InfoString_GetValue(string, "bots" , infostringvalue, sizeof(infostringvalue))) != NULL) info->numbots = atoi(s); + if ((s = InfoString_GetValue(string, "sv_maxclients", infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s); + if ((s = InfoString_GetValue(string, "gameversion" , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s); + if ((s = InfoString_GetValue(string, "qcstatus" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->qcstatus, s, sizeof(info->qcstatus)); + info->numhumans = info->numplayers - max(0, info->numbots); + info->freeslots = info->maxplayers - info->numplayers; + + NetConn_ClientParsePacket_ServerList_UpdateCache(n); + + return true; + } + if (!strncmp(string, "getserversResponse\\", 19) && serverlist_cachecount < SERVERLIST_TOTALSIZE) + { + // Extract the IP addresses + data += 18; + length -= 18; + NetConn_ClientParsePacket_ServerList_ParseDPList(peeraddress, data, length, false); + return true; + } + if (!strncmp(string, "getserversExtResponse", 21) && serverlist_cachecount < SERVERLIST_TOTALSIZE) + { + // Extract the IP addresses + data += 21; + length -= 21; + NetConn_ClientParsePacket_ServerList_ParseDPList(peeraddress, data, length, true); + return true; + } + if (!memcmp(string, "d\n", 2) && serverlist_cachecount < SERVERLIST_TOTALSIZE) + { + // Extract the IP addresses + data += 2; + length -= 2; + masterreplycount++; + if (serverlist_consoleoutput) + Con_Printf("received QuakeWorld server list from %s...\n", addressstring2); + while (length >= 6 && (data[0] != 0xFF || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF) && data[4] * 256 + data[5] != 0) + { + dpsnprintf (ipstring, sizeof (ipstring), "%u.%u.%u.%u:%u", data[0], data[1], data[2], data[3], data[4] * 256 + data[5]); + if (serverlist_consoleoutput && developer_networking.integer) + Con_Printf("Requesting info from QuakeWorld server %s\n", ipstring); + + if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_QUAKEWORLD, ipstring, false ) ) { + break; + } + + // move on to next address in packet + data += 6; + length -= 6; + } + // begin or resume serverlist queries + serverlist_querysleep = false; + serverlist_querywaittime = realtime + 3; + return true; + } + if (!strncmp(string, "extResponse ", 12)) + { + ++cl_net_extresponse_count; + if(cl_net_extresponse_count > NET_EXTRESPONSE_MAX) + cl_net_extresponse_count = NET_EXTRESPONSE_MAX; + cl_net_extresponse_last = (cl_net_extresponse_last + 1) % NET_EXTRESPONSE_MAX; + portable_snprintf(cl_net_extresponse[cl_net_extresponse_last], sizeof(cl_net_extresponse[cl_net_extresponse_last]), "\"%s\" %s", addressstring2, string + 12); + return true; + } + if (!strncmp(string, "ping", 4)) + { + if (developer_extra.integer) + Con_DPrintf("Received ping from %s, sending ack\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377ack", peeraddress); + return true; + } + if (!strncmp(string, "ack", 3)) + return true; + // QuakeWorld compatibility + if (length > 1 && string[0] == 'c' && (string[1] == '-' || (string[1] >= '0' && string[1] <= '9')) && cls.connect_trying) + { + // challenge message + Con_Printf("challenge %s received, sending QuakeWorld connect request back to %s\n", string + 1, addressstring2); + M_Update_Return_Reason("Got QuakeWorld challenge response"); + cls.qw_qport = qport.integer; + // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command) + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2); + NetConn_WriteString(mysocket, portable_va(vabuf, sizeof(vabuf), "\377\377\377\377connect %i %i %i \"%s%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo, cls.connect_userinfo), peeraddress); + return true; + } + if (length >= 1 && string[0] == 'j' && cls.connect_trying) + { + // accept message + M_Update_Return_Reason("QuakeWorld Accepted"); + NetConn_ConnectionEstablished(mysocket, peeraddress, PROTOCOL_QUAKEWORLD); + return true; + } + if (length > 2 && !memcmp(string, "n\\", 2)) + { + serverlist_info_t *info; + int n; + + // qw server status + if (serverlist_consoleoutput && developer_networking.integer >= 2) + Con_Printf("QW server status from server at %s:\n%s\n", addressstring2, string + 1); + + string += 1; + // search the cache for this server and update it + n = NetConn_ClientParsePacket_ServerList_ProcessReply(addressstring2); + if (n < 0) + return true; + + info = &serverlist_cache[n].info; + strlcpy(info->game, "QuakeWorld", sizeof(info->game)); + if ((s = InfoString_GetValue(string, "*gamedir" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->mod , s, sizeof (info->mod ));else info->mod[0] = 0; + if ((s = InfoString_GetValue(string, "map" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->map , s, sizeof (info->map ));else info->map[0] = 0; + if ((s = InfoString_GetValue(string, "hostname" , infostringvalue, sizeof(infostringvalue))) != NULL) strlcpy(info->name, s, sizeof (info->name));else info->name[0] = 0; + info->protocol = 0; + info->numplayers = 0; // updated below + info->numhumans = 0; // updated below + if ((s = InfoString_GetValue(string, "maxclients" , infostringvalue, sizeof(infostringvalue))) != NULL) info->maxplayers = atoi(s);else info->maxplayers = 0; + if ((s = InfoString_GetValue(string, "gameversion" , infostringvalue, sizeof(infostringvalue))) != NULL) info->gameversion = atoi(s);else info->gameversion = 0; + + // count active players on server + // (we could gather more info, but we're just after the number) + s = strchr(string, '\n'); + if (s) + { + s++; + while (s < string + length) + { + for (;s < string + length && *s != '\n';s++) + ; + if (s >= string + length) + break; + info->numplayers++; + info->numhumans++; + s++; + } + } + + NetConn_ClientParsePacket_ServerList_UpdateCache(n); + + return true; + } + if (string[0] == 'n') + { + // qw print command + Con_Printf("QW print command from server at %s:\n%s\n", addressstring2, string + 1); + } + // we may not have liked the packet, but it was a command packet, so + // we're done processing this packet now + return true; + } + // quakeworld ingame packet + if (fromserver && cls.protocol == PROTOCOL_QUAKEWORLD && length >= 8 && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2) + { + ret = 0; + CL_ParseServerMessage(); + return ret; + } + // netquake control packets, supported for compatibility only + if (length >= 5 && BuffBigLong(data) == ((int)NETFLAG_CTL | length) && !ENCRYPTION_REQUIRED) + { + int n; + serverlist_info_t *info; + + data += 4; + length -= 4; + SZ_Clear(&cl_message); + SZ_Write(&cl_message, data, length); + MSG_BeginReading(&cl_message); + c = MSG_ReadByte(&cl_message); + switch (c) + { + case CCREP_ACCEPT: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREP_ACCEPT from %s.\n", addressstring2); + if (cls.connect_trying) + { + lhnetaddress_t clientportaddress; + clientportaddress = *peeraddress; + LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong(&cl_message)); + // extra ProQuake stuff + if (length >= 6) + cls.proquake_servermod = MSG_ReadByte(&cl_message); // MOD_PROQUAKE + else + cls.proquake_servermod = 0; + if (length >= 7) + cls.proquake_serverversion = MSG_ReadByte(&cl_message); // version * 10 + else + cls.proquake_serverversion = 0; + if (length >= 8) + cls.proquake_serverflags = MSG_ReadByte(&cl_message); // flags (mainly PQF_CHEATFREE) + else + cls.proquake_serverflags = 0; + if (cls.proquake_servermod == 1) + Con_Printf("Connected to ProQuake %.1f server, enabling precise aim\n", cls.proquake_serverversion / 10.0f); + // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command) + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2); + M_Update_Return_Reason("Accepted"); + NetConn_ConnectionEstablished(mysocket, &clientportaddress, PROTOCOL_QUAKE); + } + break; + case CCREP_REJECT: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREP_REJECT from %s.\n", addressstring2); + cls.connect_trying = false; + M_Update_Return_Reason((char *)MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + case CCREP_SERVER_INFO: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREP_SERVER_INFO from %s.\n", addressstring2); + // LordHavoc: because the quake server may report weird addresses + // we just ignore it and keep the real address + MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)); + // search the cache for this server and update it + n = NetConn_ClientParsePacket_ServerList_ProcessReply(addressstring2); + if (n < 0) + break; + + info = &serverlist_cache[n].info; + strlcpy(info->game, "Quake", sizeof(info->game)); + strlcpy(info->mod , "", sizeof(info->mod)); // mod name is not specified + strlcpy(info->name, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(info->name)); + strlcpy(info->map , MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)), sizeof(info->map)); + info->numplayers = MSG_ReadByte(&cl_message); + info->maxplayers = MSG_ReadByte(&cl_message); + info->protocol = MSG_ReadByte(&cl_message); + + NetConn_ClientParsePacket_ServerList_UpdateCache(n); + + break; + case CCREP_RCON: // RocketGuy: ProQuake rcon support + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREP_RCON from %s.\n", addressstring2); + + Con_Printf("%s\n", MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring))); + break; + case CCREP_PLAYER_INFO: + // we got a CCREP_PLAYER_INFO?? + //if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: received CCREP_PLAYER_INFO from %s.\n", addressstring2); + break; + case CCREP_RULE_INFO: + // we got a CCREP_RULE_INFO?? + //if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: received CCREP_RULE_INFO from %s.\n", addressstring2); + break; + default: + break; + } + SZ_Clear(&cl_message); + // we may not have liked the packet, but it was a valid control + // packet, so we're done processing this packet now + return true; + } + ret = 0; + if (fromserver && length >= (int)NET_HEADERSIZE && (ret = NetConn_ReceivedMessage(cls.netcon, data, length, cls.protocol, net_messagetimeout.value)) == 2) + CL_ParseServerMessage(); + return ret; +} + +void NetConn_QueryQueueFrame(void) +{ + int index; + int queries; + int maxqueries; + double timeouttime; + static double querycounter = 0; + + if(!net_slist_pause.integer && serverlist_paused) + ServerList_RebuildViewList(); + serverlist_paused = net_slist_pause.integer != 0; + + if (serverlist_querysleep) + return; + + // apply a cool down time after master server replies, + // to avoid messing up the ping times on the servers + if (serverlist_querywaittime > realtime) + return; + + // each time querycounter reaches 1.0 issue a query + querycounter += cl.realframetime * net_slist_queriespersecond.value; + maxqueries = (int)querycounter; + maxqueries = bound(0, maxqueries, net_slist_queriesperframe.integer); + querycounter -= maxqueries; + + if( maxqueries == 0 ) { + return; + } + + // scan serverlist and issue queries as needed + serverlist_querysleep = true; + + timeouttime = realtime - net_slist_timeout.value; + for( index = 0, queries = 0 ; index < serverlist_cachecount && queries < maxqueries ; index++ ) + { + serverlist_entry_t *entry = &serverlist_cache[ index ]; + if( entry->query != SQS_QUERYING && entry->query != SQS_REFRESHING ) + { + continue; + } + + serverlist_querysleep = false; + if( entry->querycounter != 0 && entry->querytime > timeouttime ) + { + continue; + } + + if( entry->querycounter != (unsigned) net_slist_maxtries.integer ) + { + lhnetaddress_t address; + int socket; + + LHNETADDRESS_FromString(&address, entry->info.cname, 0); + if (entry->protocol == PROTOCOL_QUAKEWORLD) + { + for (socket = 0; socket < cl_numsockets ; socket++) + NetConn_WriteString(cl_sockets[socket], "\377\377\377\377status\n", &address); + } + else + { + for (socket = 0; socket < cl_numsockets ; socket++) + NetConn_WriteString(cl_sockets[socket], "\377\377\377\377getstatus", &address); + } + + // update the entry fields + entry->querytime = realtime; + entry->querycounter++; + + // if not in the slist menu we should print the server to console + if (serverlist_consoleoutput) + Con_Printf("querying %25s (%i. try)\n", entry->info.cname, entry->querycounter); + + queries++; + } + else + { + // have we tried to refresh this server? + if( entry->query == SQS_REFRESHING ) { + // yes, so update the reply count (since its not responding anymore) + serverreplycount--; + if(!serverlist_paused) + ServerList_ViewList_Remove(entry); + } + entry->query = SQS_TIMEDOUT; + } + } +} + +void NetConn_ClientFrame(void) +{ + int i, length; + lhnetaddress_t peeraddress; + unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE]; + NetConn_UpdateSockets(); + if (cls.connect_trying && cls.connect_nextsendtime < realtime) + { + if (cls.connect_remainingtries == 0) + M_Update_Return_Reason("Connect: Waiting 10 seconds for reply"); + cls.connect_nextsendtime = realtime + 1; + cls.connect_remainingtries--; + if (cls.connect_remainingtries <= -10) + { + cls.connect_trying = false; + M_Update_Return_Reason("Connect: Failed"); + return; + } + // try challenge first (newer DP server or QW) + NetConn_WriteString(cls.connect_mysocket, "\377\377\377\377getchallenge", &cls.connect_address); + // then try netquake as a fallback (old server, or netquake) + SZ_Clear(&cl_message); + // save space for the header, filled in later + MSG_WriteLong(&cl_message, 0); + MSG_WriteByte(&cl_message, CCREQ_CONNECT); + MSG_WriteString(&cl_message, "QUAKE"); + MSG_WriteByte(&cl_message, NET_PROTOCOL_VERSION); + // extended proquake stuff + MSG_WriteByte(&cl_message, 1); // mod = MOD_PROQUAKE + // this version matches ProQuake 3.40, the first version to support + // the NAT fix, and it only supports the NAT fix for ProQuake 3.40 or + // higher clients, so we pretend we are that version... + MSG_WriteByte(&cl_message, 34); // version * 10 + MSG_WriteByte(&cl_message, 0); // flags + MSG_WriteLong(&cl_message, 0); // password + // write the packetsize now... + StoreBigLong(cl_message.data, NETFLAG_CTL | (cl_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(cls.connect_mysocket, cl_message.data, cl_message.cursize, &cls.connect_address); + SZ_Clear(&cl_message); + } + for (i = 0;i < cl_numsockets;i++) + { + while (cl_sockets[i] && (length = NetConn_Read(cl_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0) + { +// R_TimeReport("clientreadnetwork"); + NetConn_ClientParsePacket(cl_sockets[i], readbuffer, length, &peeraddress); +// R_TimeReport("clientparsepacket"); + } + } + NetConn_QueryQueueFrame(); + if (cls.netcon && realtime > cls.netcon->timeout && !sv.active) + { + Con_Print("Connection timed out\n"); + CL_Disconnect(); + SV_LockThreadMutex(); + Host_ShutdownServer (); + SV_UnlockThreadMutex(); + } +} + +static void NetConn_BuildChallengeString(char *buffer, int bufferlength) +{ + int i; + char c; + for (i = 0;i < bufferlength - 1;i++) + { + do + { + c = rand () % (127 - 33) + 33; + } while (c == '\\' || c == ';' || c == '"' || c == '%' || c == '/'); + buffer[i] = c; + } + buffer[i] = 0; +} + +/// (div0) build the full response only if possible; better a getinfo response than no response at all if getstatus won't fit +static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg, size_t out_size, qboolean fullstatus) +{ + prvm_prog_t *prog = SVVM_prog; + char qcstatus[256]; + unsigned int nb_clients = 0, nb_bots = 0, i; + int length; + char teambuf[3]; + const char *crypto_idstring; + const char *str; + + // How many clients are there? + for (i = 0;i < (unsigned int)svs.maxclients;i++) + { + if (svs.clients[i].active) + { + nb_clients++; + if (!svs.clients[i].netconnection) + nb_bots++; + } + } + + *qcstatus = 0; + str = PRVM_GetString(prog, PRVM_serverglobalstring(worldstatus)); + if(str && *str) + { + char *p; + const char *q; + p = qcstatus; + for(q = str; *q && (size_t)(p - qcstatus) < (sizeof(qcstatus) - 1); ++q) + if(*q != '\\' && *q != '\n') + *p++ = *q; + *p = 0; + } + + /// \TODO: we should add more information for the full status string + crypto_idstring = Crypto_GetInfoResponseDataString(); + length = portable_snprintf(out_msg, out_size, + "\377\377\377\377%s\x0A" + "\\gamename\\%s\\modname\\%s\\gameversion\\%d\\sv_maxclients\\%d" + "\\clients\\%d\\bots\\%d\\mapname\\%s\\hostname\\%s\\protocol\\%d" + "%s%s" + "%s%s" + "%s%s" + "%s", + fullstatus ? "statusResponse" : "infoResponse", + gamename, com_modname, gameversion.integer, svs.maxclients, + nb_clients, nb_bots, sv.worldbasename, hostname.string, NET_PROTOCOL_VERSION, + *qcstatus ? "\\qcstatus\\" : "", qcstatus, + challenge ? "\\challenge\\" : "", challenge ? challenge : "", + crypto_idstring ? "\\d0_blind_id\\" : "", crypto_idstring ? crypto_idstring : "", + fullstatus ? "\n" : ""); + + // Make sure it fits in the buffer + if (length < 0) + goto bad; + + if (fullstatus) + { + char *ptr; + int left; + int savelength; + + savelength = length; + + ptr = out_msg + length; + left = (int)out_size - length; + + for (i = 0;i < (unsigned int)svs.maxclients;i++) + { + client_t *cl = &svs.clients[i]; + if (cl->active) + { + int nameind, cleanind, pingvalue; + char curchar; + char cleanname [sizeof(cl->name)]; + const char *str; + prvm_edict_t *ed; + + // Remove all characters '"' and '\' in the player name + nameind = 0; + cleanind = 0; + do + { + curchar = cl->name[nameind++]; + if (curchar != '"' && curchar != '\\') + { + cleanname[cleanind++] = curchar; + if (cleanind == sizeof(cleanname) - 1) + break; + } + } while (curchar != '\0'); + cleanname[cleanind] = 0; // cleanind is always a valid index even at this point + + pingvalue = (int)(cl->ping * 1000.0f); + if(cl->netconnection) + pingvalue = bound(1, pingvalue, 9999); + else + pingvalue = 0; + + *qcstatus = 0; + ed = PRVM_EDICT_NUM(i + 1); + str = PRVM_GetString(prog, PRVM_serveredictstring(ed, clientstatus)); + if(str && *str) + { + char *p; + const char *q; + p = qcstatus; + for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q) + if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q)) + *p++ = *q; + *p = 0; + } + + if ((gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) && (teamplay.integer > 0)) + { + if(cl->frags == -666) // spectator + strlcpy(teambuf, " 0", sizeof(teambuf)); + else if(cl->colors == 0x44) // red team + strlcpy(teambuf, " 1", sizeof(teambuf)); + else if(cl->colors == 0xDD) // blue team + strlcpy(teambuf, " 2", sizeof(teambuf)); + else if(cl->colors == 0xCC) // yellow team + strlcpy(teambuf, " 3", sizeof(teambuf)); + else if(cl->colors == 0x99) // pink team + strlcpy(teambuf, " 4", sizeof(teambuf)); + else + strlcpy(teambuf, " 0", sizeof(teambuf)); + } + else + *teambuf = 0; + + // note: team number is inserted according to SoF2 protocol + if(*qcstatus) + length = dpsnprintf(ptr, left, "%s %d%s \"%s\"\n", + qcstatus, + pingvalue, + teambuf, + cleanname); + else + length = dpsnprintf(ptr, left, "%d %d%s \"%s\"\n", + cl->frags, + pingvalue, + teambuf, + cleanname); + + if(length < 0) + { + // out of space? + // turn it into an infoResponse! + out_msg[savelength] = 0; + memcpy(out_msg + 4, "infoResponse\x0A", 13); + memmove(out_msg + 17, out_msg + 19, savelength - 19); + break; + } + left -= length; + ptr += length; + } + } + } + + return true; + +bad: + return false; +} + +static qboolean NetConn_PreventFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength, double floodtime, qboolean renew) +{ + size_t floodslotnum, bestfloodslotnum; + double bestfloodtime; + lhnetaddress_t noportpeeraddress; + // see if this is a connect flood + noportpeeraddress = *peeraddress; + LHNETADDRESS_SetPort(&noportpeeraddress, 0); + bestfloodslotnum = 0; + bestfloodtime = floodlist[bestfloodslotnum].lasttime; + for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++) + { + if (bestfloodtime >= floodlist[floodslotnum].lasttime) + { + bestfloodtime = floodlist[floodslotnum].lasttime; + bestfloodslotnum = floodslotnum; + } + if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0) + { + // this address matches an ongoing flood address + if (realtime < floodlist[floodslotnum].lasttime + floodtime) + { + if(renew) + { + // renew the ban on this address so it does not expire + // until the flood has subsided + floodlist[floodslotnum].lasttime = realtime; + } + //Con_Printf("Flood detected!\n"); + return true; + } + // the flood appears to have subsided, so allow this + bestfloodslotnum = floodslotnum; // reuse the same slot + break; + } + } + // begin a new timeout on this address + floodlist[bestfloodslotnum].address = noportpeeraddress; + floodlist[bestfloodslotnum].lasttime = realtime; + //Con_Printf("Flood detection initiated!\n"); + return false; +} + +void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength) +{ + size_t floodslotnum; + lhnetaddress_t noportpeeraddress; + // see if this is a connect flood + noportpeeraddress = *peeraddress; + LHNETADDRESS_SetPort(&noportpeeraddress, 0); + for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++) + { + if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0) + { + // this address matches an ongoing flood address + // remove the ban + floodlist[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE; + floodlist[floodslotnum].lasttime = 0; + //Con_Printf("Flood cleared!\n"); + } + } +} + +typedef qboolean (*rcon_matchfunc_t) (lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen); + +static qboolean hmac_mdfour_time_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen) +{ + char mdfourbuf[16]; + long t1, t2; + + t1 = (long) time(NULL); + t2 = strtol(s, NULL, 0); + if(abs(t1 - t2) > rcon_secure_maxdiff.integer) + return false; + + if(!HMAC_MDFOUR_16BYTES((unsigned char *) mdfourbuf, (unsigned char *) s, slen, (unsigned char *) password, strlen(password))) + return false; + + return !memcmp(mdfourbuf, hash, 16); +} + +static qboolean hmac_mdfour_challenge_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen) +{ + char mdfourbuf[16]; + int i; + + if(slen < (int)(sizeof(challenge[0].string)) - 1) + return false; + + // validate the challenge + for (i = 0;i < MAX_CHALLENGES;i++) + if(challenge[i].time > 0) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strncmp(challenge[i].string, s, sizeof(challenge[0].string) - 1)) + break; + // if the challenge is not recognized, drop the packet + if (i == MAX_CHALLENGES) + return false; + + if(!HMAC_MDFOUR_16BYTES((unsigned char *) mdfourbuf, (unsigned char *) s, slen, (unsigned char *) password, strlen(password))) + return false; + + if(memcmp(mdfourbuf, hash, 16)) + return false; + + // unmark challenge to prevent replay attacks + challenge[i].time = 0; + + return true; +} + +static qboolean plaintext_matching(lhnetaddress_t *peeraddress, const char *password, const char *hash, const char *s, int slen) +{ + return !strcmp(password, hash); +} + +/// returns a string describing the user level, or NULL for auth failure +static const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *password, const char *s, const char *endpos, rcon_matchfunc_t comparator, const char *cs, int cslen) +{ + const char *text, *userpass_start, *userpass_end, *userpass_startpass; + static char buf[MAX_INPUTLINE]; + qboolean hasquotes; + qboolean restricted = false; + qboolean have_usernames = false; + char vabuf[1024]; + + userpass_start = rcon_password.string; + while((userpass_end = strchr(userpass_start, ' '))) + { + have_usernames = true; + strlcpy(buf, userpass_start, ((size_t)(userpass_end-userpass_start) >= sizeof(buf)) ? (int)(sizeof(buf)) : (int)(userpass_end-userpass_start+1)); + if(buf[0]) + if(comparator(peeraddress, buf, password, cs, cslen)) + goto allow; + userpass_start = userpass_end + 1; + } + if(userpass_start[0]) + { + userpass_end = userpass_start + strlen(userpass_start); + if(comparator(peeraddress, userpass_start, password, cs, cslen)) + goto allow; + } + + restricted = true; + have_usernames = false; + userpass_start = rcon_restricted_password.string; + while((userpass_end = strchr(userpass_start, ' '))) + { + have_usernames = true; + strlcpy(buf, userpass_start, ((size_t)(userpass_end-userpass_start) >= sizeof(buf)) ? (int)(sizeof(buf)) : (int)(userpass_end-userpass_start+1)); + if(buf[0]) + if(comparator(peeraddress, buf, password, cs, cslen)) + goto check; + userpass_start = userpass_end + 1; + } + if(userpass_start[0]) + { + userpass_end = userpass_start + strlen(userpass_start); + if(comparator(peeraddress, userpass_start, password, cs, cslen)) + goto check; + } + + return NULL; // DENIED + +check: + for(text = s; text != endpos; ++text) + if((signed char) *text > 0 && ((signed char) *text < (signed char) ' ' || *text == ';')) + return NULL; // block possible exploits against the parser/alias expansion + + while(s != endpos) + { + size_t l = strlen(s); + if(l) + { + hasquotes = (strchr(s, '"') != NULL); + // sorry, we can't allow these substrings in wildcard expressions, + // as they can mess with the argument counts + text = rcon_restricted_commands.string; + while(COM_ParseToken_Console(&text)) + { + // com_token now contains a pattern to check for... + if(strchr(com_token, '*') || strchr(com_token, '?')) // wildcard expression, * can only match a SINGLE argument + { + if(!hasquotes) + if(matchpattern_with_separator(s, com_token, true, " ", true)) // note how we excluded tab, newline etc. above + goto match; + } + else if(strchr(com_token, ' ')) // multi-arg expression? must match in whole + { + if(!strcmp(com_token, s)) + goto match; + } + else // single-arg expression? must match the beginning of the command + { + if(!strcmp(com_token, s)) + goto match; + if(!memcmp(va(vabuf, sizeof(vabuf), "%s ", com_token), s, strlen(com_token) + 1)) + goto match; + } + } + // if we got here, nothing matched! + return NULL; + } +match: + s += l + 1; + } + +allow: + userpass_startpass = strchr(userpass_start, ':'); + if(have_usernames && userpass_startpass && userpass_startpass < userpass_end) + return va(vabuf, sizeof(vabuf), "%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start); + + return va(vabuf, sizeof(vabuf), "%srcon", restricted ? "restricted " : ""); +} + +static void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos, qboolean proquakeprotocol) +{ + if(userlevel) + { + // looks like a legitimate rcon command with the correct password + const char *s_ptr = s; + Con_Printf("server received %s command from %s: ", userlevel, host_client ? host_client->name : addressstring2); + while(s_ptr != endpos) + { + size_t l = strlen(s_ptr); + if(l) + Con_Printf(" %s;", s_ptr); + s_ptr += l + 1; + } + Con_Printf("\n"); + + if (!host_client || !host_client->netconnection || LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP) + Con_Rcon_Redirect_Init(mysocket, peeraddress, proquakeprotocol); + while(s != endpos) + { + size_t l = strlen(s); + if(l) + { + client_t *host_client_save = host_client; + Cmd_ExecuteString(s, src_command, true); + host_client = host_client_save; + // in case it is a command that changes host_client (like restart) + } + s += l + 1; + } + Con_Rcon_Redirect_End(); + } + else + { + Con_Printf("server denied rcon access to %s\n", host_client ? host_client->name : addressstring2); + } +} + +static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress) +{ + int i, ret, clientnum, best; + double besttime; + client_t *client; + char *s, *string, response[1400], addressstring2[128]; + static char stringbuf[16384]; // server only + qboolean islocal = (LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP); + char senddata[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE]; + size_t sendlength, response_len; + char infostringvalue[MAX_INPUTLINE]; + char vabuf[1024]; + + if (!sv.active) + return false; + + // convert the address to a string incase we need it + LHNETADDRESS_ToString(peeraddress, addressstring2, sizeof(addressstring2), true); + + // see if we can identify the sender as a local player + // (this is necessary for rcon to send a reliable reply if the client is + // actually on the server, not sending remotely) + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if (host_client->netconnection && host_client->netconnection->mysocket == mysocket && !LHNETADDRESS_Compare(&host_client->netconnection->peeraddress, peeraddress)) + break; + if (i == svs.maxclients) + host_client = NULL; + + if (length >= 5 && data[0] == 255 && data[1] == 255 && data[2] == 255 && data[3] == 255) + { + // received a command string - strip off the packaging and put it + // into our string buffer with NULL termination + data += 4; + length -= 4; + length = min(length, (int)sizeof(stringbuf) - 1); + memcpy(stringbuf, data, length); + stringbuf[length] = 0; + string = stringbuf; + + if (developer_extra.integer) + { + Con_Printf("NetConn_ServerParsePacket: %s sent us a command:\n", addressstring2); + Com_HexDumpToConsole(data, length); + } + + sendlength = sizeof(senddata) - 4; + switch(Crypto_ServerParsePacket(string, length, senddata+4, &sendlength, peeraddress)) + { + case CRYPTO_NOMATCH: + // nothing to do + break; + case CRYPTO_MATCH: + if(sendlength) + { + memcpy(senddata, "\377\377\377\377", 4); + NetConn_Write(mysocket, senddata, sendlength+4, peeraddress); + } + break; + case CRYPTO_DISCARD: + if(sendlength) + { + memcpy(senddata, "\377\377\377\377", 4); + NetConn_Write(mysocket, senddata, sendlength+4, peeraddress); + } + return true; + break; + case CRYPTO_REPLACE: + string = senddata+4; + length = sendlength; + break; + } + + if (length >= 12 && !memcmp(string, "getchallenge", 12) && (islocal || sv_public.integer > -3)) + { + for (i = 0, best = 0, besttime = realtime;i < MAX_CHALLENGES;i++) + { + if(challenge[i].time > 0) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address)) + break; + if (besttime > challenge[i].time) + besttime = challenge[best = i].time; + } + // if we did not find an exact match, choose the oldest and + // update address and string + if (i == MAX_CHALLENGES) + { + i = best; + challenge[i].address = *peeraddress; + NetConn_BuildChallengeString(challenge[i].string, sizeof(challenge[i].string)); + } + else + { + // flood control: drop if requesting challenge too often + if(challenge[i].time > realtime - net_challengefloodblockingtimeout.value) + return true; + } + challenge[i].time = realtime; + // send the challenge + portable_snprintf(response, sizeof(response), "\377\377\377\377challenge %s", challenge[i].string); + response_len = strlen(response) + 1; + Crypto_ServerAppendToChallenge(string, length, response, &response_len, sizeof(response)); + NetConn_Write(mysocket, response, response_len, peeraddress); + return true; + } + if (length > 8 && !memcmp(string, "connect\\", 8)) + { + crypto_t *crypto = Crypto_ServerGetInstance(peeraddress); + string += 7; + length -= 7; + + if(crypto && crypto->authenticated) + { + // no need to check challenge + if(crypto_developer.integer) + { + Con_Printf("%s connection to %s is being established: client is %s@%.*s, I am %.*s@%.*s\n", + crypto->use_aes ? "Encrypted" : "Authenticated", + addressstring2, + crypto->client_idfp[0] ? crypto->client_idfp : "-", + crypto_keyfp_recommended_length, crypto->client_keyfp[0] ? crypto->client_keyfp : "-", + crypto_keyfp_recommended_length, crypto->server_idfp[0] ? crypto->server_idfp : "-", + crypto_keyfp_recommended_length, crypto->server_keyfp[0] ? crypto->server_keyfp : "-" + ); + } + } + else + { + if ((s = InfoString_GetValue(string, "challenge", infostringvalue, sizeof(infostringvalue)))) + { + // validate the challenge + for (i = 0;i < MAX_CHALLENGES;i++) + if(challenge[i].time > 0) + if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s)) + break; + // if the challenge is not recognized, drop the packet + if (i == MAX_CHALLENGES) + return true; + } + } + + if((s = InfoString_GetValue(string, "message", infostringvalue, sizeof(infostringvalue)))) + Con_DPrintf("Connecting client %s sent us the message: %s\n", addressstring2, s); + + if(!(islocal || sv_public.integer > -2)) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"reject %s\" to %s.\n", sv_public_rejectreason.string, addressstring2); + NetConn_WriteString(mysocket, portable_va(vabuf, sizeof(vabuf), "\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress); + return true; + } + + // check engine protocol + if(!(s = InfoString_GetValue(string, "protocol", infostringvalue, sizeof(infostringvalue))) || strcmp(s, "darkplaces 3")) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Wrong game protocol.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Wrong game protocol.", peeraddress); + return true; + } + + // see if this is a duplicate connection request or a disconnected + // client who is rejoining to the same client slot + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) + { + // this is a known client... + if(crypto && crypto->authenticated) + { + // reject if changing key! + if(client->netconnection->crypto.authenticated) + { + if( + strcmp(client->netconnection->crypto.client_idfp, crypto->client_idfp) + || + strcmp(client->netconnection->crypto.server_idfp, crypto->server_idfp) + || + strcmp(client->netconnection->crypto.client_keyfp, crypto->client_keyfp) + || + strcmp(client->netconnection->crypto.server_keyfp, crypto->server_keyfp) + ) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Attempt to change key of crypto.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Attempt to change key of crypto.", peeraddress); + return true; + } + } + } + else + { + // reject if downgrading! + if(client->netconnection->crypto.authenticated) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Attempt to downgrade crypto.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Attempt to downgrade crypto.", peeraddress); + return true; + } + } + if (client->begun) + { + // client crashed and is coming back, + // keep their stuff intact + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + if(crypto && crypto->authenticated) + Crypto_ServerFinishInstance(&client->netconnection->crypto, crypto); + SV_SendServerinfo(client); + } + else + { + // client is still trying to connect, + // so we send a duplicate reply + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending duplicate accept to %s.\n", addressstring2); + if(crypto && crypto->authenticated) + Crypto_ServerFinishInstance(&client->netconnection->crypto, crypto); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + } + return true; + } + } + + if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true)) + return true; + + // find an empty client slot for this new client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + netconn_t *conn; + if (!client->active && (conn = NetConn_Open(mysocket, peeraddress))) + { + // allocated connection + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address); + NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress); + // now set up the client + if(crypto && crypto->authenticated) + Crypto_ServerFinishInstance(&conn->crypto, crypto); + SV_ConnectClient(clientnum, conn); + NetConn_Heartbeat(1); + return true; + } + } + + // no empty slots found - server is full + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending \"reject Server is full.\" to %s.\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377reject Server is full.", peeraddress); + + return true; + } + if (length >= 7 && !memcmp(string, "getinfo", 7) && (islocal || sv_public.integer > -1)) + { + const char *challenge = NULL; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + return true; + + // If there was a challenge in the getinfo message + if (length > 8 && string[7] == ' ') + challenge = string + 8; + + if (NetConn_BuildStatusResponse(challenge, response, sizeof(response), false)) + { + if (developer_extra.integer) + Con_DPrintf("Sending reply to master %s - %s\n", addressstring2, response); + NetConn_WriteString(mysocket, response, peeraddress); + } + return true; + } + if (length >= 9 && !memcmp(string, "getstatus", 9) && (islocal || sv_public.integer > -1)) + { + const char *challenge = NULL; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + return true; + + // If there was a challenge in the getinfo message + if (length > 10 && string[9] == ' ') + challenge = string + 10; + + if (NetConn_BuildStatusResponse(challenge, response, sizeof(response), true)) + { + if (developer_extra.integer) + Con_DPrintf("Sending reply to client %s - %s\n", addressstring2, response); + NetConn_WriteString(mysocket, response, peeraddress); + } + return true; + } + if (length >= 37 && !memcmp(string, "srcon HMAC-MD4 TIME ", 20)) + { + char *password = string + 20; + char *timeval = string + 37; + char *s = strchr(timeval, ' '); + char *endpos = string + length + 1; // one behind the NUL, so adding strlen+1 will eventually reach it + const char *userlevel; + + if(rcon_secure.integer > 1) + return true; + + if(!s) + return true; // invalid packet + ++s; + + userlevel = RCon_Authenticate(peeraddress, password, s, endpos, hmac_mdfour_time_matching, timeval, endpos - timeval - 1); // not including the appended \0 into the HMAC + RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false); + return true; + } + if (length >= 42 && !memcmp(string, "srcon HMAC-MD4 CHALLENGE ", 25)) + { + char *password = string + 25; + char *challenge = string + 42; + char *s = strchr(challenge, ' '); + char *endpos = string + length + 1; // one behind the NUL, so adding strlen+1 will eventually reach it + const char *userlevel; + if(!s) + return true; // invalid packet + ++s; + + userlevel = RCon_Authenticate(peeraddress, password, s, endpos, hmac_mdfour_challenge_matching, challenge, endpos - challenge - 1); // not including the appended \0 into the HMAC + RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false); + return true; + } + if (length >= 5 && !memcmp(string, "rcon ", 5)) + { + int i; + char *s = string + 5; + char *endpos = string + length + 1; // one behind the NUL, so adding strlen+1 will eventually reach it + char password[64]; + + if(rcon_secure.integer > 0) + return true; + + for (i = 0;!ISWHITESPACE(*s);s++) + if (i < (int)sizeof(password) - 1) + password[i++] = *s; + if(ISWHITESPACE(*s) && s != endpos) // skip leading ugly space + ++s; + password[i] = 0; + if (!ISWHITESPACE(password[0])) + { + const char *userlevel = RCon_Authenticate(peeraddress, password, s, endpos, plaintext_matching, NULL, 0); + RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false); + } + return true; + } + if (!strncmp(string, "extResponse ", 12)) + { + ++sv_net_extresponse_count; + if(sv_net_extresponse_count > NET_EXTRESPONSE_MAX) + sv_net_extresponse_count = NET_EXTRESPONSE_MAX; + sv_net_extresponse_last = (sv_net_extresponse_last + 1) % NET_EXTRESPONSE_MAX; + portable_snprintf(sv_net_extresponse[sv_net_extresponse_last], sizeof(sv_net_extresponse[sv_net_extresponse_last]), "'%s' %s", addressstring2, string + 12); + return true; + } + if (!strncmp(string, "ping", 4)) + { + if (developer_extra.integer) + Con_DPrintf("Received ping from %s, sending ack\n", addressstring2); + NetConn_WriteString(mysocket, "\377\377\377\377ack", peeraddress); + return true; + } + if (!strncmp(string, "ack", 3)) + return true; + // we may not have liked the packet, but it was a command packet, so + // we're done processing this packet now + return true; + } + // netquake control packets, supported for compatibility only, and only + // when running game protocols that are normally served via this connection + // protocol + // (this protects more modern protocols against being used for + // Quake packet flood Denial Of Service attacks) + if (length >= 5 && (i = BuffBigLong(data)) && (i & (~NETFLAG_LENGTH_MASK)) == (int)NETFLAG_CTL && (i & NETFLAG_LENGTH_MASK) == length && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) && !ENCRYPTION_REQUIRED) + { + int c; + int protocolnumber; + const char *protocolname; + data += 4; + length -= 4; + SZ_Clear(&sv_message); + SZ_Write(&sv_message, data, length); + MSG_BeginReading(&sv_message); + c = MSG_ReadByte(&sv_message); + switch (c) + { + case CCREQ_CONNECT: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_CONNECT from %s.\n", addressstring2); + if(!(islocal || sv_public.integer > -2)) + { + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"%s\" to %s.\n", sv_public_rejectreason.string, addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_REJECT); + MSG_WriteString(&sv_message, va(vabuf, sizeof(vabuf), "%s\n", sv_public_rejectreason.string)); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + break; + } + + protocolname = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)); + protocolnumber = MSG_ReadByte(&sv_message); + if (strcmp(protocolname, "QUAKE") || protocolnumber != NET_PROTOCOL_VERSION) + { + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Incompatible version.\" to %s.\n", addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_REJECT); + MSG_WriteString(&sv_message, "Incompatible version.\n"); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + break; + } + + // see if this connect request comes from a known client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + if (client->netconnection && LHNETADDRESS_Compare(peeraddress, &client->netconnection->peeraddress) == 0) + { + // this is either a duplicate connection request + // or coming back from a timeout + // (if so, keep their stuff intact) + + crypto_t *crypto = Crypto_ServerGetInstance(peeraddress); + if((crypto && crypto->authenticated) || client->netconnection->crypto.authenticated) + { + if (developer_extra.integer) + Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Attempt to downgrade crypto.\" to %s.\n", addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_REJECT); + MSG_WriteString(&sv_message, "Attempt to downgrade crypto.\n"); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + return true; + } + + // send a reply + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_ACCEPT); + MSG_WriteLong(&sv_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(client->netconnection->mysocket))); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + + // if client is already spawned, re-send the + // serverinfo message as they'll need it to play + if (client->begun) + SV_SendServerinfo(client); + return true; + } + } + + // this is a new client, check for connection flood + if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true)) + break; + + // find a slot for the new client + for (clientnum = 0, client = svs.clients;clientnum < svs.maxclients;clientnum++, client++) + { + netconn_t *conn; + if (!client->active && (client->netconnection = conn = NetConn_Open(mysocket, peeraddress)) != NULL) + { + // connect to the client + // everything is allocated, just fill in the details + strlcpy (conn->address, addressstring2, sizeof (conn->address)); + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_ACCEPT to %s.\n", addressstring2); + // send back the info about the server connection + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_ACCEPT); + MSG_WriteLong(&sv_message, LHNETADDRESS_GetPort(LHNET_AddressFromSocket(conn->mysocket))); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + // now set up the client struct + SV_ConnectClient(clientnum, conn); + NetConn_Heartbeat(1); + return true; + } + } + + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Server is full.\" to %s.\n", addressstring2); + // no room; try to let player know + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_REJECT); + MSG_WriteString(&sv_message, "Server is full.\n"); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + break; + case CCREQ_SERVER_INFO: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2); + if(!(islocal || sv_public.integer > -1)) + break; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + break; + + if (sv.active && !strcmp(MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), "QUAKE")) + { + int numclients; + char myaddressstring[128]; + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_SERVER_INFO to %s.\n", addressstring2); + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_SERVER_INFO); + LHNETADDRESS_ToString(LHNET_AddressFromSocket(mysocket), myaddressstring, sizeof(myaddressstring), true); + MSG_WriteString(&sv_message, myaddressstring); + MSG_WriteString(&sv_message, hostname.string); + MSG_WriteString(&sv_message, sv.name); + // How many clients are there? + for (i = 0, numclients = 0;i < svs.maxclients;i++) + if (svs.clients[i].active) + numclients++; + MSG_WriteByte(&sv_message, numclients); + MSG_WriteByte(&sv_message, svs.maxclients); + MSG_WriteByte(&sv_message, NET_PROTOCOL_VERSION); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + } + break; + case CCREQ_PLAYER_INFO: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2); + if(!(islocal || sv_public.integer > -1)) + break; + + if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false)) + break; + + if (sv.active) + { + int playerNumber, activeNumber, clientNumber; + client_t *client; + + playerNumber = MSG_ReadByte(&sv_message); + activeNumber = -1; + for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) + if (client->active && ++activeNumber == playerNumber) + break; + if (clientNumber != svs.maxclients) + { + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_PLAYER_INFO); + MSG_WriteByte(&sv_message, playerNumber); + MSG_WriteString(&sv_message, client->name); + MSG_WriteLong(&sv_message, client->colors); + MSG_WriteLong(&sv_message, client->frags); + MSG_WriteLong(&sv_message, (int)(realtime - client->connecttime)); + if(sv_status_privacy.integer) + MSG_WriteString(&sv_message, client->netconnection ? "hidden" : "botclient"); + else + MSG_WriteString(&sv_message, client->netconnection ? client->netconnection->address : "botclient"); + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + } + } + break; + case CCREQ_RULE_INFO: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2); + if(!(islocal || sv_public.integer > -1)) + break; + + // no flood check here, as it only returns one cvar for one cvar and clients may iterate quickly + + if (sv.active) + { + char *prevCvarName; + cvar_t *var; + + // find the search start location + prevCvarName = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)); + var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY); + + // send the response + SZ_Clear(&sv_message); + // save space for the header, filled in later + MSG_WriteLong(&sv_message, 0); + MSG_WriteByte(&sv_message, CCREP_RULE_INFO); + if (var) + { + MSG_WriteString(&sv_message, var->name); + MSG_WriteString(&sv_message, var->string); + } + StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress); + SZ_Clear(&sv_message); + } + break; + case CCREQ_RCON: + if (developer_extra.integer) + Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RCON from %s.\n", addressstring2); + if (sv.active && !rcon_secure.integer) + { + char password[2048]; + char cmd[2048]; + char *s; + char *endpos; + const char *userlevel; + strlcpy(password, MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), sizeof(password)); + strlcpy(cmd, MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), sizeof(cmd)); + s = cmd; + endpos = cmd + strlen(cmd) + 1; // one behind the NUL, so adding strlen+1 will eventually reach it + userlevel = RCon_Authenticate(peeraddress, password, s, endpos, plaintext_matching, NULL, 0); + RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, true); + return true; + } + break; + default: + break; + } + SZ_Clear(&sv_message); + // we may not have liked the packet, but it was a valid control + // packet, so we're done processing this packet now + return true; + } + if (host_client) + { + if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->begun ? net_messagetimeout.value : net_connecttimeout.value)) == 2) + { + SV_ReadClientMessage(); + return ret; + } + } + return 0; +} + +void NetConn_ServerFrame(void) +{ + int i, length; + lhnetaddress_t peeraddress; + unsigned char readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE]; + for (i = 0;i < sv_numsockets;i++) + while (sv_sockets[i] && (length = NetConn_Read(sv_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0) + NetConn_ServerParsePacket(sv_sockets[i], readbuffer, length, &peeraddress); + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + // never timeout loopback connections + if (host_client->netconnection && realtime > host_client->netconnection->timeout && LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP) + { + Con_Printf("Client \"%s\" connection timed out\n", host_client->name); + SV_DropClient(false); + } + } +} + +void NetConn_SleepMicroseconds(int microseconds) +{ + LHNET_SleepUntilPacket_Microseconds(microseconds); +} + +void NetConn_QueryMasters(qboolean querydp, qboolean queryqw) +{ + int i, j; + int masternum; + lhnetaddress_t masteraddress; + lhnetaddress_t broadcastaddress; + char request[256]; + + if (serverlist_cachecount >= SERVERLIST_TOTALSIZE) + return; + + // 26000 is the default quake server port, servers on other ports will not + // be found + // note this is IPv4-only, I doubt there are IPv6-only LANs out there + LHNETADDRESS_FromString(&broadcastaddress, "255.255.255.255", 26000); + + if (querydp) + { + for (i = 0;i < cl_numsockets;i++) + { + if (cl_sockets[i]) + { + const char *cmdname, *extraoptions; + int af = LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])); + + if(LHNETADDRESS_GetAddressType(&broadcastaddress) == af) + { + // search LAN for Quake servers + SZ_Clear(&cl_message); + // save space for the header, filled in later + MSG_WriteLong(&cl_message, 0); + MSG_WriteByte(&cl_message, CCREQ_SERVER_INFO); + MSG_WriteString(&cl_message, "QUAKE"); + MSG_WriteByte(&cl_message, NET_PROTOCOL_VERSION); + StoreBigLong(cl_message.data, NETFLAG_CTL | (cl_message.cursize & NETFLAG_LENGTH_MASK)); + NetConn_Write(cl_sockets[i], cl_message.data, cl_message.cursize, &broadcastaddress); + SZ_Clear(&cl_message); + + // search LAN for DarkPlaces servers + NetConn_WriteString(cl_sockets[i], "\377\377\377\377getstatus", &broadcastaddress); + } + + // build the getservers message to send to the dpmaster master servers + if (LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])) == LHNETADDRESSTYPE_INET6) + { + cmdname = "getserversExt"; + extraoptions = " ipv4 ipv6"; // ask for IPv4 and IPv6 servers + } + else + { + cmdname = "getservers"; + extraoptions = ""; + } + portable_snprintf(request, sizeof(request), "\377\377\377\377%s %s %u empty full%s", cmdname, gamename, NET_PROTOCOL_VERSION, extraoptions); + + // search internet + for (masternum = 0;sv_masters[masternum].name;masternum++) + { + if (sv_masters[masternum].string && sv_masters[masternum].string[0] && LHNETADDRESS_FromString(&masteraddress, sv_masters[masternum].string, DPMASTER_PORT) && LHNETADDRESS_GetAddressType(&masteraddress) == af) + { + masterquerycount++; + NetConn_WriteString(cl_sockets[i], request, &masteraddress); + } + } + + // search favorite servers + for(j = 0; j < nFavorites; ++j) + { + if(LHNETADDRESS_GetAddressType(&favorites[j]) == af) + { + if(LHNETADDRESS_ToString(&favorites[j], request, sizeof(request), true)) + NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_DARKPLACES7, request, true ); + } + } + } + } + } + + // only query QuakeWorld servers when the user wants to + if (queryqw) + { + for (i = 0;i < cl_numsockets;i++) + { + if (cl_sockets[i]) + { + int af = LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])); + + if(LHNETADDRESS_GetAddressType(&broadcastaddress) == af) + { + // search LAN for QuakeWorld servers + NetConn_WriteString(cl_sockets[i], "\377\377\377\377status\n", &broadcastaddress); + + // build the getservers message to send to the qwmaster master servers + // note this has no -1 prefix, and the trailing nul byte is sent + portable_snprintf(request, sizeof(request), "c\n"); + } + + // search internet + for (masternum = 0;sv_qwmasters[masternum].name;masternum++) + { + if (sv_qwmasters[masternum].string && LHNETADDRESS_FromString(&masteraddress, sv_qwmasters[masternum].string, QWMASTER_PORT) && LHNETADDRESS_GetAddressType(&masteraddress) == LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i]))) + { + if (m_state != m_slist) + { + char lookupstring[128]; + LHNETADDRESS_ToString(&masteraddress, lookupstring, sizeof(lookupstring), true); + Con_Printf("Querying master %s (resolved from %s)\n", lookupstring, sv_qwmasters[masternum].string); + } + masterquerycount++; + NetConn_Write(cl_sockets[i], request, (int)strlen(request) + 1, &masteraddress); + } + } + + // search favorite servers + for(j = 0; j < nFavorites; ++j) + { + if(LHNETADDRESS_GetAddressType(&favorites[j]) == af) + { + if(LHNETADDRESS_ToString(&favorites[j], request, sizeof(request), true)) + { + NetConn_WriteString(cl_sockets[i], "\377\377\377\377status\n", &favorites[j]); + NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_QUAKEWORLD, request, true ); + } + } + } + } + } + } + if (!masterquerycount) + { + Con_Print("Unable to query master servers, no suitable network sockets active.\n"); + M_Update_Return_Reason("No network"); + } +} + +void NetConn_Heartbeat(int priority) +{ + lhnetaddress_t masteraddress; + int masternum; + lhnetsocket_t *mysocket; + + // if it's a state change (client connected), limit next heartbeat to no + // more than 30 sec in the future + if (priority == 1 && nextheartbeattime > realtime + 30.0) + nextheartbeattime = realtime + 30.0; + + // limit heartbeatperiod to 30 to 270 second range, + // lower limit is to avoid abusing master servers with excess traffic, + // upper limit is to avoid timing out on the master server (which uses + // 300 sec timeout) + if (sv_heartbeatperiod.value < 30) + Cvar_SetValueQuick(&sv_heartbeatperiod, 30); + if (sv_heartbeatperiod.value > 270) + Cvar_SetValueQuick(&sv_heartbeatperiod, 270); + + // make advertising optional and don't advertise singleplayer games, and + // only send a heartbeat as often as the admin wants + if (sv.active && sv_public.integer > 0 && svs.maxclients >= 2 && (priority > 1 || realtime > nextheartbeattime)) + { + nextheartbeattime = realtime + sv_heartbeatperiod.value; + for (masternum = 0;sv_masters[masternum].name;masternum++) + if (sv_masters[masternum].string && sv_masters[masternum].string[0] && LHNETADDRESS_FromString(&masteraddress, sv_masters[masternum].string, DPMASTER_PORT) && (mysocket = NetConn_ChooseServerSocketForAddress(&masteraddress))) + NetConn_WriteString(mysocket, "\377\377\377\377heartbeat DarkPlaces\x0A", &masteraddress); + } +} + +static void Net_Heartbeat_f(void) +{ + if (sv.active) + NetConn_Heartbeat(2); + else + Con_Print("No server running, can not heartbeat to master server.\n"); +} + +static void PrintStats(netconn_t *conn) +{ + if ((cls.state == ca_connected && cls.protocol == PROTOCOL_QUAKEWORLD) || (sv.active && sv.protocol == PROTOCOL_QUAKEWORLD)) + Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->outgoing_unreliable_sequence, conn->qw.incoming_sequence); + else + Con_Printf("address=%21s canSend=%u sendSeq=%6u recvSeq=%6u\n", conn->address, !conn->sendMessageLength, conn->nq.sendSequence, conn->nq.receiveSequence); + Con_Printf("unreliable messages sent = %i\n", conn->unreliableMessagesSent); + Con_Printf("unreliable messages recv = %i\n", conn->unreliableMessagesReceived); + Con_Printf("reliable messages sent = %i\n", conn->reliableMessagesSent); + Con_Printf("reliable messages received = %i\n", conn->reliableMessagesReceived); + Con_Printf("packetsSent = %i\n", conn->packetsSent); + Con_Printf("packetsReSent = %i\n", conn->packetsReSent); + Con_Printf("packetsReceived = %i\n", conn->packetsReceived); + Con_Printf("receivedDuplicateCount = %i\n", conn->receivedDuplicateCount); + Con_Printf("droppedDatagrams = %i\n", conn->droppedDatagrams); +} + +void Net_Stats_f(void) +{ + netconn_t *conn; + Con_Print("connections =\n"); + for (conn = netconn_list;conn;conn = conn->next) + PrintStats(conn); +} + +void Net_Refresh_f(void) +{ + if (m_state != m_slist) { + Con_Print("Sending new requests to master servers\n"); + ServerList_QueryList(false, true, false, true); + Con_Print("Listening for replies...\n"); + } else + ServerList_QueryList(false, true, false, false); +} + +void Net_Slist_f(void) +{ + ServerList_ResetMasks(); + serverlist_sortbyfield = SLIF_PING; + serverlist_sortflags = 0; + if (m_state != m_slist) { + Con_Print("Sending requests to master servers\n"); + ServerList_QueryList(true, true, false, true); + Con_Print("Listening for replies...\n"); + } else + ServerList_QueryList(true, true, false, false); +} + +void Net_SlistQW_f(void) +{ + ServerList_ResetMasks(); + serverlist_sortbyfield = SLIF_PING; + serverlist_sortflags = 0; + if (m_state != m_slist) { + Con_Print("Sending requests to master servers\n"); + ServerList_QueryList(true, false, true, true); + serverlist_consoleoutput = true; + Con_Print("Listening for replies...\n"); + } else + ServerList_QueryList(true, false, true, false); +} + +void NetConn_Init(void) +{ + int i; + lhnetaddress_t tempaddress; + netconn_mempool = Mem_AllocPool("network connections", 0, NULL); + Cmd_AddCommand("net_stats", Net_Stats_f, "print network statistics"); + Cmd_AddCommand("net_slist", Net_Slist_f, "query dp master servers and print all server information"); + Cmd_AddCommand("net_slistqw", Net_SlistQW_f, "query qw master servers and print all server information"); + Cmd_AddCommand("net_refresh", Net_Refresh_f, "query dp master servers and refresh all server information"); + Cmd_AddCommand("heartbeat", Net_Heartbeat_f, "send a heartbeat to the master server (updates your server information)"); + Cvar_RegisterVariable(&rcon_restricted_password); + Cvar_RegisterVariable(&rcon_restricted_commands); + Cvar_RegisterVariable(&rcon_secure_maxdiff); + Cvar_RegisterVariable(&net_slist_queriespersecond); + Cvar_RegisterVariable(&net_slist_queriesperframe); + Cvar_RegisterVariable(&net_slist_timeout); + Cvar_RegisterVariable(&net_slist_maxtries); + Cvar_RegisterVariable(&net_slist_favorites); + Cvar_RegisterVariable(&net_slist_pause); + if(LHNET_DefaultDSCP(-1) >= 0) // register cvar only if supported + Cvar_RegisterVariable(&net_tos_dscp); + Cvar_RegisterVariable(&net_messagetimeout); + Cvar_RegisterVariable(&net_connecttimeout); + Cvar_RegisterVariable(&net_connectfloodblockingtimeout); + Cvar_RegisterVariable(&net_challengefloodblockingtimeout); + Cvar_RegisterVariable(&net_getstatusfloodblockingtimeout); + Cvar_RegisterVariable(&cl_netlocalping); + Cvar_RegisterVariable(&cl_netpacketloss_send); + Cvar_RegisterVariable(&cl_netpacketloss_receive); + Cvar_RegisterVariable(&hostname); + Cvar_RegisterVariable(&developer_networking); + Cvar_RegisterVariable(&cl_netport); + Cvar_RegisterVariable(&sv_netport); + Cvar_RegisterVariable(&net_address); + Cvar_RegisterVariable(&net_address_ipv6); + Cvar_RegisterVariable(&sv_public); + Cvar_RegisterVariable(&sv_public_rejectreason); + Cvar_RegisterVariable(&sv_heartbeatperiod); + for (i = 0;sv_masters[i].name;i++) + Cvar_RegisterVariable(&sv_masters[i]); + Cvar_RegisterVariable(&gameversion); + Cvar_RegisterVariable(&gameversion_min); + Cvar_RegisterVariable(&gameversion_max); +// COMMANDLINEOPTION: Server: -ip sets the ip address of this machine for purposes of networking (default 0.0.0.0 also known as INADDR_ANY), use only if you have multiple network adapters and need to choose one specifically. + if ((i = COM_CheckParm("-ip")) && i + 1 < com_argc) + { + if (LHNETADDRESS_FromString(&tempaddress, com_argv[i + 1], 0) == 1) + { + Con_Printf("-ip option used, setting net_address to \"%s\"\n", com_argv[i + 1]); + Cvar_SetQuick(&net_address, com_argv[i + 1]); + } + else + Con_Printf("-ip option used, but unable to parse the address \"%s\"\n", com_argv[i + 1]); + } +// COMMANDLINEOPTION: Server: -port sets the port to use for a server (default 26000, the same port as QUAKE itself), useful if you host multiple servers on your machine + if (((i = COM_CheckParm("-port")) || (i = COM_CheckParm("-ipport")) || (i = COM_CheckParm("-udpport"))) && i + 1 < com_argc) + { + i = atoi(com_argv[i + 1]); + if (i >= 0 && i < 65536) + { + Con_Printf("-port option used, setting port cvar to %i\n", i); + Cvar_SetValueQuick(&sv_netport, i); + } + else + Con_Printf("-port option used, but %i is not a valid port number\n", i); + } + cl_numsockets = 0; + sv_numsockets = 0; + cl_message.data = cl_message_buf; + cl_message.maxsize = sizeof(cl_message_buf); + cl_message.cursize = 0; + sv_message.data = sv_message_buf; + sv_message.maxsize = sizeof(sv_message_buf); + sv_message.cursize = 0; + LHNET_Init(); + if (Thread_HasThreads()) + netconn_mutex = Thread_CreateMutex(); +} + +void NetConn_Shutdown(void) +{ + NetConn_CloseClientPorts(); + NetConn_CloseServerPorts(); + LHNET_Shutdown(); + if (netconn_mutex) + Thread_DestroyMutex(netconn_mutex); + netconn_mutex = NULL; +} + diff --git a/app/jni/netconn.h b/app/jni/netconn.h new file mode 100644 index 0000000..69b0de5 --- /dev/null +++ b/app/jni/netconn.h @@ -0,0 +1,469 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. +Copyright (C) 2003 Forest Hale + +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 NET_H +#define NET_H + +#include "lhnet.h" + +#define NET_HEADERSIZE (2 * sizeof(unsigned int)) + +// 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 NETFLAG_CRYPTO 0x40000000 + + +#define NET_PROTOCOL_VERSION 3 +#define NET_EXTRESPONSE_MAX 16 + +/// \page netconn 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:\code +/// 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 +/// +/// CCREQ_RCON +/// string password +/// string command +/// +/// +/// +/// 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 +/// +/// CCREP_RCON +/// string reply +/// \endcode +/// \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 CCREQ_RCON 0x05 // RocketGuy: ProQuake rcon support + +#define CCREP_ACCEPT 0x81 +#define CCREP_REJECT 0x82 +#define CCREP_SERVER_INFO 0x83 +#define CCREP_PLAYER_INFO 0x84 +#define CCREP_RULE_INFO 0x85 +#define CCREP_RCON 0x86 // RocketGuy: ProQuake rcon support + +typedef struct netgraphitem_s +{ + double time; + int reliablebytes; + int unreliablebytes; + int ackbytes; +} +netgraphitem_t; + +typedef struct netconn_s +{ + struct netconn_s *next; + + lhnetsocket_t *mysocket; + lhnetaddress_t peeraddress; + + // this is mostly identical to qsocket_t from quake + + /// if this time is reached, kick off peer + double connecttime; + double timeout; + double lastMessageTime; + double lastSendTime; + + /// writing buffer to send to peer as the next reliable message + /// can be added to at any time, copied into sendMessage buffer when it is + /// possible to send a reliable message and then cleared + /// @{ + sizebuf_t message; + unsigned char messagedata[NET_MAXMESSAGE]; + /// @} + + /// reliable message that is currently sending + /// (for building fragments) + int sendMessageLength; + unsigned char sendMessage[NET_MAXMESSAGE]; + + /// reliable message that is currently being received + /// (for putting together fragments) + int receiveMessageLength; + unsigned char receiveMessage[NET_MAXMESSAGE]; + + /// used by both NQ and QW protocols + unsigned int outgoing_unreliable_sequence; + + struct netconn_nq_s + { + unsigned int ackSequence; + unsigned int sendSequence; + + unsigned int receiveSequence; + unsigned int unreliableReceiveSequence; + } + nq; + struct netconn_qw_s + { + // QW protocol + qboolean fatal_error; + + float last_received; // for timeouts + + // the statistics are cleared at each client begin, because + // the server connecting process gives a bogus picture of the data + float frame_latency; // rolling average + float frame_rate; + + int drop_count; ///< dropped packets, cleared each level + int good_count; ///< cleared each level + + int qport; + + // sequencing variables + int incoming_sequence; + int incoming_acknowledged; + int incoming_reliable_acknowledged; ///< single bit + + int incoming_reliable_sequence; ///< single bit, maintained local + + int reliable_sequence; ///< single bit + int last_reliable_sequence; ///< sequence number of last send + } + qw; + + // bandwidth estimator + double cleartime; // if realtime > nc->cleartime, free to go + + // this tracks packet loss and packet sizes on the most recent packets + // used by shownetgraph feature +#define NETGRAPH_PACKETS 256 +#define NETGRAPH_NOPACKET 0 +#define NETGRAPH_LOSTPACKET -1 +#define NETGRAPH_CHOKEDPACKET -2 + int incoming_packetcounter; + netgraphitem_t incoming_netgraph[NETGRAPH_PACKETS]; + int outgoing_packetcounter; + netgraphitem_t outgoing_netgraph[NETGRAPH_PACKETS]; + + char address[128]; + crypto_t crypto; + + // statistic counters + int packetsSent; + int packetsReSent; + int packetsReceived; + int receivedDuplicateCount; + int droppedDatagrams; + int unreliableMessagesSent; + int unreliableMessagesReceived; + int reliableMessagesSent; + int reliableMessagesReceived; +} netconn_t; + +extern netconn_t *netconn_list; +extern mempool_t *netconn_mempool; + +extern cvar_t hostname; +extern cvar_t developer_networking; + +#define SERVERLIST_VIEWLISTSIZE SERVERLIST_TOTALSIZE + +typedef enum serverlist_maskop_e +{ + // SLMO_CONTAINS is the default for strings + // SLMO_GREATEREQUAL is the default for numbers (also used when OP == CONTAINS or NOTCONTAINS + SLMO_CONTAINS, + SLMO_NOTCONTAIN, + + SLMO_LESSEQUAL, + SLMO_LESS, + SLMO_EQUAL, + SLMO_GREATER, + SLMO_GREATEREQUAL, + SLMO_NOTEQUAL, + SLMO_STARTSWITH, + SLMO_NOTSTARTSWITH +} serverlist_maskop_t; + +/// struct with all fields that you can search for or sort by +typedef struct serverlist_info_s +{ + /// address for connecting + char cname[128]; + /// ping time for sorting servers + int ping; + /// name of the game + char game[32]; + /// name of the mod + char mod[32]; + /// name of the map + char map[32]; + /// name of the session + char name[128]; + /// qc-defined short status string + char qcstatus[128]; + /// frags/ping/name list (if they fit in the packet) + char players[1400]; + /// max client number + int maxplayers; + /// number of currently connected players (including bots) + int numplayers; + /// number of currently connected players that are bots + int numbots; + /// number of currently connected players that are not bots + int numhumans; + /// number of free slots + int freeslots; + /// protocol version + int protocol; + /// game data version + /// (an integer that is used for filtering incompatible servers, + /// not filterable by QC) + int gameversion; + /// favorite server flag + qboolean isfavorite; +} serverlist_info_t; + +typedef enum +{ + SLIF_CNAME, + SLIF_PING, + SLIF_GAME, + SLIF_MOD, + SLIF_MAP, + SLIF_NAME, + SLIF_MAXPLAYERS, + SLIF_NUMPLAYERS, + SLIF_PROTOCOL, + SLIF_NUMBOTS, + SLIF_NUMHUMANS, + SLIF_FREESLOTS, + SLIF_QCSTATUS, + SLIF_PLAYERS, + SLIF_ISFAVORITE, + SLIF_COUNT +} serverlist_infofield_t; + +typedef enum +{ + SLSF_DESCENDING = 1, + SLSF_FAVORITESFIRST = 2 +} serverlist_sortflags_t; + +typedef enum +{ + SQS_NONE = 0, + SQS_QUERYING, + SQS_QUERIED, + SQS_TIMEDOUT, + SQS_REFRESHING +} serverlist_query_state; + +typedef struct serverlist_entry_s +{ + /// used to determine whether this entry should be included into the final view + serverlist_query_state query; + /// used to count the number of times the host has tried to query this server already + unsigned querycounter; + /// used to calculate ping when update comes in + double querytime; + /// query protocol to use on this server, may be PROTOCOL_QUAKEWORLD or PROTOCOL_DARKPLACES7 + int protocol; + + serverlist_info_t info; + + // legacy stuff + char line1[128]; + char line2[128]; +} serverlist_entry_t; + +typedef struct serverlist_mask_s +{ + qboolean active; + serverlist_maskop_t tests[SLIF_COUNT]; + serverlist_info_t info; +} serverlist_mask_t; + +#define ServerList_GetCacheEntry(x) (&serverlist_cache[(x)]) +#define ServerList_GetViewEntry(x) (ServerList_GetCacheEntry(serverlist_viewlist[(x)])) + +extern serverlist_mask_t serverlist_andmasks[SERVERLIST_ANDMASKCOUNT]; +extern serverlist_mask_t serverlist_ormasks[SERVERLIST_ORMASKCOUNT]; + +extern serverlist_infofield_t serverlist_sortbyfield; +extern int serverlist_sortflags; // not using the enum, as it is a bitmask + +#if SERVERLIST_TOTALSIZE > 65536 +#error too many servers, change type of index array +#endif +extern int serverlist_viewcount; +extern unsigned short serverlist_viewlist[SERVERLIST_VIEWLISTSIZE]; + +extern int serverlist_cachecount; +extern serverlist_entry_t *serverlist_cache; + +extern qboolean serverlist_consoleoutput; + +void ServerList_GetPlayerStatistics(int *numplayerspointer, int *maxplayerspointer); + +//============================================================================ +// +// public network functions +// +//============================================================================ + +extern char cl_net_extresponse[NET_EXTRESPONSE_MAX][1400]; +extern int cl_net_extresponse_count; +extern int cl_net_extresponse_last; + +extern char sv_net_extresponse[NET_EXTRESPONSE_MAX][1400]; +extern int sv_net_extresponse_count; +extern int sv_net_extresponse_last; + +extern double masterquerytime; +extern int masterquerycount; +extern int masterreplycount; +extern int serverquerycount; +extern int serverreplycount; + +extern sizebuf_t cl_message; +extern sizebuf_t sv_message; +extern char cl_readstring[MAX_INPUTLINE]; +extern char sv_readstring[MAX_INPUTLINE]; + +extern cvar_t sv_public; + +extern cvar_t cl_netlocalping; + +extern cvar_t cl_netport; +extern cvar_t sv_netport; +extern cvar_t net_address; +extern cvar_t net_address_ipv6; + +qboolean NetConn_CanSend(netconn_t *conn); +int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, qboolean quakesignon_suppressreliables); +qboolean NetConn_HaveClientPorts(void); +qboolean NetConn_HaveServerPorts(void); +void NetConn_CloseClientPorts(void); +void NetConn_OpenClientPorts(void); +void NetConn_CloseServerPorts(void); +void NetConn_OpenServerPorts(int opennetports); +void NetConn_UpdateSockets(void); +lhnetsocket_t *NetConn_ChooseClientSocketForAddress(lhnetaddress_t *address); +lhnetsocket_t *NetConn_ChooseServerSocketForAddress(lhnetaddress_t *address); +void NetConn_Init(void); +void NetConn_Shutdown(void); +netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress); +void NetConn_Close(netconn_t *conn); +void NetConn_Listen(qboolean state); +int NetConn_Read(lhnetsocket_t *mysocket, void *data, int maxlength, lhnetaddress_t *peeraddress); +int NetConn_Write(lhnetsocket_t *mysocket, const void *data, int length, const lhnetaddress_t *peeraddress); +int NetConn_WriteString(lhnetsocket_t *mysocket, const char *string, const lhnetaddress_t *peeraddress); +int NetConn_IsLocalGame(void); +void NetConn_ClientFrame(void); +void NetConn_ServerFrame(void); +void NetConn_SleepMicroseconds(int microseconds); +void NetConn_QueryMasters(qboolean querydp, qboolean queryqw); +void NetConn_Heartbeat(int priority); +void NetConn_QueryQueueFrame(void); +void Net_Stats_f(void); +void Net_Slist_f(void); +void Net_SlistQW_f(void); +void Net_Refresh_f(void); + +/// ServerList interface (public) +/// manually refresh the view set, do this after having changed the mask or any other flag +void ServerList_RebuildViewList(void); +void ServerList_ResetMasks(void); +void ServerList_QueryList(qboolean resetcache, qboolean querydp, qboolean queryqw, qboolean consoleoutput); + +/// called whenever net_slist_favorites changes +void NetConn_UpdateFavorites(void); + +#define MAX_CHALLENGES 128 +typedef struct challenge_s +{ + lhnetaddress_t address; + double time; + char string[12]; +} +challenge_t; + +extern challenge_t challenge[MAX_CHALLENGES]; + +#endif + diff --git a/app/jni/palette.c b/app/jni/palette.c new file mode 100644 index 0000000..9fb36de --- /dev/null +++ b/app/jni/palette.c @@ -0,0 +1,336 @@ + +#include "quakedef.h" + +cvar_t r_colormap_palette = {0, "r_colormap_palette", "gfx/colormap_palette.lmp", "name of a palette lmp file to override the shirt/pants colors of player models. It consists of 16 shirt colors, 16 scoreboard shirt colors, 16 pants colors and 16 scoreboard pants colors"}; + +unsigned char palette_rgb[256][3]; +unsigned char palette_rgb_pantscolormap[16][3]; +unsigned char palette_rgb_shirtcolormap[16][3]; +unsigned char palette_rgb_pantsscoreboard[16][3]; +unsigned char palette_rgb_shirtscoreboard[16][3]; + +unsigned int palette_bgra_complete[256]; +unsigned int palette_bgra_font[256]; +unsigned int palette_bgra_alpha[256]; +unsigned int palette_bgra_nocolormap[256]; +unsigned int palette_bgra_nocolormapnofullbrights[256]; +unsigned int palette_bgra_nofullbrights[256]; +unsigned int palette_bgra_onlyfullbrights[256]; +unsigned int palette_bgra_pantsaswhite[256]; +unsigned int palette_bgra_shirtaswhite[256]; +unsigned int palette_bgra_transparent[256]; +unsigned int palette_bgra_embeddedpic[256]; +unsigned char palette_featureflags[256]; + +// John Carmack said the quake palette.lmp can be considered public domain because it is not an important asset to id, so I include it here as a fallback if no external palette file is found. +unsigned char host_quakepal[768] = +{ +// marked: colormap colors: cb = (colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12; +// 0x0* + 0,0,0, 15,15,15, 31,31,31, 47,47,47, 63,63,63, 75,75,75, 91,91,91, 107,107,107, + 123,123,123, 139,139,139, 155,155,155, 171,171,171, 187,187,187, 203,203,203, 219,219,219, 235,235,235, +// 0x1* 0 ^ + 15,11,7, 23,15,11, 31,23,11, 39,27,15, 47,35,19, 55,43,23, 63,47,23, 75,55,27, + 83,59,27, 91,67,31, 99,75,31, 107,83,31, 115,87,31, 123,95,35, 131,103,35, 143,111,35, +// 0x2* 1 ^ + 11,11,15, 19,19,27, 27,27,39, 39,39,51, 47,47,63, 55,55,75, 63,63,87, 71,71,103, + 79,79,115, 91,91,127, 99,99,139, 107,107,151, 115,115,163, 123,123,175, 131,131,187, 139,139,203, +// 0x3* 2 ^ + 0,0,0, 7,7,0, 11,11,0, 19,19,0, 27,27,0, 35,35,0, 43,43,7, 47,47,7, + 55,55,7, 63,63,7, 71,71,7, 75,75,11, 83,83,11, 91,91,11, 99,99,11, 107,107,15, +// 0x4* 3 ^ + 7,0,0, 15,0,0, 23,0,0, 31,0,0, 39,0,0, 47,0,0, 55,0,0, 63,0,0, + 71,0,0, 79,0,0, 87,0,0, 95,0,0, 103,0,0, 111,0,0, 119,0,0, 127,0,0, +// 0x5* 4 ^ + 19,19,0, 27,27,0, 35,35,0, 47,43,0, 55,47,0, 67,55,0, 75,59,7, 87,67,7, + 95,71,7, 107,75,11, 119,83,15, 131,87,19, 139,91,19, 151,95,27, 163,99,31, 175,103,35, +// 0x6* 5 ^ + 35,19,7, 47,23,11, 59,31,15, 75,35,19, 87,43,23, 99,47,31, 115,55,35, 127,59,43, + 143,67,51, 159,79,51, 175,99,47, 191,119,47, 207,143,43, 223,171,39, 239,203,31, 255,243,27, +// 0x7* 6 ^ + 11,7,0, 27,19,0, 43,35,15, 55,43,19, 71,51,27, 83,55,35, 99,63,43, 111,71,51, + 127,83,63, 139,95,71, 155,107,83, 167,123,95, 183,135,107, 195,147,123, 211,163,139, 227,179,151, +// 0x8* 7 ^ v 8 + 171,139,163, 159,127,151, 147,115,135, 139,103,123, 127,91,111, 119,83,99, 107,75,87, 95,63,75, + 87,55,67, 75,47,55, 67,39,47, 55,31,35, 43,23,27, 35,19,19, 23,11,11, 15,7,7, +// 0x9* 9 v + 187,115,159, 175,107,143, 163,95,131, 151,87,119, 139,79,107, 127,75,95, 115,67,83, 107,59,75, + 95,51,63, 83,43,55, 71,35,43, 59,31,35, 47,23,27, 35,19,19, 23,11,11, 15,7,7, +// 0xA* 10 v + 219,195,187, 203,179,167, 191,163,155, 175,151,139, 163,135,123, 151,123,111, 135,111,95, 123,99,83, + 107,87,71, 95,75,59, 83,63,51, 67,51,39, 55,43,31, 39,31,23, 27,19,15, 15,11,7, +// 0xB* 11 v + 111,131,123, 103,123,111, 95,115,103, 87,107,95, 79,99,87, 71,91,79, 63,83,71, 55,75,63, + 47,67,55, 43,59,47, 35,51,39, 31,43,31, 23,35,23, 15,27,19, 11,19,11, 7,11,7, +// 0xC* 12 v + 255,243,27, 239,223,23, 219,203,19, 203,183,15, 187,167,15, 171,151,11, 155,131,7, 139,115,7, + 123,99,7, 107,83,0, 91,71,0, 75,55,0, 59,43,0, 43,31,0, 27,15,0, 11,7,0, +// 0xD* 13 v + 0,0,255, 11,11,239, 19,19,223, 27,27,207, 35,35,191, 43,43,175, 47,47,159, 47,47,143, + 47,47,127, 47,47,111, 47,47,95, 43,43,79, 35,35,63, 27,27,47, 19,19,31, 11,11,15, +// 0xE* + 43,0,0, 59,0,0, 75,7,0, 95,7,0, 111,15,0, 127,23,7, 147,31,7, 163,39,11, + 183,51,15, 195,75,27, 207,99,43, 219,127,59, 227,151,79, 231,171,95, 239,191,119, 247,211,139, +// 0xF* 14 ^ + 167,123,59, 183,155,55, 199,195,55, 231,227,87, 127,191,255, 171,231,255, 215,255,255, 103,0,0, + 139,0,0, 179,0,0, 215,0,0, 255,0,0, 255,243,147, 255,247,199, 255,255,255, 159,91,83 +}; // 15 ^ + +static void Palette_SetupSpecialPalettes(void) +{ + int i; + int fullbright_start, fullbright_end; + int pants_start, pants_end; + int shirt_start, shirt_end; + int reversed_start, reversed_end; + int transparentcolor; + unsigned char *colormap; + fs_offset_t filesize; + union + { + int i; + unsigned char b[4]; + } + u; + + colormap = FS_LoadFile("gfx/colormap.lmp", tempmempool, true, &filesize); + if (colormap && filesize >= 16385) + fullbright_start = 256 - colormap[16384]; + else + fullbright_start = 256; + if (colormap) + Mem_Free(colormap); + fullbright_end = 256; + pants_start = 96; + pants_end = 112; + shirt_start = 16; + shirt_end = 32; + reversed_start = 128; + reversed_end = 224; + transparentcolor = 255; + + for (i = 0;i < 256;i++) + palette_featureflags[i] = PALETTEFEATURE_STANDARD; + for (i = reversed_start;i < reversed_end;i++) + palette_featureflags[i] = PALETTEFEATURE_REVERSED; + for (i = pants_start;i < pants_end;i++) + palette_featureflags[i] = PALETTEFEATURE_PANTS; + for (i = shirt_start;i < shirt_end;i++) + palette_featureflags[i] = PALETTEFEATURE_SHIRT; + for (i = fullbright_start;i < fullbright_end;i++) + palette_featureflags[i] = PALETTEFEATURE_GLOW; + palette_featureflags[0] = PALETTEFEATURE_ZERO; + palette_featureflags[transparentcolor] = PALETTEFEATURE_TRANSPARENT; + + for (i = 0;i < 256;i++) + palette_bgra_transparent[i] = palette_bgra_complete[i]; + palette_bgra_transparent[transparentcolor] = 0; + + for (i = 0;i < fullbright_start;i++) + palette_bgra_nofullbrights[i] = palette_bgra_complete[i]; + for (i = fullbright_start;i < fullbright_end;i++) + palette_bgra_nofullbrights[i] = palette_bgra_complete[0]; + + for (i = 0;i < 256;i++) + palette_bgra_onlyfullbrights[i] = 0; + for (i = fullbright_start;i < fullbright_end;i++) + palette_bgra_onlyfullbrights[i] = palette_bgra_complete[i]; + + for (i = 0;i < 256;i++) + palette_bgra_nocolormapnofullbrights[i] = palette_bgra_complete[i]; + for (i = pants_start;i < pants_end;i++) + palette_bgra_nocolormapnofullbrights[i] = 0; + for (i = shirt_start;i < shirt_end;i++) + palette_bgra_nocolormapnofullbrights[i] = 0; + for (i = fullbright_start;i < fullbright_end;i++) + palette_bgra_nocolormapnofullbrights[i] = 0; + + for (i = 0;i < 256;i++) + palette_bgra_nocolormap[i] = palette_bgra_complete[i]; + for (i = pants_start;i < pants_end;i++) + palette_bgra_nocolormap[i] = 0; + for (i = shirt_start;i < shirt_end;i++) + palette_bgra_nocolormap[i] = 0; + + for (i = 0;i < 256;i++) + palette_bgra_pantsaswhite[i] = 0; + for (i = pants_start;i < pants_end;i++) + { + if (i >= reversed_start && i < reversed_end) + palette_bgra_pantsaswhite[i] = palette_bgra_complete[15 - (i - pants_start)]; + else + palette_bgra_pantsaswhite[i] = palette_bgra_complete[i - pants_start]; + } + + for (i = 0;i < 256;i++) + palette_bgra_shirtaswhite[i] = 0; + for (i = shirt_start;i < shirt_end;i++) + { + if (i >= reversed_start && i < reversed_end) + palette_bgra_shirtaswhite[i] = palette_bgra_complete[15 - (i - shirt_start)]; + else + palette_bgra_shirtaswhite[i] = palette_bgra_complete[i - shirt_start]; + } + + for (i = 0;i < 256;i++) + palette_bgra_alpha[i] = 0xFFFFFFFF; + u.i = 0xFFFFFFFF; + u.b[3] = 0; + palette_bgra_alpha[transparentcolor] = u.i; + + for (i = 0;i < 256;i++) + palette_bgra_font[i] = palette_bgra_complete[i]; + palette_bgra_font[0] = 0; +} + +void BuildGammaTable8(float prescale, float gamma, float scale, float base, float contrastboost, unsigned char *out, int rampsize) +{ + int i, adjusted; + double invgamma; + double t, d; + + invgamma = 1.0 / gamma; + prescale /= (double) (rampsize - 1); + for (i = 0;i < rampsize;i++) + { + t = i * prescale; + d = ((contrastboost - 1) * t + 1); + if(d == 0) + t = 0; // we could just as well assume 1 here, depending on which side of the division by zero we want to be + else + t = contrastboost * t / d; + adjusted = (int) (255.0 * (pow(t, invgamma) * scale + base) + 0.5); + out[i] = bound(0, adjusted, 255); + } +} + +void BuildGammaTable16(float prescale, float gamma, float scale, float base, float contrastboost, unsigned short *out, int rampsize) +{ + int i, adjusted; + double invgamma; + double t; + + invgamma = 1.0 / gamma; + prescale /= (double) (rampsize - 1); + for (i = 0;i < rampsize;i++) + { + t = i * prescale; + t = contrastboost * t / ((contrastboost - 1) * t + 1); + adjusted = (int) (65535.0 * (pow(t, invgamma) * scale + base) + 0.5); + out[i] = bound(0, adjusted, 65535); + } +} + +static void Palette_Shutdown(void) +{ +} + +static void Palette_NewMap(void) +{ +} + +static void Palette_Load(void) +{ + int i; + unsigned char *out; + float gamma, scale, base; + fs_offset_t filesize; + unsigned char *palfile; + unsigned char texturegammaramp[256]; + union + { + unsigned char b[4]; + unsigned int i; + } + bgra; + + gamma = 1; + scale = 1; + base = 0; +// COMMANDLINEOPTION: Client: -texgamma sets the quake palette gamma, allowing you to make quake textures brighter/darker, not recommended + i = COM_CheckParm("-texgamma"); + if (i) + gamma = atof(com_argv[i + 1]); +// COMMANDLINEOPTION: Client: -texcontrast sets the quake palette contrast, allowing you to make quake textures brighter/darker, not recommended + i = COM_CheckParm("-texcontrast"); + if (i) + scale = atof(com_argv[i + 1]); +// COMMANDLINEOPTION: Client: -texbrightness sets the quake palette brightness (brightness of black), allowing you to make quake textures brighter/darker, not recommended + i = COM_CheckParm("-texbrightness"); + if (i) + base = atof(com_argv[i + 1]); + gamma = bound(0.01, gamma, 10.0); + scale = bound(0.01, scale, 10.0); + base = bound(0, base, 0.95); + + BuildGammaTable8(1.0f, gamma, scale, base, 1, texturegammaramp, 256); + + palfile = (unsigned char *)FS_LoadFile ("gfx/palette.lmp", tempmempool, false, &filesize); + if (palfile && filesize >= 768) + memcpy(palette_rgb, palfile, 768); + else + { + Con_DPrint("Couldn't load gfx/palette.lmp, falling back on internal palette\n"); + memcpy(palette_rgb, host_quakepal, 768); + } + if (palfile) + Mem_Free(palfile); + + out = (unsigned char *) palette_bgra_complete; // palette is accessed as 32bit for speed reasons, but is created as 8bit bytes + for (i = 0;i < 256;i++) + { + out[i*4+2] = texturegammaramp[palette_rgb[i][0]]; + out[i*4+1] = texturegammaramp[palette_rgb[i][1]]; + out[i*4+0] = texturegammaramp[palette_rgb[i][2]]; + out[i*4+3] = 255; + } + + if(*r_colormap_palette.string) + palfile = (unsigned char *)FS_LoadFile (r_colormap_palette.string, tempmempool, false, &filesize); + else + palfile = NULL; + + if (palfile && filesize >= 48*2) + { + memcpy(palette_rgb_shirtcolormap[0], palfile, 48); + memcpy(palette_rgb_shirtscoreboard[0], palfile + 48, 48); + } + else + { + for(i = 0;i < 16;i++) + { + VectorCopy(palette_rgb[(i << 4) | ((i >= 8 && i <= 13) ? 0x04 : 0x0C)], palette_rgb_shirtcolormap[i]); + VectorCopy(palette_rgb[(i << 4) | 0x08], palette_rgb_shirtscoreboard[i]); + } + } + + if (palfile && filesize >= 48*4) + { + memcpy(palette_rgb_pantscolormap[0], palfile + 48*2, 48); + memcpy(palette_rgb_pantsscoreboard[0], palfile + 48*3, 48); + } + else + { + memcpy(palette_rgb_pantscolormap, palette_rgb_shirtcolormap, sizeof(palette_rgb_pantscolormap)); + memcpy(palette_rgb_pantsscoreboard, palette_rgb_shirtscoreboard, sizeof(palette_rgb_pantsscoreboard)); + } + + if(palfile) + Mem_Free(palfile); + + memset(palette_bgra_embeddedpic, 0, sizeof(palette_bgra_embeddedpic)); + for (i = '1';i <= '7';i++) + { + Vector4Set(bgra.b, 255, 255, 255, (i - '0') * 255 / 7); + palette_bgra_embeddedpic[i] = bgra.i; + } + + Palette_SetupSpecialPalettes(); +} + +void Palette_Init(void) +{ + R_RegisterModule("Palette", Palette_Load, Palette_Shutdown, Palette_NewMap, NULL, NULL); + Cvar_RegisterVariable(&r_colormap_palette); + Palette_Load(); +} diff --git a/app/jni/palette.h b/app/jni/palette.h new file mode 100644 index 0000000..f904465 --- /dev/null +++ b/app/jni/palette.h @@ -0,0 +1,39 @@ + +#ifndef PALLETE_H +#define PALLETE_H + +#define PALETTEFEATURE_STANDARD 1 +#define PALETTEFEATURE_REVERSED 2 +#define PALETTEFEATURE_PANTS 4 +#define PALETTEFEATURE_SHIRT 8 +#define PALETTEFEATURE_GLOW 16 +#define PALETTEFEATURE_ZERO 32 +#define PALETTEFEATURE_TRANSPARENT 128 + +extern unsigned char palette_rgb[256][3]; +extern unsigned char palette_rgb_pantscolormap[16][3]; +extern unsigned char palette_rgb_shirtcolormap[16][3]; +extern unsigned char palette_rgb_pantsscoreboard[16][3]; +extern unsigned char palette_rgb_shirtscoreboard[16][3]; + +extern unsigned int palette_bgra_complete[256]; +extern unsigned int palette_bgra_font[256]; +extern unsigned int palette_bgra_alpha[256]; +extern unsigned int palette_bgra_nocolormap[256]; +extern unsigned int palette_bgra_nocolormapnofullbrights[256]; +extern unsigned int palette_bgra_nofullbrights[256]; +extern unsigned int palette_bgra_onlyfullbrights[256]; +extern unsigned int palette_bgra_pantsaswhite[256]; +extern unsigned int palette_bgra_shirtaswhite[256]; +extern unsigned int palette_bgra_transparent[256]; +extern unsigned int palette_bgra_embeddedpic[256]; +extern unsigned char palette_featureflags[256]; + +// used by hardware gamma functions in vid_* files +void BuildGammaTable8(float prescale, float gamma, float scale, float base, float contrastboost, unsigned char *out, int rampsize); +void BuildGammaTable16(float prescale, float gamma, float scale, float base, float contrastboost, unsigned short *out, int rampsize); + +void Palette_Init(void); + +#endif + diff --git a/app/jni/polygon.c b/app/jni/polygon.c new file mode 100644 index 0000000..99ceb0b --- /dev/null +++ b/app/jni/polygon.c @@ -0,0 +1,310 @@ + +/* +Polygon clipping routines written by Forest Hale and placed into public domain. +*/ + +#include +#include "polygon.h" + +void PolygonF_QuadForPlane(float *outpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float quadsize) +{ + float d, quadright[3], quadup[3]; + if (fabs(planenormalz) > fabs(planenormalx) && fabs(planenormalz) > fabs(planenormaly)) + { + quadup[0] = 1; + quadup[1] = 0; + quadup[2] = 0; + } + else + { + quadup[0] = 0; + quadup[1] = 0; + quadup[2] = 1; + } + // d = -DotProduct(quadup, planenormal); + d = -(quadup[0] * planenormalx + quadup[1] * planenormaly + quadup[2] * planenormalz); + // VectorMA(quadup, d, planenormal, quadup); + quadup[0] += d * planenormalx; + quadup[1] += d * planenormaly; + quadup[2] += d * planenormalz; + // VectorNormalize(quadup); + d = (float)(1.0 / sqrt(quadup[0] * quadup[0] + quadup[1] * quadup[1] + quadup[2] * quadup[2])); + quadup[0] *= d; + quadup[1] *= d; + quadup[2] *= d; + // CrossProduct(quadup,planenormal,quadright); + quadright[0] = quadup[1] * planenormalz - quadup[2] * planenormaly; + quadright[1] = quadup[2] * planenormalx - quadup[0] * planenormalz; + quadright[2] = quadup[0] * planenormaly - quadup[1] * planenormalx; + // make the points + outpoints[0] = planedist * planenormalx - quadsize * quadright[0] + quadsize * quadup[0]; + outpoints[1] = planedist * planenormaly - quadsize * quadright[1] + quadsize * quadup[1]; + outpoints[2] = planedist * planenormalz - quadsize * quadright[2] + quadsize * quadup[2]; + outpoints[3] = planedist * planenormalx + quadsize * quadright[0] + quadsize * quadup[0]; + outpoints[4] = planedist * planenormaly + quadsize * quadright[1] + quadsize * quadup[1]; + outpoints[5] = planedist * planenormalz + quadsize * quadright[2] + quadsize * quadup[2]; + outpoints[6] = planedist * planenormalx + quadsize * quadright[0] - quadsize * quadup[0]; + outpoints[7] = planedist * planenormaly + quadsize * quadright[1] - quadsize * quadup[1]; + outpoints[8] = planedist * planenormalz + quadsize * quadright[2] - quadsize * quadup[2]; + outpoints[9] = planedist * planenormalx - quadsize * quadright[0] - quadsize * quadup[0]; + outpoints[10] = planedist * planenormaly - quadsize * quadright[1] - quadsize * quadup[1]; + outpoints[11] = planedist * planenormalz - quadsize * quadright[2] - quadsize * quadup[2]; +} + +void PolygonD_QuadForPlane(double *outpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double quadsize) +{ + double d, quadright[3], quadup[3]; + if (fabs(planenormalz) > fabs(planenormalx) && fabs(planenormalz) > fabs(planenormaly)) + { + quadup[0] = 1; + quadup[1] = 0; + quadup[2] = 0; + } + else + { + quadup[0] = 0; + quadup[1] = 0; + quadup[2] = 1; + } + // d = -DotProduct(quadup, planenormal); + d = -(quadup[0] * planenormalx + quadup[1] * planenormaly + quadup[2] * planenormalz); + // VectorMA(quadup, d, planenormal, quadup); + quadup[0] += d * planenormalx; + quadup[1] += d * planenormaly; + quadup[2] += d * planenormalz; + // VectorNormalize(quadup); + d = 1.0 / sqrt(quadup[0] * quadup[0] + quadup[1] * quadup[1] + quadup[2] * quadup[2]); + quadup[0] *= d; + quadup[1] *= d; + quadup[2] *= d; + // CrossProduct(quadup,planenormal,quadright); + quadright[0] = quadup[1] * planenormalz - quadup[2] * planenormaly; + quadright[1] = quadup[2] * planenormalx - quadup[0] * planenormalz; + quadright[2] = quadup[0] * planenormaly - quadup[1] * planenormalx; + // make the points + outpoints[0] = planedist * planenormalx - quadsize * quadright[0] + quadsize * quadup[0]; + outpoints[1] = planedist * planenormaly - quadsize * quadright[1] + quadsize * quadup[1]; + outpoints[2] = planedist * planenormalz - quadsize * quadright[2] + quadsize * quadup[2]; + outpoints[3] = planedist * planenormalx + quadsize * quadright[0] + quadsize * quadup[0]; + outpoints[4] = planedist * planenormaly + quadsize * quadright[1] + quadsize * quadup[1]; + outpoints[5] = planedist * planenormalz + quadsize * quadright[2] + quadsize * quadup[2]; + outpoints[6] = planedist * planenormalx + quadsize * quadright[0] - quadsize * quadup[0]; + outpoints[7] = planedist * planenormaly + quadsize * quadright[1] - quadsize * quadup[1]; + outpoints[8] = planedist * planenormalz + quadsize * quadright[2] - quadsize * quadup[2]; + outpoints[9] = planedist * planenormalx - quadsize * quadright[0] - quadsize * quadup[0]; + outpoints[10] = planedist * planenormaly - quadsize * quadright[1] - quadsize * quadup[1]; + outpoints[11] = planedist * planenormalz - quadsize * quadright[2] - quadsize * quadup[2]; +} + +int PolygonF_Clip(int innumpoints, const float *inpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float epsilon, int outfrontmaxpoints, float *outfrontpoints) +{ + int i, frontcount = 0; + const float *n, *p; + float frac, pdist, ndist; + if (innumpoints < 1) + return 0; + n = inpoints; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + for(i = 0;i < innumpoints;i++) + { + p = n; + pdist = ndist; + n = inpoints + ((i + 1) < innumpoints ? (i + 1) : 0) * 3; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + if (pdist >= -epsilon) + { + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0]; + *outfrontpoints++ = p[1]; + *outfrontpoints++ = p[2]; + } + frontcount++; + } + if ((pdist > epsilon && ndist < -epsilon) || (pdist < -epsilon && ndist > epsilon)) + { + frac = pdist / (pdist - ndist); + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0] + frac * (n[0] - p[0]); + *outfrontpoints++ = p[1] + frac * (n[1] - p[1]); + *outfrontpoints++ = p[2] + frac * (n[2] - p[2]); + } + frontcount++; + } + } + return frontcount; +} + +int PolygonD_Clip(int innumpoints, const double *inpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double epsilon, int outfrontmaxpoints, double *outfrontpoints) +{ + int i, frontcount = 0; + const double *n, *p; + double frac, pdist, ndist; + if (innumpoints < 1) + return 0; + n = inpoints; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + for(i = 0;i < innumpoints;i++) + { + p = n; + pdist = ndist; + n = inpoints + ((i + 1) < innumpoints ? (i + 1) : 0) * 3; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + if (pdist >= -epsilon) + { + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0]; + *outfrontpoints++ = p[1]; + *outfrontpoints++ = p[2]; + } + frontcount++; + } + if ((pdist > epsilon && ndist < -epsilon) || (pdist < -epsilon && ndist > epsilon)) + { + frac = pdist / (pdist - ndist); + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0] + frac * (n[0] - p[0]); + *outfrontpoints++ = p[1] + frac * (n[1] - p[1]); + *outfrontpoints++ = p[2] + frac * (n[2] - p[2]); + } + frontcount++; + } + } + return frontcount; +} + +void PolygonF_Divide(int innumpoints, const float *inpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float epsilon, int outfrontmaxpoints, float *outfrontpoints, int *neededfrontpoints, int outbackmaxpoints, float *outbackpoints, int *neededbackpoints, int *oncountpointer) +{ + int i, frontcount = 0, backcount = 0, oncount = 0; + const float *n, *p; + float frac, pdist, ndist; + if (innumpoints) + { + n = inpoints; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + for(i = 0;i < innumpoints;i++) + { + p = n; + pdist = ndist; + n = inpoints + ((i + 1) < innumpoints ? (i + 1) : 0) * 3; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + if (pdist >= -epsilon) + { + if (pdist <= epsilon) + oncount++; + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0]; + *outfrontpoints++ = p[1]; + *outfrontpoints++ = p[2]; + } + frontcount++; + } + if (pdist <= epsilon) + { + if (backcount < outbackmaxpoints) + { + *outbackpoints++ = p[0]; + *outbackpoints++ = p[1]; + *outbackpoints++ = p[2]; + } + backcount++; + } + if ((pdist > epsilon && ndist < -epsilon) || (pdist < -epsilon && ndist > epsilon)) + { + oncount++; + frac = pdist / (pdist - ndist); + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0] + frac * (n[0] - p[0]); + *outfrontpoints++ = p[1] + frac * (n[1] - p[1]); + *outfrontpoints++ = p[2] + frac * (n[2] - p[2]); + } + frontcount++; + if (backcount < outbackmaxpoints) + { + *outbackpoints++ = p[0] + frac * (n[0] - p[0]); + *outbackpoints++ = p[1] + frac * (n[1] - p[1]); + *outbackpoints++ = p[2] + frac * (n[2] - p[2]); + } + backcount++; + } + } + } + if (neededfrontpoints) + *neededfrontpoints = frontcount; + if (neededbackpoints) + *neededbackpoints = backcount; + if (oncountpointer) + *oncountpointer = oncount; +} + +void PolygonD_Divide(int innumpoints, const double *inpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double epsilon, int outfrontmaxpoints, double *outfrontpoints, int *neededfrontpoints, int outbackmaxpoints, double *outbackpoints, int *neededbackpoints, int *oncountpointer) +{ + int i = 0, frontcount = 0, backcount = 0, oncount = 0; + const double *n, *p; + double frac, pdist, ndist; + if (innumpoints) + { + n = inpoints; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + for(i = 0;i < innumpoints;i++) + { + p = n; + pdist = ndist; + n = inpoints + ((i + 1) < innumpoints ? (i + 1) : 0) * 3; + ndist = n[0] * planenormalx + n[1] * planenormaly + n[2] * planenormalz - planedist; + if (pdist >= -epsilon) + { + if (pdist <= epsilon) + oncount++; + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0]; + *outfrontpoints++ = p[1]; + *outfrontpoints++ = p[2]; + } + frontcount++; + } + if (pdist <= epsilon) + { + if (backcount < outbackmaxpoints) + { + *outbackpoints++ = p[0]; + *outbackpoints++ = p[1]; + *outbackpoints++ = p[2]; + } + backcount++; + } + if ((pdist > epsilon && ndist < -epsilon) || (pdist < -epsilon && ndist > epsilon)) + { + oncount++; + frac = pdist / (pdist - ndist); + if (frontcount < outfrontmaxpoints) + { + *outfrontpoints++ = p[0] + frac * (n[0] - p[0]); + *outfrontpoints++ = p[1] + frac * (n[1] - p[1]); + *outfrontpoints++ = p[2] + frac * (n[2] - p[2]); + } + frontcount++; + if (backcount < outbackmaxpoints) + { + *outbackpoints++ = p[0] + frac * (n[0] - p[0]); + *outbackpoints++ = p[1] + frac * (n[1] - p[1]); + *outbackpoints++ = p[2] + frac * (n[2] - p[2]); + } + backcount++; + } + } + } + if (neededfrontpoints) + *neededfrontpoints = frontcount; + if (neededbackpoints) + *neededbackpoints = backcount; + if (oncountpointer) + *oncountpointer = oncount; +} + diff --git a/app/jni/polygon.h b/app/jni/polygon.h new file mode 100644 index 0000000..e8bf2e8 --- /dev/null +++ b/app/jni/polygon.h @@ -0,0 +1,16 @@ + +#ifndef POLYGON_H +#define POLYGON_H + +/* +Polygon clipping routines written by Forest Hale and placed into public domain. +*/ + +void PolygonF_QuadForPlane(float *outpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float quadsize); +void PolygonD_QuadForPlane(double *outpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double quadsize); +int PolygonF_Clip(int innumpoints, const float *inpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float epsilon, int outfrontmaxpoints, float *outfrontpoints); +int PolygonD_Clip(int innumpoints, const double *inpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double epsilon, int outfrontmaxpoints, double *outfrontpoints); +void PolygonF_Divide(int innumpoints, const float *inpoints, float planenormalx, float planenormaly, float planenormalz, float planedist, float epsilon, int outfrontmaxpoints, float *outfrontpoints, int *neededfrontpoints, int outbackmaxpoints, float *outbackpoints, int *neededbackpoints, int *oncountpointer); +void PolygonD_Divide(int innumpoints, const double *inpoints, double planenormalx, double planenormaly, double planenormalz, double planedist, double epsilon, int outfrontmaxpoints, double *outfrontpoints, int *neededfrontpoints, int outbackmaxpoints, double *outbackpoints, int *neededbackpoints, int *oncountpointer); + +#endif diff --git a/app/jni/portals.c b/app/jni/portals.c new file mode 100644 index 0000000..2872a8c --- /dev/null +++ b/app/jni/portals.c @@ -0,0 +1,480 @@ + +#include "quakedef.h" +#include "polygon.h" +#include "portals.h" + +#define MAXRECURSIVEPORTALPLANES 1024 +#define MAXRECURSIVEPORTALS 256 + +static tinyplane_t portalplanes[MAXRECURSIVEPORTALPLANES]; +static int ranoutofportalplanes; +static int ranoutofportals; +static float portaltemppoints[2][256][3]; +static float portaltemppoints2[256][3]; +static int portal_markid = 0; +static float boxpoints[4*3]; + +static int Portal_PortalThroughPortalPlanes(tinyplane_t *clipplanes, int clipnumplanes, float *targpoints, int targnumpoints, float *out, int maxpoints) +{ + int numpoints = targnumpoints, i, w; + if (numpoints < 1) + return numpoints; + if (maxpoints > 256) + maxpoints = 256; + w = 0; + memcpy(&portaltemppoints[w][0][0], targpoints, numpoints * 3 * sizeof(float)); + for (i = 0;i < clipnumplanes && numpoints > 0;i++) + { + PolygonF_Divide(numpoints, &portaltemppoints[w][0][0], clipplanes[i].normal[0], clipplanes[i].normal[1], clipplanes[i].normal[2], clipplanes[i].dist, 1.0f/32.0f, 256, &portaltemppoints[1-w][0][0], &numpoints, 0, NULL, NULL, NULL); + w = 1-w; + numpoints = min(numpoints, 256); + } + numpoints = min(numpoints, maxpoints); + if (numpoints > 0) + memcpy(out, &portaltemppoints[w][0][0], numpoints * 3 * sizeof(float)); + return numpoints; +} + +static int Portal_RecursiveFlowSearch (mleaf_t *leaf, vec3_t eye, int firstclipplane, int numclipplanes) +{ + mportal_t *p; + int newpoints, i, prev; + vec3_t center, v1, v2; + tinyplane_t *newplanes; + + if (leaf->portalmarkid == portal_markid) + return true; + + // follow portals into other leafs + for (p = leaf->portals;p;p = p->next) + { + // only flow through portals facing away from the viewer + if (PlaneDiff(eye, (&p->plane)) < 0) + { + newpoints = Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, (float *) p->points, p->numpoints, &portaltemppoints2[0][0], 256); + if (newpoints < 3) + continue; + else if (firstclipplane + numclipplanes + newpoints > MAXRECURSIVEPORTALPLANES) + ranoutofportalplanes = true; + else + { + // find the center by averaging + VectorClear(center); + for (i = 0;i < newpoints;i++) + VectorAdd(center, portaltemppoints2[i], center); + // ixtable is a 1.0f / N table + VectorScale(center, ixtable[newpoints], center); + // calculate the planes, and make sure the polygon can see it's own center + newplanes = &portalplanes[firstclipplane + numclipplanes]; + for (prev = newpoints - 1, i = 0;i < newpoints;prev = i, i++) + { + VectorSubtract(eye, portaltemppoints2[i], v1); + VectorSubtract(portaltemppoints2[prev], portaltemppoints2[i], v2); + CrossProduct(v1, v2, newplanes[i].normal); + VectorNormalize(newplanes[i].normal); + newplanes[i].dist = DotProduct(eye, newplanes[i].normal); + if (DotProduct(newplanes[i].normal, center) <= newplanes[i].dist) + { + // polygon can't see it's own center, discard and use parent portal + break; + } + } + if (i == newpoints) + { + if (Portal_RecursiveFlowSearch(p->past, eye, firstclipplane + numclipplanes, newpoints)) + return true; + } + else + { + if (Portal_RecursiveFlowSearch(p->past, eye, firstclipplane, numclipplanes)) + return true; + } + } + } + } + + return false; +} + +static void Portal_PolygonRecursiveMarkLeafs(mnode_t *node, float *polypoints, int numpoints) +{ + int i, front; + float *p; + +loc0: + if (!node->plane) + { + ((mleaf_t *)node)->portalmarkid = portal_markid; + return; + } + + front = 0; + for (i = 0, p = polypoints;i < numpoints;i++, p += 3) + { + if (DotProduct(p, node->plane->normal) > node->plane->dist) + front++; + } + if (front > 0) + { + if (front == numpoints) + { + node = node->children[0]; + goto loc0; + } + else + Portal_PolygonRecursiveMarkLeafs(node->children[0], polypoints, numpoints); + } + node = node->children[1]; + goto loc0; +} + +int Portal_CheckPolygon(dp_model_t *model, vec3_t eye, float *polypoints, int numpoints) +{ + int i, prev, returnvalue; + mleaf_t *eyeleaf; + vec3_t center, v1, v2; + + // if there is no model, it can not block visibility + if (model == NULL || !model->brush.PointInLeaf) + return true; + + portal_markid++; + + Portal_PolygonRecursiveMarkLeafs(model->brush.data_nodes, polypoints, numpoints); + + eyeleaf = model->brush.PointInLeaf(model, eye); + + // find the center by averaging + VectorClear(center); + for (i = 0;i < numpoints;i++) + VectorAdd(center, (&polypoints[i * 3]), center); + // ixtable is a 1.0f / N table + VectorScale(center, ixtable[numpoints], center); + + // calculate the planes, and make sure the polygon can see it's own center + for (prev = numpoints - 1, i = 0;i < numpoints;prev = i, i++) + { + VectorSubtract(eye, (&polypoints[i * 3]), v1); + VectorSubtract((&polypoints[prev * 3]), (&polypoints[i * 3]), v2); + CrossProduct(v1, v2, portalplanes[i].normal); + VectorNormalize(portalplanes[i].normal); + portalplanes[i].dist = DotProduct(eye, portalplanes[i].normal); + if (DotProduct(portalplanes[i].normal, center) <= portalplanes[i].dist) + { + // polygon can't see it's own center, discard + return false; + } + } + + ranoutofportalplanes = false; + ranoutofportals = false; + + returnvalue = Portal_RecursiveFlowSearch(eyeleaf, eye, 0, numpoints); + + if (ranoutofportalplanes) + Con_Printf("Portal_RecursiveFlowSearch: ran out of %d plane stack when recursing through portals\n", MAXRECURSIVEPORTALPLANES); + if (ranoutofportals) + Con_Printf("Portal_RecursiveFlowSearch: ran out of %d portal stack when recursing through portals\n", MAXRECURSIVEPORTALS); + + return returnvalue; +} + +#define Portal_MinsBoxPolygon(axis, axisvalue, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) \ +{\ + if (eye[(axis)] < ((axisvalue) - 0.5f))\ + {\ + boxpoints[ 0] = x1;boxpoints[ 1] = y1;boxpoints[ 2] = z1;\ + boxpoints[ 3] = x2;boxpoints[ 4] = y2;boxpoints[ 5] = z2;\ + boxpoints[ 6] = x3;boxpoints[ 7] = y3;boxpoints[ 8] = z3;\ + boxpoints[ 9] = x4;boxpoints[10] = y4;boxpoints[11] = z4;\ + if (Portal_CheckPolygon(model, eye, boxpoints, 4))\ + return true;\ + }\ +} + +#define Portal_MaxsBoxPolygon(axis, axisvalue, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) \ +{\ + if (eye[(axis)] > ((axisvalue) + 0.5f))\ + {\ + boxpoints[ 0] = x1;boxpoints[ 1] = y1;boxpoints[ 2] = z1;\ + boxpoints[ 3] = x2;boxpoints[ 4] = y2;boxpoints[ 5] = z2;\ + boxpoints[ 6] = x3;boxpoints[ 7] = y3;boxpoints[ 8] = z3;\ + boxpoints[ 9] = x4;boxpoints[10] = y4;boxpoints[11] = z4;\ + if (Portal_CheckPolygon(model, eye, boxpoints, 4))\ + return true;\ + }\ +} + +int Portal_CheckBox(dp_model_t *model, vec3_t eye, vec3_t a, vec3_t b) +{ + if (eye[0] >= (a[0] - 1.0f) && eye[0] < (b[0] + 1.0f) + && eye[1] >= (a[1] - 1.0f) && eye[1] < (b[1] + 1.0f) + && eye[2] >= (a[2] - 1.0f) && eye[2] < (b[2] + 1.0f)) + return true; + + Portal_MinsBoxPolygon + ( + 0, a[0], + a[0], a[1], a[2], + a[0], b[1], a[2], + a[0], b[1], b[2], + a[0], a[1], b[2] + ); + Portal_MaxsBoxPolygon + ( + 0, b[0], + b[0], b[1], a[2], + b[0], a[1], a[2], + b[0], a[1], b[2], + b[0], b[1], b[2] + ); + Portal_MinsBoxPolygon + ( + 1, a[1], + b[0], a[1], a[2], + a[0], a[1], a[2], + a[0], a[1], b[2], + b[0], a[1], b[2] + ); + Portal_MaxsBoxPolygon + ( + 1, b[1], + a[0], b[1], a[2], + b[0], b[1], a[2], + b[0], b[1], b[2], + a[0], b[1], b[2] + ); + Portal_MinsBoxPolygon + ( + 2, a[2], + a[0], a[1], a[2], + b[0], a[1], a[2], + b[0], b[1], a[2], + a[0], b[1], a[2] + ); + Portal_MaxsBoxPolygon + ( + 2, b[2], + b[0], a[1], b[2], + a[0], a[1], b[2], + a[0], b[1], b[2], + b[0], b[1], b[2] + ); + + return false; +} + +typedef struct portalrecursioninfo_s +{ + int exact; + int numfrustumplanes; + vec3_t boxmins; + vec3_t boxmaxs; + int numsurfaces; + int *surfacelist; + unsigned char *surfacepvs; + int numleafs; + unsigned char *visitingleafpvs; // used to prevent infinite loops + int *leaflist; + unsigned char *leafpvs; + unsigned char *shadowtrispvs; + unsigned char *lighttrispvs; + dp_model_t *model; + vec3_t eye; + float *updateleafsmins; + float *updateleafsmaxs; +} +portalrecursioninfo_t; + +static void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, int firstclipplane, int numclipplanes) +{ + mportal_t *p; + int newpoints, i, prev; + float dist; + vec3_t center; + tinyplane_t *newplanes; + int leafindex = leaf - info->model->brush.data_leafs; + + if (CHECKPVSBIT(info->visitingleafpvs, leafindex)) + return; // recursive loop of leafs (cmc.bsp for megatf coop) + + SETPVSBIT(info->visitingleafpvs, leafindex); + + for (i = 0;i < 3;i++) + { + if (info->updateleafsmins && info->updateleafsmins[i] > leaf->mins[i]) info->updateleafsmins[i] = leaf->mins[i]; + if (info->updateleafsmaxs && info->updateleafsmaxs[i] < leaf->maxs[i]) info->updateleafsmaxs[i] = leaf->maxs[i]; + } + + + if (info->leafpvs) + { + if (!CHECKPVSBIT(info->leafpvs, leafindex)) + { + SETPVSBIT(info->leafpvs, leafindex); + info->leaflist[info->numleafs++] = leafindex; + } + } + + // mark surfaces in leaf that can be seen through portal + if (leaf->numleafsurfaces && info->surfacepvs) + { + for (i = 0;i < leaf->numleafsurfaces;i++) + { + int surfaceindex = leaf->firstleafsurface[i]; + msurface_t *surface = info->model->data_surfaces + surfaceindex; + if (BoxesOverlap(surface->mins, surface->maxs, info->boxmins, info->boxmaxs)) + { + qboolean insidebox = BoxInsideBox(surface->mins, surface->maxs, info->boxmins, info->boxmaxs); + qboolean addedtris = false; + int t, tend; + const int *elements; + const float *vertex3f; + float v[9]; + vertex3f = info->model->surfmesh.data_vertex3f; + elements = (info->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle); + for (t = surface->num_firsttriangle, tend = t + surface->num_triangles;t < tend;t++, elements += 3) + { + VectorCopy(vertex3f + elements[0] * 3, v + 0); + VectorCopy(vertex3f + elements[1] * 3, v + 3); + VectorCopy(vertex3f + elements[2] * 3, v + 6); + if (PointInfrontOfTriangle(info->eye, v + 0, v + 3, v + 6) + && (insidebox || TriangleBBoxOverlapsBox(v, v + 3, v + 6, info->boxmins, info->boxmaxs)) + && (!info->exact || Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, v, 3, &portaltemppoints2[0][0], 256) > 0)) + { + addedtris = true; + if (info->shadowtrispvs) + SETPVSBIT(info->shadowtrispvs, t); + if (info->lighttrispvs) + SETPVSBIT(info->lighttrispvs, t); + } + } + if (addedtris && !CHECKPVSBIT(info->surfacepvs, surfaceindex)) + { + SETPVSBIT(info->surfacepvs, surfaceindex); + info->surfacelist[info->numsurfaces++] = surfaceindex; + } + } + } + } + + // follow portals into other leafs + for (p = leaf->portals;p;p = p->next) + { + // only flow through portals facing the viewer + dist = PlaneDiff(info->eye, (&p->plane)); + if (dist < 0 && BoxesOverlap(p->past->mins, p->past->maxs, info->boxmins, info->boxmaxs)) + { + newpoints = Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, (float *) p->points, p->numpoints, &portaltemppoints2[0][0], 256); + if (newpoints < 3) + continue; + else if (firstclipplane + numclipplanes + newpoints > MAXRECURSIVEPORTALPLANES) + ranoutofportalplanes = true; + else + { + // find the center by averaging + VectorClear(center); + for (i = 0;i < newpoints;i++) + VectorAdd(center, portaltemppoints2[i], center); + // ixtable is a 1.0f / N table + VectorScale(center, ixtable[newpoints], center); + // calculate the planes, and make sure the polygon can see its own center + newplanes = &portalplanes[firstclipplane + numclipplanes]; + for (prev = newpoints - 1, i = 0;i < newpoints;prev = i, i++) + { + TriangleNormal(portaltemppoints2[prev], portaltemppoints2[i], info->eye, newplanes[i].normal); + VectorNormalize(newplanes[i].normal); + newplanes[i].dist = DotProduct(info->eye, newplanes[i].normal); + if (DotProduct(newplanes[i].normal, center) <= newplanes[i].dist) + { + // polygon can't see its own center, discard and use parent portal + break; + } + } + if (i == newpoints) + Portal_RecursiveFlow(info, p->past, firstclipplane + numclipplanes, newpoints); + else + Portal_RecursiveFlow(info, p->past, firstclipplane, numclipplanes); + } + } + } + + CLEARPVSBIT(info->visitingleafpvs, leafindex); +} + +static void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t *node) +{ + if (node->plane) + { + float f = DotProduct(info->eye, node->plane->normal) - node->plane->dist; + if (f > -0.1) + Portal_RecursiveFindLeafForFlow(info, node->children[0]); + if (f < 0.1) + Portal_RecursiveFindLeafForFlow(info, node->children[1]); + } + else + { + mleaf_t *leaf = (mleaf_t *)node; + if (leaf->clusterindex >= 0) + Portal_RecursiveFlow(info, leaf, 0, info->numfrustumplanes); + } +} + +void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs, unsigned char *visitingleafpvs) +{ + int i; + portalrecursioninfo_t info; + + // if there is no model, it can not block visibility + if (model == NULL) + { + Con_Print("Portal_Visibility: NULL model\n"); + return; + } + + if (!model->brush.data_nodes) + { + Con_Print("Portal_Visibility: not a brush model\n"); + return; + } + + // put frustum planes (if any) into tinyplane format at start of buffer + for (i = 0;i < numfrustumplanes;i++) + { + VectorCopy(frustumplanes[i].normal, portalplanes[i].normal); + portalplanes[i].dist = frustumplanes[i].dist; + } + + ranoutofportalplanes = false; + ranoutofportals = false; + + VectorCopy(boxmins, info.boxmins); + VectorCopy(boxmaxs, info.boxmaxs); + info.exact = exact; + info.numsurfaces = 0; + info.surfacelist = surfacelist; + info.surfacepvs = surfacepvs; + info.numleafs = 0; + info.visitingleafpvs = visitingleafpvs; + info.leaflist = leaflist; + info.leafpvs = leafpvs; + info.model = model; + VectorCopy(eye, info.eye); + info.numfrustumplanes = numfrustumplanes; + info.updateleafsmins = updateleafsmins; + info.updateleafsmaxs = updateleafsmaxs; + info.shadowtrispvs = shadowtrispvs; + info.lighttrispvs = lighttrispvs; + + Portal_RecursiveFindLeafForFlow(&info, model->brush.data_nodes); + + if (ranoutofportalplanes) + Con_Printf("Portal_RecursiveFlow: ran out of %d plane stack when recursing through portals\n", MAXRECURSIVEPORTALPLANES); + if (ranoutofportals) + Con_Printf("Portal_RecursiveFlow: ran out of %d portal stack when recursing through portals\n", MAXRECURSIVEPORTALS); + if (numsurfacespointer) + *numsurfacespointer = info.numsurfaces; + if (numleafspointer) + *numleafspointer = info.numleafs; +} + diff --git a/app/jni/portals.h b/app/jni/portals.h new file mode 100644 index 0000000..fb61328 --- /dev/null +++ b/app/jni/portals.h @@ -0,0 +1,10 @@ + +#ifndef PORTALS_H +#define PORTALS_H + +int Portal_CheckPolygon(dp_model_t *model, vec3_t eye, float *polypoints, int numpoints); +int Portal_CheckBox(dp_model_t *model, vec3_t eye, vec3_t a, vec3_t b); +void Portal_Visibility(dp_model_t *model, const vec3_t eye, int *leaflist, unsigned char *leafpvs, int *numleafspointer, int *surfacelist, unsigned char *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs, unsigned char *shadowtrispvs, unsigned char *lighttrispvs, unsigned char *visitingleafpvs); + +#endif + diff --git a/app/jni/pr_comp.h b/app/jni/pr_comp.h new file mode 100644 index 0000000..d1643b6 --- /dev/null +++ b/app/jni/pr_comp.h @@ -0,0 +1,225 @@ +/* +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 + +#ifndef PR_COMP_H +#define PR_COMP_H + +typedef unsigned int func_t; +typedef int string_t; + +typedef enum etype_e {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 + + +typedef enum opcode_e +{ + 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 +} +opcode_t; + + +typedef struct statement_s +{ + unsigned short op; + signed short a,b,c; +} +dstatement_t; + +typedef struct ddef_s +{ + 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 dfunction_s +{ + 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; + unsigned char parm_size[MAX_PARMS]; +} +dfunction_t; + +typedef struct mfunction_s +{ + int first_statement; // negative numbers are builtins + int parm_start; + int locals; // total ints of parms + locals + + // these are doubles so that they can count up to 54bits or so rather than 32bit + double tprofile; // realtime in this function + double tbprofile; // realtime in builtins called by this function (NOTE: builtins also have a tprofile!) + double profile; // runtime + double builtinsprofile; // cost of builtin functions called by this function + double callcount; // times the functions has been called since the last profile call + double totaltime; // total execution time of this function DIRECTLY FROM THE ENGINE + double tprofile_total; // runtime (NOTE: tbprofile_total makes no real sense, so not accumulating that) + double profile_total; // runtime + double builtinsprofile_total; // cost of builtin functions called by this function + int recursion; + + int s_name; + int s_file; // source file defined in + + int numparms; + unsigned char parm_size[MAX_PARMS]; +} +mfunction_t; + +typedef struct mstatement_s +{ + opcode_t op; + int operand[3]; // always a global or -1 for unused + int jumpabsolute; // only used by IF, IFNOT, GOTO +} +mstatement_t; + + +#define PROG_VERSION 6 +typedef struct dprograms_s +{ + 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; + +#endif + diff --git a/app/jni/progdefs.h b/app/jni/progdefs.h new file mode 100644 index 0000000..7086dbd --- /dev/null +++ b/app/jni/progdefs.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. + +*/ + +/* file generated by qcc, do not modify */ + +#ifndef PROGDEFS_H +#define PROGDEFS_H + +typedef struct globalvars_s +{ + 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 entvars_s +{ + 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 +#define PROGHEADER_CRC_TENEBRAE 32401 + +#endif + diff --git a/app/jni/progs.h b/app/jni/progs.h new file mode 100644 index 0000000..ed09789 --- /dev/null +++ b/app/jni/progs.h @@ -0,0 +1,151 @@ +/* +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 PROGS_H +#define PROGS_H +#include "pr_comp.h" // defs shared with qcc + +#define ENTITYGRIDAREAS 16 +#define MAX_ENTITYCLUSTERS 16 + +#define GEOMTYPE_NONE -1 +#define GEOMTYPE_SOLID 0 +#define GEOMTYPE_BOX 1 +#define GEOMTYPE_SPHERE 2 +#define GEOMTYPE_CAPSULE 3 +#define GEOMTYPE_TRIMESH 4 +#define GEOMTYPE_CYLINDER 5 +#define GEOMTYPE_CAPSULE_X 6 +#define GEOMTYPE_CAPSULE_Y 7 +#define GEOMTYPE_CAPSULE_Z 8 +#define GEOMTYPE_CYLINDER_X 9 +#define GEOMTYPE_CYLINDER_Y 10 +#define GEOMTYPE_CYLINDER_Z 11 + +#define JOINTTYPE_NONE 0 +#define JOINTTYPE_POINT 1 +#define JOINTTYPE_HINGE 2 +#define JOINTTYPE_SLIDER 3 +#define JOINTTYPE_UNIVERSAL 4 +#define JOINTTYPE_HINGE2 5 +#define JOINTTYPE_FIXED -1 + +#define FORCETYPE_NONE 0 +#define FORCETYPE_FORCE 1 +#define FORCETYPE_FORCEATPOS 2 +#define FORCETYPE_TORQUE 3 + +#define ODEFUNC_ENABLE 1 +#define ODEFUNC_DISABLE 2 +#define ODEFUNC_FORCE 3 +#define ODEFUNC_TORQUE 4 + +typedef struct edict_odefunc_s +{ + int type; + vec3_t v1; + vec3_t v2; + struct edict_odefunc_s *next; +}edict_odefunc_t; + +typedef struct edict_engineprivate_s +{ + // true if this edict is unused + qboolean free; + // sv.time when the object was freed (to prevent early reuse which could + // mess up client interpolation or obscure severe QuakeC bugs) + float freetime; + // mark for the leak detector + int mark; + // place in the code where it was allocated (for the leak detector) + const char *allocation_origin; + // initially false to prevent projectiles from moving on their first frame + // (even if they were spawned by an synchronous client think) + qboolean move; + + // cached cluster links for quick stationary object visibility checking + vec3_t cullmins, cullmaxs; + int pvs_numclusters; + int pvs_clusterlist[MAX_ENTITYCLUSTERS]; + + // physics grid areas this edict is linked into + link_t areagrid[ENTITYGRIDAREAS]; + // since the areagrid can have multiple references to one entity, + // we should avoid extensive checking on entities already encountered + int areagridmarknumber; + // mins/maxs passed to World_LinkEdict + vec3_t areamins, areamaxs; + + // PROTOCOL_QUAKE, PROTOCOL_QUAKEDP, PROTOCOL_NEHAHRAMOVIE, PROTOCOL_QUAKEWORLD + // baseline values + entity_state_t baseline; + + // LordHavoc: gross hack to make floating items still work + int suspendedinairflag; + + // cached position to avoid redundant SV_CheckWaterTransition calls on monsters + qboolean waterposition_forceupdate; // force an update on this entity (set by SV_PushMove code for moving water entities) + vec3_t waterposition_origin; // updates whenever this changes + + // used by PushMove to keep track of where objects were before they were + // moved, in case they need to be moved back + vec3_t moved_from; + vec3_t moved_fromangles; + + framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS]; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + skeleton_t skeleton; + + // physics parameters + qboolean ode_physics; + void *ode_body; + void *ode_geom; + void *ode_joint; + float *ode_vertex3f; + int *ode_element3i; + int ode_numvertices; + int ode_numtriangles; + edict_odefunc_t *ode_func; + vec3_t ode_mins; + vec3_t ode_maxs; + vec3_t ode_scale; + vec_t ode_mass; + float ode_friction; + vec3_t ode_origin; + vec3_t ode_velocity; + vec3_t ode_angles; + vec3_t ode_avelocity; + qboolean ode_gravity; + int ode_modelindex; + vec_t ode_movelimit; // smallest component of (maxs[]-mins[]) + matrix4x4_t ode_offsetmatrix; + matrix4x4_t ode_offsetimatrix; + int ode_joint_type; + int ode_joint_enemy; + int ode_joint_aiment; + vec3_t ode_joint_origin; // joint anchor + vec3_t ode_joint_angles; // joint axis + vec3_t ode_joint_velocity; // second joint axis + vec3_t ode_joint_movedir; // parameters + void *ode_massbuf; +} +edict_engineprivate_t; + +#endif diff --git a/app/jni/progsvm.h b/app/jni/progsvm.h new file mode 100644 index 0000000..9ca932b --- /dev/null +++ b/app/jni/progsvm.h @@ -0,0 +1,886 @@ +/* +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 is a try to make the vm more generic, it is mainly based on the progs.h file. +For the license refer to progs.h. + +Generic means, less as possible hard-coded links with the other parts of the engine. +This means no edict_engineprivate struct usage, etc. +The code uses void pointers instead. +*/ + +#ifndef PROGSVM_H +#define PROGSVM_H + +#include "pr_comp.h" // defs shared with qcc +#include "progdefs.h" // generated by program cdefs +#include "clprogdefs.h" // generated by program cdefs + +#ifndef DP_SMALLMEMORY +//#define PROFILING +#endif + +typedef struct prvm_stack_s +{ + int s; + mfunction_t *f; + double tprofile_acc; + double profile_acc; + double builtinsprofile_acc; +} prvm_stack_t; + + +typedef union prvm_eval_s +{ + prvm_int_t string; + prvm_vec_t _float; + prvm_vec_t vector[3]; + prvm_int_t function; + prvm_int_t ivector[3]; + prvm_int_t _int; + prvm_int_t edict; +} prvm_eval_t; + +typedef struct prvm_required_field_s +{ + int type; + const char *name; +} prvm_required_field_t; + + +// AK: I dont call it engine private cause it doesnt really belongs to the engine +// it belongs to prvm. +typedef struct prvm_edict_private_s +{ + qboolean free; + float freetime; + int mark; // used during leaktest (0 = unref, >0 = referenced); special values during server physics: +#define PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN -1 +#define PRVM_EDICT_MARK_SETORIGIN_CAUGHT -2 + const char *allocation_origin; +} prvm_edict_private_t; + +typedef struct prvm_edict_s +{ + // engine-private fields (stored in dynamically resized array) + //edict_engineprivate_t *e; + union + { + prvm_edict_private_t *required; + prvm_vec_t *fp; + prvm_int_t *ip; + // FIXME: this server pointer really means world, not server + // (it is used by both server qc and client qc, but not menu qc) + edict_engineprivate_t *server; + // add other private structs as you desire + // new structs have to start with the elements of prvm_edit_private_t + // e.g. a new struct has to either look like this: + // typedef struct server_edict_private_s { + // prvm_edict_private_t base; + // vec3_t moved_from; + // vec3_t moved_fromangles; + // ... } server_edict_private_t; + // or: + // typedef struct server_edict_private_s { + // qboolean free; + // float freetime; + // vec3_t moved_from; + // vec3_t moved_fromangles; + // ... } server_edict_private_t; + // However, the first one should be preferred. + } priv; + // QuakeC fields (stored in dynamically resized array) + union + { + prvm_vec_t *fp; + prvm_int_t *ip; +// entvars_t *server; +// cl_entvars_t *client; + } fields; +} prvm_edict_t; + +#define VMPOLYGONS_MAXPOINTS 64 + +typedef struct vmpolygons_triangle_s +{ + rtexture_t *texture; + int drawflag; + qboolean hasalpha; + unsigned short elements[3]; +} vmpolygons_triangle_t; + +typedef struct vmpolygons_s +{ + mempool_t *pool; + qboolean initialized; + + int max_vertices; + int num_vertices; + float *data_vertex3f; + float *data_color4f; + float *data_texcoord2f; + + int max_triangles; + int num_triangles; + vmpolygons_triangle_t *data_triangles; + unsigned short *data_sortedelement3s; + + qboolean begin_active; + int begin_draw2d; + rtexture_t *begin_texture; + int begin_drawflag; + int begin_vertices; + float begin_vertex[VMPOLYGONS_MAXPOINTS][3]; + float begin_color[VMPOLYGONS_MAXPOINTS][4]; + float begin_texcoord[VMPOLYGONS_MAXPOINTS][2]; + qboolean begin_texture_hasalpha; +} vmpolygons_t; + +extern prvm_eval_t prvm_badvalue; + +#define PRVM_alledictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_alledictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_alledictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_alledictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_alledictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_allglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_allglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_allglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_allglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_allglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_allfunction(funcname) (prog->funcoffsets.funcname) + +#define PRVM_drawedictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_drawedictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_drawedictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_drawedictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_drawedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_drawglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_drawglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_drawglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_drawglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_drawglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_drawfunction(funcname) (prog->funcoffsets.funcname) + +#define PRVM_gameedictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_gameedictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_gameedictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_gameedictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_gameedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_gameglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_gameglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_gameglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_gameglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_gameglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_gamefunction(funcname) (prog->funcoffsets.funcname) + +#define PRVM_serveredictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_serveredictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_serveredictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_serveredictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_serveredictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_serverglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_serverglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_serverglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_serverglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_serverglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_serverfunction(funcname) (prog->funcoffsets.funcname) + +#define PRVM_clientedictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_clientedictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_clientedictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_clientedictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_clientedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_clientglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_clientglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_clientglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_clientglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_clientglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_clientfunction(funcname) (prog->funcoffsets.funcname) + +#define PRVM_menuedictfloat(ed, fieldname) (PRVM_EDICTFIELDFLOAT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_menuedictvector(ed, fieldname) (PRVM_EDICTFIELDVECTOR(ed, prog->fieldoffsets.fieldname)) +#define PRVM_menuedictstring(ed, fieldname) (PRVM_EDICTFIELDSTRING(ed, prog->fieldoffsets.fieldname)) +#define PRVM_menuedictedict(ed, fieldname) (PRVM_EDICTFIELDEDICT(ed, prog->fieldoffsets.fieldname)) +#define PRVM_menuedictfunction(ed, fieldname) (PRVM_EDICTFIELDFUNCTION(ed, prog->fieldoffsets.fieldname)) +#define PRVM_menuglobalfloat(fieldname) (PRVM_GLOBALFIELDFLOAT(prog->globaloffsets.fieldname)) +#define PRVM_menuglobalvector(fieldname) (PRVM_GLOBALFIELDVECTOR(prog->globaloffsets.fieldname)) +#define PRVM_menuglobalstring(fieldname) (PRVM_GLOBALFIELDSTRING(prog->globaloffsets.fieldname)) +#define PRVM_menuglobaledict(fieldname) (PRVM_GLOBALFIELDEDICT(prog->globaloffsets.fieldname)) +#define PRVM_menuglobalfunction(fieldname) (PRVM_GLOBALFIELDFUNCTION(prog->globaloffsets.fieldname)) +#define PRVM_menufunction(funcname) (prog->funcoffsets.funcname) + +#if 1 +#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((fieldoffset) < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)((ed)->fields.fp + (fieldoffset))) +#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->_float) +#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->vector) +#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->string) +#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->edict) +#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (PRVM_EDICTFIELDVALUE(ed, fieldoffset)->function) +#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((fieldoffset) < 0 ? Con_Printf("Invalid fieldoffset at %s:%i\n", __FILE__, __LINE__), &prvm_badvalue : (prvm_eval_t *)(prog->globals.fp + (fieldoffset))) +#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->_float) +#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->vector) +#define PRVM_GLOBALFIELDSTRING(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->string) +#define PRVM_GLOBALFIELDEDICT(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->edict) +#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (PRVM_GLOBALFIELDVALUE(fieldoffset)->function) +#else +#define PRVM_EDICTFIELDVALUE(ed, fieldoffset) ((prvm_eval_t *)(ed->fields.fp + fieldoffset)) +#define PRVM_EDICTFIELDFLOAT(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->_float) +#define PRVM_EDICTFIELDVECTOR(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->vector) +#define PRVM_EDICTFIELDSTRING(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->string) +#define PRVM_EDICTFIELDEDICT(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->edict) +#define PRVM_EDICTFIELDFUNCTION(ed, fieldoffset) (((prvm_eval_t *)(ed->fields.fp + fieldoffset))->function) +#define PRVM_GLOBALFIELDVALUE(fieldoffset) ((prvm_eval_t *)(prog->globals.fp + fieldoffset)) +#define PRVM_GLOBALFIELDFLOAT(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->_float) +#define PRVM_GLOBALFIELDVECTOR(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->vector) +#define PRVM_GLOBALFIELDSTRING(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->string) +#define PRVM_GLOBALFIELDEDICT(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->edict) +#define PRVM_GLOBALFIELDFUNCTION(fieldoffset) (((prvm_eval_t *)(prog->globals.fp + fieldoffset))->function) +#endif + +//============================================================================ +#define PRVM_OP_STATE 1 + +#ifdef DP_SMALLMEMORY +#define PRVM_MAX_STACK_DEPTH 128 +#define PRVM_LOCALSTACK_SIZE 2048 + +#define PRVM_MAX_OPENFILES 16 +#define PRVM_MAX_OPENSEARCHES 8 +#else +#define PRVM_MAX_STACK_DEPTH 1024 +#define PRVM_LOCALSTACK_SIZE 16384 + +#define PRVM_MAX_OPENFILES 256 +#define PRVM_MAX_OPENSEARCHES 128 +#endif + +struct prvm_prog_s; +typedef void (*prvm_builtin_t) (struct prvm_prog_s *prog); + +// NOTE: field offsets use -1 for NULL +typedef struct prvm_prog_fieldoffsets_s +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) int x; +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +} +prvm_prog_fieldoffsets_t; + +// NOTE: global offsets use -1 for NULL +typedef struct prvm_prog_globaloffsets_s +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) int x; +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +} +prvm_prog_globaloffsets_t; + +// NOTE: function offsets use 0 for NULL +typedef struct prvm_prog_funcoffsets_s +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) int x; +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +} +prvm_prog_funcoffsets_t; + +// stringbuffer flags +#define STRINGBUFFER_SAVED 1 // saved in savegames +#define STRINGBUFFER_QCFLAGS 1 // allowed to be set by QC +#define STRINGBUFFER_TEMP 128 // internal use ONLY +typedef struct prvm_stringbuffer_s +{ + int max_strings; + int num_strings; + char **strings; + const char *origin; + unsigned char flags; +} +prvm_stringbuffer_t; + +// [INIT] variables flagged with this token can be initialized by 'you' +// NOTE: external code has to create and free the mempools but everything else is done by prvm ! +typedef struct prvm_prog_s +{ + double starttime; // system time when PRVM_Prog_Load was called + double profiletime; // system time when last PRVM_CallProfile was called (or PRVM_Prog_Load initially) + unsigned int id; // increasing unique id of progs instance + mfunction_t *functions; + char *strings; + int stringssize; + ddef_t *fielddefs; + ddef_t *globaldefs; + mstatement_t *statements; + int entityfields; // number of vec_t fields in progs (some variables are 3) + int entityfieldsarea; // LordHavoc: equal to max_edicts * entityfields (for bounds checking) + + // loaded values from the disk format + int progs_version; + int progs_crc; + int progs_numstatements; + int progs_numglobaldefs; + int progs_numfielddefs; + int progs_numfunctions; + int progs_numstrings; + int progs_numglobals; + int progs_entityfields; + + // real values in memory (some modified by loader) + int numstatements; + int numglobaldefs; + int numfielddefs; + int numfunctions; + int numstrings; + int numglobals; + + int *statement_linenums; // NULL if not available + + double *statement_profile; // only incremented if prvm_statementprofiling is on + + union { + prvm_vec_t *fp; + prvm_int_t *ip; +// globalvars_t *server; +// cl_globalvars_t *client; + } globals; + + int maxknownstrings; + int numknownstrings; + // this is updated whenever a string is removed or added + // (simple optimization of the free string search) + int firstfreeknownstring; + const char **knownstrings; + unsigned char *knownstrings_freeable; + const char **knownstrings_origin; + const char ***stringshash; + + memexpandablearray_t stringbuffersarray; + + // all memory allocations related to this vm_prog (code, edicts, strings) + mempool_t *progs_mempool; // [INIT] + + prvm_builtin_t *builtins; // [INIT] + int numbuiltins; // [INIT] + + int argc; + + int trace; + int break_statement; + int break_stack_index; + int watch_global; + etype_t watch_global_type; + prvm_eval_t watch_global_value; + int watch_edict; + int watch_field; + etype_t watch_field_type; + prvm_eval_t watch_edictfield_value; + + mfunction_t *xfunction; + int xstatement; + + // stacktrace writes into stack[MAX_STACK_DEPTH] + // thus increase the array, so depth wont be overwritten + prvm_stack_t stack[PRVM_MAX_STACK_DEPTH+1]; + int depth; + + prvm_int_t localstack[PRVM_LOCALSTACK_SIZE]; + int localstack_used; + + unsigned short filecrc; + + //============================================================================ + // until this point everything also exists (with the pr_ prefix) in the old vm + + qfile_t *openfiles[PRVM_MAX_OPENFILES]; + const char * openfiles_origin[PRVM_MAX_OPENFILES]; + fssearch_t *opensearches[PRVM_MAX_OPENSEARCHES]; + const char * opensearches_origin[PRVM_MAX_OPENSEARCHES]; + skeleton_t *skeletons[MAX_EDICTS]; + + // buffer for storing all tempstrings created during one invocation of ExecuteProgram + sizebuf_t tempstringsbuf; + + // LordHavoc: moved this here to clean up things that relied on prvm_prog_list too much + // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions? + vmpolygons_t vmpolygons; + + // copies of some vars that were former read from sv + int num_edicts; + // number of edicts for which space has been (should be) allocated + int max_edicts; // [INIT] + // used instead of the constant MAX_EDICTS + int limit_edicts; // [INIT] + + // number of reserved edicts (allocated from 1) + int reserved_edicts; // [INIT] + + prvm_edict_t *edicts; + prvm_vec_t *edictsfields; + void *edictprivate; + + // size of the engine private struct + int edictprivate_size; // [INIT] + + prvm_prog_fieldoffsets_t fieldoffsets; + prvm_prog_globaloffsets_t globaloffsets; + prvm_prog_funcoffsets_t funcoffsets; + + // allow writing to world entity fields, this is set by server init and + // cleared before first server frame + qboolean allowworldwrites; + + // name of the prog, e.g. "Server", "Client" or "Menu" (used for text output) + const char *name; // [INIT] + + // flag - used to store general flags like PRVM_GE_SELF, etc. + int flag; + + const char *extensionstring; // [INIT] + + qboolean loadintoworld; // [INIT] + + // used to indicate whether a prog is loaded + qboolean loaded; + qboolean leaktest_active; + + // translation buffer (only needs to be freed on unloading progs, type is private to prvm_edict.c) + void *po; + + // printed together with backtraces + const char *statestring; + +// prvm_builtin_mem_t *mem_list; + +// now passed as parameter of PRVM_LoadProgs +// char **required_func; +// int numrequiredfunc; + + //============================================================================ + + ddef_t *self; // if self != 0 then there is a global self + + //============================================================================ + // function pointers + + void (*begin_increase_edicts)(struct prvm_prog_s *prog); // [INIT] used by PRVM_MEM_Increase_Edicts + void (*end_increase_edicts)(struct prvm_prog_s *prog); // [INIT] + + void (*init_edict)(struct prvm_prog_s *prog, prvm_edict_t *edict); // [INIT] used by PRVM_ED_ClearEdict + void (*free_edict)(struct prvm_prog_s *prog, prvm_edict_t *ed); // [INIT] used by PRVM_ED_Free + + void (*count_edicts)(struct prvm_prog_s *prog); // [INIT] used by PRVM_ED_Count_f + + qboolean (*load_edict)(struct prvm_prog_s *prog, prvm_edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile + + void (*init_cmd)(struct prvm_prog_s *prog); // [INIT] used by PRVM_InitProg + void (*reset_cmd)(struct prvm_prog_s *prog); // [INIT] used by PRVM_ResetProg + + void (*error_cmd)(const char *format, ...) DP_FUNC_PRINTF(1); // [INIT] + + void (*ExecuteProgram)(struct prvm_prog_s *prog, func_t fnum, const char *errormessage); // pointer to one of the *VM_ExecuteProgram functions +} prvm_prog_t; + +typedef enum prvm_progindex_e +{ + PRVM_PROG_SERVER, + PRVM_PROG_CLIENT, + PRVM_PROG_MENU, + PRVM_PROG_MAX +} +prvm_progindex_t; + +extern prvm_prog_t prvm_prog_list[PRVM_PROG_MAX]; +prvm_prog_t *PRVM_ProgFromString(const char *str); +prvm_prog_t *PRVM_FriendlyProgFromString(const char *str); // for console commands (prints error if name unknown and returns NULL, prints error if prog not loaded and returns NULL) +#define PRVM_GetProg(n) (&prvm_prog_list[(n)]) +#define PRVM_ProgLoaded(n) (PRVM_GetProg(n)->loaded) +#define SVVM_prog (&prvm_prog_list[PRVM_PROG_SERVER]) +#define CLVM_prog (&prvm_prog_list[PRVM_PROG_CLIENT]) +#define MVM_prog (&prvm_prog_list[PRVM_PROG_MENU]) + +//============================================================================ +// prvm_cmds part + +extern prvm_builtin_t vm_sv_builtins[]; +extern prvm_builtin_t vm_cl_builtins[]; +extern prvm_builtin_t vm_m_builtins[]; + +extern const int vm_sv_numbuiltins; +extern const int vm_cl_numbuiltins; +extern const int vm_m_numbuiltins; + +extern const char * vm_sv_extensions; // client also uses this +extern const char * vm_m_extensions; + +void SVVM_init_cmd(prvm_prog_t *prog); +void SVVM_reset_cmd(prvm_prog_t *prog); + +void CLVM_init_cmd(prvm_prog_t *prog); +void CLVM_reset_cmd(prvm_prog_t *prog); + +void MVM_init_cmd(prvm_prog_t *prog); +void MVM_reset_cmd(prvm_prog_t *prog); + +void VM_Cmd_Init(prvm_prog_t *prog); +void VM_Cmd_Reset(prvm_prog_t *prog); +//============================================================================ + +void PRVM_Init (void); + +#ifdef PROFILING +void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage); +void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage); +void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage); +#else +#define SVVM_ExecuteProgram PRVM_ExecuteProgram +#define CLVM_ExecuteProgram PRVM_ExecuteProgram +#define MVM_ExecuteProgram PRVM_ExecuteProgram +void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage); +#endif + +#define PRVM_Alloc(buffersize) Mem_Alloc(prog->progs_mempool, buffersize) +#define PRVM_Free(buffer) Mem_Free(buffer) + +void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby); +void PRVM_Profile_f (void); +void PRVM_ChildProfile_f (void); +void PRVM_CallProfile_f (void); +void PRVM_PrintFunction_f (void); + +void PRVM_PrintState(prvm_prog_t *prog, int stack_index); +void PRVM_Crash(prvm_prog_t *prog); +void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize); +const char *PRVM_AllocationOrigin(prvm_prog_t *prog); + +ddef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name); +ddef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name); +mfunction_t *PRVM_ED_FindFunction(prvm_prog_t *prog, const char *name); + +int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *name); +int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *name); +func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *name); +#define PRVM_ED_FindFieldOffset_FromStruct(st, field) prog->fieldoffsets . field = ((int *)(&((st *)NULL)-> field ) - ((int *)NULL)) +#define PRVM_ED_FindGlobalOffset_FromStruct(st, field) prog->globaloffsets . field = ((int *)(&((st *)NULL)-> field ) - ((int *)NULL)) + +void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog); + +qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e); +prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog); +void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed); +void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e); + +void PRVM_PrintFunctionStatements(prvm_prog_t *prog, const char *name); +void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname); +void PRVM_ED_Write(prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed); +const char *PRVM_ED_ParseEdict(prvm_prog_t *prog, const char *data, prvm_edict_t *ent); + +void PRVM_ED_WriteGlobals(prvm_prog_t *prog, qfile_t *f); +void PRVM_ED_ParseGlobals(prvm_prog_t *prog, const char *data); + +void PRVM_ED_LoadFromFile(prvm_prog_t *prog, const char *data); + +unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline); +#define PRVM_EDICT(n) (((unsigned)(n) < (unsigned int)prog->max_edicts) ? (unsigned int)(n) : PRVM_EDICT_NUM_ERROR(prog, (unsigned int)(n), __FILE__, __LINE__)) +#define PRVM_EDICT_NUM(n) (prog->edicts + PRVM_EDICT(n)) + +//int NUM_FOR_EDICT_ERROR(prvm_edict_t *e); +#define PRVM_NUM_FOR_EDICT(e) ((int)((prvm_edict_t *)(e) - prog->edicts)) +//int PRVM_NUM_FOR_EDICT(prvm_edict_t *e); + +#define PRVM_NEXT_EDICT(e) ((e) + 1) + +#define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e)) +//int PRVM_EDICT_TO_PROG(prvm_edict_t *e); +#define PRVM_PROG_TO_EDICT(n) (PRVM_EDICT_NUM(n)) +//prvm_edict_t *PRVM_PROG_TO_EDICT(int n); + +//============================================================================ + +#define PRVM_G_FLOAT(o) (prog->globals.fp[o]) +#define PRVM_G_INT(o) (prog->globals.ip[o]) +#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(prog->globals.ip[o])) +#define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o)) +#define PRVM_G_VECTOR(o) (&prog->globals.fp[o]) +#define PRVM_G_STRING(o) (PRVM_GetString(prog, prog->globals.ip[o])) +//#define PRVM_G_FUNCTION(prog, o) (prog->globals.ip[o]) + +// FIXME: make these go away? +#define PRVM_E_FLOAT(e,o) (e->fields.fp[o]) +#define PRVM_E_INT(e,o) (e->fields.ip[o]) +//#define PRVM_E_VECTOR(e,o) (&(e->fields.fp[o])) +#define PRVM_E_STRING(e,o) (PRVM_GetString(prog, e->fields.ip[o])) + +extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to +// make the new vm mostly independent from the old one, thus if it's necessary, I copy everything + +void PRVM_Init_Exec(prvm_prog_t *prog); + +void PRVM_ED_PrintEdicts_f (void); +void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname); + +const char *PRVM_GetString(prvm_prog_t *prog, int num); +int PRVM_SetEngineString(prvm_prog_t *prog, const char *s); +const char *PRVM_ChangeEngineString(prvm_prog_t *prog, int i, const char *s); +int PRVM_SetTempString(prvm_prog_t *prog, const char *s); +int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer); +void PRVM_FreeString(prvm_prog_t *prog, int num); + +ddef_t *PRVM_ED_FieldAtOfs(prvm_prog_t *prog, int ofs); +qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash); +char *PRVM_UglyValueString(prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength); +char *PRVM_GlobalString(prvm_prog_t *prog, int ofs, char *line, size_t linelength); +char *PRVM_GlobalStringNoContents(prvm_prog_t *prog, int ofs, char *line, size_t linelength); + +//============================================================================ + +/* +Initializing a vm: +Call InitProg with the num +Set up the fields marked with [INIT] in the prog struct +Load a program with LoadProgs +*/ +// Load expects to be called right after Reset +void PRVM_Prog_Init(prvm_prog_t *prog); +void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global); +void PRVM_Prog_Reset(prvm_prog_t *prog); + +void PRVM_StackTrace(prvm_prog_t *prog); +void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text); +void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n); + +void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) DP_FUNC_PRINTF(2); + +void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed); +void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model, double curtime); +void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend); +void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed); + +#endif diff --git a/app/jni/protocol.c b/app/jni/protocol.c new file mode 100644 index 0000000..db2de2f --- /dev/null +++ b/app/jni/protocol.c @@ -0,0 +1,3387 @@ +#include "quakedef.h" + +#define ENTITYSIZEPROFILING_START(msg, num) \ + int entityprofiling_startsize = msg->cursize + +#define ENTITYSIZEPROFILING_END(msg, num) \ + if(developer_networkentities.integer >= 2) \ + { \ + prvm_edict_t *ed = prog->edicts + num; \ + Con_Printf("sent entity update of size %d for a %s\n", (msg->cursize - entityprofiling_startsize), PRVM_serveredictstring(ed, classname) ? PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)) : "(no classname)"); \ + } + +// this is 88 bytes (must match entity_state_t in protocol.h) +entity_state_t defaultstate = +{ + // ! means this is not sent to client + 0,//double time; // ! time this state was built (used on client for interpolation) + {0,0,0},//float netcenter[3]; // ! for network prioritization, this is the center of the bounding box (which may differ from the origin) + {0,0,0},//float origin[3]; + {0,0,0},//float angles[3]; + 0,//int effects; + 0,//unsigned int customizeentityforclient; // ! + 0,//unsigned short number; // entity number this state is for + 0,//unsigned short modelindex; + 0,//unsigned short frame; + 0,//unsigned short tagentity; + 0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light + 0,//unsigned short viewmodelforclient; // ! + 0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases + 0,//unsigned short nodrawtoclient; // ! + 0,//unsigned short drawonlytoclient; // ! + 0,//unsigned short traileffectnum; + {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1 + ACTIVE_NOT,//unsigned char active; // true if a valid state + 0,//unsigned char lightstyle; + 0,//unsigned char lightpflags; + 0,//unsigned char colormap; + 0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC + 255,//unsigned char alpha; + 16,//unsigned char scale; + 0,//unsigned char glowsize; + 254,//unsigned char glowcolor; + 0,//unsigned char flags; + 0,//unsigned char internaleffects; // INTEF_FLAG1QW and so on + 0,//unsigned char tagindex; + {32, 32, 32},//unsigned char colormod[3]; + {32, 32, 32},//unsigned char glowmod[3]; +}; + +// LordHavoc: I own protocol ranges 96, 97, 3500-3599 + +struct protocolversioninfo_s +{ + int number; + protocolversion_t version; + const char *name; +} +protocolversioninfo[] = +{ + { 3504, PROTOCOL_DARKPLACES7 , "DP7"}, + { 3503, PROTOCOL_DARKPLACES6 , "DP6"}, + { 3502, PROTOCOL_DARKPLACES5 , "DP5"}, + { 3501, PROTOCOL_DARKPLACES4 , "DP4"}, + { 3500, PROTOCOL_DARKPLACES3 , "DP3"}, + { 97, PROTOCOL_DARKPLACES2 , "DP2"}, + { 96, PROTOCOL_DARKPLACES1 , "DP1"}, + { 15, PROTOCOL_QUAKEDP , "QUAKEDP"}, + { 15, PROTOCOL_QUAKE , "QUAKE"}, + { 28, PROTOCOL_QUAKEWORLD , "QW"}, + { 250, PROTOCOL_NEHAHRAMOVIE, "NEHAHRAMOVIE"}, + {10000, PROTOCOL_NEHAHRABJP , "NEHAHRABJP"}, + {10001, PROTOCOL_NEHAHRABJP2 , "NEHAHRABJP2"}, + {10002, PROTOCOL_NEHAHRABJP3 , "NEHAHRABJP3"}, + { 0, PROTOCOL_UNKNOWN , NULL} +}; + +protocolversion_t Protocol_EnumForName(const char *s) +{ + int i; + for (i = 0;protocolversioninfo[i].name;i++) + if (!strcasecmp(s, protocolversioninfo[i].name)) + return protocolversioninfo[i].version; + return PROTOCOL_UNKNOWN; +} + +const char *Protocol_NameForEnum(protocolversion_t p) +{ + int i; + for (i = 0;protocolversioninfo[i].name;i++) + if (protocolversioninfo[i].version == p) + return protocolversioninfo[i].name; + return "UNKNOWN"; +} + +protocolversion_t Protocol_EnumForNumber(int n) +{ + int i; + for (i = 0;protocolversioninfo[i].name;i++) + if (protocolversioninfo[i].number == n) + return protocolversioninfo[i].version; + return PROTOCOL_UNKNOWN; +} + +int Protocol_NumberForEnum(protocolversion_t p) +{ + int i; + for (i = 0;protocolversioninfo[i].name;i++) + if (protocolversioninfo[i].version == p) + return protocolversioninfo[i].number; + return 0; +} + +void Protocol_Names(char *buffer, size_t buffersize) +{ + int i; + if (buffersize < 1) + return; + buffer[0] = 0; + for (i = 0;protocolversioninfo[i].name;i++) + { + if (i > 1) + strlcat(buffer, " ", buffersize); + strlcat(buffer, protocolversioninfo[i].name, buffersize); + } +} + +void EntityFrameQuake_ReadEntity(int bits) +{ + int num; + entity_t *ent; + entity_state_t s; + + if (bits & U_MOREBITS) + bits |= (MSG_ReadByte(&cl_message)<<8); + if ((bits & U_EXTEND1) && cls.protocol != PROTOCOL_NEHAHRAMOVIE) + { + bits |= MSG_ReadByte(&cl_message) << 16; + if (bits & U_EXTEND2) + bits |= MSG_ReadByte(&cl_message) << 24; + } + + if (bits & U_LONGENTITY) + num = (unsigned short) MSG_ReadShort(&cl_message); + else + num = MSG_ReadByte(&cl_message); + + if (num >= MAX_EDICTS) + Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)", num, MAX_EDICTS); + if (num < 1) + Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)", num); + + if (cl.num_entities <= num) + { + cl.num_entities = num + 1; + if (num >= cl.max_entities) + CL_ExpandEntities(num); + } + + ent = cl.entities + num; + + // note: this inherits the 'active' state of the baseline chosen + // (state_baseline is always active, state_current may not be active if + // the entity was missing in the last frame) + if (bits & U_DELTA) + s = ent->state_current; + else + { + s = ent->state_baseline; + s.active = ACTIVE_NETWORK; + } + + cl.isquakeentity[num] = true; + if (cl.lastquakeentity < num) + cl.lastquakeentity = num; + s.number = num; + s.time = cl.mtime[0]; + s.flags = 0; + if (bits & U_MODEL) + { + if (cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3) + s.modelindex = (unsigned short) MSG_ReadShort(&cl_message); + else + s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte(&cl_message); + } + if (bits & U_FRAME) s.frame = (s.frame & 0xFF00) | MSG_ReadByte(&cl_message); + if (bits & U_COLORMAP) s.colormap = MSG_ReadByte(&cl_message); + if (bits & U_SKIN) s.skin = MSG_ReadByte(&cl_message); + if (bits & U_EFFECTS) s.effects = (s.effects & 0xFF00) | MSG_ReadByte(&cl_message); + if (bits & U_ORIGIN1) s.origin[0] = MSG_ReadCoord(&cl_message, cls.protocol); + if (bits & U_ANGLE1) s.angles[0] = MSG_ReadAngle(&cl_message, cls.protocol); + if (bits & U_ORIGIN2) s.origin[1] = MSG_ReadCoord(&cl_message, cls.protocol); + if (bits & U_ANGLE2) s.angles[1] = MSG_ReadAngle(&cl_message, cls.protocol); + if (bits & U_ORIGIN3) s.origin[2] = MSG_ReadCoord(&cl_message, cls.protocol); + if (bits & U_ANGLE3) s.angles[2] = MSG_ReadAngle(&cl_message, cls.protocol); + if (bits & U_STEP) s.flags |= RENDER_STEP; + if (bits & U_ALPHA) s.alpha = MSG_ReadByte(&cl_message); + if (bits & U_SCALE) s.scale = MSG_ReadByte(&cl_message); + if (bits & U_EFFECTS2) s.effects = (s.effects & 0x00FF) | (MSG_ReadByte(&cl_message) << 8); + if (bits & U_GLOWSIZE) s.glowsize = MSG_ReadByte(&cl_message); + if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte(&cl_message); + if (bits & U_COLORMOD) {int c = MSG_ReadByte(&cl_message);s.colormod[0] = (unsigned char)(((c >> 5) & 7) * (32.0f / 7.0f));s.colormod[1] = (unsigned char)(((c >> 2) & 7) * (32.0f / 7.0f));s.colormod[2] = (unsigned char)((c & 3) * (32.0f / 3.0f));} + if (bits & U_GLOWTRAIL) s.flags |= RENDER_GLOWTRAIL; + if (bits & U_FRAME2) s.frame = (s.frame & 0x00FF) | (MSG_ReadByte(&cl_message) << 8); + if (bits & U_MODEL2) s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte(&cl_message) << 8); + if (bits & U_VIEWMODEL) s.flags |= RENDER_VIEWMODEL; + if (bits & U_EXTERIORMODEL) s.flags |= RENDER_EXTERIORMODEL; + + // LordHavoc: to allow playback of the Nehahra movie + if (cls.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1)) + { + // LordHavoc: evil format + int i = (int)MSG_ReadFloat(&cl_message); + int j = (int)(MSG_ReadFloat(&cl_message) * 255.0f); + if (i == 2) + { + i = (int)MSG_ReadFloat(&cl_message); + if (i) + s.effects |= EF_FULLBRIGHT; + } + if (j < 0) + s.alpha = 0; + else if (j == 0 || j >= 255) + s.alpha = 255; + else + s.alpha = j; + } + + ent->state_previous = ent->state_current; + ent->state_current = s; + if (ent->state_current.active == ACTIVE_NETWORK) + { + CL_MoveLerpEntityStates(ent); + cl.entities_active[ent->state_current.number] = true; + } + + if (cl_message.badread) + Host_Error("EntityFrameQuake_ReadEntity: read error"); +} + +void EntityFrameQuake_ISeeDeadEntities(void) +{ + int num, lastentity; + if (cl.lastquakeentity == 0) + return; + lastentity = cl.lastquakeentity; + cl.lastquakeentity = 0; + for (num = 0;num <= lastentity;num++) + { + if (cl.isquakeentity[num]) + { + if (cl.entities_active[num] && cl.entities[num].state_current.time == cl.mtime[0]) + { + cl.isquakeentity[num] = true; + cl.lastquakeentity = num; + } + else + { + cl.isquakeentity[num] = false; + cl.entities_active[num] = ACTIVE_NOT; + cl.entities[num].state_current = defaultstate; + cl.entities[num].state_current.number = num; + } + } + } +} + +// NOTE: this only works with DP5 protocol and upwards. For lower protocols +// (including QUAKE), no packet loss handling for CSQC is done, which makes +// CSQC basically useless. +// Always use the DP5 protocol, or a higher one, when using CSQC entities. +static void EntityFrameCSQC_LostAllFrames(client_t *client) +{ + prvm_prog_t *prog = SVVM_prog; + // mark ALL csqc entities as requiring a FULL resend! + // I know this is a bad workaround, but better than nothing. + int i, n; + prvm_edict_t *ed; + + n = client->csqcnumedicts; + for(i = 0; i < n; ++i) + { + if(client->csqcentityglobalhistory[i]) + { + ed = prog->edicts + i; + if (PRVM_serveredictfunction(ed, SendEntity)) + client->csqcentitysendflags[i] |= 0xFFFFFF; // FULL RESEND + else // if it was ever sent to that client as a CSQC entity + { + client->csqcentityscope[i] = 1; // REMOVE + client->csqcentitysendflags[i] |= 0xFFFFFF; + } + } + } +} +void EntityFrameCSQC_LostFrame(client_t *client, int framenum) +{ + // marks a frame as lost + int i, j; + qboolean valid; + int ringfirst, ringlast; + static int recoversendflags[MAX_EDICTS]; // client only + csqcentityframedb_t *d; + + if(client->csqcentityframe_lastreset < 0) + return; + if(framenum < client->csqcentityframe_lastreset) + return; // no action required, as we resent that data anyway + + // is our frame out of history? + ringfirst = client->csqcentityframehistory_next; // oldest entry + ringlast = (ringfirst + NUM_CSQCENTITYDB_FRAMES - 1) % NUM_CSQCENTITYDB_FRAMES; // most recently added entry + + valid = false; + + for(j = 0; j < NUM_CSQCENTITYDB_FRAMES; ++j) + { + d = &client->csqcentityframehistory[(ringfirst + j) % NUM_CSQCENTITYDB_FRAMES]; + if(d->framenum < 0) + continue; + if(d->framenum == framenum) + break; + else if(d->framenum < framenum) + valid = true; + } + if(j == NUM_CSQCENTITYDB_FRAMES) + { + if(valid) // got beaten, i.e. there is a frame < framenum + { + // a non-csqc frame got lost... great + return; + } + else + { + // a too old frame got lost... sorry, cannot handle this + Con_DPrintf("CSQC entity DB: lost a frame too early to do any handling (resending ALL)...\n"); + Con_DPrintf("Lost frame = %d\n", framenum); + Con_DPrintf("Entity DB = %d to %d\n", client->csqcentityframehistory[ringfirst].framenum, client->csqcentityframehistory[ringlast].framenum); + EntityFrameCSQC_LostAllFrames(client); + client->csqcentityframe_lastreset = -1; + } + return; + } + + // so j is the frame that got lost + // ringlast is the frame that we have to go to + ringfirst = (ringfirst + j) % NUM_CSQCENTITYDB_FRAMES; + if(ringlast < ringfirst) + ringlast += NUM_CSQCENTITYDB_FRAMES; + + memset(recoversendflags, 0, sizeof(recoversendflags)); + + for(j = ringfirst; j <= ringlast; ++j) + { + d = &client->csqcentityframehistory[j % NUM_CSQCENTITYDB_FRAMES]; + if(d->framenum < 0) + { + // deleted frame + } + else if(d->framenum < framenum) + { + // a frame in the past... should never happen + Con_Printf("CSQC entity DB encountered a frame from the past when recovering from PL...?\n"); + } + else if(d->framenum == framenum) + { + // handling the actually lost frame now + for(i = 0; i < d->num; ++i) + { + int sf = d->sendflags[i]; + int ent = d->entno[i]; + if(sf < 0) // remove + recoversendflags[ent] |= -1; // all bits, including sign + else if(sf > 0) + recoversendflags[ent] |= sf; + } + } + else + { + // handling the frames that followed it now + for(i = 0; i < d->num; ++i) + { + int sf = d->sendflags[i]; + int ent = d->entno[i]; + if(sf < 0) // remove + { + recoversendflags[ent] = 0; // no need to update, we got a more recent remove (and will fix it THEN) + break; // no flags left to remove... + } + else if(sf > 0) + recoversendflags[ent] &= ~sf; // no need to update these bits, we already got them later + } + } + } + + for(i = 0; i < client->csqcnumedicts; ++i) + { + if(recoversendflags[i] < 0) + { + // a remove got lost, then either send a remove or - if it was + // recreated later - a FULL update to make totally sure + client->csqcentityscope[i] = 1; + client->csqcentitysendflags[i] = 0xFFFFFF; + } + else + client->csqcentitysendflags[i] |= recoversendflags[i]; + } +} +static int EntityFrameCSQC_AllocFrame(client_t *client, int framenum) +{ + int ringfirst = client->csqcentityframehistory_next; // oldest entry + client->csqcentityframehistory_next += 1; + client->csqcentityframehistory_next %= NUM_CSQCENTITYDB_FRAMES; + client->csqcentityframehistory[ringfirst].framenum = framenum; + client->csqcentityframehistory[ringfirst].num = 0; + return ringfirst; +} +static void EntityFrameCSQC_DeallocFrame(client_t *client, int framenum) +{ + int ringfirst = client->csqcentityframehistory_next; // oldest entry + int ringlast = (ringfirst + NUM_CSQCENTITYDB_FRAMES - 1) % NUM_CSQCENTITYDB_FRAMES; // most recently added entry + if(framenum == client->csqcentityframehistory[ringlast].framenum) + { + client->csqcentityframehistory[ringlast].framenum = -1; + client->csqcentityframehistory[ringlast].num = 0; + client->csqcentityframehistory_next = ringlast; + } + else + Con_Printf("Trying to dealloc the wrong entity frame\n"); +} + +//[515]: we use only one array per-client for SendEntity feature +// TODO: add some handling for entity send priorities, to better deal with huge +// amounts of csqc networked entities +qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers, const unsigned short *numbers, int framenum) +{ + prvm_prog_t *prog = SVVM_prog; + int num, number, end, sendflags; + qboolean sectionstarted = false; + const unsigned short *n; + prvm_edict_t *ed; + client_t *client = svs.clients + sv.writeentitiestoclient_clientnumber; + int dbframe = EntityFrameCSQC_AllocFrame(client, framenum); + csqcentityframedb_t *db = &client->csqcentityframehistory[dbframe]; + + if(client->csqcentityframe_lastreset < 0) + client->csqcentityframe_lastreset = framenum; + + maxsize -= 24; // always fit in an empty svc_entities message (for packet loss detection!) + + // make sure there is enough room to store the svc_csqcentities byte, + // the terminator (0x0000) and at least one entity update + if (msg->cursize + 32 >= maxsize) + return false; + + if (client->csqcnumedicts < prog->num_edicts) + client->csqcnumedicts = prog->num_edicts; + + number = 1; + for (num = 0, n = numbers;num < numnumbers;num++, n++) + { + end = *n; + for (;number < end;number++) + { + if (client->csqcentityscope[number]) + { + client->csqcentityscope[number] = 1; + client->csqcentitysendflags[number] = 0xFFFFFF; + } + } + ed = prog->edicts + number; + if (PRVM_serveredictfunction(ed, SendEntity)) + client->csqcentityscope[number] = 2; + else if (client->csqcentityscope[number]) + { + client->csqcentityscope[number] = 1; + client->csqcentitysendflags[number] = 0xFFFFFF; + } + number++; + } + end = client->csqcnumedicts; + for (;number < end;number++) + { + if (client->csqcentityscope[number]) + { + client->csqcentityscope[number] = 1; + client->csqcentitysendflags[number] = 0xFFFFFF; + } + } + + /* + // mark all scope entities as remove + for (number = 1;number < client->csqcnumedicts;number++) + if (client->csqcentityscope[number]) + client->csqcentityscope[number] = 1; + // keep visible entities + for (i = 0, n = numbers;i < numnumbers;i++, n++) + { + number = *n; + ed = prog->edicts + number; + if (PRVM_serveredictfunction(ed, SendEntity)) + client->csqcentityscope[number] = 2; + } + */ + + // now try to emit the entity updates + // (FIXME: prioritize by distance?) + end = client->csqcnumedicts; + for (number = 1;number < end;number++) + { + if (!client->csqcentityscope[number]) + continue; + sendflags = client->csqcentitysendflags[number]; + if (!sendflags) + continue; + if(db->num >= NUM_CSQCENTITIES_PER_FRAME) + break; + ed = prog->edicts + number; + // entity scope is either update (2) or remove (1) + if (client->csqcentityscope[number] == 1) + { + // write a remove message + // first write the message identifier if needed + if(!sectionstarted) + { + sectionstarted = 1; + MSG_WriteByte(msg, svc_csqcentities); + } + // write the remove message + { + ENTITYSIZEPROFILING_START(msg, number); + MSG_WriteShort(msg, (unsigned short)number | 0x8000); + client->csqcentityscope[number] = 0; + client->csqcentitysendflags[number] = 0xFFFFFF; // resend completely if it becomes active again + db->entno[db->num] = number; + db->sendflags[db->num] = -1; + db->num += 1; + client->csqcentityglobalhistory[number] = 1; + ENTITYSIZEPROFILING_END(msg, number); + } + if (msg->cursize + 17 >= maxsize) + break; + } + else + { + // write an update + // save the cursize value in case we overflow and have to rollback + int oldcursize = msg->cursize; + client->csqcentityscope[number] = 1; + if (PRVM_serveredictfunction(ed, SendEntity)) + { + if(!sectionstarted) + MSG_WriteByte(msg, svc_csqcentities); + { + ENTITYSIZEPROFILING_START(msg, number); + MSG_WriteShort(msg, number); + msg->allowoverflow = true; + PRVM_G_INT(OFS_PARM0) = sv.writeentitiestoclient_cliententitynumber; + PRVM_G_FLOAT(OFS_PARM1) = sendflags; + PRVM_serverglobaledict(self) = number; + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, SendEntity), "Null SendEntity\n"); + msg->allowoverflow = false; + if(PRVM_G_FLOAT(OFS_RETURN) && msg->cursize + 2 <= maxsize) + { + // an update has been successfully written + client->csqcentitysendflags[number] = 0; + db->entno[db->num] = number; + db->sendflags[db->num] = sendflags; + db->num += 1; + client->csqcentityglobalhistory[number] = 1; + // and take note that we have begun the svc_csqcentities + // section of the packet + sectionstarted = 1; + ENTITYSIZEPROFILING_END(msg, number); + if (msg->cursize + 17 >= maxsize) + break; + continue; + } + } + } + // self.SendEntity returned false (or does not exist) or the + // update was too big for this packet - rollback the buffer to its + // state before the writes occurred, we'll try again next frame + msg->cursize = oldcursize; + msg->overflowed = false; + } + } + if (sectionstarted) + { + // write index 0 to end the update (0 is never used by real entities) + MSG_WriteShort(msg, 0); + } + + if(db->num == 0) + // if no single ent got added, remove the frame from the DB again, to allow + // for a larger history + EntityFrameCSQC_DeallocFrame(client, framenum); + + return sectionstarted; +} + +void Protocol_UpdateClientStats(const int *stats) +{ + int i; + // update the stats array and set deltabits for any changed stats + for (i = 0;i < MAX_CL_STATS;i++) + { + if (host_client->stats[i] != stats[i]) + { + host_client->statsdeltabits[i >> 3] |= 1 << (i & 7); + host_client->stats[i] = stats[i]; + } + } +} + +// only a few stats are within the 32 stat limit of Quake, and most of them +// are sent every frame in svc_clientdata messages, so we only send the +// remaining ones here +static const int sendquakestats[] = +{ +// quake did not send these secrets/monsters stats in this way, but doing so +// allows a mod to increase STAT_TOTALMONSTERS during the game, and ensures +// that STAT_SECRETS and STAT_MONSTERS are always correct (even if a client +// didn't receive an svc_foundsecret or svc_killedmonster), which may be most +// valuable if randomly seeking around in a demo +STAT_TOTALSECRETS, // never changes during game +STAT_TOTALMONSTERS, // changes in some mods +STAT_SECRETS, // this makes svc_foundsecret unnecessary +STAT_MONSTERS, // this makes svc_killedmonster unnecessary +STAT_VIEWHEIGHT, // sent just for FTEQW clients +STAT_VIEWZOOM, // this rarely changes +-1, +}; + +void Protocol_WriteStatsReliable(void) +{ + int i, j; + if (!host_client->netconnection) + return; + // detect changes in stats and write reliable messages + // this only deals with 32 stats because the older protocols which use + // this function can only cope with 32 stats, + // they also do not support svc_updatestatubyte which was introduced in + // DP6 protocol (except for QW) + for (j = 0;sendquakestats[j] >= 0;j++) + { + i = sendquakestats[j]; + // check if this bit is set + if (host_client->statsdeltabits[i >> 3] & (1 << (i & 7))) + { + host_client->statsdeltabits[i >> 3] -= (1 << (i & 7)); + // send the stat as a byte if possible + if (sv.protocol == PROTOCOL_QUAKEWORLD) + { + if (host_client->stats[i] >= 0 && host_client->stats[i] < 256) + { + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestat); + MSG_WriteByte(&host_client->netconnection->message, i); + MSG_WriteByte(&host_client->netconnection->message, host_client->stats[i]); + } + else + { + MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestatlong); + MSG_WriteByte(&host_client->netconnection->message, i); + MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]); + } + } + else + { + // this could make use of svc_updatestatubyte in DP6 and later + // protocols but those protocols do not use this function + MSG_WriteByte(&host_client->netconnection->message, svc_updatestat); + MSG_WriteByte(&host_client->netconnection->message, i); + MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]); + } + } + } +} + + +qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t **states) +{ + prvm_prog_t *prog = SVVM_prog; + const entity_state_t *s; + entity_state_t baseline; + int i, bits; + sizebuf_t buf; + unsigned char data[128]; + qboolean success = false; + + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + for (i = 0;i < numstates;i++) + { + ENTITYSIZEPROFILING_START(msg, states[i]->number); + s = states[i]; + if(PRVM_serveredictfunction((&prog->edicts[s->number]), SendEntity)) + continue; + + // prepare the buffer + SZ_Clear(&buf); + +// send an update + bits = 0; + if (s->number >= 256) + bits |= U_LONGENTITY; + if (s->flags & RENDER_STEP) + bits |= U_STEP; + if (s->flags & RENDER_VIEWMODEL) + bits |= U_VIEWMODEL; + if (s->flags & RENDER_GLOWTRAIL) + bits |= U_GLOWTRAIL; + if (s->flags & RENDER_EXTERIORMODEL) + bits |= U_EXTERIORMODEL; + + // LordHavoc: old stuff, but rewritten to have more exact tolerances + baseline = prog->edicts[s->number].priv.server->baseline; + if (baseline.origin[0] != s->origin[0]) + bits |= U_ORIGIN1; + if (baseline.origin[1] != s->origin[1]) + bits |= U_ORIGIN2; + if (baseline.origin[2] != s->origin[2]) + bits |= U_ORIGIN3; + if (baseline.angles[0] != s->angles[0]) + bits |= U_ANGLE1; + if (baseline.angles[1] != s->angles[1]) + bits |= U_ANGLE2; + if (baseline.angles[2] != s->angles[2]) + bits |= U_ANGLE3; + if (baseline.colormap != s->colormap) + bits |= U_COLORMAP; + if (baseline.skin != s->skin) + bits |= U_SKIN; + if (baseline.frame != s->frame) + { + bits |= U_FRAME; + if (s->frame & 0xFF00) + bits |= U_FRAME2; + } + if (baseline.effects != s->effects) + { + bits |= U_EFFECTS; + if (s->effects & 0xFF00) + bits |= U_EFFECTS2; + } + if (baseline.modelindex != s->modelindex) + { + bits |= U_MODEL; + if ((s->modelindex & 0xFF00) && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3) + bits |= U_MODEL2; + } + if (baseline.alpha != s->alpha) + bits |= U_ALPHA; + if (baseline.scale != s->scale) + bits |= U_SCALE; + if (baseline.glowsize != s->glowsize) + bits |= U_GLOWSIZE; + if (baseline.glowcolor != s->glowcolor) + bits |= U_GLOWCOLOR; + if (!VectorCompare(baseline.colormod, s->colormod)) + bits |= U_COLORMOD; + + // if extensions are disabled, clear the relevant update flags + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_NEHAHRAMOVIE) + bits &= 0x7FFF; + if (sv.protocol == PROTOCOL_NEHAHRAMOVIE) + if (s->alpha != 255 || s->effects & EF_FULLBRIGHT) + bits |= U_EXTEND1; + + // write the message + if (bits >= 16777216) + bits |= U_EXTEND2; + if (bits >= 65536) + bits |= U_EXTEND1; + if (bits >= 256) + bits |= U_MOREBITS; + bits |= U_SIGNAL; + + MSG_WriteByte (&buf, bits); + if (bits & U_MOREBITS) MSG_WriteByte(&buf, bits>>8); + if (sv.protocol != PROTOCOL_NEHAHRAMOVIE) + { + if (bits & U_EXTEND1) MSG_WriteByte(&buf, bits>>16); + if (bits & U_EXTEND2) MSG_WriteByte(&buf, bits>>24); + } + if (bits & U_LONGENTITY) MSG_WriteShort(&buf, s->number); + else MSG_WriteByte(&buf, s->number); + + if (bits & U_MODEL) + { + if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + MSG_WriteShort(&buf, s->modelindex); + else + MSG_WriteByte(&buf, s->modelindex); + } + if (bits & U_FRAME) MSG_WriteByte(&buf, s->frame); + if (bits & U_COLORMAP) MSG_WriteByte(&buf, s->colormap); + if (bits & U_SKIN) MSG_WriteByte(&buf, s->skin); + if (bits & U_EFFECTS) MSG_WriteByte(&buf, s->effects); + if (bits & U_ORIGIN1) MSG_WriteCoord(&buf, s->origin[0], sv.protocol); + if (bits & U_ANGLE1) MSG_WriteAngle(&buf, s->angles[0], sv.protocol); + if (bits & U_ORIGIN2) MSG_WriteCoord(&buf, s->origin[1], sv.protocol); + if (bits & U_ANGLE2) MSG_WriteAngle(&buf, s->angles[1], sv.protocol); + if (bits & U_ORIGIN3) MSG_WriteCoord(&buf, s->origin[2], sv.protocol); + if (bits & U_ANGLE3) MSG_WriteAngle(&buf, s->angles[2], sv.protocol); + if (bits & U_ALPHA) MSG_WriteByte(&buf, s->alpha); + if (bits & U_SCALE) MSG_WriteByte(&buf, s->scale); + if (bits & U_EFFECTS2) MSG_WriteByte(&buf, s->effects >> 8); + if (bits & U_GLOWSIZE) MSG_WriteByte(&buf, s->glowsize); + if (bits & U_GLOWCOLOR) MSG_WriteByte(&buf, s->glowcolor); + if (bits & U_COLORMOD) {int c = ((int)bound(0, s->colormod[0] * (7.0f / 32.0f), 7) << 5) | ((int)bound(0, s->colormod[1] * (7.0f / 32.0f), 7) << 2) | ((int)bound(0, s->colormod[2] * (3.0f / 32.0f), 3) << 0);MSG_WriteByte(&buf, c);} + if (bits & U_FRAME2) MSG_WriteByte(&buf, s->frame >> 8); + if (bits & U_MODEL2) MSG_WriteByte(&buf, s->modelindex >> 8); + + // the nasty protocol + if ((bits & U_EXTEND1) && sv.protocol == PROTOCOL_NEHAHRAMOVIE) + { + if (s->effects & EF_FULLBRIGHT) + { + MSG_WriteFloat(&buf, 2); // QSG protocol version + MSG_WriteFloat(&buf, s->alpha <= 0 ? 0 : (s->alpha >= 255 ? 1 : s->alpha * (1.0f / 255.0f))); // alpha + MSG_WriteFloat(&buf, 1); // fullbright + } + else + { + MSG_WriteFloat(&buf, 1); // QSG protocol version + MSG_WriteFloat(&buf, s->alpha <= 0 ? 0 : (s->alpha >= 255 ? 1 : s->alpha * (1.0f / 255.0f))); // alpha + } + } + + // if the commit is full, we're done this frame + if (msg->cursize + buf.cursize > maxsize) + { + // next frame we will continue where we left off + break; + } + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); + success = true; + ENTITYSIZEPROFILING_END(msg, s->number); + } + return success; +} + +int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n) +{ + unsigned int bits; + // if o is not active, delta from default + if (o->active != ACTIVE_NETWORK) + o = &defaultstate; + bits = 0; + if (fabs(n->origin[0] - o->origin[0]) > (1.0f / 256.0f)) + bits |= E_ORIGIN1; + if (fabs(n->origin[1] - o->origin[1]) > (1.0f / 256.0f)) + bits |= E_ORIGIN2; + if (fabs(n->origin[2] - o->origin[2]) > (1.0f / 256.0f)) + bits |= E_ORIGIN3; + if ((unsigned char) (n->angles[0] * (256.0f / 360.0f)) != (unsigned char) (o->angles[0] * (256.0f / 360.0f))) + bits |= E_ANGLE1; + if ((unsigned char) (n->angles[1] * (256.0f / 360.0f)) != (unsigned char) (o->angles[1] * (256.0f / 360.0f))) + bits |= E_ANGLE2; + if ((unsigned char) (n->angles[2] * (256.0f / 360.0f)) != (unsigned char) (o->angles[2] * (256.0f / 360.0f))) + bits |= E_ANGLE3; + if ((n->modelindex ^ o->modelindex) & 0x00FF) + bits |= E_MODEL1; + if ((n->modelindex ^ o->modelindex) & 0xFF00) + bits |= E_MODEL2; + if ((n->frame ^ o->frame) & 0x00FF) + bits |= E_FRAME1; + if ((n->frame ^ o->frame) & 0xFF00) + bits |= E_FRAME2; + if ((n->effects ^ o->effects) & 0x00FF) + bits |= E_EFFECTS1; + if ((n->effects ^ o->effects) & 0xFF00) + bits |= E_EFFECTS2; + if (n->colormap != o->colormap) + bits |= E_COLORMAP; + if (n->skin != o->skin) + bits |= E_SKIN; + if (n->alpha != o->alpha) + bits |= E_ALPHA; + if (n->scale != o->scale) + bits |= E_SCALE; + if (n->glowsize != o->glowsize) + bits |= E_GLOWSIZE; + if (n->glowcolor != o->glowcolor) + bits |= E_GLOWCOLOR; + if (n->flags != o->flags) + bits |= E_FLAGS; + if (n->tagindex != o->tagindex || n->tagentity != o->tagentity) + bits |= E_TAGATTACHMENT; + if (n->light[0] != o->light[0] || n->light[1] != o->light[1] || n->light[2] != o->light[2] || n->light[3] != o->light[3]) + bits |= E_LIGHT; + if (n->lightstyle != o->lightstyle) + bits |= E_LIGHTSTYLE; + if (n->lightpflags != o->lightpflags) + bits |= E_LIGHTPFLAGS; + + if (bits) + { + if (bits & 0xFF000000) + bits |= 0x00800000; + if (bits & 0x00FF0000) + bits |= 0x00008000; + if (bits & 0x0000FF00) + bits |= 0x00000080; + } + return bits; +} + +void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits) +{ + MSG_WriteByte(msg, bits & 0xFF); + if (bits & 0x00000080) + { + MSG_WriteByte(msg, (bits >> 8) & 0xFF); + if (bits & 0x00008000) + { + MSG_WriteByte(msg, (bits >> 16) & 0xFF); + if (bits & 0x00800000) + MSG_WriteByte(msg, (bits >> 24) & 0xFF); + } + } +} + +void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits) +{ + if (sv.protocol == PROTOCOL_DARKPLACES2) + { + if (bits & E_ORIGIN1) + MSG_WriteCoord16i(msg, ent->origin[0]); + if (bits & E_ORIGIN2) + MSG_WriteCoord16i(msg, ent->origin[1]); + if (bits & E_ORIGIN3) + MSG_WriteCoord16i(msg, ent->origin[2]); + } + else + { + // LordHavoc: have to write flags first, as they can modify protocol + if (bits & E_FLAGS) + MSG_WriteByte(msg, ent->flags); + if (ent->flags & RENDER_LOWPRECISION) + { + if (bits & E_ORIGIN1) + MSG_WriteCoord16i(msg, ent->origin[0]); + if (bits & E_ORIGIN2) + MSG_WriteCoord16i(msg, ent->origin[1]); + if (bits & E_ORIGIN3) + MSG_WriteCoord16i(msg, ent->origin[2]); + } + else + { + if (bits & E_ORIGIN1) + MSG_WriteCoord32f(msg, ent->origin[0]); + if (bits & E_ORIGIN2) + MSG_WriteCoord32f(msg, ent->origin[1]); + if (bits & E_ORIGIN3) + MSG_WriteCoord32f(msg, ent->origin[2]); + } + } + if ((sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4) && (ent->flags & RENDER_LOWPRECISION)) + { + if (bits & E_ANGLE1) + MSG_WriteAngle8i(msg, ent->angles[0]); + if (bits & E_ANGLE2) + MSG_WriteAngle8i(msg, ent->angles[1]); + if (bits & E_ANGLE3) + MSG_WriteAngle8i(msg, ent->angles[2]); + } + else + { + if (bits & E_ANGLE1) + MSG_WriteAngle16i(msg, ent->angles[0]); + if (bits & E_ANGLE2) + MSG_WriteAngle16i(msg, ent->angles[1]); + if (bits & E_ANGLE3) + MSG_WriteAngle16i(msg, ent->angles[2]); + } + if (bits & E_MODEL1) + MSG_WriteByte(msg, ent->modelindex & 0xFF); + if (bits & E_MODEL2) + MSG_WriteByte(msg, (ent->modelindex >> 8) & 0xFF); + if (bits & E_FRAME1) + MSG_WriteByte(msg, ent->frame & 0xFF); + if (bits & E_FRAME2) + MSG_WriteByte(msg, (ent->frame >> 8) & 0xFF); + if (bits & E_EFFECTS1) + MSG_WriteByte(msg, ent->effects & 0xFF); + if (bits & E_EFFECTS2) + MSG_WriteByte(msg, (ent->effects >> 8) & 0xFF); + if (bits & E_COLORMAP) + MSG_WriteByte(msg, ent->colormap); + if (bits & E_SKIN) + MSG_WriteByte(msg, ent->skin); + if (bits & E_ALPHA) + MSG_WriteByte(msg, ent->alpha); + if (bits & E_SCALE) + MSG_WriteByte(msg, ent->scale); + if (bits & E_GLOWSIZE) + MSG_WriteByte(msg, ent->glowsize); + if (bits & E_GLOWCOLOR) + MSG_WriteByte(msg, ent->glowcolor); + if (sv.protocol == PROTOCOL_DARKPLACES2) + if (bits & E_FLAGS) + MSG_WriteByte(msg, ent->flags); + if (bits & E_TAGATTACHMENT) + { + MSG_WriteShort(msg, ent->tagentity); + MSG_WriteByte(msg, ent->tagindex); + } + if (bits & E_LIGHT) + { + MSG_WriteShort(msg, ent->light[0]); + MSG_WriteShort(msg, ent->light[1]); + MSG_WriteShort(msg, ent->light[2]); + MSG_WriteShort(msg, ent->light[3]); + } + if (bits & E_LIGHTSTYLE) + MSG_WriteByte(msg, ent->lightstyle); + if (bits & E_LIGHTPFLAGS) + MSG_WriteByte(msg, ent->lightpflags); +} + +void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta) +{ + prvm_prog_t *prog = SVVM_prog; + unsigned int bits; + ENTITYSIZEPROFILING_START(msg, ent->number); + if (ent->active == ACTIVE_NETWORK) + { + // entity is active, check for changes from the delta + if ((bits = EntityState_DeltaBits(delta, ent))) + { + // write the update number, bits, and fields + MSG_WriteShort(msg, ent->number); + EntityState_WriteExtendBits(msg, bits); + EntityState_WriteFields(ent, msg, bits); + } + } + else + { + // entity is inactive, check if the delta was active + if (delta->active == ACTIVE_NETWORK) + { + // write the remove number + MSG_WriteShort(msg, ent->number | 0x8000); + } + } + ENTITYSIZEPROFILING_END(msg, ent->number); +} + +int EntityState_ReadExtendBits(void) +{ + unsigned int bits; + bits = MSG_ReadByte(&cl_message); + if (bits & 0x00000080) + { + bits |= MSG_ReadByte(&cl_message) << 8; + if (bits & 0x00008000) + { + bits |= MSG_ReadByte(&cl_message) << 16; + if (bits & 0x00800000) + bits |= MSG_ReadByte(&cl_message) << 24; + } + } + return bits; +} + +void EntityState_ReadFields(entity_state_t *e, unsigned int bits) +{ + if (cls.protocol == PROTOCOL_DARKPLACES2) + { + if (bits & E_ORIGIN1) + e->origin[0] = MSG_ReadCoord16i(&cl_message); + if (bits & E_ORIGIN2) + e->origin[1] = MSG_ReadCoord16i(&cl_message); + if (bits & E_ORIGIN3) + e->origin[2] = MSG_ReadCoord16i(&cl_message); + } + else + { + if (bits & E_FLAGS) + e->flags = MSG_ReadByte(&cl_message); + if (e->flags & RENDER_LOWPRECISION) + { + if (bits & E_ORIGIN1) + e->origin[0] = MSG_ReadCoord16i(&cl_message); + if (bits & E_ORIGIN2) + e->origin[1] = MSG_ReadCoord16i(&cl_message); + if (bits & E_ORIGIN3) + e->origin[2] = MSG_ReadCoord16i(&cl_message); + } + else + { + if (bits & E_ORIGIN1) + e->origin[0] = MSG_ReadCoord32f(&cl_message); + if (bits & E_ORIGIN2) + e->origin[1] = MSG_ReadCoord32f(&cl_message); + if (bits & E_ORIGIN3) + e->origin[2] = MSG_ReadCoord32f(&cl_message); + } + } + if ((cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6) && !(e->flags & RENDER_LOWPRECISION)) + { + if (bits & E_ANGLE1) + e->angles[0] = MSG_ReadAngle16i(&cl_message); + if (bits & E_ANGLE2) + e->angles[1] = MSG_ReadAngle16i(&cl_message); + if (bits & E_ANGLE3) + e->angles[2] = MSG_ReadAngle16i(&cl_message); + } + else + { + if (bits & E_ANGLE1) + e->angles[0] = MSG_ReadAngle8i(&cl_message); + if (bits & E_ANGLE2) + e->angles[1] = MSG_ReadAngle8i(&cl_message); + if (bits & E_ANGLE3) + e->angles[2] = MSG_ReadAngle8i(&cl_message); + } + if (bits & E_MODEL1) + e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message); + if (bits & E_MODEL2) + e->modelindex = (e->modelindex & 0x00FF) | ((unsigned int) MSG_ReadByte(&cl_message) << 8); + if (bits & E_FRAME1) + e->frame = (e->frame & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message); + if (bits & E_FRAME2) + e->frame = (e->frame & 0x00FF) | ((unsigned int) MSG_ReadByte(&cl_message) << 8); + if (bits & E_EFFECTS1) + e->effects = (e->effects & 0xFF00) | (unsigned int) MSG_ReadByte(&cl_message); + if (bits & E_EFFECTS2) + e->effects = (e->effects & 0x00FF) | ((unsigned int) MSG_ReadByte(&cl_message) << 8); + if (bits & E_COLORMAP) + e->colormap = MSG_ReadByte(&cl_message); + if (bits & E_SKIN) + e->skin = MSG_ReadByte(&cl_message); + if (bits & E_ALPHA) + e->alpha = MSG_ReadByte(&cl_message); + if (bits & E_SCALE) + e->scale = MSG_ReadByte(&cl_message); + if (bits & E_GLOWSIZE) + e->glowsize = MSG_ReadByte(&cl_message); + if (bits & E_GLOWCOLOR) + e->glowcolor = MSG_ReadByte(&cl_message); + if (cls.protocol == PROTOCOL_DARKPLACES2) + if (bits & E_FLAGS) + e->flags = MSG_ReadByte(&cl_message); + if (bits & E_TAGATTACHMENT) + { + e->tagentity = (unsigned short) MSG_ReadShort(&cl_message); + e->tagindex = MSG_ReadByte(&cl_message); + } + if (bits & E_LIGHT) + { + e->light[0] = (unsigned short) MSG_ReadShort(&cl_message); + e->light[1] = (unsigned short) MSG_ReadShort(&cl_message); + e->light[2] = (unsigned short) MSG_ReadShort(&cl_message); + e->light[3] = (unsigned short) MSG_ReadShort(&cl_message); + } + if (bits & E_LIGHTSTYLE) + e->lightstyle = MSG_ReadByte(&cl_message); + if (bits & E_LIGHTPFLAGS) + e->lightpflags = MSG_ReadByte(&cl_message); + + if (developer_networkentities.integer >= 2) + { + Con_Printf("ReadFields e%i", e->number); + + if (bits & E_ORIGIN1) + Con_Printf(" E_ORIGIN1 %f", e->origin[0]); + if (bits & E_ORIGIN2) + Con_Printf(" E_ORIGIN2 %f", e->origin[1]); + if (bits & E_ORIGIN3) + Con_Printf(" E_ORIGIN3 %f", e->origin[2]); + if (bits & E_ANGLE1) + Con_Printf(" E_ANGLE1 %f", e->angles[0]); + if (bits & E_ANGLE2) + Con_Printf(" E_ANGLE2 %f", e->angles[1]); + if (bits & E_ANGLE3) + Con_Printf(" E_ANGLE3 %f", e->angles[2]); + if (bits & (E_MODEL1 | E_MODEL2)) + Con_Printf(" E_MODEL %i", e->modelindex); + + if (bits & (E_FRAME1 | E_FRAME2)) + Con_Printf(" E_FRAME %i", e->frame); + if (bits & (E_EFFECTS1 | E_EFFECTS2)) + Con_Printf(" E_EFFECTS %i", e->effects); + if (bits & E_ALPHA) + Con_Printf(" E_ALPHA %f", e->alpha / 255.0f); + if (bits & E_SCALE) + Con_Printf(" E_SCALE %f", e->scale / 16.0f); + if (bits & E_COLORMAP) + Con_Printf(" E_COLORMAP %i", e->colormap); + if (bits & E_SKIN) + Con_Printf(" E_SKIN %i", e->skin); + + if (bits & E_GLOWSIZE) + Con_Printf(" E_GLOWSIZE %i", e->glowsize * 4); + if (bits & E_GLOWCOLOR) + Con_Printf(" E_GLOWCOLOR %i", e->glowcolor); + + if (bits & E_LIGHT) + Con_Printf(" E_LIGHT %i:%i:%i:%i", e->light[0], e->light[1], e->light[2], e->light[3]); + if (bits & E_LIGHTPFLAGS) + Con_Printf(" E_LIGHTPFLAGS %i", e->lightpflags); + + if (bits & E_TAGATTACHMENT) + Con_Printf(" E_TAGATTACHMENT e%i:%i", e->tagentity, e->tagindex); + if (bits & E_LIGHTSTYLE) + Con_Printf(" E_LIGHTSTYLE %i", e->lightstyle); + Con_Print("\n"); + } +} + +// (client and server) allocates a new empty database +entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool) +{ + return (entityframe_database_t *)Mem_Alloc(mempool, sizeof(entityframe_database_t)); +} + +// (client and server) frees the database +void EntityFrame_FreeDatabase(entityframe_database_t *d) +{ + Mem_Free(d); +} + +// (server) clears the database to contain no frames (thus delta compression compresses against nothing) +void EntityFrame_ClearDatabase(entityframe_database_t *d) +{ + memset(d, 0, sizeof(*d)); +} + +// (server and client) removes frames older than 'frame' from database +void EntityFrame_AckFrame(entityframe_database_t *d, int frame) +{ + int i; + d->ackframenum = frame; + for (i = 0;i < d->numframes && d->frames[i].framenum < frame;i++); + // ignore outdated frame acks (out of order packets) + if (i == 0) + return; + d->numframes -= i; + // if some queue is left, slide it down to beginning of array + if (d->numframes) + memmove(&d->frames[0], &d->frames[i], sizeof(d->frames[0]) * d->numframes); +} + +// (server) clears frame, to prepare for adding entities +void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum) +{ + f->time = 0; + f->framenum = framenum; + f->numentities = 0; + if (eye == NULL) + VectorClear(f->eye); + else + VectorCopy(eye, f->eye); +} + +// (server and client) reads a frame from the database +void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f) +{ + int i, n; + EntityFrame_Clear(f, NULL, -1); + for (i = 0;i < d->numframes && d->frames[i].framenum < framenum;i++); + if (i < d->numframes && framenum == d->frames[i].framenum) + { + f->framenum = framenum; + f->numentities = d->frames[i].endentity - d->frames[i].firstentity; + n = MAX_ENTITY_DATABASE - (d->frames[i].firstentity % MAX_ENTITY_DATABASE); + if (n > f->numentities) + n = f->numentities; + memcpy(f->entitydata, d->entitydata + d->frames[i].firstentity % MAX_ENTITY_DATABASE, sizeof(*f->entitydata) * n); + if (f->numentities > n) + memcpy(f->entitydata + n, d->entitydata, sizeof(*f->entitydata) * (f->numentities - n)); + VectorCopy(d->eye, f->eye); + } +} + +// (client) adds a entity_frame to the database, for future reference +void EntityFrame_AddFrame_Client(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata) +{ + int n, e; + entity_frameinfo_t *info; + + VectorCopy(eye, d->eye); + + // figure out how many entity slots are used already + if (d->numframes) + { + n = d->frames[d->numframes - 1].endentity - d->frames[0].firstentity; + if (n + numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY) + { + // ran out of room, dump database + EntityFrame_ClearDatabase(d); + } + } + + info = &d->frames[d->numframes]; + info->framenum = framenum; + e = -1000; + // make sure we check the newly added frame as well, but we haven't incremented numframes yet + for (n = 0;n <= d->numframes;n++) + { + if (e >= d->frames[n].framenum) + { + if (e == framenum) + Con_Print("EntityFrame_AddFrame: tried to add out of sequence frame to database\n"); + else + Con_Print("EntityFrame_AddFrame: out of sequence frames in database\n"); + return; + } + e = d->frames[n].framenum; + } + // if database still has frames after that... + if (d->numframes) + info->firstentity = d->frames[d->numframes - 1].endentity; + else + info->firstentity = 0; + info->endentity = info->firstentity + numentities; + d->numframes++; + + n = info->firstentity % MAX_ENTITY_DATABASE; + e = MAX_ENTITY_DATABASE - n; + if (e > numentities) + e = numentities; + memcpy(d->entitydata + n, entitydata, sizeof(entity_state_t) * e); + if (numentities > e) + memcpy(d->entitydata, entitydata + e, sizeof(entity_state_t) * (numentities - e)); +} + +// (server) adds a entity_frame to the database, for future reference +void EntityFrame_AddFrame_Server(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t **entitydata) +{ + int n, e; + entity_frameinfo_t *info; + + VectorCopy(eye, d->eye); + + // figure out how many entity slots are used already + if (d->numframes) + { + n = d->frames[d->numframes - 1].endentity - d->frames[0].firstentity; + if (n + numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY) + { + // ran out of room, dump database + EntityFrame_ClearDatabase(d); + } + } + + info = &d->frames[d->numframes]; + info->framenum = framenum; + e = -1000; + // make sure we check the newly added frame as well, but we haven't incremented numframes yet + for (n = 0;n <= d->numframes;n++) + { + if (e >= d->frames[n].framenum) + { + if (e == framenum) + Con_Print("EntityFrame_AddFrame: tried to add out of sequence frame to database\n"); + else + Con_Print("EntityFrame_AddFrame: out of sequence frames in database\n"); + return; + } + e = d->frames[n].framenum; + } + // if database still has frames after that... + if (d->numframes) + info->firstentity = d->frames[d->numframes - 1].endentity; + else + info->firstentity = 0; + info->endentity = info->firstentity + numentities; + d->numframes++; + + n = info->firstentity % MAX_ENTITY_DATABASE; + e = MAX_ENTITY_DATABASE - n; + if (e > numentities) + e = numentities; + memcpy(d->entitydata + n, entitydata, sizeof(entity_state_t) * e); + if (numentities > e) + memcpy(d->entitydata, entitydata + e, sizeof(entity_state_t) * (numentities - e)); +} + +// (server) writes a frame to network stream +qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t **states, int viewentnum) +{ + prvm_prog_t *prog = SVVM_prog; + int i, onum, number; + entity_frame_t *o = &d->deltaframe; + const entity_state_t *ent, *delta; + vec3_t eye; + + d->latestframenum++; + + VectorClear(eye); + for (i = 0;i < numstates;i++) + { + ent = states[i]; + if (ent->number == viewentnum) + { + VectorSet(eye, ent->origin[0], ent->origin[1], ent->origin[2] + 22); + break; + } + } + + EntityFrame_AddFrame_Server(d, eye, d->latestframenum, numstates, states); + + EntityFrame_FetchFrame(d, d->ackframenum, o); + + MSG_WriteByte (msg, svc_entities); + MSG_WriteLong (msg, o->framenum); + MSG_WriteLong (msg, d->latestframenum); + MSG_WriteFloat (msg, eye[0]); + MSG_WriteFloat (msg, eye[1]); + MSG_WriteFloat (msg, eye[2]); + + onum = 0; + for (i = 0;i < numstates;i++) + { + ent = states[i]; + number = ent->number; + + if (PRVM_serveredictfunction((&prog->edicts[number]), SendEntity)) + continue; + for (;onum < o->numentities && o->entitydata[onum].number < number;onum++) + { + // write remove message + MSG_WriteShort(msg, o->entitydata[onum].number | 0x8000); + } + if (onum < o->numentities && (o->entitydata[onum].number == number)) + { + // delta from previous frame + delta = o->entitydata + onum; + // advance to next entity in delta frame + onum++; + } + else + { + // delta from defaults + delta = &defaultstate; + } + EntityState_WriteUpdate(ent, msg, delta); + } + for (;onum < o->numentities;onum++) + { + // write remove message + MSG_WriteShort(msg, o->entitydata[onum].number | 0x8000); + } + MSG_WriteShort(msg, 0xFFFF); + + return true; +} + +// (client) reads a frame from network stream +void EntityFrame_CL_ReadFrame(void) +{ + int i, number, removed; + entity_frame_t *f, *delta; + entity_state_t *e, *old, *oldend; + entity_t *ent; + entityframe_database_t *d; + if (!cl.entitydatabase) + cl.entitydatabase = EntityFrame_AllocDatabase(cls.levelmempool); + d = cl.entitydatabase; + f = &d->framedata; + delta = &d->deltaframe; + + EntityFrame_Clear(f, NULL, -1); + + // read the frame header info + f->time = cl.mtime[0]; + number = MSG_ReadLong(&cl_message); + f->framenum = MSG_ReadLong(&cl_message); + CL_NewFrameReceived(f->framenum); + f->eye[0] = MSG_ReadFloat(&cl_message); + f->eye[1] = MSG_ReadFloat(&cl_message); + f->eye[2] = MSG_ReadFloat(&cl_message); + EntityFrame_AckFrame(d, number); + EntityFrame_FetchFrame(d, number, delta); + old = delta->entitydata; + oldend = old + delta->numentities; + // read entities until we hit the magic 0xFFFF end tag + while ((number = (unsigned short) MSG_ReadShort(&cl_message)) != 0xFFFF && !cl_message.badread) + { + if (cl_message.badread) + Host_Error("EntityFrame_Read: read error"); + removed = number & 0x8000; + number &= 0x7FFF; + if (number >= MAX_EDICTS) + Host_Error("EntityFrame_Read: number (%i) >= MAX_EDICTS (%i)", number, MAX_EDICTS); + + // seek to entity, while copying any skipped entities (assume unchanged) + while (old < oldend && old->number < number) + { + if (f->numentities >= MAX_ENTITY_DATABASE) + Host_Error("EntityFrame_Read: entity list too big"); + f->entitydata[f->numentities] = *old++; + f->entitydata[f->numentities++].time = cl.mtime[0]; + } + if (removed) + { + if (old < oldend && old->number == number) + old++; + else + Con_Printf("EntityFrame_Read: REMOVE on unused entity %i\n", number); + } + else + { + if (f->numentities >= MAX_ENTITY_DATABASE) + Host_Error("EntityFrame_Read: entity list too big"); + + // reserve this slot + e = f->entitydata + f->numentities++; + + if (old < oldend && old->number == number) + { + // delta from old entity + *e = *old++; + } + else + { + // delta from defaults + *e = defaultstate; + } + + if (cl.num_entities <= number) + { + cl.num_entities = number + 1; + if (number >= cl.max_entities) + CL_ExpandEntities(number); + } + cl.entities_active[number] = true; + e->active = ACTIVE_NETWORK; + e->time = cl.mtime[0]; + e->number = number; + EntityState_ReadFields(e, EntityState_ReadExtendBits()); + } + } + while (old < oldend) + { + if (f->numentities >= MAX_ENTITY_DATABASE) + Host_Error("EntityFrame_Read: entity list too big"); + f->entitydata[f->numentities] = *old++; + f->entitydata[f->numentities++].time = cl.mtime[0]; + } + EntityFrame_AddFrame_Client(d, f->eye, f->framenum, f->numentities, f->entitydata); + + memset(cl.entities_active, 0, cl.num_entities * sizeof(unsigned char)); + number = 1; + for (i = 0;i < f->numentities;i++) + { + for (;number < f->entitydata[i].number && number < cl.num_entities;number++) + { + if (cl.entities_active[number]) + { + cl.entities_active[number] = false; + cl.entities[number].state_current.active = ACTIVE_NOT; + } + } + if (number >= cl.num_entities) + break; + // update the entity + ent = &cl.entities[number]; + ent->state_previous = ent->state_current; + ent->state_current = f->entitydata[i]; + CL_MoveLerpEntityStates(ent); + // the entity lives again... + cl.entities_active[number] = true; + number++; + } + for (;number < cl.num_entities;number++) + { + if (cl.entities_active[number]) + { + cl.entities_active[number] = false; + cl.entities[number].state_current.active = ACTIVE_NOT; + } + } +} + + +// (client) returns the frame number of the most recent frame recieved +int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d) +{ + if (d->numframes) + return d->frames[d->numframes - 1].framenum; + else + return -1; +} + + + + + + +entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number) +{ + if (d->maxreferenceentities <= number) + { + int oldmax = d->maxreferenceentities; + entity_state_t *oldentity = d->referenceentity; + d->maxreferenceentities = (number + 15) & ~7; + d->referenceentity = (entity_state_t *)Mem_Alloc(d->mempool, d->maxreferenceentities * sizeof(*d->referenceentity)); + if (oldentity) + { + memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity)); + Mem_Free(oldentity); + } + // clear the newly created entities + for (;oldmax < d->maxreferenceentities;oldmax++) + { + d->referenceentity[oldmax] = defaultstate; + d->referenceentity[oldmax].number = oldmax; + } + } + return d->referenceentity + number; +} + +void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s) +{ + // resize commit's entity list if full + if (d->currentcommit->maxentities <= d->currentcommit->numentities) + { + entity_state_t *oldentity = d->currentcommit->entity; + d->currentcommit->maxentities += 8; + d->currentcommit->entity = (entity_state_t *)Mem_Alloc(d->mempool, d->currentcommit->maxentities * sizeof(*d->currentcommit->entity)); + if (oldentity) + { + memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity)); + Mem_Free(oldentity); + } + } + d->currentcommit->entity[d->currentcommit->numentities++] = *s; +} + +entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool) +{ + entityframe4_database_t *d; + d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d)); + d->mempool = pool; + EntityFrame4_ResetDatabase(d); + return d; +} + +void EntityFrame4_FreeDatabase(entityframe4_database_t *d) +{ + int i; + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].entity) + Mem_Free(d->commit[i].entity); + if (d->referenceentity) + Mem_Free(d->referenceentity); + Mem_Free(d); +} + +void EntityFrame4_ResetDatabase(entityframe4_database_t *d) +{ + int i; + d->referenceframenum = -1; + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + d->commit[i].numentities = 0; + for (i = 0;i < d->maxreferenceentities;i++) + d->referenceentity[i] = defaultstate; +} + +int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode) +{ + int i, j, found; + entity_database4_commit_t *commit; + if (framenum == -1) + { + // reset reference, but leave commits alone + d->referenceframenum = -1; + for (i = 0;i < d->maxreferenceentities;i++) + d->referenceentity[i] = defaultstate; + // if this is the server, remove commits + for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++) + commit->numentities = 0; + found = true; + } + else if (d->referenceframenum == framenum) + found = true; + else + { + found = false; + for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++) + { + if (commit->numentities && commit->framenum <= framenum) + { + if (commit->framenum == framenum) + { + found = true; + d->referenceframenum = framenum; + if (developer_networkentities.integer >= 3) + { + for (j = 0;j < commit->numentities;j++) + { + entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number); + if (commit->entity[j].active != s->active) + { + if (commit->entity[j].active == ACTIVE_NETWORK) + Con_Printf("commit entity %i has become active (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex); + else + Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex); + } + *s = commit->entity[j]; + } + } + else + for (j = 0;j < commit->numentities;j++) + *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j]; + } + commit->numentities = 0; + } + } + } + if (developer_networkentities.integer >= 1) + { + Con_Printf("ack ref:%i database updated to: ref:%i commits:", framenum, d->referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].numentities) + Con_Printf(" %i", d->commit[i].framenum); + Con_Print("\n"); + } + return found; +} + +void EntityFrame4_CL_ReadFrame(void) +{ + int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false; + entity_state_t *s; + entityframe4_database_t *d; + if (!cl.entitydatabase4) + cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool); + d = cl.entitydatabase4; + // read the number of the frame this refers to + referenceframenum = MSG_ReadLong(&cl_message); + // read the number of this frame + framenum = MSG_ReadLong(&cl_message); + CL_NewFrameReceived(framenum); + // read the start number + enumber = (unsigned short) MSG_ReadShort(&cl_message); + if (developer_networkentities.integer >= 10) + { + Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].numentities) + Con_Printf(" %i", d->commit[i].framenum); + Con_Print("\n"); + } + if (!EntityFrame4_AckFrame(d, referenceframenum, false)) + { + Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n"); + skip = true; + } + d->currentcommit = NULL; + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + { + if (!d->commit[i].numentities) + { + d->currentcommit = d->commit + i; + d->currentcommit->framenum = framenum; + d->currentcommit->numentities = 0; + } + } + if (d->currentcommit == NULL) + { + Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum); + skip = true; + } + done = false; + while (!done && !cl_message.badread) + { + // read the number of the modified entity + // (gaps will be copied unmodified) + n = (unsigned short)MSG_ReadShort(&cl_message); + if (n == 0x8000) + { + // no more entities in this update, but we still need to copy the + // rest of the reference entities (final gap) + done = true; + // read end of range number, then process normally + n = (unsigned short)MSG_ReadShort(&cl_message); + } + // high bit means it's a remove message + cnumber = n & 0x7FFF; + // if this is a live entity we may need to expand the array + if (cl.num_entities <= cnumber && !(n & 0x8000)) + { + cl.num_entities = cnumber + 1; + if (cnumber >= cl.max_entities) + CL_ExpandEntities(cnumber); + } + // add one (the changed one) if not done + stopnumber = cnumber + !done; + // process entities in range from the last one to the changed one + for (;enumber < stopnumber;enumber++) + { + if (skip || enumber >= cl.num_entities) + { + if (enumber == cnumber && (n & 0x8000) == 0) + { + entity_state_t tempstate; + EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits()); + } + continue; + } + // slide the current into the previous slot + cl.entities[enumber].state_previous = cl.entities[enumber].state_current; + // copy a new current from reference database + cl.entities[enumber].state_current = *EntityFrame4_GetReferenceEntity(d, enumber); + s = &cl.entities[enumber].state_current; + // if this is the one to modify, read more data... + if (enumber == cnumber) + { + if (n & 0x8000) + { + // simply removed + if (developer_networkentities.integer >= 2) + Con_Printf("entity %i: remove\n", enumber); + *s = defaultstate; + } + else + { + // read the changes + if (developer_networkentities.integer >= 2) + Con_Printf("entity %i: update\n", enumber); + s->active = ACTIVE_NETWORK; + EntityState_ReadFields(s, EntityState_ReadExtendBits()); + } + } + else if (developer_networkentities.integer >= 4) + Con_Printf("entity %i: copy\n", enumber); + // set the cl.entities_active flag + cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK); + // set the update time + s->time = cl.mtime[0]; + // fix the number (it gets wiped occasionally by copying from defaultstate) + s->number = enumber; + // check if we need to update the lerp stuff + if (s->active == ACTIVE_NETWORK) + CL_MoveLerpEntityStates(&cl.entities[enumber]); + // add this to the commit entry whether it is modified or not + if (d->currentcommit) + EntityFrame4_AddCommitEntity(d, &cl.entities[enumber].state_current); + // print extra messages if desired + if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active) + { + if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK) + Con_Printf("entity #%i has become active\n", enumber); + else if (cl.entities[enumber].state_previous.active) + Con_Printf("entity #%i has become inactive\n", enumber); + } + } + } + d->currentcommit = NULL; + if (skip) + EntityFrame4_ResetDatabase(d); +} + +qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states) +{ + prvm_prog_t *prog = SVVM_prog; + const entity_state_t *e, *s; + entity_state_t inactiveentitystate; + int i, n, startnumber; + sizebuf_t buf; + unsigned char data[128]; + + // if there isn't enough space to accomplish anything, skip it + if (msg->cursize + 24 > maxsize) + return false; + + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (!d->commit[i].numentities) + break; + // if commit buffer full, just don't bother writing an update this frame + if (i == MAX_ENTITY_HISTORY) + return false; + d->currentcommit = d->commit + i; + + // this state's number gets played around with later + inactiveentitystate = defaultstate; + + d->currentcommit->numentities = 0; + d->currentcommit->framenum = ++d->latestframenumber; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, d->referenceframenum); + MSG_WriteLong(msg, d->currentcommit->framenum); + if (developer_networkentities.integer >= 10) + { + Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].numentities) + Con_Printf(" %i", d->commit[i].framenum); + Con_Print(")\n"); + } + if (d->currententitynumber >= prog->max_edicts) + startnumber = 1; + else + startnumber = bound(1, d->currententitynumber, prog->max_edicts - 1); + MSG_WriteShort(msg, startnumber); + // reset currententitynumber so if the loop does not break it we will + // start at beginning next frame (if it does break, it will set it) + d->currententitynumber = 1; + for (i = 0, n = startnumber;n < prog->max_edicts;n++) + { + if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity)) + continue; + // find the old state to delta from + e = EntityFrame4_GetReferenceEntity(d, n); + // prepare the buffer + SZ_Clear(&buf); + // entity exists, build an update (if empty there is no change) + // find the state in the list + for (;i < numstates && states[i]->number < n;i++); + // make the message + s = states[i]; + if (s->number == n) + { + // build the update + EntityState_WriteUpdate(s, &buf, e); + } + else + { + inactiveentitystate.number = n; + s = &inactiveentitystate; + if (e->active == ACTIVE_NETWORK) + { + // entity used to exist but doesn't anymore, send remove + MSG_WriteShort(&buf, n | 0x8000); + } + } + // if the commit is full, we're done this frame + if (msg->cursize + buf.cursize > maxsize - 4) + { + // next frame we will continue where we left off + break; + } + // add the entity to the commit + EntityFrame4_AddCommitEntity(d, s); + // if the message is empty, skip out now + if (buf.cursize) + { + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); + } + } + d->currententitynumber = n; + + // remove world message (invalid, and thus a good terminator) + MSG_WriteShort(msg, 0x8000); + // write the number of the end entity + MSG_WriteShort(msg, d->currententitynumber); + // just to be sure + d->currentcommit = NULL; + + return true; +} + + + + +entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool) +{ + int i; + entityframe5_database_t *d; + d = (entityframe5_database_t *)Mem_Alloc(pool, sizeof(*d)); + d->latestframenum = 0; + for (i = 0;i < d->maxedicts;i++) + d->states[i] = defaultstate; + return d; +} + +void EntityFrame5_FreeDatabase(entityframe5_database_t *d) +{ + // all the [maxedicts] memory is allocated at once, so there's only one + // thing to free + if (d->maxedicts) + Mem_Free(d->deltabits); + Mem_Free(d); +} + +static void EntityFrame5_ExpandEdicts(entityframe5_database_t *d, int newmax) +{ + if (d->maxedicts < newmax) + { + unsigned char *data; + int oldmaxedicts = d->maxedicts; + int *olddeltabits = d->deltabits; + unsigned char *oldpriorities = d->priorities; + int *oldupdateframenum = d->updateframenum; + entity_state_t *oldstates = d->states; + unsigned char *oldvisiblebits = d->visiblebits; + d->maxedicts = newmax; + data = (unsigned char *)Mem_Alloc(sv_mempool, d->maxedicts * sizeof(int) + d->maxedicts * sizeof(unsigned char) + d->maxedicts * sizeof(int) + d->maxedicts * sizeof(entity_state_t) + (d->maxedicts+7)/8 * sizeof(unsigned char)); + d->deltabits = (int *)data;data += d->maxedicts * sizeof(int); + d->priorities = (unsigned char *)data;data += d->maxedicts * sizeof(unsigned char); + d->updateframenum = (int *)data;data += d->maxedicts * sizeof(int); + d->states = (entity_state_t *)data;data += d->maxedicts * sizeof(entity_state_t); + d->visiblebits = (unsigned char *)data;data += (d->maxedicts+7)/8 * sizeof(unsigned char); + if (oldmaxedicts) + { + memcpy(d->deltabits, olddeltabits, oldmaxedicts * sizeof(int)); + memcpy(d->priorities, oldpriorities, oldmaxedicts * sizeof(unsigned char)); + memcpy(d->updateframenum, oldupdateframenum, oldmaxedicts * sizeof(int)); + memcpy(d->states, oldstates, oldmaxedicts * sizeof(entity_state_t)); + memcpy(d->visiblebits, oldvisiblebits, (oldmaxedicts+7)/8 * sizeof(unsigned char)); + // the previous buffers were a single allocation, so just one free + Mem_Free(olddeltabits); + } + } +} + +static int EntityState5_Priority(entityframe5_database_t *d, int stateindex) +{ + int limit, priority; + entity_state_t *s = NULL; // hush compiler warning by initializing this + // if it is the player, update urgently + if (stateindex == d->viewentnum) + return ENTITYFRAME5_PRIORITYLEVELS - 1; + // priority increases each frame no matter what happens + priority = d->priorities[stateindex] + 1; + // players get an extra priority boost + if (stateindex <= svs.maxclients) + priority++; + // remove dead entities very quickly because they are just 2 bytes + if (d->states[stateindex].active != ACTIVE_NETWORK) + { + priority++; + return bound(1, priority, ENTITYFRAME5_PRIORITYLEVELS - 1); + } + // certain changes are more noticable than others + if (d->deltabits[stateindex] & (E5_FULLUPDATE | E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP)) + priority++; + // find the root entity this one is attached to, and judge relevance by it + for (limit = 0;limit < 256;limit++) + { + s = d->states + stateindex; + if (s->flags & RENDER_VIEWMODEL) + stateindex = d->viewentnum; + else if (s->tagentity) + stateindex = s->tagentity; + else + break; + if (d->maxedicts < stateindex) + EntityFrame5_ExpandEdicts(d, (stateindex+256)&~255); + } + if (limit >= 256) + Con_DPrintf("Protocol: Runaway loop recursing tagentity links on entity %i\n", stateindex); + // now that we have the parent entity we can make some decisions based on + // distance from the player + if (VectorDistance(d->states[d->viewentnum].netcenter, s->netcenter) < 1024.0f) + priority++; + return bound(1, priority, ENTITYFRAME5_PRIORITYLEVELS - 1); +} + +static double anim_reducetime(double t, double frameduration, double maxtime) +{ + if(t < 0) // clamp to non-negative + return 0; + if(t <= maxtime) // time can be represented normally + return t; + if(frameduration == 0) // don't like dividing by zero + return t; + if(maxtime <= 2 * frameduration) // if two frames don't fit, we better not do this + return t; + t -= frameduration * ceil((t - maxtime) / frameduration); + // now maxtime - frameduration < t <= maxtime + return t; +} + +// see VM_SV_frameduration +static double anim_frameduration(dp_model_t *model, int framenum) +{ + if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes) + return 0; + if(model->animscenes[framenum].framerate) + return model->animscenes[framenum].framecount / model->animscenes[framenum].framerate; + return 0; +} + +void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg) +{ + prvm_prog_t *prog = SVVM_prog; + unsigned int bits = 0; + //dp_model_t *model; + ENTITYSIZEPROFILING_START(msg, s->number); + + if (s->active != ACTIVE_NETWORK) + MSG_WriteShort(msg, number | 0x8000); + else + { + if (PRVM_serveredictfunction((&prog->edicts[s->number]), SendEntity)) + return; + + bits = changedbits; + if ((bits & E5_ORIGIN) && (!(s->flags & RENDER_LOWPRECISION) || s->exteriormodelforclient || s->tagentity || s->viewmodelforclient || (s->number >= 1 && s->number <= svs.maxclients) || s->origin[0] <= -4096.0625 || s->origin[0] >= 4095.9375 || s->origin[1] <= -4096.0625 || s->origin[1] >= 4095.9375 || s->origin[2] <= -4096.0625 || s->origin[2] >= 4095.9375)) + // maybe also add: ((model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*') + bits |= E5_ORIGIN32; + // possible values: + // negative origin: + // (int)(f * 8 - 0.5) >= -32768 + // (f * 8 - 0.5) > -32769 + // f > -4096.0625 + // positive origin: + // (int)(f * 8 + 0.5) <= 32767 + // (f * 8 + 0.5) < 32768 + // f * 8 + 0.5) < 4095.9375 + if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION)) + bits |= E5_ANGLES16; + if ((bits & E5_MODEL) && s->modelindex >= 256) + bits |= E5_MODEL16; + if ((bits & E5_FRAME) && s->frame >= 256) + bits |= E5_FRAME16; + if (bits & E5_EFFECTS) + { + if (s->effects & 0xFFFF0000) + bits |= E5_EFFECTS32; + else if (s->effects & 0xFFFFFF00) + bits |= E5_EFFECTS16; + } + if (bits >= 256) + bits |= E5_EXTEND1; + if (bits >= 65536) + bits |= E5_EXTEND2; + if (bits >= 16777216) + bits |= E5_EXTEND3; + MSG_WriteShort(msg, number); + MSG_WriteByte(msg, bits & 0xFF); + if (bits & E5_EXTEND1) + MSG_WriteByte(msg, (bits >> 8) & 0xFF); + if (bits & E5_EXTEND2) + MSG_WriteByte(msg, (bits >> 16) & 0xFF); + if (bits & E5_EXTEND3) + MSG_WriteByte(msg, (bits >> 24) & 0xFF); + if (bits & E5_FLAGS) + MSG_WriteByte(msg, s->flags); + if (bits & E5_ORIGIN) + { + if (bits & E5_ORIGIN32) + { + MSG_WriteCoord32f(msg, s->origin[0]); + MSG_WriteCoord32f(msg, s->origin[1]); + MSG_WriteCoord32f(msg, s->origin[2]); + } + else + { + MSG_WriteCoord13i(msg, s->origin[0]); + MSG_WriteCoord13i(msg, s->origin[1]); + MSG_WriteCoord13i(msg, s->origin[2]); + } + } + if (bits & E5_ANGLES) + { + if (bits & E5_ANGLES16) + { + MSG_WriteAngle16i(msg, s->angles[0]); + MSG_WriteAngle16i(msg, s->angles[1]); + MSG_WriteAngle16i(msg, s->angles[2]); + } + else + { + MSG_WriteAngle8i(msg, s->angles[0]); + MSG_WriteAngle8i(msg, s->angles[1]); + MSG_WriteAngle8i(msg, s->angles[2]); + } + } + if (bits & E5_MODEL) + { + if (bits & E5_MODEL16) + MSG_WriteShort(msg, s->modelindex); + else + MSG_WriteByte(msg, s->modelindex); + } + if (bits & E5_FRAME) + { + if (bits & E5_FRAME16) + MSG_WriteShort(msg, s->frame); + else + MSG_WriteByte(msg, s->frame); + } + if (bits & E5_SKIN) + MSG_WriteByte(msg, s->skin); + if (bits & E5_EFFECTS) + { + if (bits & E5_EFFECTS32) + MSG_WriteLong(msg, s->effects); + else if (bits & E5_EFFECTS16) + MSG_WriteShort(msg, s->effects); + else + MSG_WriteByte(msg, s->effects); + } + if (bits & E5_ALPHA) + MSG_WriteByte(msg, s->alpha); + if (bits & E5_SCALE) + MSG_WriteByte(msg, s->scale); + if (bits & E5_COLORMAP) + MSG_WriteByte(msg, s->colormap); + if (bits & E5_ATTACHMENT) + { + MSG_WriteShort(msg, s->tagentity); + MSG_WriteByte(msg, s->tagindex); + } + if (bits & E5_LIGHT) + { + MSG_WriteShort(msg, s->light[0]); + MSG_WriteShort(msg, s->light[1]); + MSG_WriteShort(msg, s->light[2]); + MSG_WriteShort(msg, s->light[3]); + MSG_WriteByte(msg, s->lightstyle); + MSG_WriteByte(msg, s->lightpflags); + } + if (bits & E5_GLOW) + { + MSG_WriteByte(msg, s->glowsize); + MSG_WriteByte(msg, s->glowcolor); + } + if (bits & E5_COLORMOD) + { + MSG_WriteByte(msg, s->colormod[0]); + MSG_WriteByte(msg, s->colormod[1]); + MSG_WriteByte(msg, s->colormod[2]); + } + if (bits & E5_GLOWMOD) + { + MSG_WriteByte(msg, s->glowmod[0]); + MSG_WriteByte(msg, s->glowmod[1]); + MSG_WriteByte(msg, s->glowmod[2]); + } + if (bits & E5_COMPLEXANIMATION) + { + if (s->skeletonobject.model && s->skeletonobject.relativetransforms) + { + int numbones = s->skeletonobject.model->num_bones; + int bonenum; + short pose7s[7]; + MSG_WriteByte(msg, 4); + MSG_WriteShort(msg, s->modelindex); + MSG_WriteByte(msg, numbones); + for (bonenum = 0;bonenum < numbones;bonenum++) + { + Matrix4x4_ToBonePose7s(s->skeletonobject.relativetransforms + bonenum, 64, pose7s); + MSG_WriteShort(msg, pose7s[0]); + MSG_WriteShort(msg, pose7s[1]); + MSG_WriteShort(msg, pose7s[2]); + MSG_WriteShort(msg, pose7s[3]); + MSG_WriteShort(msg, pose7s[4]); + MSG_WriteShort(msg, pose7s[5]); + MSG_WriteShort(msg, pose7s[6]); + } + } + else + { + dp_model_t *model = SV_GetModelByIndex(s->modelindex); + if (s->framegroupblend[3].lerp > 0) + { + MSG_WriteByte(msg, 3); + MSG_WriteShort(msg, s->framegroupblend[0].frame); + MSG_WriteShort(msg, s->framegroupblend[1].frame); + MSG_WriteShort(msg, s->framegroupblend[2].frame); + MSG_WriteShort(msg, s->framegroupblend[3].frame); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[2].start, anim_frameduration(model, s->framegroupblend[2].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[3].start, anim_frameduration(model, s->framegroupblend[3].frame), 65.535) * 1000.0)); + MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[2].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[3].lerp * 255.0f); + } + else if (s->framegroupblend[2].lerp > 0) + { + MSG_WriteByte(msg, 2); + MSG_WriteShort(msg, s->framegroupblend[0].frame); + MSG_WriteShort(msg, s->framegroupblend[1].frame); + MSG_WriteShort(msg, s->framegroupblend[2].frame); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[2].start, anim_frameduration(model, s->framegroupblend[2].frame), 65.535) * 1000.0)); + MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[2].lerp * 255.0f); + } + else if (s->framegroupblend[1].lerp > 0) + { + MSG_WriteByte(msg, 1); + MSG_WriteShort(msg, s->framegroupblend[0].frame); + MSG_WriteShort(msg, s->framegroupblend[1].frame); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 1000.0)); + MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f); + MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f); + } + else + { + MSG_WriteByte(msg, 0); + MSG_WriteShort(msg, s->framegroupblend[0].frame); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + } + } + } + if (bits & E5_TRAILEFFECTNUM) + MSG_WriteShort(msg, s->traileffectnum); + } + + ENTITYSIZEPROFILING_END(msg, s->number); +} + +static void EntityState5_ReadUpdate(entity_state_t *s, int number) +{ + int bits; + int startoffset = cl_message.readcount; + int bytes = 0; + bits = MSG_ReadByte(&cl_message); + if (bits & E5_EXTEND1) + { + bits |= MSG_ReadByte(&cl_message) << 8; + if (bits & E5_EXTEND2) + { + bits |= MSG_ReadByte(&cl_message) << 16; + if (bits & E5_EXTEND3) + bits |= MSG_ReadByte(&cl_message) << 24; + } + } + if (bits & E5_FULLUPDATE) + { + *s = defaultstate; + s->active = ACTIVE_NETWORK; + } + if (bits & E5_FLAGS) + s->flags = MSG_ReadByte(&cl_message); + if (bits & E5_ORIGIN) + { + if (bits & E5_ORIGIN32) + { + s->origin[0] = MSG_ReadCoord32f(&cl_message); + s->origin[1] = MSG_ReadCoord32f(&cl_message); + s->origin[2] = MSG_ReadCoord32f(&cl_message); + } + else + { + s->origin[0] = MSG_ReadCoord13i(&cl_message); + s->origin[1] = MSG_ReadCoord13i(&cl_message); + s->origin[2] = MSG_ReadCoord13i(&cl_message); + } + } + if (bits & E5_ANGLES) + { + if (bits & E5_ANGLES16) + { + s->angles[0] = MSG_ReadAngle16i(&cl_message); + s->angles[1] = MSG_ReadAngle16i(&cl_message); + s->angles[2] = MSG_ReadAngle16i(&cl_message); + } + else + { + s->angles[0] = MSG_ReadAngle8i(&cl_message); + s->angles[1] = MSG_ReadAngle8i(&cl_message); + s->angles[2] = MSG_ReadAngle8i(&cl_message); + } + } + if (bits & E5_MODEL) + { + if (bits & E5_MODEL16) + s->modelindex = (unsigned short) MSG_ReadShort(&cl_message); + else + s->modelindex = MSG_ReadByte(&cl_message); + } + if (bits & E5_FRAME) + { + if (bits & E5_FRAME16) + s->frame = (unsigned short) MSG_ReadShort(&cl_message); + else + s->frame = MSG_ReadByte(&cl_message); + } + if (bits & E5_SKIN) + s->skin = MSG_ReadByte(&cl_message); + if (bits & E5_EFFECTS) + { + if (bits & E5_EFFECTS32) + s->effects = (unsigned int) MSG_ReadLong(&cl_message); + else if (bits & E5_EFFECTS16) + s->effects = (unsigned short) MSG_ReadShort(&cl_message); + else + s->effects = MSG_ReadByte(&cl_message); + } + if (bits & E5_ALPHA) + s->alpha = MSG_ReadByte(&cl_message); + if (bits & E5_SCALE) + s->scale = MSG_ReadByte(&cl_message); + if (bits & E5_COLORMAP) + s->colormap = MSG_ReadByte(&cl_message); + if (bits & E5_ATTACHMENT) + { + s->tagentity = (unsigned short) MSG_ReadShort(&cl_message); + s->tagindex = MSG_ReadByte(&cl_message); + } + if (bits & E5_LIGHT) + { + s->light[0] = (unsigned short) MSG_ReadShort(&cl_message); + s->light[1] = (unsigned short) MSG_ReadShort(&cl_message); + s->light[2] = (unsigned short) MSG_ReadShort(&cl_message); + s->light[3] = (unsigned short) MSG_ReadShort(&cl_message); + s->lightstyle = MSG_ReadByte(&cl_message); + s->lightpflags = MSG_ReadByte(&cl_message); + } + if (bits & E5_GLOW) + { + s->glowsize = MSG_ReadByte(&cl_message); + s->glowcolor = MSG_ReadByte(&cl_message); + } + if (bits & E5_COLORMOD) + { + s->colormod[0] = MSG_ReadByte(&cl_message); + s->colormod[1] = MSG_ReadByte(&cl_message); + s->colormod[2] = MSG_ReadByte(&cl_message); + } + if (bits & E5_GLOWMOD) + { + s->glowmod[0] = MSG_ReadByte(&cl_message); + s->glowmod[1] = MSG_ReadByte(&cl_message); + s->glowmod[2] = MSG_ReadByte(&cl_message); + } + if (bits & E5_COMPLEXANIMATION) + { + skeleton_t *skeleton; + const dp_model_t *model; + int modelindex; + int type; + int bonenum; + int numbones; + short pose7s[7]; + type = MSG_ReadByte(&cl_message); + switch(type) + { + case 0: + s->framegroupblend[0].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[1].frame = 0; + s->framegroupblend[2].frame = 0; + s->framegroupblend[3].frame = 0; + s->framegroupblend[0].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[1].start = 0; + s->framegroupblend[2].start = 0; + s->framegroupblend[3].start = 0; + s->framegroupblend[0].lerp = 1; + s->framegroupblend[1].lerp = 0; + s->framegroupblend[2].lerp = 0; + s->framegroupblend[3].lerp = 0; + break; + case 1: + s->framegroupblend[0].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[1].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[2].frame = 0; + s->framegroupblend[3].frame = 0; + s->framegroupblend[0].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[2].start = 0; + s->framegroupblend[3].start = 0; + s->framegroupblend[0].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[1].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[2].lerp = 0; + s->framegroupblend[3].lerp = 0; + break; + case 2: + s->framegroupblend[0].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[1].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[2].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[3].frame = 0; + s->framegroupblend[0].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[2].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[3].start = 0; + s->framegroupblend[0].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[1].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[2].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[3].lerp = 0; + break; + case 3: + s->framegroupblend[0].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[1].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[2].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[3].frame = MSG_ReadShort(&cl_message); + s->framegroupblend[0].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[2].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[3].start = cl.time - (unsigned short)MSG_ReadShort(&cl_message) * (1.0f / 1000.0f); + s->framegroupblend[0].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[1].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[2].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + s->framegroupblend[3].lerp = MSG_ReadByte(&cl_message) * (1.0f / 255.0f); + break; + case 4: + if (!cl.engineskeletonobjects) + cl.engineskeletonobjects = (skeleton_t *) Mem_Alloc(cls.levelmempool, sizeof(*cl.engineskeletonobjects) * MAX_EDICTS); + skeleton = &cl.engineskeletonobjects[number]; + modelindex = MSG_ReadShort(&cl_message); + model = CL_GetModelByIndex(modelindex); + numbones = MSG_ReadByte(&cl_message); + if (model && numbones != model->num_bones) + Host_Error("E5_COMPLEXANIMATION: model has different number of bones than network packet describes\n"); + if (!skeleton->relativetransforms || skeleton->model != model) + { + skeleton->model = model; + skeleton->relativetransforms = (matrix4x4_t *) Mem_Realloc(cls.levelmempool, skeleton->relativetransforms, sizeof(*skeleton->relativetransforms) * skeleton->model->num_bones); + for (bonenum = 0;bonenum < model->num_bones;bonenum++) + skeleton->relativetransforms[bonenum] = identitymatrix; + } + for (bonenum = 0;bonenum < numbones;bonenum++) + { + pose7s[0] = (short)MSG_ReadShort(&cl_message); + pose7s[1] = (short)MSG_ReadShort(&cl_message); + pose7s[2] = (short)MSG_ReadShort(&cl_message); + pose7s[3] = (short)MSG_ReadShort(&cl_message); + pose7s[4] = (short)MSG_ReadShort(&cl_message); + pose7s[5] = (short)MSG_ReadShort(&cl_message); + pose7s[6] = (short)MSG_ReadShort(&cl_message); + Matrix4x4_FromBonePose7s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose7s); + } + s->skeletonobject = *skeleton; + break; + default: + Host_Error("E5_COMPLEXANIMATION: Parse error - unknown type %i\n", type); + break; + } + } + if (bits & E5_TRAILEFFECTNUM) + s->traileffectnum = (unsigned short) MSG_ReadShort(&cl_message); + + + bytes = cl_message.readcount - startoffset; + if (developer_networkentities.integer >= 2) + { + Con_Printf("ReadFields e%i (%i bytes)", number, bytes); + + if (bits & E5_ORIGIN) + Con_Printf(" E5_ORIGIN %f %f %f", s->origin[0], s->origin[1], s->origin[2]); + if (bits & E5_ANGLES) + Con_Printf(" E5_ANGLES %f %f %f", s->angles[0], s->angles[1], s->angles[2]); + if (bits & E5_MODEL) + Con_Printf(" E5_MODEL %i", s->modelindex); + if (bits & E5_FRAME) + Con_Printf(" E5_FRAME %i", s->frame); + if (bits & E5_SKIN) + Con_Printf(" E5_SKIN %i", s->skin); + if (bits & E5_EFFECTS) + Con_Printf(" E5_EFFECTS %i", s->effects); + if (bits & E5_FLAGS) + { + Con_Printf(" E5_FLAGS %i (", s->flags); + if (s->flags & RENDER_STEP) + Con_Print(" STEP"); + if (s->flags & RENDER_GLOWTRAIL) + Con_Print(" GLOWTRAIL"); + if (s->flags & RENDER_VIEWMODEL) + Con_Print(" VIEWMODEL"); + if (s->flags & RENDER_EXTERIORMODEL) + Con_Print(" EXTERIORMODEL"); + if (s->flags & RENDER_LOWPRECISION) + Con_Print(" LOWPRECISION"); + if (s->flags & RENDER_COLORMAPPED) + Con_Print(" COLORMAPPED"); + if (s->flags & RENDER_SHADOW) + Con_Print(" SHADOW"); + if (s->flags & RENDER_LIGHT) + Con_Print(" LIGHT"); + if (s->flags & RENDER_NOSELFSHADOW) + Con_Print(" NOSELFSHADOW"); + Con_Print(")"); + } + if (bits & E5_ALPHA) + Con_Printf(" E5_ALPHA %f", s->alpha / 255.0f); + if (bits & E5_SCALE) + Con_Printf(" E5_SCALE %f", s->scale / 16.0f); + if (bits & E5_COLORMAP) + Con_Printf(" E5_COLORMAP %i", s->colormap); + if (bits & E5_ATTACHMENT) + Con_Printf(" E5_ATTACHMENT e%i:%i", s->tagentity, s->tagindex); + if (bits & E5_LIGHT) + Con_Printf(" E5_LIGHT %i:%i:%i:%i %i:%i", s->light[0], s->light[1], s->light[2], s->light[3], s->lightstyle, s->lightpflags); + if (bits & E5_GLOW) + Con_Printf(" E5_GLOW %i:%i", s->glowsize * 4, s->glowcolor); + if (bits & E5_COLORMOD) + Con_Printf(" E5_COLORMOD %f:%f:%f", s->colormod[0] / 32.0f, s->colormod[1] / 32.0f, s->colormod[2] / 32.0f); + if (bits & E5_GLOWMOD) + Con_Printf(" E5_GLOWMOD %f:%f:%f", s->glowmod[0] / 32.0f, s->glowmod[1] / 32.0f, s->glowmod[2] / 32.0f); + if (bits & E5_COMPLEXANIMATION) + Con_Printf(" E5_COMPLEXANIMATION"); + if (bits & E5_TRAILEFFECTNUM) + Con_Printf(" E5_TRAILEFFECTNUM %i", s->traileffectnum); + Con_Print("\n"); + } +} + +static int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n) +{ + unsigned int bits = 0; + if (n->active == ACTIVE_NETWORK) + { + if (o->active != ACTIVE_NETWORK) + bits |= E5_FULLUPDATE; + if (!VectorCompare(o->origin, n->origin)) + bits |= E5_ORIGIN; + if (!VectorCompare(o->angles, n->angles)) + bits |= E5_ANGLES; + if (o->modelindex != n->modelindex) + bits |= E5_MODEL; + if (o->frame != n->frame) + bits |= E5_FRAME; + if (o->skin != n->skin) + bits |= E5_SKIN; + if (o->effects != n->effects) + bits |= E5_EFFECTS; + if (o->flags != n->flags) + bits |= E5_FLAGS; + if (o->alpha != n->alpha) + bits |= E5_ALPHA; + if (o->scale != n->scale) + bits |= E5_SCALE; + if (o->colormap != n->colormap) + bits |= E5_COLORMAP; + if (o->tagentity != n->tagentity || o->tagindex != n->tagindex) + bits |= E5_ATTACHMENT; + if (o->light[0] != n->light[0] || o->light[1] != n->light[1] || o->light[2] != n->light[2] || o->light[3] != n->light[3] || o->lightstyle != n->lightstyle || o->lightpflags != n->lightpflags) + bits |= E5_LIGHT; + if (o->glowsize != n->glowsize || o->glowcolor != n->glowcolor) + bits |= E5_GLOW; + if (o->colormod[0] != n->colormod[0] || o->colormod[1] != n->colormod[1] || o->colormod[2] != n->colormod[2]) + bits |= E5_COLORMOD; + if (o->glowmod[0] != n->glowmod[0] || o->glowmod[1] != n->glowmod[1] || o->glowmod[2] != n->glowmod[2]) + bits |= E5_GLOWMOD; + if (n->flags & RENDER_COMPLEXANIMATION) + { + if ((o->skeletonobject.model && o->skeletonobject.relativetransforms) != (n->skeletonobject.model && n->skeletonobject.relativetransforms)) + { + bits |= E5_COMPLEXANIMATION; + } + else if (o->skeletonobject.model && o->skeletonobject.relativetransforms) + { + if(o->modelindex != n->modelindex) + bits |= E5_COMPLEXANIMATION; + else if(o->skeletonobject.model->num_bones != n->skeletonobject.model->num_bones) + bits |= E5_COMPLEXANIMATION; + else if(memcmp(o->skeletonobject.relativetransforms, n->skeletonobject.relativetransforms, o->skeletonobject.model->num_bones * sizeof(*o->skeletonobject.relativetransforms))) + bits |= E5_COMPLEXANIMATION; + } + else if (memcmp(o->framegroupblend, n->framegroupblend, sizeof(o->framegroupblend))) + { + bits |= E5_COMPLEXANIMATION; + } + } + if (o->traileffectnum != n->traileffectnum) + bits |= E5_TRAILEFFECTNUM; + } + else + if (o->active == ACTIVE_NETWORK) + bits |= E5_FULLUPDATE; + return bits; +} + +void EntityFrame5_CL_ReadFrame(void) +{ + int n, enumber, framenum; + entity_t *ent; + entity_state_t *s; + // read the number of this frame to echo back in next input packet + framenum = MSG_ReadLong(&cl_message); + CL_NewFrameReceived(framenum); + if (cls.protocol != PROTOCOL_QUAKE && cls.protocol != PROTOCOL_QUAKEDP && cls.protocol != PROTOCOL_NEHAHRAMOVIE && cls.protocol != PROTOCOL_DARKPLACES1 && cls.protocol != PROTOCOL_DARKPLACES2 && cls.protocol != PROTOCOL_DARKPLACES3 && cls.protocol != PROTOCOL_DARKPLACES4 && cls.protocol != PROTOCOL_DARKPLACES5 && cls.protocol != PROTOCOL_DARKPLACES6) + cls.servermovesequence = MSG_ReadLong(&cl_message); + // read entity numbers until we find a 0x8000 + // (which would be remove world entity, but is actually a terminator) + while ((n = (unsigned short)MSG_ReadShort(&cl_message)) != 0x8000 && !cl_message.badread) + { + // get the entity number + enumber = n & 0x7FFF; + // we may need to expand the array + if (cl.num_entities <= enumber) + { + cl.num_entities = enumber + 1; + if (enumber >= cl.max_entities) + CL_ExpandEntities(enumber); + } + // look up the entity + ent = cl.entities + enumber; + // slide the current into the previous slot + ent->state_previous = ent->state_current; + // read the update + s = &ent->state_current; + if (n & 0x8000) + { + // remove entity + *s = defaultstate; + } + else + { + // update entity + EntityState5_ReadUpdate(s, enumber); + } + // set the cl.entities_active flag + cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK); + // set the update time + s->time = cl.mtime[0]; + // fix the number (it gets wiped occasionally by copying from defaultstate) + s->number = enumber; + // check if we need to update the lerp stuff + if (s->active == ACTIVE_NETWORK) + CL_MoveLerpEntityStates(&cl.entities[enumber]); + // print extra messages if desired + if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active) + { + if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK) + Con_Printf("entity #%i has become active\n", enumber); + else if (cl.entities[enumber].state_previous.active) + Con_Printf("entity #%i has become inactive\n", enumber); + } + } +} + +static int packetlog5cmp(const void *a_, const void *b_) +{ + const entityframe5_packetlog_t *a = (const entityframe5_packetlog_t *) a_; + const entityframe5_packetlog_t *b = (const entityframe5_packetlog_t *) b_; + return a->packetnumber - b->packetnumber; +} + +void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum) +{ + int i, j, l, bits; + entityframe5_changestate_t *s; + entityframe5_packetlog_t *p; + static unsigned char statsdeltabits[(MAX_CL_STATS+7)/8]; + static int deltabits[MAX_EDICTS]; + entityframe5_packetlog_t *packetlogs[ENTITYFRAME5_MAXPACKETLOGS]; + + for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++) + packetlogs[i] = p; + qsort(packetlogs, sizeof(*packetlogs), ENTITYFRAME5_MAXPACKETLOGS, packetlog5cmp); + + memset(deltabits, 0, sizeof(deltabits)); + memset(statsdeltabits, 0, sizeof(statsdeltabits)); + for (i = 0; i < ENTITYFRAME5_MAXPACKETLOGS; i++) + { + p = packetlogs[i]; + + if (!p->packetnumber) + continue; + + if (p->packetnumber <= framenum) + { + for (j = 0, s = p->states;j < p->numstates;j++, s++) + deltabits[s->number] |= s->bits; + + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + statsdeltabits[l] |= p->statsdeltabits[l]; + + p->packetnumber = 0; + } + else + { + for (j = 0, s = p->states;j < p->numstates;j++, s++) + deltabits[s->number] &= ~s->bits; + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + statsdeltabits[l] &= ~p->statsdeltabits[l]; + } + } + + for(i = 0; i < d->maxedicts; ++i) + { + bits = deltabits[i] & ~d->deltabits[i]; + if(bits) + { + d->deltabits[i] |= bits; + // if it was a very important update, set priority higher + if (bits & (E5_FULLUPDATE | E5_ATTACHMENT | E5_MODEL | E5_COLORMAP)) + d->priorities[i] = max(d->priorities[i], 4); + else + d->priorities[i] = max(d->priorities[i], 1); + } + } + + for (l = 0;l < (MAX_CL_STATS+7)/8;l++) + host_client->statsdeltabits[l] |= statsdeltabits[l]; + // no need to mask out the already-set bits here, as we do not + // do that priorities stuff +} + +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum) +{ + int i; + // scan for packets made obsolete by this ack and delete them + for (i = 0;i < ENTITYFRAME5_MAXPACKETLOGS;i++) + if (d->packetlog[i].packetnumber <= framenum) + d->packetlog[i].packetnumber = 0; +} + +qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t **states, int viewentnum, int movesequence, qboolean need_empty) +{ + prvm_prog_t *prog = SVVM_prog; + const entity_state_t *n; + int i, num, l, framenum, packetlognumber, priority; + sizebuf_t buf; + unsigned char data[128]; + entityframe5_packetlog_t *packetlog; + + if (prog->max_edicts > d->maxedicts) + EntityFrame5_ExpandEdicts(d, prog->max_edicts); + + framenum = d->latestframenum + 1; + d->viewentnum = viewentnum; + + // if packet log is full, mark all frames as lost, this will cause + // it to send the lost data again + for (packetlognumber = 0;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++) + if (d->packetlog[packetlognumber].packetnumber == 0) + break; + if (packetlognumber == ENTITYFRAME5_MAXPACKETLOGS) + { + Con_DPrintf("EntityFrame5_WriteFrame: packetlog overflow for a client, resetting\n"); + EntityFrame5_LostFrame(d, framenum); + packetlognumber = 0; + } + + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + // detect changes in states + num = 1; + for (i = 0;i < numstates;i++) + { + n = states[i]; + // mark gaps in entity numbering as removed entities + for (;num < n->number;num++) + { + // if the entity used to exist, clear it + if (CHECKPVSBIT(d->visiblebits, num)) + { + CLEARPVSBIT(d->visiblebits, num); + d->deltabits[num] = E5_FULLUPDATE; + d->priorities[num] = max(d->priorities[num], 8); // removal is cheap + d->states[num] = defaultstate; + d->states[num].number = num; + } + } + // update the entity state data + if (!CHECKPVSBIT(d->visiblebits, num)) + { + // entity just spawned in, don't let it completely hog priority + // because of being ancient on the first frame + d->updateframenum[num] = framenum; + // initial priority is a bit high to make projectiles send on the + // first frame, among other things + d->priorities[num] = max(d->priorities[num], 4); + } + SETPVSBIT(d->visiblebits, num); + d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n); + d->priorities[num] = max(d->priorities[num], 1); + d->states[num] = *n; + d->states[num].number = num; + // advance to next entity so the next iteration doesn't immediately remove it + num++; + } + // all remaining entities are dead + for (;num < d->maxedicts;num++) + { + if (CHECKPVSBIT(d->visiblebits, num)) + { + CLEARPVSBIT(d->visiblebits, num); + d->deltabits[num] = E5_FULLUPDATE; + d->priorities[num] = max(d->priorities[num], 8); // removal is cheap + d->states[num] = defaultstate; + d->states[num].number = num; + } + } + + // if there isn't at least enough room for an empty svc_entities, + // don't bother trying... + if (buf.cursize + 11 > buf.maxsize) + return false; + + // build lists of entities by priority level + memset(d->prioritychaincounts, 0, sizeof(d->prioritychaincounts)); + l = 0; + for (num = 0;num < d->maxedicts;num++) + { + if (d->priorities[num]) + { + if (d->deltabits[num]) + { + if (d->priorities[num] < (ENTITYFRAME5_PRIORITYLEVELS - 1)) + d->priorities[num] = EntityState5_Priority(d, num); + l = num; + priority = d->priorities[num]; + if (d->prioritychaincounts[priority] < ENTITYFRAME5_MAXSTATES) + d->prioritychains[priority][d->prioritychaincounts[priority]++] = num; + } + else + d->priorities[num] = 0; + } + } + + packetlog = NULL; + // write stat updates + if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5) + { + for (i = 0;i < MAX_CL_STATS && msg->cursize + 6 + 11 <= maxsize;i++) + { + if (host_client->statsdeltabits[i>>3] & (1<<(i&7))) + { + host_client->statsdeltabits[i>>3] &= ~(1<<(i&7)); + // add packetlog entry now that we have something for it + if (!packetlog) + { + packetlog = d->packetlog + packetlognumber; + packetlog->packetnumber = framenum; + packetlog->numstates = 0; + memset(packetlog->statsdeltabits, 0, sizeof(packetlog->statsdeltabits)); + } + packetlog->statsdeltabits[i>>3] |= (1<<(i&7)); + if (host_client->stats[i] >= 0 && host_client->stats[i] < 256) + { + MSG_WriteByte(msg, svc_updatestatubyte); + MSG_WriteByte(msg, i); + MSG_WriteByte(msg, host_client->stats[i]); + l = 1; + } + else + { + MSG_WriteByte(msg, svc_updatestat); + MSG_WriteByte(msg, i); + MSG_WriteLong(msg, host_client->stats[i]); + l = 1; + } + } + } + } + + // only send empty svc_entities frame if needed + if(!l && !need_empty) + return false; + + // add packetlog entry now that we have something for it + if (!packetlog) + { + packetlog = d->packetlog + packetlognumber; + packetlog->packetnumber = framenum; + packetlog->numstates = 0; + memset(packetlog->statsdeltabits, 0, sizeof(packetlog->statsdeltabits)); + } + + // write state updates + if (developer_networkentities.integer >= 10) + Con_Printf("send: svc_entities %i\n", framenum); + d->latestframenum = framenum; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, framenum); + if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6) + MSG_WriteLong(msg, movesequence); + for (priority = ENTITYFRAME5_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--) + { + for (i = 0;i < d->prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++) + { + num = d->prioritychains[priority][i]; + n = d->states + num; + if (d->deltabits[num] & E5_FULLUPDATE) + d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n); + buf.cursize = 0; + EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf); + // if the entity won't fit, try the next one + if (msg->cursize + buf.cursize + 2 > maxsize) + continue; + // write entity to the packet + SZ_Write(msg, buf.data, buf.cursize); + // mark age on entity for prioritization + d->updateframenum[num] = framenum; + // log entity so deltabits can be restored later if lost + packetlog->states[packetlog->numstates].number = num; + packetlog->states[packetlog->numstates].bits = d->deltabits[num]; + packetlog->numstates++; + // clear deltabits and priority so it won't be sent again + d->deltabits[num] = 0; + d->priorities[num] = 0; + } + } + MSG_WriteShort(msg, 0x8000); + + return true; +} + + +static void QW_TranslateEffects(entity_state_t *s, int qweffects) +{ + s->effects = 0; + s->internaleffects = 0; + if (qweffects & QW_EF_BRIGHTFIELD) + s->effects |= EF_BRIGHTFIELD; + if (qweffects & QW_EF_MUZZLEFLASH) + s->effects |= EF_MUZZLEFLASH; + if (qweffects & QW_EF_FLAG1) + { + // mimic FTEQW's interpretation of EF_FLAG1 as EF_NODRAW on non-player entities + if (s->number > cl.maxclients) + s->effects |= EF_NODRAW; + else + s->internaleffects |= INTEF_FLAG1QW; + } + if (qweffects & QW_EF_FLAG2) + { + // mimic FTEQW's interpretation of EF_FLAG2 as EF_ADDITIVE on non-player entities + if (s->number > cl.maxclients) + s->effects |= EF_ADDITIVE; + else + s->internaleffects |= INTEF_FLAG2QW; + } + if (qweffects & QW_EF_RED) + { + if (qweffects & QW_EF_BLUE) + s->effects |= EF_RED | EF_BLUE; + else + s->effects |= EF_RED; + } + else if (qweffects & QW_EF_BLUE) + s->effects |= EF_BLUE; + else if (qweffects & QW_EF_BRIGHTLIGHT) + s->effects |= EF_BRIGHTLIGHT; + else if (qweffects & QW_EF_DIMLIGHT) + s->effects |= EF_DIMLIGHT; +} + +void EntityStateQW_ReadPlayerUpdate(void) +{ + int slot = MSG_ReadByte(&cl_message); + int enumber = slot + 1; + int weaponframe; + int msec; + int playerflags; + int bits; + entity_state_t *s; + // look up the entity + entity_t *ent = cl.entities + enumber; + vec3_t viewangles; + vec3_t velocity; + + // slide the current state into the previous + ent->state_previous = ent->state_current; + + // read the update + s = &ent->state_current; + *s = defaultstate; + s->active = ACTIVE_NETWORK; + s->number = enumber; + s->colormap = enumber; + playerflags = MSG_ReadShort(&cl_message); + MSG_ReadVector(&cl_message, s->origin, cls.protocol); + s->frame = MSG_ReadByte(&cl_message); + + VectorClear(viewangles); + VectorClear(velocity); + + if (playerflags & QW_PF_MSEC) + { + // time difference between last update this player sent to the server, + // and last input we sent to the server (this packet is in response to + // our input, so msec is how long ago the last update of this player + // entity occurred, compared to our input being received) + msec = MSG_ReadByte(&cl_message); + } + else + msec = 0; + if (playerflags & QW_PF_COMMAND) + { + bits = MSG_ReadByte(&cl_message); + if (bits & QW_CM_ANGLE1) + viewangles[0] = MSG_ReadAngle16i(&cl_message); // cmd->angles[0] + if (bits & QW_CM_ANGLE2) + viewangles[1] = MSG_ReadAngle16i(&cl_message); // cmd->angles[1] + if (bits & QW_CM_ANGLE3) + viewangles[2] = MSG_ReadAngle16i(&cl_message); // cmd->angles[2] + if (bits & QW_CM_FORWARD) + MSG_ReadShort(&cl_message); // cmd->forwardmove + if (bits & QW_CM_SIDE) + MSG_ReadShort(&cl_message); // cmd->sidemove + if (bits & QW_CM_UP) + MSG_ReadShort(&cl_message); // cmd->upmove + if (bits & QW_CM_BUTTONS) + (void) MSG_ReadByte(&cl_message); // cmd->buttons + if (bits & QW_CM_IMPULSE) + (void) MSG_ReadByte(&cl_message); // cmd->impulse + (void) MSG_ReadByte(&cl_message); // cmd->msec + } + if (playerflags & QW_PF_VELOCITY1) + velocity[0] = MSG_ReadShort(&cl_message); + if (playerflags & QW_PF_VELOCITY2) + velocity[1] = MSG_ReadShort(&cl_message); + if (playerflags & QW_PF_VELOCITY3) + velocity[2] = MSG_ReadShort(&cl_message); + if (playerflags & QW_PF_MODEL) + s->modelindex = MSG_ReadByte(&cl_message); + else + s->modelindex = cl.qw_modelindex_player; + if (playerflags & QW_PF_SKINNUM) + s->skin = MSG_ReadByte(&cl_message); + if (playerflags & QW_PF_EFFECTS) + QW_TranslateEffects(s, MSG_ReadByte(&cl_message)); + if (playerflags & QW_PF_WEAPONFRAME) + weaponframe = MSG_ReadByte(&cl_message); + else + weaponframe = 0; + + if (enumber == cl.playerentity) + { + // if this is an update on our player, update the angles + VectorCopy(cl.viewangles, viewangles); + } + + // calculate the entity angles from the viewangles + s->angles[0] = viewangles[0] * -0.0333; + s->angles[1] = viewangles[1]; + s->angles[2] = 0; + s->angles[2] = V_CalcRoll(s->angles, velocity)*4; + + // if this is an update on our player, update interpolation state + if (enumber == cl.playerentity) + { + VectorCopy (cl.mpunchangle[0], cl.mpunchangle[1]); + VectorCopy (cl.mpunchvector[0], cl.mpunchvector[1]); + VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + cl.mviewzoom[1] = cl.mviewzoom[0]; + + cl.idealpitch = 0; + cl.mpunchangle[0][0] = 0; + cl.mpunchangle[0][1] = 0; + cl.mpunchangle[0][2] = 0; + cl.mpunchvector[0][0] = 0; + cl.mpunchvector[0][1] = 0; + cl.mpunchvector[0][2] = 0; + cl.mvelocity[0][0] = 0; + cl.mvelocity[0][1] = 0; + cl.mvelocity[0][2] = 0; + cl.mviewzoom[0] = 1; + + VectorCopy(velocity, cl.mvelocity[0]); + cl.stats[STAT_WEAPONFRAME] = weaponframe; + if (playerflags & QW_PF_GIB) + cl.stats[STAT_VIEWHEIGHT] = 8; + else if (playerflags & QW_PF_DEAD) + cl.stats[STAT_VIEWHEIGHT] = -16; + else + cl.stats[STAT_VIEWHEIGHT] = 22; + } + + // set the cl.entities_active flag + cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK); + // set the update time + s->time = cl.mtime[0] - msec * 0.001; // qw has no clock + // check if we need to update the lerp stuff + if (s->active == ACTIVE_NETWORK) + CL_MoveLerpEntityStates(&cl.entities[enumber]); +} + +static void EntityStateQW_ReadEntityUpdate(entity_state_t *s, int bits) +{ + int qweffects = 0; + s->active = ACTIVE_NETWORK; + s->number = bits & 511; + bits &= ~511; + if (bits & QW_U_MOREBITS) + bits |= MSG_ReadByte(&cl_message); + + // store the QW_U_SOLID bit here? + + if (bits & QW_U_MODEL) + s->modelindex = MSG_ReadByte(&cl_message); + if (bits & QW_U_FRAME) + s->frame = MSG_ReadByte(&cl_message); + if (bits & QW_U_COLORMAP) + s->colormap = MSG_ReadByte(&cl_message); + if (bits & QW_U_SKIN) + s->skin = MSG_ReadByte(&cl_message); + if (bits & QW_U_EFFECTS) + QW_TranslateEffects(s, qweffects = MSG_ReadByte(&cl_message)); + if (bits & QW_U_ORIGIN1) + s->origin[0] = MSG_ReadCoord13i(&cl_message); + if (bits & QW_U_ANGLE1) + s->angles[0] = MSG_ReadAngle8i(&cl_message); + if (bits & QW_U_ORIGIN2) + s->origin[1] = MSG_ReadCoord13i(&cl_message); + if (bits & QW_U_ANGLE2) + s->angles[1] = MSG_ReadAngle8i(&cl_message); + if (bits & QW_U_ORIGIN3) + s->origin[2] = MSG_ReadCoord13i(&cl_message); + if (bits & QW_U_ANGLE3) + s->angles[2] = MSG_ReadAngle8i(&cl_message); + + if (developer_networkentities.integer >= 2) + { + Con_Printf("ReadFields e%i", s->number); + if (bits & QW_U_MODEL) + Con_Printf(" U_MODEL %i", s->modelindex); + if (bits & QW_U_FRAME) + Con_Printf(" U_FRAME %i", s->frame); + if (bits & QW_U_COLORMAP) + Con_Printf(" U_COLORMAP %i", s->colormap); + if (bits & QW_U_SKIN) + Con_Printf(" U_SKIN %i", s->skin); + if (bits & QW_U_EFFECTS) + Con_Printf(" U_EFFECTS %i", qweffects); + if (bits & QW_U_ORIGIN1) + Con_Printf(" U_ORIGIN1 %f", s->origin[0]); + if (bits & QW_U_ANGLE1) + Con_Printf(" U_ANGLE1 %f", s->angles[0]); + if (bits & QW_U_ORIGIN2) + Con_Printf(" U_ORIGIN2 %f", s->origin[1]); + if (bits & QW_U_ANGLE2) + Con_Printf(" U_ANGLE2 %f", s->angles[1]); + if (bits & QW_U_ORIGIN3) + Con_Printf(" U_ORIGIN3 %f", s->origin[2]); + if (bits & QW_U_ANGLE3) + Con_Printf(" U_ANGLE3 %f", s->angles[2]); + if (bits & QW_U_SOLID) + Con_Printf(" U_SOLID"); + Con_Print("\n"); + } +} + +entityframeqw_database_t *EntityFrameQW_AllocDatabase(mempool_t *pool) +{ + entityframeqw_database_t *d; + d = (entityframeqw_database_t *)Mem_Alloc(pool, sizeof(*d)); + return d; +} + +void EntityFrameQW_FreeDatabase(entityframeqw_database_t *d) +{ + Mem_Free(d); +} + +void EntityFrameQW_CL_ReadFrame(qboolean delta) +{ + qboolean invalid = false; + int number, oldsnapindex, newsnapindex, oldindex, newindex, oldnum, newnum; + entity_t *ent; + entityframeqw_database_t *d; + entityframeqw_snapshot_t *oldsnap, *newsnap; + + if (!cl.entitydatabaseqw) + cl.entitydatabaseqw = EntityFrameQW_AllocDatabase(cls.levelmempool); + d = cl.entitydatabaseqw; + + // there is no cls.netcon in demos, so this reading code can't access + // cls.netcon-> at all... so cls.qw_incoming_sequence and + // cls.qw_outgoing_sequence are updated every time the corresponding + // cls.netcon->qw. variables are updated + // read the number of this frame to echo back in next input packet + cl.qw_validsequence = cls.qw_incoming_sequence; + newsnapindex = cl.qw_validsequence & QW_UPDATE_MASK; + newsnap = d->snapshot + newsnapindex; + memset(newsnap, 0, sizeof(*newsnap)); + oldsnap = NULL; + if (delta) + { + number = MSG_ReadByte(&cl_message); + oldsnapindex = cl.qw_deltasequence[newsnapindex]; + if ((number & QW_UPDATE_MASK) != (oldsnapindex & QW_UPDATE_MASK)) + Con_DPrintf("WARNING: from mismatch\n"); + if (oldsnapindex != -1) + { + if (cls.qw_outgoing_sequence - oldsnapindex >= QW_UPDATE_BACKUP-1) + { + Con_DPrintf("delta update too old\n"); + newsnap->invalid = invalid = true; // too old + delta = false; + } + oldsnap = d->snapshot + (oldsnapindex & QW_UPDATE_MASK); + } + else + delta = false; + } + + // if we can't decode this frame properly, report that to the server + if (invalid) + cl.qw_validsequence = 0; + + // read entity numbers until we find a 0x0000 + // (which would be an empty update on world entity, but is actually a terminator) + newsnap->num_entities = 0; + oldindex = 0; + for (;;) + { + int word = (unsigned short)MSG_ReadShort(&cl_message); + if (cl_message.badread) + return; // just return, the main parser will print an error + newnum = word == 0 ? 512 : (word & 511); + oldnum = delta ? (oldindex >= oldsnap->num_entities ? 9999 : oldsnap->entities[oldindex].number) : 9999; + + // copy unmodified oldsnap entities + while (newnum > oldnum) // delta only + { + if (developer_networkentities.integer >= 2) + Con_Printf("copy %i\n", oldnum); + // copy one of the old entities + if (newsnap->num_entities >= QW_MAX_PACKET_ENTITIES) + Host_Error("EntityFrameQW_CL_ReadFrame: newsnap->num_entities == MAX_PACKETENTITIES"); + newsnap->entities[newsnap->num_entities] = oldsnap->entities[oldindex++]; + newsnap->num_entities++; + oldnum = oldindex >= oldsnap->num_entities ? 9999 : oldsnap->entities[oldindex].number; + } + + if (word == 0) + break; + + if (developer_networkentities.integer >= 2) + { + if (word & QW_U_REMOVE) + Con_Printf("remove %i\n", newnum); + else if (newnum == oldnum) + Con_Printf("delta %i\n", newnum); + else + Con_Printf("baseline %i\n", newnum); + } + + if (word & QW_U_REMOVE) + { + if (newnum != oldnum && !delta && !invalid) + { + cl.qw_validsequence = 0; + Con_Printf("WARNING: U_REMOVE %i on full update\n", newnum); + } + } + else + { + if (newsnap->num_entities >= QW_MAX_PACKET_ENTITIES) + Host_Error("EntityFrameQW_CL_ReadFrame: newsnap->num_entities == MAX_PACKETENTITIES"); + newsnap->entities[newsnap->num_entities] = (newnum == oldnum) ? oldsnap->entities[oldindex] : cl.entities[newnum].state_baseline; + EntityStateQW_ReadEntityUpdate(newsnap->entities + newsnap->num_entities, word); + newsnap->num_entities++; + } + + if (newnum == oldnum) + oldindex++; + } + + // expand cl.num_entities to include every entity we've seen this game + newnum = newsnap->num_entities ? newsnap->entities[newsnap->num_entities - 1].number : 1; + if (cl.num_entities <= newnum) + { + cl.num_entities = newnum + 1; + if (cl.max_entities < newnum + 1) + CL_ExpandEntities(newnum); + } + + // now update the non-player entities from the snapshot states + number = cl.maxclients + 1; + for (newindex = 0;;newindex++) + { + newnum = newindex >= newsnap->num_entities ? cl.num_entities : newsnap->entities[newindex].number; + // kill any missing entities + for (;number < newnum;number++) + { + if (cl.entities_active[number]) + { + cl.entities_active[number] = false; + cl.entities[number].state_current.active = ACTIVE_NOT; + } + } + if (number >= cl.num_entities) + break; + // update the entity + ent = &cl.entities[number]; + ent->state_previous = ent->state_current; + ent->state_current = newsnap->entities[newindex]; + ent->state_current.time = cl.mtime[0]; + CL_MoveLerpEntityStates(ent); + // the entity lives again... + cl.entities_active[number] = true; + number++; + } +} diff --git a/app/jni/protocol.h b/app/jni/protocol.h new file mode 100644 index 0000000..3c0c6ce --- /dev/null +++ b/app/jni/protocol.h @@ -0,0 +1,1024 @@ +/* +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 + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +// protocolversion_t is defined in common.h + +protocolversion_t Protocol_EnumForName(const char *s); +const char *Protocol_NameForEnum(protocolversion_t p); +protocolversion_t Protocol_EnumForNumber(int n); +int Protocol_NumberForEnum(protocolversion_t p); +void Protocol_Names(char *buffer, size_t buffersize); + +// model effects +#define MF_ROCKET 1 // leave a trail +#define MF_GRENADE 2 // leave a trail +#define MF_GIB 4 // leave a trail +#define MF_ROTATE 8 // rotate (bonus items) +#define MF_TRACER 16 // green split trail +#define MF_ZOMGIB 32 // small blood trail +#define MF_TRACER2 64 // orange split trail + rotate +#define MF_TRACER3 128 // purple trail + +// entity effects +#define EF_BRIGHTFIELD 1 +#define EF_MUZZLEFLASH 2 +#define EF_BRIGHTLIGHT 4 +#define EF_DIMLIGHT 8 +#define EF_NODRAW 16 +#define EF_ADDITIVE 32 +#define EF_BLUE 64 +#define EF_RED 128 +#define EF_NOGUNBOB 256 // LordHavoc: when used with .viewmodelforclient this makes the entity attach to the view without gun bobbing and such effects, it also works on the player entity to disable gun bobbing of the engine-managed .viewmodel (without affecting any .viewmodelforclient entities attached to the player) +#define EF_FULLBRIGHT 512 // LordHavoc: fullbright +#define EF_FLAME 1024 // LordHavoc: on fire +#define EF_STARDUST 2048 // LordHavoc: showering sparks +#define EF_NOSHADOW 4096 // LordHavoc: does not cast a shadow +#define EF_NODEPTHTEST 8192 // LordHavoc: shows through walls +#define EF_SELECTABLE 16384 // LordHavoc: highlights when PRYDON_CLIENTCURSOR mouse is over it +#define EF_DOUBLESIDED 32768 //[515]: disable cull face for this entity +#define EF_NOSELFSHADOW 65536 // LordHavoc: does not cast a shadow on itself (or any other EF_NOSELFSHADOW entities) +#define EF_DYNAMICMODELLIGHT 131072 +#define EF_UNUSED18 262144 +#define EF_UNUSED19 524288 +#define EF_RESTARTANIM_BIT 1048576 // div0: restart animation bit (like teleport bit, but lerps between end and start of the anim, and doesn't stop player lerping) +#define EF_TELEPORT_BIT 2097152 // div0: teleport bit (toggled when teleporting, prevents lerping when the bit has changed) +#define EF_LOWPRECISION 4194304 // LordHavoc: entity is low precision (integer coordinates) to save network bandwidth (serverside only) +#define EF_NOMODELFLAGS 8388608 // indicates the model's .effects should be ignored (allows overriding them) +#define EF_ROCKET 16777216 // leave a trail +#define EF_GRENADE 33554432 // leave a trail +#define EF_GIB 67108864 // leave a trail +#define EF_ROTATE 134217728 // rotate (bonus items) +#define EF_TRACER 268435456 // green split trail +#define EF_ZOMGIB 536870912 // small blood trail +#define EF_TRACER2 1073741824 // orange split trail + rotate +#define EF_TRACER3 0x80000000 // purple trail + +// internaleffects bits (no overlap with EF_ bits): +#define INTEF_FLAG1QW 1 +#define INTEF_FLAG2QW 2 + +// flags for the pflags field of entities +#define PFLAGS_NOSHADOW 1 +#define PFLAGS_CORONA 2 +#define PFLAGS_FULLDYNAMIC 128 // must be set or the light fields are ignored + +// 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) +// LordHavoc: U_NOLERP was only ever used for monsters, so I renamed it U_STEP +#define U_STEP (1<<5) +#define U_FRAME (1<<6) +// just differentiates from other updates +#define U_SIGNAL (1<<7) + +#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) + +// LordHavoc: protocol extension +#define U_EXTEND1 (1<<15) +// LordHavoc: first extend byte +#define U_DELTA (1<<16) // no data, while this is set the entity is delta compressed (uses previous frame as a baseline, meaning only things that have changed from the previous frame are sent, except for the forced full update every half second) +#define U_ALPHA (1<<17) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 1, and the entity is not sent if <=0 unless it has effects (model effects are checked as well) +#define U_SCALE (1<<18) // 1 byte, scale / 16 positive, not sent if 1.0 +#define U_EFFECTS2 (1<<19) // 1 byte, this is .effects & 0xFF00 (second byte) +#define U_GLOWSIZE (1<<20) // 1 byte, encoding is float/4.0, unsigned, not sent if 0 +#define U_GLOWCOLOR (1<<21) // 1 byte, palette index, default is 254 (white), this IS used for darklight (allowing colored darklight), however the particles from a darklight are always black, not sent if default value (even if glowsize or glowtrail is set) +#define U_COLORMOD (1<<22) // 1 byte, 3 bit red, 3 bit green, 2 bit blue, this lets you tint an object artifically, so you could make a red rocket, or a blue fiend... +#define U_EXTEND2 (1<<23) // another byte to follow +// LordHavoc: second extend byte +#define U_GLOWTRAIL (1<<24) // leaves a trail of particles (of color .glowcolor, or black if it is a negative glowsize) +#define U_VIEWMODEL (1<<25) // attachs the model to the view (origin and angles become relative to it), only shown to owner, a more powerful alternative to .weaponmodel and such +#define U_FRAME2 (1<<26) // 1 byte, this is .frame & 0xFF00 (second byte) +#define U_MODEL2 (1<<27) // 1 byte, this is .modelindex & 0xFF00 (second byte) +#define U_EXTERIORMODEL (1<<28) // causes this model to not be drawn when using a first person view (third person will draw it, first person will not) +#define U_UNUSED29 (1<<29) // future expansion +#define U_UNUSED30 (1<<30) // future expansion +#define U_EXTEND3 (1<<31) // another byte to follow, future expansion + +#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) +#define SU_EXTEND1 (1<<15) +// first extend byte +#define SU_PUNCHVEC1 (1<<16) +#define SU_PUNCHVEC2 (1<<17) +#define SU_PUNCHVEC3 (1<<18) +#define SU_VIEWZOOM (1<<19) // byte factor (0 = 0.0 (not valid), 255 = 1.0) +#define SU_UNUSED20 (1<<20) +#define SU_UNUSED21 (1<<21) +#define SU_UNUSED22 (1<<22) +#define SU_EXTEND2 (1<<23) // another byte to follow, future expansion +// second extend byte +#define SU_UNUSED24 (1<<24) +#define SU_UNUSED25 (1<<25) +#define SU_UNUSED26 (1<<26) +#define SU_UNUSED27 (1<<27) +#define SU_UNUSED28 (1<<28) +#define SU_UNUSED29 (1<<29) +#define SU_UNUSED30 (1<<30) +#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion + +// 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 +#define SND_LARGEENTITY (1<<3) // a short and a byte (instead of a short) +#define SND_LARGESOUND (1<<4) // a short (instead of a byte) +#define SND_SPEEDUSHORT4000 (1<<5) // ushort speed*4000 (speed is usually 1.0, a value of 0.0 is the same as 1.0) + + +// 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 + +#define svc_showlmp 35 // [string] slotname [string] lmpfilename [short] x [short] y +#define svc_hidelmp 36 // [string] slotname +#define svc_skybox 37 // [string] skyname + +// LordHavoc: my svc_ range, 50-69 +#define svc_downloaddata 50 // [int] start [short] size +#define svc_updatestatubyte 51 // [byte] stat [byte] value +#define svc_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate +#define svc_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate +#define svc_sound2 54 // (obsolete in DP6 and later) short soundindex instead of byte +#define svc_precache 54 // [short] precacheindex [string] filename, precacheindex is + 0 for modelindex and +32768 for soundindex +#define svc_spawnbaseline2 55 // short modelindex instead of byte +#define svc_spawnstatic2 56 // short modelindex instead of byte +#define svc_entities 57 // [int] deltaframe [int] thisframe [float vector] eye [variable length] entitydata +#define svc_csqcentities 58 // [short] entnum [variable length] entitydata ... [short] 0x0000 +#define svc_spawnstaticsound2 59 // [coord3] [short] samp [byte] vol [byte] aten +#define svc_trailparticles 60 // [short] entnum [short] effectnum [vector] start [vector] end +#define svc_pointparticles 61 // [short] effectnum [vector] start [vector] velocity [short] count +#define svc_pointparticles1 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 + +// +// 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 + +// LordHavoc: my clc_ range, 50-59 +#define clc_ackframe 50 // [int] framenumber +#define clc_ackdownloaddata 51 // [int] start [short] size (note: exact echo of latest values received in svc_downloaddata, packet-loss handling is in the server) +#define clc_unusedlh2 52 +#define clc_unusedlh3 53 +#define clc_unusedlh4 54 +#define clc_unusedlh5 55 +#define clc_unusedlh6 56 +#define clc_unusedlh7 57 +#define clc_unusedlh8 58 +#define clc_unusedlh9 59 + +// +// temp entity events +// +#define TE_SPIKE 0 // [vector] origin +#define TE_SUPERSPIKE 1 // [vector] origin +#define TE_GUNSHOT 2 // [vector] origin +#define TE_EXPLOSION 3 // [vector] origin +#define TE_TAREXPLOSION 4 // [vector] origin +#define TE_LIGHTNING1 5 // [entity] entity [vector] start [vector] end +#define TE_LIGHTNING2 6 // [entity] entity [vector] start [vector] end +#define TE_WIZSPIKE 7 // [vector] origin +#define TE_KNIGHTSPIKE 8 // [vector] origin +#define TE_LIGHTNING3 9 // [entity] entity [vector] start [vector] end +#define TE_LAVASPLASH 10 // [vector] origin +#define TE_TELEPORT 11 // [vector] origin +#define TE_EXPLOSION2 12 // [vector] origin [byte] startcolor [byte] colorcount + +// PGM 01/21/97 +#define TE_BEAM 13 // [entity] entity [vector] start [vector] end +// PGM 01/21/97 + +// Nehahra effects used in the movie (TE_EXPLOSION3 also got written up in a QSG tutorial, hence it's not marked NEH) +#define TE_EXPLOSION3 16 // [vector] origin [coord] red [coord] green [coord] blue +#define TE_LIGHTNING4NEH 17 // [string] model [entity] entity [vector] start [vector] end + +// LordHavoc: added some TE_ codes (block1 - 50-60) +#define TE_BLOOD 50 // [vector] origin [byte] xvel [byte] yvel [byte] zvel [byte] count +#define TE_SPARK 51 // [vector] origin [byte] xvel [byte] yvel [byte] zvel [byte] count +#define TE_BLOODSHOWER 52 // [vector] min [vector] max [coord] explosionspeed [short] count +#define TE_EXPLOSIONRGB 53 // [vector] origin [byte] red [byte] green [byte] blue +#define TE_PARTICLECUBE 54 // [vector] min [vector] max [vector] dir [short] count [byte] color [byte] gravity [coord] randomvel +#define TE_PARTICLERAIN 55 // [vector] min [vector] max [vector] dir [short] count [byte] color +#define TE_PARTICLESNOW 56 // [vector] min [vector] max [vector] dir [short] count [byte] color +#define TE_GUNSHOTQUAD 57 // [vector] origin +#define TE_SPIKEQUAD 58 // [vector] origin +#define TE_SUPERSPIKEQUAD 59 // [vector] origin +// LordHavoc: block2 - 70-80 +#define TE_EXPLOSIONQUAD 70 // [vector] origin +#define TE_UNUSED1 71 // unused +#define TE_SMALLFLASH 72 // [vector] origin +#define TE_CUSTOMFLASH 73 // [vector] origin [byte] radius / 8 - 1 [byte] lifetime / 256 - 1 [byte] red [byte] green [byte] blue +#define TE_FLAMEJET 74 // [vector] origin [vector] velocity [byte] count +#define TE_PLASMABURN 75 // [vector] origin +// LordHavoc: Tei grabbed these codes +#define TE_TEI_G3 76 // [vector] start [vector] end [vector] angles +#define TE_TEI_SMOKE 77 // [vector] origin [vector] dir [byte] count +#define TE_TEI_BIGEXPLOSION 78 // [vector] origin +#define TE_TEI_PLASMAHIT 79 // [vector} origin [vector] dir [byte] count + + +// these are bits for the 'flags' field of the entity_state_t +#define RENDER_STEP 1 +#define RENDER_GLOWTRAIL 2 +#define RENDER_VIEWMODEL 4 +#define RENDER_EXTERIORMODEL 8 +#define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth +#define RENDER_COLORMAPPED 32 +#define RENDER_WORLDOBJECT 64 // do not cull this entity with r_cullentities +#define RENDER_COMPLEXANIMATION 128 + +#define RENDER_SHADOW 65536 // cast shadow +#define RENDER_LIGHT 131072 // receive light +#define RENDER_NOSELFSHADOW 262144 // render lighting on this entity before its own shadow is added to the scene +// (note: all RENDER_NOSELFSHADOW entities are grouped together and rendered in a batch before their shadows are rendered, so they can not shadow eachother either) +#define RENDER_EQUALIZE 524288 // (subflag of RENDER_LIGHT) equalize the light from the light grid hitting this ent (less invasive EF_FULLBRIGHT implementation) +#define RENDER_NODEPTHTEST 1048576 +#define RENDER_ADDITIVE 2097152 +#define RENDER_DOUBLESIDED 4194304 +#define RENDER_CUSTOMIZEDMODELLIGHT 4096 +#define RENDER_DYNAMICMODELLIGHT 8388608 // origin dependent model light + +#define MAX_FRAMEGROUPBLENDS 4 +typedef struct framegroupblend_s +{ + // animation number and blend factor + // (for most models this is the frame number) + int frame; + float lerp; + // time frame began playing (for framegroup animations) + double start; +} +framegroupblend_t; + +struct matrix4x4_s; +struct model_s; + +typedef struct skeleton_s +{ + const struct model_s *model; + struct matrix4x4_s *relativetransforms; +} +skeleton_t; + +typedef enum entity_state_active_e +{ + ACTIVE_NOT = 0, + ACTIVE_NETWORK = 1, + ACTIVE_SHARED = 2 +} +entity_state_active_t; + +// this was 96 bytes, now 168 bytes (32bit) or 176 bytes (64bit) +typedef struct entity_state_s +{ + // ! means this is not sent to client + double time; // ! time this state was built (used on client for interpolation) + float netcenter[3]; // ! for network prioritization, this is the center of the bounding box (which may differ from the origin) + float origin[3]; + float angles[3]; + int effects; + unsigned int customizeentityforclient; // ! + unsigned short number; // entity number this state is for + unsigned short modelindex; + unsigned short frame; + unsigned short tagentity; + unsigned short specialvisibilityradius; // ! larger if it has effects/light + unsigned short viewmodelforclient; // ! + unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases + unsigned short nodrawtoclient; // ! + unsigned short drawonlytoclient; // ! + unsigned short traileffectnum; + unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1 + unsigned char active; // true if a valid state + unsigned char lightstyle; + unsigned char lightpflags; + unsigned char colormap; + unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC + unsigned char alpha; + unsigned char scale; + unsigned char glowsize; + unsigned char glowcolor; + unsigned char flags; + unsigned char internaleffects; // INTEF_FLAG1QW and so on + unsigned char tagindex; + unsigned char colormod[3]; + unsigned char glowmod[3]; + // LordHavoc: very big data here :( + framegroupblend_t framegroupblend[4]; + skeleton_t skeletonobject; +} +entity_state_t; + +// baseline state values +extern entity_state_t defaultstate; +// reads a quake entity from the network stream +void EntityFrameQuake_ReadEntity(int bits); +// checks for stats changes and sets corresponding host_client->statsdeltabits +// (also updates host_client->stats array) +void Protocol_UpdateClientStats(const int *stats); +// writes reliable messages updating stats (not used by DP6 and later +// protocols which send updates in their WriteFrame function using a different +// method of reliable messaging) +void Protocol_WriteStatsReliable(void); +// writes a list of quake entities to the network stream +// (or as many will fit) +qboolean EntityFrameQuake_WriteFrame(sizebuf_t *msg, int maxsize, int numstates, const entity_state_t **states); +// cleans up dead entities each frame after ReadEntity (which doesn't clear unused entities) +void EntityFrameQuake_ISeeDeadEntities(void); + +/* +PROTOCOL_DARKPLACES3 +server updates entities according to some (unmentioned) scheme. + +a frame consists of all visible entities, some of which are up to date, +often some are not up to date. + +these entities are stored in a range (firstentity/endentity) of structs in the +entitydata[] buffer. + +to make a commit the server performs these steps: +1. duplicate oldest frame in database (this is the baseline) as new frame, and + write frame numbers (oldest frame's number, new frame's number) and eye + location to network packet (eye location is obsolete and will be removed in + future revisions) +2. write an entity change to packet and modify new frame accordingly + (this repeats until packet is sufficiently full or new frame is complete) +3. write terminator (0xFFFF) to network packet + (FIXME: this terminator value conflicts with MAX_EDICTS 32768...) + +to read a commit the client performs these steps: +1. reads frame numbers from packet and duplicates baseline frame as new frame, + also reads eye location but does nothing with it (obsolete). +2. delete frames older than the baseline which was used +3. read entity changes from packet until terminator (0xFFFF) is encountered, + each change is applied to entity frame. +4. sends ack framenumber to server as part of input packet + +if server receives ack message in put packet it performs these steps: +1. remove all older frames from database. +*/ + +/* +PROTOCOL_DARKPLACES4 +a frame consists of some visible entities in a range (this is stored as start and end, note that end may be less than start if it wrapped). + +these entities are stored in a range (firstentity/endentity) of structs in the entitydata[] buffer. + +to make a commit the server performs these steps: +1. build an entity_frame_t using appropriate functions, containing (some of) the visible entities, this is passed to the Write function to send it. + +This documention is unfinished! +the Write function performs these steps: +1. check if entity frame is larger than MAX_ENTITYFRAME or is larger than available space in database, if so the baseline is defaults, otherwise it is the current baseline of the database. +2. write differences of an entity compared to selected baseline. +3. add entity to entity update in database. +4. if there are more entities to write and packet is not full, go back to step 2. +5. write terminator (0xFFFF) as entity number. +6. return. + + + + + +server updates entities in looping ranges, a frame consists of a range of visible entities (not always all visible entities), +*/ + +#define MAX_ENTITY_HISTORY 64 +#define MAX_ENTITY_DATABASE (MAX_EDICTS * 2) + +// build entity data in this, to pass to entity read/write functions +typedef struct entity_frame_s +{ + double time; + int framenum; + int numentities; + int firstentitynum; + int lastentitynum; + vec3_t eye; + entity_state_t entitydata[MAX_ENTITY_DATABASE]; +} +entity_frame_t; + +typedef struct entity_frameinfo_s +{ + double time; + int framenum; + int firstentity; // index into entitydata, modulo MAX_ENTITY_DATABASE + int endentity; // index into entitydata, firstentity + numentities +} +entity_frameinfo_t; + +typedef struct entityframe_database_s +{ + // note: these can be far out of range, modulo with MAX_ENTITY_DATABASE to get a valid range (which may wrap) + // start and end of used area, when adding a new update to database, store at endpos, and increment endpos + // when removing updates from database, nudge down frames array to only contain useful frames + // this logic should explain better: + // if (numframes >= MAX_ENTITY_HISTORY || (frames[numframes - 1].endentity - frames[0].firstentity) + entitiestoadd > MAX_ENTITY_DATABASE) + // flushdatabase(); + // note: if numframes == 0, insert at start (0 in entitydata) + // the only reason this system is used is to avoid copying memory when frames are removed + int numframes; + // server only: last sent frame + int latestframenum; + // server only: last acknowledged frame + int ackframenum; + // the current state in the database + vec3_t eye; + // table of entities in the entityhistorydata + entity_frameinfo_t frames[MAX_ENTITY_HISTORY]; + // entities + entity_state_t entitydata[MAX_ENTITY_DATABASE]; + + // structs for building new frames and reading them + entity_frame_t deltaframe; + entity_frame_t framedata; +} +entityframe_database_t; + +// LordHavoc: these are in approximately sorted order, according to cost and +// likelyhood of being used for numerous objects in a frame + +// note that the bytes are not written/read in this order, this is only the +// order of the bits to minimize overhead from extend bytes + +// enough to describe a nail, gib, shell casing, bullet hole, or rocket +#define E_ORIGIN1 (1<<0) +#define E_ORIGIN2 (1<<1) +#define E_ORIGIN3 (1<<2) +#define E_ANGLE1 (1<<3) +#define E_ANGLE2 (1<<4) +#define E_ANGLE3 (1<<5) +#define E_MODEL1 (1<<6) +#define E_EXTEND1 (1<<7) + +// enough to describe almost anything +#define E_FRAME1 (1<<8) +#define E_EFFECTS1 (1<<9) +#define E_ALPHA (1<<10) +#define E_SCALE (1<<11) +#define E_COLORMAP (1<<12) +#define E_SKIN (1<<13) +#define E_FLAGS (1<<14) +#define E_EXTEND2 (1<<15) + +// players, custom color glows, high model numbers +#define E_FRAME2 (1<<16) +#define E_MODEL2 (1<<17) +#define E_EFFECTS2 (1<<18) +#define E_GLOWSIZE (1<<19) +#define E_GLOWCOLOR (1<<20) +#define E_LIGHT (1<<21) +#define E_LIGHTPFLAGS (1<<22) +#define E_EXTEND3 (1<<23) + +#define E_SOUND1 (1<<24) +#define E_SOUNDVOL (1<<25) +#define E_SOUNDATTEN (1<<26) +#define E_TAGATTACHMENT (1<<27) +#define E_LIGHTSTYLE (1<<28) +#define E_UNUSED6 (1<<29) +#define E_UNUSED7 (1<<30) +#define E_EXTEND4 (1<<31) + +// returns difference between two states as E_ flags +int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n); +// write E_ flags to a msg +void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits); +// write values for the E_ flagged fields to a msg +void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits); +// write entity number and E_ flags and their values, or a remove number, describing the change from delta to ent +void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta); +// read E_ flags +int EntityState_ReadExtendBits(void); +// read values for E_ flagged fields and apply them to a state +void EntityState_ReadFields(entity_state_t *e, unsigned int bits); + +// (client and server) allocates a new empty database +entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool); +// (client and server) frees the database +void EntityFrame_FreeDatabase(entityframe_database_t *d); +// (server) clears the database to contain no frames (thus delta compression +// compresses against nothing) +void EntityFrame_ClearDatabase(entityframe_database_t *d); +// (server and client) removes frames older than 'frame' from database +void EntityFrame_AckFrame(entityframe_database_t *d, int frame); +// (server) clears frame, to prepare for adding entities +void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum); +// (server and client) reads a frame from the database +void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f); +// (client) adds a entity_frame to the database, for future reference +void EntityFrame_AddFrame_Client(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata); +// (server) adds a entity_frame to the database, for future reference +void EntityFrame_AddFrame_Server(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t **entitydata); +// (server) writes a frame to network stream +qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t **states, int viewentnum); +// (client) reads a frame from network stream +void EntityFrame_CL_ReadFrame(void); +// (client) returns the frame number of the most recent frame recieved +int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d); + +typedef struct entity_database4_commit_s +{ + // frame number this commit represents + int framenum; + // number of entities in entity[] array + int numentities; + // maximum number of entities in entity[] array (dynamic resizing) + int maxentities; + entity_state_t *entity; +} +entity_database4_commit_t; + +typedef struct entity_database4_s +{ + // what mempool to use for allocations + mempool_t *mempool; + // reference frame + int referenceframenum; + // reference entities array is resized according to demand + int maxreferenceentities; + // array of states for entities, these are indexable by their entity number (yes there are gaps) + entity_state_t *referenceentity; + // commits waiting to be applied to the reference database when confirmed + // (commit[i]->numentities == 0 means it is empty) + entity_database4_commit_t commit[MAX_ENTITY_HISTORY]; + // (server only) the current commit being worked on + entity_database4_commit_t *currentcommit; + // (server only) if a commit won't fit entirely, continue where it left + // off next frame + int currententitynumber; + // (server only) + int latestframenumber; +} +entityframe4_database_t; + +// should-be-private functions that aren't +entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number); +void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s); + +// allocate a database +entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool); +// free a database +void EntityFrame4_FreeDatabase(entityframe4_database_t *d); +// reset a database (resets compression but does not reallocate anything) +void EntityFrame4_ResetDatabase(entityframe4_database_t *d); +// updates database to account for a frame-received acknowledgment +int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode); +// writes a frame to the network stream +qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states); +// reads a frame from the network stream +void EntityFrame4_CL_ReadFrame(void); + +// reset all entity fields (typically used if status changed) +#define E5_FULLUPDATE (1<<0) +// E5_ORIGIN32=0: short[3] = s->origin[0] * 8, s->origin[1] * 8, s->origin[2] * 8 +// E5_ORIGIN32=1: float[3] = s->origin[0], s->origin[1], s->origin[2] +#define E5_ORIGIN (1<<1) +// E5_ANGLES16=0: byte[3] = s->angle[0] * 256 / 360, s->angle[1] * 256 / 360, s->angle[2] * 256 / 360 +// E5_ANGLES16=1: short[3] = s->angle[0] * 65536 / 360, s->angle[1] * 65536 / 360, s->angle[2] * 65536 / 360 +#define E5_ANGLES (1<<2) +// E5_MODEL16=0: byte = s->modelindex +// E5_MODEL16=1: short = s->modelindex +#define E5_MODEL (1<<3) +// E5_FRAME16=0: byte = s->frame +// E5_FRAME16=1: short = s->frame +#define E5_FRAME (1<<4) +// byte = s->skin +#define E5_SKIN (1<<5) +// E5_EFFECTS16=0 && E5_EFFECTS32=0: byte = s->effects +// E5_EFFECTS16=1 && E5_EFFECTS32=0: short = s->effects +// E5_EFFECTS16=0 && E5_EFFECTS32=1: int = s->effects +// E5_EFFECTS16=1 && E5_EFFECTS32=1: int = s->effects +#define E5_EFFECTS (1<<6) +// bits >= (1<<8) +#define E5_EXTEND1 (1<<7) + +// byte = s->renderflags +#define E5_FLAGS (1<<8) +// byte = bound(0, s->alpha * 255, 255) +#define E5_ALPHA (1<<9) +// byte = bound(0, s->scale * 16, 255) +#define E5_SCALE (1<<10) +// flag +#define E5_ORIGIN32 (1<<11) +// flag +#define E5_ANGLES16 (1<<12) +// flag +#define E5_MODEL16 (1<<13) +// byte = s->colormap +#define E5_COLORMAP (1<<14) +// bits >= (1<<16) +#define E5_EXTEND2 (1<<15) + +// short = s->tagentity +// byte = s->tagindex +#define E5_ATTACHMENT (1<<16) +// short[4] = s->light[0], s->light[1], s->light[2], s->light[3] +// byte = s->lightstyle +// byte = s->lightpflags +#define E5_LIGHT (1<<17) +// byte = s->glowsize +// byte = s->glowcolor +#define E5_GLOW (1<<18) +// short = s->effects +#define E5_EFFECTS16 (1<<19) +// int = s->effects +#define E5_EFFECTS32 (1<<20) +// flag +#define E5_FRAME16 (1<<21) +// byte[3] = s->colormod[0], s->colormod[1], s->colormod[2] +#define E5_COLORMOD (1<<22) +// bits >= (1<<24) +#define E5_EXTEND3 (1<<23) + +// byte[3] = s->glowmod[0], s->glowmod[1], s->glowmod[2] +#define E5_GLOWMOD (1<<24) +// byte type=0 short frames[1] short times[1] +// byte type=1 short frames[2] short times[2] byte lerps[2] +// byte type=2 short frames[3] short times[3] byte lerps[3] +// byte type=3 short frames[4] short times[4] byte lerps[4] +// byte type=4 short modelindex byte numbones {short pose7s[7]} +// see also RENDER_COMPLEXANIMATION +#define E5_COMPLEXANIMATION (1<<25) +// ushort traileffectnum +#define E5_TRAILEFFECTNUM (1<<26) +// unused +#define E5_UNUSED27 (1<<27) +// unused +#define E5_UNUSED28 (1<<28) +// unused +#define E5_UNUSED29 (1<<29) +// unused +#define E5_UNUSED30 (1<<30) +// bits2 > 0 +#define E5_EXTEND4 (1<<31) + +#define ENTITYFRAME5_MAXPACKETLOGS 64 +#define ENTITYFRAME5_MAXSTATES 1024 +#define ENTITYFRAME5_PRIORITYLEVELS 32 + +typedef struct entityframe5_changestate_s +{ + unsigned int number; + unsigned int bits; +} +entityframe5_changestate_t; + +typedef struct entityframe5_packetlog_s +{ + int packetnumber; + int numstates; + entityframe5_changestate_t states[ENTITYFRAME5_MAXSTATES]; + unsigned char statsdeltabits[(MAX_CL_STATS+7)/8]; +} +entityframe5_packetlog_t; + +typedef struct entityframe5_database_s +{ + // number of the latest message sent to client + int latestframenum; + // updated by WriteFrame for internal use + int viewentnum; + + // logs of all recently sent messages (between acked and latest) + entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS]; + + // this goes up as needed and causes all the arrays to be reallocated + int maxedicts; + + // which properties of each entity have changed since last send + int *deltabits; // [maxedicts] + // priorities of entities (updated whenever deltabits change) + // (derived from deltabits) + unsigned char *priorities; // [maxedicts] + // last frame this entity was sent on, for prioritzation + int *updateframenum; // [maxedicts] + + // database of current status of all entities + entity_state_t *states; // [maxedicts] + // which entities are currently active + // (duplicate of the active bit of every state in states[]) + // (derived from states) + unsigned char *visiblebits; // [(maxedicts+7)/8] + + // old notes + + // this is used to decide which changestates to set each frame + //int numvisiblestates; + //entity_state_t visiblestates[MAX_EDICTS]; + + // sorted changing states that need to be sent to the client + // kept sorted in lowest to highest priority order, because this allows + // the numchangestates to simply be decremented whenever an state is sent, + // rather than a memmove to remove them from the start. + //int numchangestates; + //entityframe5_changestate_t changestates[MAX_EDICTS]; + + // buffers for building priority info + int prioritychaincounts[ENTITYFRAME5_PRIORITYLEVELS]; + unsigned short prioritychains[ENTITYFRAME5_PRIORITYLEVELS][ENTITYFRAME5_MAXSTATES]; +} +entityframe5_database_t; + +entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool); +void EntityFrame5_FreeDatabase(entityframe5_database_t *d); +void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg); +int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n); +void EntityFrame5_CL_ReadFrame(void); +void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum); +void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum); +qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t **states, int viewentnum, int movesequence, qboolean need_empty); + +extern cvar_t developer_networkentities; + +// QUAKEWORLD +// server to client +#define qw_svc_bad 0 +#define qw_svc_nop 1 +#define qw_svc_disconnect 2 +#define qw_svc_updatestat 3 // [byte] [byte] +#define qw_svc_setview 5 // [short] entity number +#define qw_svc_sound 6 // +#define qw_svc_print 8 // [byte] id [string] null terminated string +#define qw_svc_stufftext 9 // [string] stuffed into client's console buffer +#define qw_svc_setangle 10 // [angle3] set the view angle to this absolute value +#define qw_svc_serverdata 11 // [long] protocol ... +#define qw_svc_lightstyle 12 // [byte] [string] +#define qw_svc_updatefrags 14 // [byte] [short] +#define qw_svc_stopsound 16 // +#define qw_svc_damage 19 +#define qw_svc_spawnstatic 20 +#define qw_svc_spawnbaseline 22 +#define qw_svc_temp_entity 23 // variable +#define qw_svc_setpause 24 // [byte] on / off +#define qw_svc_centerprint 26 // [string] to put in center of the screen +#define qw_svc_killedmonster 27 +#define qw_svc_foundsecret 28 +#define qw_svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten +#define qw_svc_intermission 30 // [vec3_t] origin [vec3_t] angle +#define qw_svc_finale 31 // [string] text +#define qw_svc_cdtrack 32 // [byte] track +#define qw_svc_sellscreen 33 +#define qw_svc_smallkick 34 // set client punchangle to 2 +#define qw_svc_bigkick 35 // set client punchangle to 4 +#define qw_svc_updateping 36 // [byte] [short] +#define qw_svc_updateentertime 37 // [byte] [float] +#define qw_svc_updatestatlong 38 // [byte] [long] +#define qw_svc_muzzleflash 39 // [short] entity +#define qw_svc_updateuserinfo 40 // [byte] slot [long] uid +#define qw_svc_download 41 // [short] size [size bytes] +#define qw_svc_playerinfo 42 // variable +#define qw_svc_nails 43 // [byte] num [48 bits] xyzpy 12 12 12 4 8 +#define qw_svc_chokecount 44 // [byte] packets choked +#define qw_svc_modellist 45 // [strings] +#define qw_svc_soundlist 46 // [strings] +#define qw_svc_packetentities 47 // [...] +#define qw_svc_deltapacketentities 48 // [...] +#define qw_svc_maxspeed 49 // maxspeed change, for prediction +#define qw_svc_entgravity 50 // gravity change, for prediction +#define qw_svc_setinfo 51 // setinfo on a client +#define qw_svc_serverinfo 52 // serverinfo +#define qw_svc_updatepl 53 // [byte] [byte] +// QUAKEWORLD +// client to server +#define qw_clc_bad 0 +#define qw_clc_nop 1 +#define qw_clc_move 3 // [[usercmd_t] +#define qw_clc_stringcmd 4 // [string] message +#define qw_clc_delta 5 // [byte] sequence number, requests delta compression of message +#define qw_clc_tmove 6 // teleport request, spectator only +#define qw_clc_upload 7 // teleport request, spectator only +// QUAKEWORLD +// playerinfo flags from server +// playerinfo always sends: playernum, flags, origin[] and framenumber +#define QW_PF_MSEC (1<<0) +#define QW_PF_COMMAND (1<<1) +#define QW_PF_VELOCITY1 (1<<2) +#define QW_PF_VELOCITY2 (1<<3) +#define QW_PF_VELOCITY3 (1<<4) +#define QW_PF_MODEL (1<<5) +#define QW_PF_SKINNUM (1<<6) +#define QW_PF_EFFECTS (1<<7) +#define QW_PF_WEAPONFRAME (1<<8) // only sent for view player +#define QW_PF_DEAD (1<<9) // don't block movement any more +#define QW_PF_GIB (1<<10) // offset the view height differently +#define QW_PF_NOGRAV (1<<11) // don't apply gravity for prediction +// QUAKEWORLD +// if the high bit of the client to server byte is set, the low bits are +// client move cmd bits +// ms and angle2 are allways sent, the others are optional +#define QW_CM_ANGLE1 (1<<0) +#define QW_CM_ANGLE3 (1<<1) +#define QW_CM_FORWARD (1<<2) +#define QW_CM_SIDE (1<<3) +#define QW_CM_UP (1<<4) +#define QW_CM_BUTTONS (1<<5) +#define QW_CM_IMPULSE (1<<6) +#define QW_CM_ANGLE2 (1<<7) +// QUAKEWORLD +// the first 16 bits of a packetentities update holds 9 bits +// of entity number and 7 bits of flags +#define QW_U_ORIGIN1 (1<<9) +#define QW_U_ORIGIN2 (1<<10) +#define QW_U_ORIGIN3 (1<<11) +#define QW_U_ANGLE2 (1<<12) +#define QW_U_FRAME (1<<13) +#define QW_U_REMOVE (1<<14) // REMOVE this entity, don't add it +#define QW_U_MOREBITS (1<<15) +// if MOREBITS is set, these additional flags are read in next +#define QW_U_ANGLE1 (1<<0) +#define QW_U_ANGLE3 (1<<1) +#define QW_U_MODEL (1<<2) +#define QW_U_COLORMAP (1<<3) +#define QW_U_SKIN (1<<4) +#define QW_U_EFFECTS (1<<5) +#define QW_U_SOLID (1<<6) // the entity should be solid for prediction +// QUAKEWORLD +// temp entity events +#define QW_TE_SPIKE 0 +#define QW_TE_SUPERSPIKE 1 +#define QW_TE_GUNSHOT 2 +#define QW_TE_EXPLOSION 3 +#define QW_TE_TAREXPLOSION 4 +#define QW_TE_LIGHTNING1 5 +#define QW_TE_LIGHTNING2 6 +#define QW_TE_WIZSPIKE 7 +#define QW_TE_KNIGHTSPIKE 8 +#define QW_TE_LIGHTNING3 9 +#define QW_TE_LAVASPLASH 10 +#define QW_TE_TELEPORT 11 +#define QW_TE_BLOOD 12 +#define QW_TE_LIGHTNINGBLOOD 13 +// QUAKEWORLD +// effect flags +#define QW_EF_BRIGHTFIELD 1 +#define QW_EF_MUZZLEFLASH 2 +#define QW_EF_BRIGHTLIGHT 4 +#define QW_EF_DIMLIGHT 8 +#define QW_EF_FLAG1 16 +#define QW_EF_FLAG2 32 +#define QW_EF_BLUE 64 +#define QW_EF_RED 128 + +#define QW_UPDATE_BACKUP 64 +#define QW_UPDATE_MASK (QW_UPDATE_BACKUP - 1) +#define QW_MAX_PACKET_ENTITIES 64 + +// note: QW stats are directly compatible with NQ +// (but FRAGS, WEAPONFRAME, and VIEWHEIGHT are unused) +// so these defines are not actually used by darkplaces, but kept for reference +#define QW_STAT_HEALTH 0 +//#define QW_STAT_FRAGS 1 +#define QW_STAT_WEAPON 2 +#define QW_STAT_AMMO 3 +#define QW_STAT_ARMOR 4 +//#define QW_STAT_WEAPONFRAME 5 +#define QW_STAT_SHELLS 6 +#define QW_STAT_NAILS 7 +#define QW_STAT_ROCKETS 8 +#define QW_STAT_CELLS 9 +#define QW_STAT_ACTIVEWEAPON 10 +#define QW_STAT_TOTALSECRETS 11 +#define QW_STAT_TOTALMONSTERS 12 +#define QW_STAT_SECRETS 13 // bumped on client side by svc_foundsecret +#define QW_STAT_MONSTERS 14 // bumped by svc_killedmonster +#define QW_STAT_ITEMS 15 +//#define QW_STAT_VIEWHEIGHT 16 + +// build entity data in this, to pass to entity read/write functions +typedef struct entityframeqw_snapshot_s +{ + double time; + qboolean invalid; + int num_entities; + entity_state_t entities[QW_MAX_PACKET_ENTITIES]; +} +entityframeqw_snapshot_t; + +typedef struct entityframeqw_database_s +{ + entityframeqw_snapshot_t snapshot[QW_UPDATE_BACKUP]; +} +entityframeqw_database_t; + +entityframeqw_database_t *EntityFrameQW_AllocDatabase(mempool_t *pool); +void EntityFrameQW_FreeDatabase(entityframeqw_database_t *d); +void EntityStateQW_ReadPlayerUpdate(void); +void EntityFrameQW_CL_ReadFrame(qboolean delta); + +struct client_s; +void EntityFrameCSQC_LostFrame(struct client_s *client, int framenum); +qboolean EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numnumbers, const unsigned short *numbers, int framenum); + +#endif + diff --git a/app/jni/prvm_cmds.c b/app/jni/prvm_cmds.c new file mode 100644 index 0000000..c9f5527 --- /dev/null +++ b/app/jni/prvm_cmds.c @@ -0,0 +1,7334 @@ +// AK +// Basically every vm builtin cmd should be in here. +// All 3 builtin and extension lists can be found here +// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds +// also applies here + +#include "quakedef.h" + +#include "prvm_cmds.h" +#include "libcurl.h" +#include + +#include "cl_collision.h" +#include "clvm_cmds.h" +#include "csprogs.h" +#include "ft2.h" +#include "mdfour.h" + +extern cvar_t prvm_backtraceforwarnings; +extern dllhandle_t ode_dll; + +// LordHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value +void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + static double recursive = -1; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + Con_Print(msg); + + // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black] + if(prvm_backtraceforwarnings.integer && recursive != realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set + { + recursive = realtime; + PRVM_PrintState(prog, 0); + recursive = -1; + } +} + + +//============================================================================ +// Common + +// TODO DONE: move vm_files and vm_fssearchlist to prvm_prog_t struct +// TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black] +// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct again) [2007-01-23 LordHavoc] +// TODO: will this war ever end? [2007-01-23 LordHavoc] + +void VM_CheckEmptyString(prvm_prog_t *prog, const char *s) +{ + if (ISWHITESPACE(s[0])) + prog->error_cmd("%s: Bad string", prog->name); +} + +void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed) +{ + // self.frame is the interpolation target (new frame) + // self.frame1time is the animation base time for the interpolation target + // self.frame2 is the interpolation start (previous frame) + // self.frame2time is the animation base time for the interpolation start + // self.lerpfrac is the interpolation strength for self.frame2 + // self.lerpfrac3 is the interpolation strength for self.frame3 + // self.lerpfrac4 is the interpolation strength for self.frame4 + // pitch angle on a player model where the animator set up 5 sets of + // animations and the csqc simply lerps between sets) + framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame ); + framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2 ); + framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3 ); + framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4 ); + framegroupblend[0].start = PRVM_gameedictfloat(ed, frame1time); + framegroupblend[1].start = PRVM_gameedictfloat(ed, frame2time); + framegroupblend[2].start = PRVM_gameedictfloat(ed, frame3time); + framegroupblend[3].start = PRVM_gameedictfloat(ed, frame4time); + framegroupblend[1].lerp = PRVM_gameedictfloat(ed, lerpfrac ); + framegroupblend[2].lerp = PRVM_gameedictfloat(ed, lerpfrac3 ); + framegroupblend[3].lerp = PRVM_gameedictfloat(ed, lerpfrac4 ); + // assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed + framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp; +} + +// LordHavoc: quite tempting to break apart this function to reuse the +// duplicated code, but I suspect it is better for performance +// this way +void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model, double curtime) +{ + int sub2, numframes, f, i, k; + int isfirstframegroup = true; + int nolerp; + double sublerp, lerp, d; + const animscene_t *scene; + const framegroupblend_t *g; + frameblend_t *blend = frameblend; + + memset(blend, 0, MAX_FRAMEBLENDS * sizeof(*blend)); + + if (!model || !model->surfmesh.isanimated) + { + blend[0].lerp = 1; + return; + } + + nolerp = (model->type == mod_sprite) ? !r_lerpsprites.integer : !r_lerpmodels.integer; + numframes = model->numframes; + for (k = 0, g = framegroupblend;k < MAX_FRAMEGROUPBLENDS;k++, g++) + { + f = g->frame; + if ((unsigned int)f >= (unsigned int)numframes) + { + if (developer_extra.integer) + Con_DPrintf("VM_FrameBlendFromFrameGroupBlend: no such frame %d in model %s\n", f, model->name); + f = 0; + } + d = lerp = g->lerp; + if (lerp <= 0) + continue; + if (nolerp) + { + if (isfirstframegroup) + { + d = lerp = 1; + isfirstframegroup = false; + } + else + continue; + } + if (model->animscenes) + { + scene = model->animscenes + f; + f = scene->firstframe; + if (scene->framecount > 1) + { + // this code path is only used on .zym models and torches + sublerp = scene->framerate * (curtime - g->start); + f = (int) floor(sublerp); + sublerp -= f; + sub2 = f + 1; + if (sublerp < (1.0 / 65536.0f)) + sublerp = 0; + if (sublerp > (65535.0f / 65536.0f)) + sublerp = 1; + if (nolerp) + sublerp = 0; + if (scene->loop) + { + f = (f % scene->framecount); + sub2 = (sub2 % scene->framecount); + } + f = bound(0, f, (scene->framecount - 1)) + scene->firstframe; + sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe; + d = sublerp * lerp; + // two framelerps produced from one animation + if (d > 0) + { + for (i = 0;i < MAX_FRAMEBLENDS;i++) + { + if (blend[i].lerp <= 0 || blend[i].subframe == sub2) + { + blend[i].subframe = sub2; + blend[i].lerp += d; + break; + } + } + } + d = (1 - sublerp) * lerp; + } + } + if (d > 0) + { + for (i = 0;i < MAX_FRAMEBLENDS;i++) + { + if (blend[i].lerp <= 0 || blend[i].subframe == f) + { + blend[i].subframe = f; + blend[i].lerp += d; + break; + } + } + } + } +} + +void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend) +{ + if (ed->priv.server->skeleton.model != edmodel) + { + VM_RemoveEdictSkeleton(prog, ed); + ed->priv.server->skeleton.model = edmodel; + } + if (!ed->priv.server->skeleton.model || !ed->priv.server->skeleton.model->num_bones) + { + if(ed->priv.server->skeleton.relativetransforms) + Mem_Free(ed->priv.server->skeleton.relativetransforms); + ed->priv.server->skeleton.relativetransforms = NULL; + return; + } + + { + int skeletonindex = -1; + skeleton_t *skeleton; + skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1; + if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones) + { + // custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS) + if (!ed->priv.server->skeleton.relativetransforms) + ed->priv.server->skeleton.relativetransforms = (matrix4x4_t *)Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t)); + memcpy(ed->priv.server->skeleton.relativetransforms, skeleton->relativetransforms, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t)); + } + else + { + if(ed->priv.server->skeleton.relativetransforms) + Mem_Free(ed->priv.server->skeleton.relativetransforms); + ed->priv.server->skeleton.relativetransforms = NULL; + } + } +} + +void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed) +{ + if (ed->priv.server->skeleton.relativetransforms) + Mem_Free(ed->priv.server->skeleton.relativetransforms); + memset(&ed->priv.server->skeleton, 0, sizeof(ed->priv.server->skeleton)); +} + + + + +//============================================================================ +//BUILT-IN FUNCTIONS + +void VM_VarString(prvm_prog_t *prog, int first, char *out, int outlength) +{ + int i; + const char *s; + char *outend; + + outend = out + outlength - 1; + for (i = first;i < prog->argc && out < outend;i++) + { + s = PRVM_G_STRING((OFS_PARM0+i*3)); + while (out < outend && *s) + *out++ = *s++; + } + *out++ = 0; +} + +/* +================= +VM_checkextension + +returns true if the extension is supported by the server + +checkextension(extensionname) +================= +*/ + +// kind of helper function +static qboolean checkextension(prvm_prog_t *prog, const char *name) +{ + int len; + const char *e, *start; + len = (int)strlen(name); + + for (e = prog->extensionstring;*e;e++) + { + while (*e == ' ') + e++; + if (!*e) + break; + start = e; + while (*e && *e != ' ') + e++; + if ((e - start) == len && !strncasecmp(start, name, len)) + { + // special sheck for ODE + if (!strncasecmp("DP_PHYSICS_ODE", name, 14)) + { +#ifdef ODE_DYNAMIC + return ode_dll ? true : false; +#else +#ifdef ODE_STATIC + return true; +#else + return false; +#endif +#endif + } + + // special sheck for d0_blind_id + if (!strcasecmp("DP_CRYPTO", name)) + return Crypto_Available(); + if (!strcasecmp("DP_QC_DIGEST_SHA256", name)) + return Crypto_Available(); + + return true; + } + } + return false; +} + +void VM_checkextension(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_checkextension); + + PRVM_G_FLOAT(OFS_RETURN) = checkextension(prog, PRVM_G_STRING(OFS_PARM0)); +} + +/* +================= +VM_error + +This is a TERMINAL error, which will kill off the entire prog. +Dumps self. + +error(value) +================= +*/ +void VM_error(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(prog, 0, string, sizeof(string)); + Con_Printf("======%s ERROR in %s:\n%s\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string); + ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)); + PRVM_ED_Print(prog, ed, NULL); + + prog->error_cmd("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string); +} + +/* +================= +VM_objerror + +Dumps out self, then an error message. The program is aborted and self is +removed, but the level can continue. + +objerror(value) +================= +*/ +void VM_objerror(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(prog, 0, string, sizeof(string)); + Con_Printf("======OBJECT ERROR======\n"); // , prog->name, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME + ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)); + PRVM_ED_Print(prog, ed, NULL); + PRVM_ED_Free (prog, ed); + Con_Printf("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string); +} + +/* +================= +VM_print + +print to console + +print(...[string]) +================= +*/ +void VM_print(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(prog, 0, string, sizeof(string)); + Con_Print(string); +} + +/* +================= +VM_bprint + +broadcast print to everyone on server + +bprint(...[string]) +================= +*/ +void VM_bprint(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + + if(!sv.active) + { + VM_Warning(prog, "VM_bprint: game is not server(%s) !\n", prog->name); + return; + } + + VM_VarString(prog, 0, string, sizeof(string)); + SV_BroadcastPrint(string); +} + +/* +================= +VM_sprint (menu & client but only if server.active == true) + +single print to a specific client + +sprint(float clientnum,...[string]) +================= +*/ +void VM_sprint(prvm_prog_t *prog) +{ + client_t *client; + int clientnum; + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_sprint); + + //find client for this entity + clientnum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active) + { + VM_Warning(prog, "VM_sprint: %s: invalid client or server is not active !\n", prog->name); + return; + } + + client = svs.clients + clientnum; + if (!client->netconnection) + return; + + VM_VarString(prog, 1, string, sizeof(string)); + MSG_WriteChar(&client->netconnection->message,svc_print); + MSG_WriteString(&client->netconnection->message, string); +} + +/* +================= +VM_centerprint + +single print to the screen + +centerprint(value) +================= +*/ +void VM_centerprint(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_centerprint); + VM_VarString(prog, 0, string, sizeof(string)); + SCR_CenterPrint(string); +} + +/* +================= +VM_normalize + +vector normalize(vector) +================= +*/ +void VM_normalize(prvm_prog_t *prog) +{ + prvm_vec_t *value1; + vec3_t newvalue; + double f; + + VM_SAFEPARMCOUNT(1,VM_normalize); + + value1 = PRVM_G_VECTOR(OFS_PARM0); + + f = VectorLength2(value1); + if (f) + { + f = 1.0 / sqrt(f); + VectorScale(value1, f, newvalue); + } + else + VectorClear(newvalue); + + VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN)); +} + +/* +================= +VM_vlen + +scalar vlen(vector) +================= +*/ +void VM_vlen(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_vlen); + PRVM_G_FLOAT(OFS_RETURN) = VectorLength(PRVM_G_VECTOR(OFS_PARM0)); +} + +/* +================= +VM_vectoyaw + +float vectoyaw(vector) +================= +*/ +void VM_vectoyaw(prvm_prog_t *prog) +{ + prvm_vec_t *value1; + prvm_vec_t yaw; + + VM_SAFEPARMCOUNT(1,VM_vectoyaw); + + value1 = PRVM_G_VECTOR(OFS_PARM0); + + if (value1[1] == 0 && value1[0] == 0) + yaw = 0; + else + { + yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + } + + PRVM_G_FLOAT(OFS_RETURN) = yaw; +} + + +/* +================= +VM_vectoangles + +vector vectoangles(vector[, vector]) +================= +*/ +void VM_vectoangles(prvm_prog_t *prog) +{ + vec3_t result, forward, up; + VM_SAFEPARMCOUNTRANGE(1, 2,VM_vectoangles); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), forward); + if (prog->argc >= 2) + { + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), up); + AnglesFromVectors(result, forward, up, true); + } + else + AnglesFromVectors(result, forward, NULL, true); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); +} + +/* +================= +VM_random + +Returns a number from 0<= num < 1 + +float random() +================= +*/ +void VM_random(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_random); + + PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0, 1); +} + +/* +========= +VM_localsound + +localsound(string sample) +========= +*/ +void VM_localsound(prvm_prog_t *prog) +{ + const char *s; + + VM_SAFEPARMCOUNT(1,VM_localsound); + + s = PRVM_G_STRING(OFS_PARM0); + + if(!S_LocalSound (s)) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning(prog, "VM_localsound: Failed to play %s for %s !\n", s, prog->name); + return; + } + + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +================= +VM_break + +break() +================= +*/ +void VM_break(prvm_prog_t *prog) +{ + prog->error_cmd("%s: break statement", prog->name); +} + +//============================================================================ + +/* +================= +VM_localcmd + +Sends text over to the client's execution buffer + +[localcmd (string, ...) or] +cmd (string, ...) +================= +*/ +void VM_localcmd(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd); + VM_VarString(prog, 0, string, sizeof(string)); + Cbuf_AddText(string); +} + +static qboolean PRVM_Cvar_ReadOk(const char *string) +{ + cvar_t *cvar; + cvar = Cvar_FindVar(string); + return ((cvar) && ((cvar->flags & CVAR_PRIVATE) == 0)); +} + +/* +================= +VM_cvar + +float cvar (string) +================= +*/ +void VM_cvar(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar); + VM_VarString(prog, 0, string, sizeof(string)); + VM_CheckEmptyString(prog, string); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_Cvar_ReadOk(string) ? Cvar_VariableValue(string) : 0; +} + +/* +================= +VM_cvar + +float cvar_type (string) +float CVAR_TYPEFLAG_EXISTS = 1; +float CVAR_TYPEFLAG_SAVED = 2; +float CVAR_TYPEFLAG_PRIVATE = 4; +float CVAR_TYPEFLAG_ENGINE = 8; +float CVAR_TYPEFLAG_HASDESCRIPTION = 16; +float CVAR_TYPEFLAG_READONLY = 32; +================= +*/ +void VM_cvar_type(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + cvar_t *cvar; + int ret; + + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar); + VM_VarString(prog, 0, string, sizeof(string)); + VM_CheckEmptyString(prog, string); + cvar = Cvar_FindVar(string); + + + if(!cvar) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; // CVAR_TYPE_NONE + } + + ret = 1; // CVAR_EXISTS + if(cvar->flags & CVAR_SAVE) + ret |= 2; // CVAR_TYPE_SAVED + if(cvar->flags & CVAR_PRIVATE) + ret |= 4; // CVAR_TYPE_PRIVATE + if(!(cvar->flags & CVAR_ALLOCATED)) + ret |= 8; // CVAR_TYPE_ENGINE + if(cvar->description != cvar_dummy_description) + ret |= 16; // CVAR_TYPE_HASDESCRIPTION + if(cvar->flags & CVAR_READONLY) + ret |= 32; // CVAR_TYPE_READONLY + + PRVM_G_FLOAT(OFS_RETURN) = ret; +} + +/* +================= +VM_cvar_string + +const string VM_cvar_string (string, ...) +================= +*/ +void VM_cvar_string(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_string); + VM_VarString(prog, 0, string, sizeof(string)); + VM_CheckEmptyString(prog, string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_Cvar_ReadOk(string) ? Cvar_VariableString(string) : ""); +} + + +/* +======================== +VM_cvar_defstring + +const string VM_cvar_defstring (string, ...) +======================== +*/ +void VM_cvar_defstring(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_defstring); + VM_VarString(prog, 0, string, sizeof(string)); + VM_CheckEmptyString(prog, string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDefString(string)); +} + +/* +======================== +VM_cvar_defstring + +const string VM_cvar_description (string, ...) +======================== +*/ +void VM_cvar_description(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_description); + VM_VarString(prog, 0, string, sizeof(string)); + VM_CheckEmptyString(prog, string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDescription(string)); +} +/* +================= +VM_cvar_set + +void cvar_set (string,string, ...) +================= +*/ +void VM_cvar_set(prvm_prog_t *prog) +{ + const char *name; + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2,8,VM_cvar_set); + VM_VarString(prog, 1, string, sizeof(string)); + name = PRVM_G_STRING(OFS_PARM0); + VM_CheckEmptyString(prog, name); + Cvar_Set(name, string); +} + +/* +========= +VM_dprint + +dprint(...[string]) +========= +*/ +void VM_dprint(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_dprint); + VM_VarString(prog, 0, string, sizeof(string)); +#if 1 + Con_DPrintf("%s", string); +#else + Con_DPrintf("%s: %s", prog->name, string); +#endif +} + +/* +========= +VM_ftos + +string ftos(float) +========= +*/ + +void VM_ftos(prvm_prog_t *prog) +{ + prvm_vec_t v; + char s[128]; + + VM_SAFEPARMCOUNT(1, VM_ftos); + + v = PRVM_G_FLOAT(OFS_PARM0); + + if ((prvm_vec_t)((prvm_int_t)v) == v) + dpsnprintf(s, sizeof(s), "%.0f", v); + else + dpsnprintf(s, sizeof(s), "%f", v); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +/* +========= +VM_fabs + +float fabs(float) +========= +*/ + +void VM_fabs(prvm_prog_t *prog) +{ + prvm_vec_t v; + + VM_SAFEPARMCOUNT(1,VM_fabs); + + v = PRVM_G_FLOAT(OFS_PARM0); + PRVM_G_FLOAT(OFS_RETURN) = fabs(v); +} + +/* +========= +VM_vtos + +string vtos(vector) +========= +*/ + +void VM_vtos(prvm_prog_t *prog) +{ + char s[512]; + + VM_SAFEPARMCOUNT(1,VM_vtos); + + dpsnprintf (s, sizeof(s), "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +/* +========= +VM_etos + +string etos(entity) +========= +*/ + +void VM_etos(prvm_prog_t *prog) +{ + char s[128]; + + VM_SAFEPARMCOUNT(1, VM_etos); + + dpsnprintf (s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +/* +========= +VM_stof + +float stof(...[string]) +========= +*/ +void VM_stof(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_stof); + VM_VarString(prog, 0, string, sizeof(string)); + PRVM_G_FLOAT(OFS_RETURN) = atof(string); +} + +/* +======================== +VM_itof + +float itof(int ent) +======================== +*/ +void VM_itof(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_itof); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +/* +======================== +VM_ftoe + +entity ftoe(float num) +======================== +*/ +void VM_ftoe(prvm_prog_t *prog) +{ + prvm_int_t ent; + VM_SAFEPARMCOUNT(1, VM_ftoe); + + ent = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM0); + if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free) + ent = 0; // return world instead of a free or invalid entity + + PRVM_G_INT(OFS_RETURN) = ent; +} + +/* +======================== +VM_etof + +float etof(entity ent) +======================== +*/ +void VM_etof(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_etof); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICTNUM(OFS_PARM0); +} + +/* +========= +VM_strftime + +string strftime(float uselocaltime, string[, string ...]) +========= +*/ +void VM_strftime(prvm_prog_t *prog) +{ + time_t t; +#if _MSC_VER >= 1400 + struct tm tm; + int tmresult; +#else + struct tm *tm; +#endif + char fmt[VM_STRINGTEMP_LENGTH]; + char result[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2, 8, VM_strftime); + VM_VarString(prog, 1, fmt, sizeof(fmt)); + t = time(NULL); +#if _MSC_VER >= 1400 + if (PRVM_G_FLOAT(OFS_PARM0)) + tmresult = localtime_s(&tm, &t); + else + tmresult = gmtime_s(&tm, &t); + if (!tmresult) +#else + if (PRVM_G_FLOAT(OFS_PARM0)) + tm = localtime(&t); + else + tm = gmtime(&t); + if (!tm) +#endif + { + PRVM_G_INT(OFS_RETURN) = 0; + return; + } +#if _MSC_VER >= 1400 + strftime(result, sizeof(result), fmt, &tm); +#else + strftime(result, sizeof(result), fmt, tm); +#endif + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result); +} + +/* +========= +VM_spawn + +entity spawn() +========= +*/ + +void VM_spawn(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + VM_SAFEPARMCOUNT(0, VM_spawn); + prog->xfunction->builtinsprofile += 20; + ed = PRVM_ED_Alloc(prog); + VM_RETURN_EDICT(ed); +} + +/* +========= +VM_remove + +remove(entity e) +========= +*/ + +void VM_remove(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + prog->xfunction->builtinsprofile += 20; + + VM_SAFEPARMCOUNT(1, VM_remove); + + ed = PRVM_G_EDICT(OFS_PARM0); + if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts ) + { + if (developer.integer > 0) + VM_Warning(prog, "VM_remove: tried to remove the null entity or a reserved entity!\n" ); + } + else if( ed->priv.required->free ) + { + if (developer.integer > 0) + VM_Warning(prog, "VM_remove: tried to remove an already freed entity!\n" ); + } + else + PRVM_ED_Free (prog, ed); +} + +/* +========= +VM_find + +entity find(entity start, .string field, string match) +========= +*/ + +void VM_find(prvm_prog_t *prog) +{ + int e; + int f; + const char *s, *t; + prvm_edict_t *ed; + + VM_SAFEPARMCOUNT(3,VM_find); + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = PRVM_G_STRING(OFS_PARM2); + + // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and + // expects it to find all the monsters, so we must be careful to support + // searching for "" + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.required->free) + continue; + t = PRVM_E_STRING(ed,f); + if (!t) + t = ""; + if (!strcmp(t,s)) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +========= +VM_findfloat + + entity findfloat(entity start, .float field, float match) + entity findentity(entity start, .entity field, entity match) +========= +*/ +// LordHavoc: added this for searching float, int, and entity reference fields +void VM_findfloat(prvm_prog_t *prog) +{ + int e; + int f; + float s; + prvm_edict_t *ed; + + VM_SAFEPARMCOUNT(3,VM_findfloat); + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = PRVM_G_FLOAT(OFS_PARM2); + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.required->free) + continue; + if (PRVM_E_FLOAT(ed,f) == s) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +========= +VM_findchain + +entity findchain(.string field, string match) +========= +*/ +// chained search for strings in entity fields +// entity(.string field, string match) findchain = #402; +void VM_findchain(prvm_prog_t *prog) +{ + int i; + int f; + const char *s, *t; + prvm_edict_t *ent, *chain; + int chainfield; + + VM_SAFEPARMCOUNTRANGE(2,3,VM_findchain); + + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name); + + chain = prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = PRVM_G_STRING(OFS_PARM1); + + // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and + // expects it to find all the monsters, so we must be careful to support + // searching for "" + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.required->free) + continue; + t = PRVM_E_STRING(ent,f); + if (!t) + t = ""; + if (strcmp(t,s)) + continue; + + PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_NUM_FOR_EDICT(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +========= +VM_findchainfloat + +entity findchainfloat(.string field, float match) +entity findchainentity(.string field, entity match) +========= +*/ +// LordHavoc: chained search for float, int, and entity reference fields +// entity(.string field, float match) findchainfloat = #403; +void VM_findchainfloat(prvm_prog_t *prog) +{ + int i; + int f; + float s; + prvm_edict_t *ent, *chain; + int chainfield; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainfloat); + + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name); + + chain = (prvm_edict_t *)prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = PRVM_G_FLOAT(OFS_PARM1); + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.required->free) + continue; + if (PRVM_E_FLOAT(ent,f) != s) + continue; + + PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +======================== +VM_findflags + +entity findflags(entity start, .float field, float match) +======================== +*/ +// LordHavoc: search for flags in float fields +void VM_findflags(prvm_prog_t *prog) +{ + prvm_int_t e; + prvm_int_t f; + prvm_int_t s; + prvm_edict_t *ed; + + VM_SAFEPARMCOUNT(3, VM_findflags); + + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM2); + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.required->free) + continue; + if (!PRVM_E_FLOAT(ed,f)) + continue; + if ((prvm_int_t)PRVM_E_FLOAT(ed,f) & s) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +======================== +VM_findchainflags + +entity findchainflags(.float field, float match) +======================== +*/ +// LordHavoc: chained search for flags in float fields +void VM_findchainflags(prvm_prog_t *prog) +{ + prvm_int_t i; + prvm_int_t f; + prvm_int_t s; + prvm_edict_t *ent, *chain; + int chainfield; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainflags); + + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name); + + chain = (prvm_edict_t *)prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM1); + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.required->free) + continue; + if (!PRVM_E_FLOAT(ent,f)) + continue; + if (!((prvm_int_t)PRVM_E_FLOAT(ent,f) & s)) + continue; + + PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +========= +VM_precache_sound + +string precache_sound (string sample) +========= +*/ +void VM_precache_sound(prvm_prog_t *prog) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_precache_sound); + + s = PRVM_G_STRING(OFS_PARM0); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); + //VM_CheckEmptyString(prog, s); + + if(snd_initialized.integer && !S_PrecacheSound(s, true, true)) + { + VM_Warning(prog, "VM_precache_sound: Failed to load %s for %s\n", s, prog->name); + return; + } +} + +/* +================= +VM_precache_file + +returns the same string as output + +does nothing, only used by qcc to build .pak archives +================= +*/ +void VM_precache_file(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_precache_file); + // precache_file is only used to copy files with qcc, it does nothing + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +/* +========= +VM_coredump + +coredump() +========= +*/ +void VM_coredump(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_coredump); + + Cbuf_AddText("prvm_edicts "); + Cbuf_AddText(prog->name); + Cbuf_AddText("\n"); +} + +/* +========= +VM_stackdump + +stackdump() +========= +*/ +void VM_stackdump(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_stackdump); + + PRVM_StackTrace(prog); +} + +/* +========= +VM_crash + +crash() +========= +*/ + +void VM_crash(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_crash); + + prog->error_cmd("Crash called by %s",prog->name); +} + +/* +========= +VM_traceon + +traceon() +========= +*/ +void VM_traceon(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_traceon); + + prog->trace = true; +} + +/* +========= +VM_traceoff + +traceoff() +========= +*/ +void VM_traceoff(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_traceoff); + + prog->trace = false; +} + +/* +========= +VM_eprint + +eprint(entity e) +========= +*/ +void VM_eprint(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_eprint); + + PRVM_ED_PrintNum (prog, PRVM_G_EDICTNUM(OFS_PARM0), NULL); +} + +/* +========= +VM_rint + +float rint(float) +========= +*/ +void VM_rint(prvm_prog_t *prog) +{ + prvm_vec_t f; + VM_SAFEPARMCOUNT(1,VM_rint); + + f = PRVM_G_FLOAT(OFS_PARM0); + if (f > 0) + PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5); + else + PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5); +} + +/* +========= +VM_floor + +float floor(float) +========= +*/ +void VM_floor(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_floor); + + PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_ceil + +float ceil(float) +========= +*/ +void VM_ceil(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_ceil); + + PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0)); +} + + +/* +============= +VM_nextent + +entity nextent(entity) +============= +*/ +void VM_nextent(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + + VM_SAFEPARMCOUNT(1, VM_nextent); + + i = PRVM_G_EDICTNUM(OFS_PARM0); + while (1) + { + prog->xfunction->builtinsprofile++; + i++; + if (i == prog->num_edicts) + { + VM_RETURN_EDICT(prog->edicts); + return; + } + ent = PRVM_EDICT_NUM(i); + if (!ent->priv.required->free) + { + VM_RETURN_EDICT(ent); + return; + } + } +} + +//============================================================================= + +/* +============== +VM_changelevel +server and menu + +changelevel(string map) +============== +*/ +void VM_changelevel(prvm_prog_t *prog) +{ + char vabuf[1024]; + VM_SAFEPARMCOUNT(1, VM_changelevel); + + if(!sv.active) + { + VM_Warning(prog, "VM_changelevel: game is not server (%s)\n", prog->name); + return; + } + +// make sure we don't issue two changelevels + if (svs.changelevel_issued) + return; + svs.changelevel_issued = true; + + Cbuf_AddText(va(vabuf, sizeof(vabuf), "changelevel %s\n",PRVM_G_STRING(OFS_PARM0))); +} + +/* +========= +VM_sin + +float sin(float) +========= +*/ +void VM_sin(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_sin); + PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_cos +float cos(float) +========= +*/ +void VM_cos(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_cos); + PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_sqrt + +float sqrt(float) +========= +*/ +void VM_sqrt(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_sqrt); + PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_asin + +float asin(float) +========= +*/ +void VM_asin(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_asin); + PRVM_G_FLOAT(OFS_RETURN) = asin(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_acos +float acos(float) +========= +*/ +void VM_acos(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_acos); + PRVM_G_FLOAT(OFS_RETURN) = acos(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_atan +float atan(float) +========= +*/ +void VM_atan(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_atan); + PRVM_G_FLOAT(OFS_RETURN) = atan(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_atan2 +float atan2(float,float) +========= +*/ +void VM_atan2(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2,VM_atan2); + PRVM_G_FLOAT(OFS_RETURN) = atan2(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); +} + +/* +========= +VM_tan +float tan(float) +========= +*/ +void VM_tan(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_tan); + PRVM_G_FLOAT(OFS_RETURN) = tan(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +================= +VM_randomvec + +Returns a vector of length < 1 and > 0 + +vector randomvec() +================= +*/ +void VM_randomvec(prvm_prog_t *prog) +{ + vec3_t temp; + VM_SAFEPARMCOUNT(0, VM_randomvec); + VectorRandom(temp); + VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN)); +} + +//============================================================================= + +/* +========= +VM_registercvar + +float registercvar (string name, string value[, float flags]) +========= +*/ +void VM_registercvar(prvm_prog_t *prog) +{ + const char *name, *value; + int flags; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_registercvar); + + name = PRVM_G_STRING(OFS_PARM0); + value = PRVM_G_STRING(OFS_PARM1); + flags = prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : 0; + PRVM_G_FLOAT(OFS_RETURN) = 0; + + if(flags > CVAR_MAXFLAGSVAL) + return; + +// first check to see if it has already been defined + if (Cvar_FindVar (name)) + return; + +// check for overlap with a command + if (Cmd_Exists (name)) + { + VM_Warning(prog, "VM_registercvar: %s is a command\n", name); + return; + } + + Cvar_Get(name, value, flags, NULL); + + PRVM_G_FLOAT(OFS_RETURN) = 1; // success +} + + +/* +================= +VM_min + +returns the minimum of two supplied floats + +float min(float a, float b, ...[float]) +================= +*/ +void VM_min(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNTRANGE(2, 8, VM_min); + // LordHavoc: 3+ argument enhancement suggested by FrikaC + if (prog->argc >= 3) + { + int i; + float f = PRVM_G_FLOAT(OFS_PARM0); + for (i = 1;i < prog->argc;i++) + if (f > PRVM_G_FLOAT((OFS_PARM0+i*3))) + f = PRVM_G_FLOAT((OFS_PARM0+i*3)); + PRVM_G_FLOAT(OFS_RETURN) = f; + } + else + PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); +} + +/* +================= +VM_max + +returns the maximum of two supplied floats + +float max(float a, float b, ...[float]) +================= +*/ +void VM_max(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNTRANGE(2, 8, VM_max); + // LordHavoc: 3+ argument enhancement suggested by FrikaC + if (prog->argc >= 3) + { + int i; + float f = PRVM_G_FLOAT(OFS_PARM0); + for (i = 1;i < prog->argc;i++) + if (f < PRVM_G_FLOAT((OFS_PARM0+i*3))) + f = PRVM_G_FLOAT((OFS_PARM0+i*3)); + PRVM_G_FLOAT(OFS_RETURN) = f; + } + else + PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); +} + +/* +================= +VM_bound + +returns number bounded by supplied range + +float bound(float min, float value, float max) +================= +*/ +void VM_bound(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3,VM_bound); + PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2)); +} + +/* +================= +VM_pow + +returns a raised to power b + +float pow(float a, float b) +================= +*/ +void VM_pow(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2,VM_pow); + PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); +} + +void VM_log(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_log); + PRVM_G_FLOAT(OFS_RETURN) = log(PRVM_G_FLOAT(OFS_PARM0)); +} + +void VM_Files_Init(prvm_prog_t *prog) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENFILES;i++) + prog->openfiles[i] = NULL; +} + +void VM_Files_CloseAll(prvm_prog_t *prog) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENFILES;i++) + { + if (prog->openfiles[i]) + FS_Close(prog->openfiles[i]); + prog->openfiles[i] = NULL; + } +} + +static qfile_t *VM_GetFileHandle(prvm_prog_t *prog, int index) +{ + if (index < 0 || index >= PRVM_MAX_OPENFILES) + { + Con_Printf("VM_GetFileHandle: invalid file handle %i used in %s\n", index, prog->name); + return NULL; + } + if (prog->openfiles[index] == NULL) + { + Con_Printf("VM_GetFileHandle: no such file handle %i (or file has been closed) in %s\n", index, prog->name); + return NULL; + } + return prog->openfiles[index]; +} + +/* +========= +VM_fopen + +float fopen(string filename, float mode) +========= +*/ +// float(string filename, float mode) fopen = #110; +// opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), +// returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason +void VM_fopen(prvm_prog_t *prog) +{ + int filenum, mode; + const char *modestring, *filename; + char vabuf[1024]; + + VM_SAFEPARMCOUNT(2,VM_fopen); + + for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++) + if (prog->openfiles[filenum] == NULL) + break; + if (filenum >= PRVM_MAX_OPENFILES) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_fopen: %s ran out of file handles (%i)\n", prog->name, PRVM_MAX_OPENFILES); + return; + } + filename = PRVM_G_STRING(OFS_PARM0); + mode = (int)PRVM_G_FLOAT(OFS_PARM1); + switch(mode) + { + case 0: // FILE_READ + modestring = "rb"; + prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false); + if (prog->openfiles[filenum] == NULL) + prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false); + break; + case 1: // FILE_APPEND + modestring = "a"; + prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false); + break; + case 2: // FILE_WRITE + modestring = "w"; + prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false); + break; + default: + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning(prog, "VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", prog->name, mode); + return; + } + + if (prog->openfiles[filenum] == NULL) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + if (developer_extra.integer) + VM_Warning(prog, "VM_fopen: %s: %s mode %s failed\n", prog->name, filename, modestring); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = filenum; + if (developer_extra.integer) + Con_DPrintf("VM_fopen: %s: %s mode %s opened as #%i\n", prog->name, filename, modestring, filenum); + prog->openfiles_origin[filenum] = PRVM_AllocationOrigin(prog); + } +} + +/* +========= +VM_fclose + +fclose(float fhandle) +========= +*/ +//void(float fhandle) fclose = #111; // closes a file +void VM_fclose(prvm_prog_t *prog) +{ + int filenum; + + VM_SAFEPARMCOUNT(1,VM_fclose); + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning(prog, "VM_fclose: invalid file handle %i used in %s\n", filenum, prog->name); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning(prog, "VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name); + return; + } + FS_Close(prog->openfiles[filenum]); + prog->openfiles[filenum] = NULL; + if(prog->openfiles_origin[filenum]) + PRVM_Free((char *)prog->openfiles_origin[filenum]); + if (developer_extra.integer) + Con_DPrintf("VM_fclose: %s: #%i closed\n", prog->name, filenum); +} + +/* +========= +VM_fgets + +string fgets(float fhandle) +========= +*/ +//string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring +void VM_fgets(prvm_prog_t *prog) +{ + int c, end; + char string[VM_STRINGTEMP_LENGTH]; + int filenum; + + VM_SAFEPARMCOUNT(1,VM_fgets); + + // set the return value regardless of any possible errors + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning(prog, "VM_fgets: invalid file handle %i used in %s\n", filenum, prog->name); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning(prog, "VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name); + return; + } + end = 0; + for (;;) + { + c = FS_Getc(prog->openfiles[filenum]); + if (c == '\r' || c == '\n' || c < 0) + break; + if (end < VM_STRINGTEMP_LENGTH - 1) + string[end++] = c; + } + string[end] = 0; + // remove \n following \r + if (c == '\r') + { + c = FS_Getc(prog->openfiles[filenum]); + if (c != '\n') + FS_UnGetc(prog->openfiles[filenum], (unsigned char)c); + } + if (developer_extra.integer) + Con_DPrintf("fgets: %s: %s\n", prog->name, string); + if (c >= 0 || end) + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +/* +========= +VM_fputs + +fputs(float fhandle, string s) +========= +*/ +//void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file +void VM_fputs(prvm_prog_t *prog) +{ + int stringlength; + char string[VM_STRINGTEMP_LENGTH]; + int filenum; + + VM_SAFEPARMCOUNT(2,VM_fputs); + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning(prog, "VM_fputs: invalid file handle %i used in %s\n", filenum, prog->name); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning(prog, "VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name); + return; + } + VM_VarString(prog, 1, string, sizeof(string)); + if ((stringlength = (int)strlen(string))) + FS_Write(prog->openfiles[filenum], string, stringlength); + if (developer_extra.integer) + Con_DPrintf("fputs: %s: %s\n", prog->name, string); +} + +/* +========= +VM_writetofile + + writetofile(float fhandle, entity ent) +========= +*/ +void VM_writetofile(prvm_prog_t *prog) +{ + prvm_edict_t * ent; + qfile_t *file; + + VM_SAFEPARMCOUNT(2, VM_writetofile); + + file = VM_GetFileHandle(prog, (int)PRVM_G_FLOAT(OFS_PARM0)); + if( !file ) + { + VM_Warning(prog, "VM_writetofile: invalid or closed file handle\n"); + return; + } + + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + VM_Warning(prog, "VM_writetofile: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent)); + return; + } + + PRVM_ED_Write (prog, file, ent); +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_numentityfields + +float() numentityfields +Return the number of entity fields - NOT offsets +========= +*/ +void VM_numentityfields(prvm_prog_t *prog) +{ + PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs; +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_entityfieldname + +string(float fieldnum) entityfieldname +Return name of the specified field as a string, or empty if the field is invalid (warning) +========= +*/ +void VM_entityfieldname(prvm_prog_t *prog) +{ + ddef_t *d; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->numfielddefs) + { + VM_Warning(prog, "VM_entityfieldname: %s: field index out of bounds\n", prog->name); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); + return; + } + + d = &prog->fielddefs[i]; + PRVM_G_INT(OFS_RETURN) = d->s_name; // presuming that s_name points to a string already +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_entityfieldtype + +float(float fieldnum) entityfieldtype +========= +*/ +void VM_entityfieldtype(prvm_prog_t *prog) +{ + ddef_t *d; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->numfielddefs) + { + VM_Warning(prog, "VM_entityfieldtype: %s: field index out of bounds\n", prog->name); + PRVM_G_FLOAT(OFS_RETURN) = -1.0; + return; + } + + d = &prog->fielddefs[i]; + PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t)d->type; +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_getentityfieldstring + +string(float fieldnum, entity ent) getentityfieldstring +========= +*/ +void VM_getentityfieldstring(prvm_prog_t *prog) +{ + // put the data into a string + ddef_t *d; + int type, j; + prvm_eval_t *val; + prvm_edict_t * ent; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + char valuebuf[MAX_INPUTLINE]; + + if (i < 0 || i >= prog->numfielddefs) + { + VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); + return; + } + + d = &prog->fielddefs[i]; + + // get the entity + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); + VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent)); + return; + } + val = (prvm_eval_t *)(ent->fields.fp + d->ofs); + + // if it's 0 or blank, return an empty string + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jivector[j]) + break; + if (j == prvm_type_size[type]) + { + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); + return; + } + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf))); +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_putentityfieldstring + +float(float fieldnum, entity ent, string s) putentityfieldstring +========= +*/ +void VM_putentityfieldstring(prvm_prog_t *prog) +{ + ddef_t *d; + prvm_edict_t * ent; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->numfielddefs) + { + VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0.0f; + return; + } + + d = &prog->fielddefs[i]; + + // get the entity + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent)); + PRVM_G_FLOAT(OFS_RETURN) = 0.0f; + return; + } + + // parse the string into the value + PRVM_G_FLOAT(OFS_RETURN) = ( PRVM_ED_ParseEpair(prog, ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f; +} + +/* +========= +VM_strlen + +float strlen(string s) +========= +*/ +//float(string s) strlen = #114; // returns how many characters are in a string +void VM_strlen(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_strlen); + + //PRVM_G_FLOAT(OFS_RETURN) = strlen(PRVM_G_STRING(OFS_PARM0)); + PRVM_G_FLOAT(OFS_RETURN) = u8_strlen(PRVM_G_STRING(OFS_PARM0)); +} + +// DRESK - Decolorized String +/* +========= +VM_strdecolorize + +string strdecolorize(string s) +========= +*/ +// string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped +void VM_strdecolorize(prvm_prog_t *prog) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strdecolorize); + szString = PRVM_G_STRING(OFS_PARM0); + COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), TRUE); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString); +} + +// DRESK - String Length (not counting color codes) +/* +========= +VM_strlennocol + +float strlennocol(string s) +========= +*/ +// float(string s) strlennocol = #471; // returns how many characters are in a string not including color codes +// For example, ^2Dresk returns a length of 5 +void VM_strlennocol(prvm_prog_t *prog) +{ + const char *szString; + int nCnt; + + VM_SAFEPARMCOUNT(1,VM_strlennocol); + + szString = PRVM_G_STRING(OFS_PARM0); + + //nCnt = COM_StringLengthNoColors(szString, 0, NULL); + nCnt = u8_COM_StringLengthNoColors(szString, 0, NULL); + + PRVM_G_FLOAT(OFS_RETURN) = nCnt; +} + +// DRESK - String to Uppercase and Lowercase +/* +========= +VM_strtolower + +string strtolower(string s) +========= +*/ +// string (string s) strtolower = #480; // returns passed in string in lowercase form +void VM_strtolower(prvm_prog_t *prog) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strtolower); + szString = PRVM_G_STRING(OFS_PARM0); + + COM_ToLowerString(szString, szNewString, sizeof(szNewString) ); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString); +} + +/* +========= +VM_strtoupper + +string strtoupper(string s) +========= +*/ +// string (string s) strtoupper = #481; // returns passed in string in uppercase form +void VM_strtoupper(prvm_prog_t *prog) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strtoupper); + szString = PRVM_G_STRING(OFS_PARM0); + + COM_ToUpperString(szString, szNewString, sizeof(szNewString) ); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString); +} + +/* +========= +VM_strcat + +string strcat(string,string,...[string]) +========= +*/ +//string(string s1, string s2) strcat = #115; +// concatenates two strings (for example "abc", "def" would return "abcdef") +// and returns as a tempstring +void VM_strcat(prvm_prog_t *prog) +{ + char s[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_strcat); + + VM_VarString(prog, 0, s, sizeof(s)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +/* +========= +VM_substring + +string substring(string s, float start, float length) +========= +*/ +// string(string s, float start, float length) substring = #116; +// returns a section of a string as a tempstring +void VM_substring(prvm_prog_t *prog) +{ + int start, length; + int u_slength = 0, u_start; + size_t u_length; + const char *s; + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(3,VM_substring); + + /* + s = PRVM_G_STRING(OFS_PARM0); + start = (int)PRVM_G_FLOAT(OFS_PARM1); + length = (int)PRVM_G_FLOAT(OFS_PARM2); + slength = strlen(s); + + if (start < 0) // FTE_STRINGS feature + start += slength; + start = bound(0, start, slength); + + if (length < 0) // FTE_STRINGS feature + length += slength - start + 1; + maxlen = min((int)sizeof(string) - 1, slength - start); + length = bound(0, length, maxlen); + + memcpy(string, s + start, length); + string[length] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); + */ + + s = PRVM_G_STRING(OFS_PARM0); + start = (int)PRVM_G_FLOAT(OFS_PARM1); + length = (int)PRVM_G_FLOAT(OFS_PARM2); + + if (start < 0) // FTE_STRINGS feature + { + u_slength = u8_strlen(s); + start += u_slength; + start = bound(0, start, u_slength); + } + + if (length < 0) // FTE_STRINGS feature + { + if (!u_slength) // it's not calculated when it's not needed above + u_slength = u8_strlen(s); + length += u_slength - start + 1; + } + + // positive start, positive length + u_start = u8_byteofs(s, start, NULL); + if (u_start < 0) + { + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); + return; + } + u_length = u8_bytelen(s + u_start, length); + if (u_length >= sizeof(string)-1) + u_length = sizeof(string)-1; + + memcpy(string, s + u_start, u_length); + string[u_length] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +/* +========= +VM_strreplace + +string(string search, string replace, string subject) strreplace = #484; +========= +*/ +// replaces all occurrences of search with replace in the string subject, and returns the result +void VM_strreplace(prvm_prog_t *prog) +{ + int i, j, si; + const char *search, *replace, *subject; + char string[VM_STRINGTEMP_LENGTH]; + int search_len, replace_len, subject_len; + + VM_SAFEPARMCOUNT(3,VM_strreplace); + + search = PRVM_G_STRING(OFS_PARM0); + replace = PRVM_G_STRING(OFS_PARM1); + subject = PRVM_G_STRING(OFS_PARM2); + + search_len = (int)strlen(search); + replace_len = (int)strlen(replace); + subject_len = (int)strlen(subject); + + si = 0; + for (i = 0; i <= subject_len - search_len; i++) + { + for (j = 0; j < search_len; j++) // thus, i+j < subject_len + if (subject[i+j] != search[j]) + break; + if (j == search_len) + { + // NOTE: if search_len == 0, we always hit THIS case, and never the other + // found it at offset 'i' + for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++) + string[si++] = replace[j]; + if(search_len > 0) + { + i += search_len - 1; + } + else + { + // the above would subtract 1 from i... so we + // don't do that, but instead output the next + // char + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + else + { + // in THIS case, we know search_len > 0, thus i < subject_len + // not found + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + // remaining chars (these cannot match) + for (; i < subject_len; i++) + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + string[si] = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +/* +========= +VM_strireplace + +string(string search, string replace, string subject) strireplace = #485; +========= +*/ +// case-insensitive version of strreplace +void VM_strireplace(prvm_prog_t *prog) +{ + int i, j, si; + const char *search, *replace, *subject; + char string[VM_STRINGTEMP_LENGTH]; + int search_len, replace_len, subject_len; + + VM_SAFEPARMCOUNT(3,VM_strreplace); + + search = PRVM_G_STRING(OFS_PARM0); + replace = PRVM_G_STRING(OFS_PARM1); + subject = PRVM_G_STRING(OFS_PARM2); + + search_len = (int)strlen(search); + replace_len = (int)strlen(replace); + subject_len = (int)strlen(subject); + + si = 0; + for (i = 0; i <= subject_len - search_len; i++) + { + for (j = 0; j < search_len; j++) // thus, i+j < subject_len + if (tolower(subject[i+j]) != tolower(search[j])) + break; + if (j == search_len) + { + // NOTE: if search_len == 0, we always hit THIS case, and never the other + // found it at offset 'i' + for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++) + string[si++] = replace[j]; + if(search_len > 0) + { + i += search_len - 1; + } + else + { + // the above would subtract 1 from i... so we + // don't do that, but instead output the next + // char + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + else + { + // in THIS case, we know search_len > 0, thus i < subject_len + // not found + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + // remaining chars (these cannot match) + for (; i < subject_len; i++) + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + string[si] = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +/* +========= +VM_stov + +vector stov(string s) +========= +*/ +//vector(string s) stov = #117; // returns vector value from a string +void VM_stov(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(1,VM_stov); + + VM_VarString(prog, 0, string, sizeof(string)); + Math_atov(string, PRVM_G_VECTOR(OFS_RETURN)); +} + +/* +========= +VM_strzone + +string strzone(string s) +========= +*/ +//string(string s, ...) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often) +void VM_strzone(prvm_prog_t *prog) +{ + char *out; + char string[VM_STRINGTEMP_LENGTH]; + size_t alloclen; + + VM_SAFEPARMCOUNT(1,VM_strzone); + + VM_VarString(prog, 0, string, sizeof(string)); + alloclen = strlen(string) + 1; + PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(prog, alloclen, &out); + memcpy(out, string, alloclen); +} + +/* +========= +VM_strunzone + +strunzone(string s) +========= +*/ +//void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!) +void VM_strunzone(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_strunzone); + PRVM_FreeString(prog, PRVM_G_INT(OFS_PARM0)); +} + +/* +========= +VM_command (used by client and menu) + +clientcommand(float client, string s) (for client and menu) +========= +*/ +//void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client +//this function originally written by KrimZon, made shorter by LordHavoc +void VM_clcommand (prvm_prog_t *prog) +{ + client_t *temp_client; + int i; + + VM_SAFEPARMCOUNT(2,VM_clcommand); + + i = (int)PRVM_G_FLOAT(OFS_PARM0); + if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active) + { + VM_Warning(prog, "VM_clientcommand: %s: invalid client/server is not active !\n", prog->name); + return; + } + + temp_client = host_client; + host_client = svs.clients + i; + Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true); + host_client = temp_client; +} + + +/* +========= +VM_tokenize + +float tokenize(string s) +========= +*/ +//float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many +//this function originally written by KrimZon, made shorter by LordHavoc +//20040203: rewritten by LordHavoc (no longer uses allocations) +static int num_tokens = 0; +static int tokens[VM_STRINGTEMP_LENGTH / 2]; +static int tokens_startpos[VM_STRINGTEMP_LENGTH / 2]; +static int tokens_endpos[VM_STRINGTEMP_LENGTH / 2]; +static char tokenize_string[VM_STRINGTEMP_LENGTH]; +void VM_tokenize (prvm_prog_t *prog) +{ + const char *p; + + VM_SAFEPARMCOUNT(1,VM_tokenize); + + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; + + num_tokens = 0; + for(;;) + { + if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0]))) + break; + + // skip whitespace here to find token start pos + while(*p && ISWHITESPACE(*p)) + ++p; + + tokens_startpos[num_tokens] = p - tokenize_string; + if(!COM_ParseToken_VM_Tokenize(&p, false)) + break; + tokens_endpos[num_tokens] = p - tokenize_string; + tokens[num_tokens] = PRVM_SetTempString(prog, com_token); + ++num_tokens; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +//float(string s) tokenize = #514; // takes apart a string into individal words (access them with argv), returns how many +void VM_tokenize_console (prvm_prog_t *prog) +{ + const char *p; + + VM_SAFEPARMCOUNT(1,VM_tokenize); + + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; + + num_tokens = 0; + for(;;) + { + if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0]))) + break; + + // skip whitespace here to find token start pos + while(*p && ISWHITESPACE(*p)) + ++p; + + tokens_startpos[num_tokens] = p - tokenize_string; + if(!COM_ParseToken_Console(&p)) + break; + tokens_endpos[num_tokens] = p - tokenize_string; + tokens[num_tokens] = PRVM_SetTempString(prog, com_token); + ++num_tokens; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +/* +========= +VM_tokenizebyseparator + +float tokenizebyseparator(string s, string separator1, ...) +========= +*/ +//float(string s, string separator1, ...) tokenizebyseparator = #479; // takes apart a string into individal words (access them with argv), returns how many +//this function returns the token preceding each instance of a separator (of +//which there can be multiple), and the text following the last separator +//useful for parsing certain kinds of data like IP addresses +//example: +//numnumbers = tokenizebyseparator("10.1.2.3", "."); +//returns 4 and the tokens "10" "1" "2" "3". +void VM_tokenizebyseparator (prvm_prog_t *prog) +{ + int j, k; + int numseparators; + int separatorlen[7]; + const char *separators[7]; + const char *p, *p0; + const char *token; + char tokentext[MAX_INPUTLINE]; + + VM_SAFEPARMCOUNTRANGE(2, 8,VM_tokenizebyseparator); + + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; + + numseparators = 0; + for (j = 1;j < prog->argc;j++) + { + // skip any blank separator strings + const char *s = PRVM_G_STRING(OFS_PARM0+j*3); + if (!s[0]) + continue; + separators[numseparators] = s; + separatorlen[numseparators] = strlen(s); + numseparators++; + } + + num_tokens = 0; + j = 0; + + while (num_tokens < (int)(sizeof(tokens)/sizeof(tokens[0]))) + { + token = tokentext + j; + tokens_startpos[num_tokens] = p - tokenize_string; + p0 = p; + while (*p) + { + for (k = 0;k < numseparators;k++) + { + if (!strncmp(p, separators[k], separatorlen[k])) + { + p += separatorlen[k]; + break; + } + } + if (k < numseparators) + break; + if (j < (int)sizeof(tokentext)-1) + tokentext[j++] = *p; + p++; + p0 = p; + } + tokens_endpos[num_tokens] = p0 - tokenize_string; + if (j >= (int)sizeof(tokentext)) + break; + tokentext[j++] = 0; + tokens[num_tokens++] = PRVM_SetTempString(prog, token); + if (!*p) + break; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +//string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index) +//this function originally written by KrimZon, made shorter by LordHavoc +void VM_argv (prvm_prog_t *prog) +{ + int token_num; + + VM_SAFEPARMCOUNT(1,VM_argv); + + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(token_num < 0) + token_num += num_tokens; + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_INT(OFS_RETURN) = tokens[token_num]; + else + PRVM_G_INT(OFS_RETURN) = OFS_NULL; +} + +//float(float n) argv_start_index = #515; // returns the start index of a token +void VM_argv_start_index (prvm_prog_t *prog) +{ + int token_num; + + VM_SAFEPARMCOUNT(1,VM_argv); + + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(token_num < 0) + token_num += num_tokens; + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_FLOAT(OFS_RETURN) = tokens_startpos[token_num]; + else + PRVM_G_FLOAT(OFS_RETURN) = -1; +} + +//float(float n) argv_end_index = #516; // returns the end index of a token +void VM_argv_end_index (prvm_prog_t *prog) +{ + int token_num; + + VM_SAFEPARMCOUNT(1,VM_argv); + + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(token_num < 0) + token_num += num_tokens; + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_FLOAT(OFS_RETURN) = tokens_endpos[token_num]; + else + PRVM_G_FLOAT(OFS_RETURN) = -1; +} + +/* +========= +VM_isserver + +float isserver() +========= +*/ +void VM_isserver(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_serverstate); + + PRVM_G_FLOAT(OFS_RETURN) = sv.active && (svs.maxclients > 1 || cls.state == ca_dedicated); +} + +/* +========= +VM_clientcount + +float clientcount() +========= +*/ +void VM_clientcount(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_clientcount); + + PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients; +} + +/* +========= +VM_clientstate + +float clientstate() +========= +*/ +void VM_clientstate(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_clientstate); + + + switch( cls.state ) { + case ca_uninitialized: + case ca_dedicated: + PRVM_G_FLOAT(OFS_RETURN) = 0; + break; + case ca_disconnected: + PRVM_G_FLOAT(OFS_RETURN) = 1; + break; + case ca_connected: + PRVM_G_FLOAT(OFS_RETURN) = 2; + break; + default: + // should never be reached! + break; + } +} + +/* +========= +VM_getostype + +float getostype(prvm_prog_t *prog) +========= +*/ // not used at the moment -> not included in the common list +void VM_getostype(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_getostype); + + /* + OS_WINDOWS + OS_LINUX + OS_MAC - not supported + */ + +#ifdef WIN32 + PRVM_G_FLOAT(OFS_RETURN) = 0; +#elif defined(MACOSX) + PRVM_G_FLOAT(OFS_RETURN) = 2; +#else + PRVM_G_FLOAT(OFS_RETURN) = 1; +#endif +} + +/* +========= +VM_gettime + +float gettime(prvm_prog_t *prog) +========= +*/ +float CDAudio_GetPosition(void); +void VM_gettime(prvm_prog_t *prog) +{ + int timer_index; + + VM_SAFEPARMCOUNTRANGE(0,1,VM_gettime); + + if(prog->argc == 0) + { + PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t) realtime; + } + else + { + timer_index = (int) PRVM_G_FLOAT(OFS_PARM0); + switch(timer_index) + { + case 0: // GETTIME_FRAMESTART + PRVM_G_FLOAT(OFS_RETURN) = realtime; + break; + case 1: // GETTIME_REALTIME + PRVM_G_FLOAT(OFS_RETURN) = Sys_DirtyTime(); + break; + case 2: // GETTIME_HIRES + PRVM_G_FLOAT(OFS_RETURN) = (Sys_DirtyTime() - host_dirtytime); + break; + case 3: // GETTIME_UPTIME + PRVM_G_FLOAT(OFS_RETURN) = realtime; + break; + case 4: // GETTIME_CDTRACK + PRVM_G_FLOAT(OFS_RETURN) = CDAudio_GetPosition(); + break; + default: + VM_Warning(prog, "VM_gettime: %s: unsupported timer specified, returning realtime\n", prog->name); + PRVM_G_FLOAT(OFS_RETURN) = realtime; + break; + } + } +} + +/* +========= +VM_getsoundtime + +float getsoundtime(prvm_prog_t *prog) +========= +*/ + +void VM_getsoundtime (prvm_prog_t *prog) +{ + int entnum, entchannel; + VM_SAFEPARMCOUNT(2,VM_getsoundtime); + + if (prog == SVVM_prog) + entnum = PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)); + else if (prog == CLVM_prog) + entnum = MAX_EDICTS + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)); + else + { + VM_Warning(prog, "VM_getsoundtime: %s: not supported on this progs\n", prog->name); + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + entchannel = (int)PRVM_G_FLOAT(OFS_PARM1); + entchannel = CHAN_USER2ENGINE(entchannel); + if (!IS_CHAN(entchannel)) + VM_Warning(prog, "VM_getsoundtime: %s: bad channel %i\n", prog->name, entchannel); + PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t)S_GetEntChannelPosition(entnum, entchannel); +} + +/* +========= +VM_GetSoundLen + +string soundlength (string sample) +========= +*/ +void VM_soundlength (prvm_prog_t *prog) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_soundlength); + + s = PRVM_G_STRING(OFS_PARM0); + PRVM_G_FLOAT(OFS_RETURN) = S_SoundLength(s); +} + +/* +========= +VM_loadfromdata + +loadfromdata(string data) +========= +*/ +void VM_loadfromdata(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_loadentsfromfile); + + PRVM_ED_LoadFromFile(prog, PRVM_G_STRING(OFS_PARM0)); +} + +/* +======================== +VM_parseentitydata + +parseentitydata(entity ent, string data) +======================== +*/ +void VM_parseentitydata(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + const char *data; + + VM_SAFEPARMCOUNT(2, VM_parseentitydata); + + // get edict and test it + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent->priv.required->free) + prog->error_cmd("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", prog->name, PRVM_NUM_FOR_EDICT(ent)); + + data = PRVM_G_STRING(OFS_PARM1); + + // parse the opening brace + if (!COM_ParseToken_Simple(&data, false, false, true) || com_token[0] != '{' ) + prog->error_cmd("VM_parseentitydata: %s: Couldn't parse entity data:\n%s", prog->name, data ); + + PRVM_ED_ParseEdict (prog, data, ent); +} + +/* +========= +VM_loadfromfile + +loadfromfile(string file) +========= +*/ +void VM_loadfromfile(prvm_prog_t *prog) +{ + const char *filename; + char *data; + + VM_SAFEPARMCOUNT(1,VM_loadfromfile); + + filename = PRVM_G_STRING(OFS_PARM0); + if (FS_CheckNastyPath(filename, false)) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning(prog, "VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", prog->name, filename); + return; + } + + // not conform with VM_fopen + data = (char *)FS_LoadFile(filename, tempmempool, false, NULL); + if (data == NULL) + PRVM_G_FLOAT(OFS_RETURN) = -1; + + PRVM_ED_LoadFromFile(prog, data); + + if(data) + Mem_Free(data); +} + + +/* +========= +VM_modulo + +float mod(float val, float m) +========= +*/ +void VM_modulo(prvm_prog_t *prog) +{ + prvm_int_t val, m; + VM_SAFEPARMCOUNT(2,VM_module); + + val = (prvm_int_t) PRVM_G_FLOAT(OFS_PARM0); + m = (prvm_int_t) PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t) (val % m); +} + +static void VM_Search_Init(prvm_prog_t *prog) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENSEARCHES;i++) + prog->opensearches[i] = NULL; +} + +static void VM_Search_Reset(prvm_prog_t *prog) +{ + int i; + // reset the fssearch list + for(i = 0; i < PRVM_MAX_OPENSEARCHES; i++) + { + if(prog->opensearches[i]) + FS_FreeSearch(prog->opensearches[i]); + prog->opensearches[i] = NULL; + } +} + +/* +========= +VM_search_begin + +float search_begin(string pattern, float caseinsensitive, float quiet) +========= +*/ +void VM_search_begin(prvm_prog_t *prog) +{ + int handle; + const char *pattern; + int caseinsens, quiet; + + VM_SAFEPARMCOUNT(3, VM_search_begin); + + pattern = PRVM_G_STRING(OFS_PARM0); + + VM_CheckEmptyString(prog, pattern); + + caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1); + quiet = (int)PRVM_G_FLOAT(OFS_PARM2); + + for(handle = 0; handle < PRVM_MAX_OPENSEARCHES; handle++) + if(!prog->opensearches[handle]) + break; + + if(handle >= PRVM_MAX_OPENSEARCHES) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_search_begin: %s ran out of search handles (%i)\n", prog->name, PRVM_MAX_OPENSEARCHES); + return; + } + + if(!(prog->opensearches[handle] = FS_Search(pattern,caseinsens, quiet))) + PRVM_G_FLOAT(OFS_RETURN) = -1; + else + { + prog->opensearches_origin[handle] = PRVM_AllocationOrigin(prog); + PRVM_G_FLOAT(OFS_RETURN) = handle; + } +} + +/* +========= +VM_search_end + +void search_end(float handle) +========= +*/ +void VM_search_end(prvm_prog_t *prog) +{ + int handle; + VM_SAFEPARMCOUNT(1, VM_search_end); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning(prog, "VM_search_end: invalid handle %i used in %s\n", handle, prog->name); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning(prog, "VM_search_end: no such handle %i in %s\n", handle, prog->name); + return; + } + + FS_FreeSearch(prog->opensearches[handle]); + prog->opensearches[handle] = NULL; + if(prog->opensearches_origin[handle]) + PRVM_Free((char *)prog->opensearches_origin[handle]); +} + +/* +========= +VM_search_getsize + +float search_getsize(float handle) +========= +*/ +void VM_search_getsize(prvm_prog_t *prog) +{ + int handle; + VM_SAFEPARMCOUNT(1, VM_M_search_getsize); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning(prog, "VM_search_getsize: invalid handle %i used in %s\n", handle, prog->name); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning(prog, "VM_search_getsize: no such handle %i in %s\n", handle, prog->name); + return; + } + + PRVM_G_FLOAT(OFS_RETURN) = prog->opensearches[handle]->numfilenames; +} + +/* +========= +VM_search_getfilename + +string search_getfilename(float handle, float num) +========= +*/ +void VM_search_getfilename(prvm_prog_t *prog) +{ + int handle, filenum; + VM_SAFEPARMCOUNT(2, VM_search_getfilename); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + filenum = (int)PRVM_G_FLOAT(OFS_PARM1); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning(prog, "VM_search_getfilename: invalid handle %i used in %s\n", handle, prog->name); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning(prog, "VM_search_getfilename: no such handle %i in %s\n", handle, prog->name); + return; + } + if(filenum < 0 || filenum >= prog->opensearches[handle]->numfilenames) + { + VM_Warning(prog, "VM_search_getfilename: invalid filenum %i in %s\n", filenum, prog->name); + return; + } + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, prog->opensearches[handle]->filenames[filenum]); +} + +/* +========= +VM_chr + +string chr(float ascii) +========= +*/ +void VM_chr(prvm_prog_t *prog) +{ + /* + char tmp[2]; + VM_SAFEPARMCOUNT(1, VM_chr); + + tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0); + tmp[1] = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp); + */ + + char tmp[8]; + int len; + VM_SAFEPARMCOUNT(1, VM_chr); + + len = u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0), tmp, sizeof(tmp)); + tmp[len] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp); +} + +//============================================================================= +// Draw builtins (client & menu) + +/* +========= +VM_iscachedpic + +float iscachedpic(string pic) +========= +*/ +void VM_iscachedpic(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_iscachedpic); + + // drawq hasnt such a function, thus always return true + PRVM_G_FLOAT(OFS_RETURN) = false; +} + +/* +========= +VM_precache_pic + +string precache_pic(string pic) +========= +*/ +#define PRECACHE_PIC_FROMWAD 1 /* FTEQW, not supported here */ +#define PRECACHE_PIC_NOTPERSISTENT 2 +//#define PRECACHE_PIC_NOCLAMP 4 +#define PRECACHE_PIC_MIPMAP 8 +void VM_precache_pic(prvm_prog_t *prog) +{ + const char *s; + int flags = 0; + + VM_SAFEPARMCOUNTRANGE(1, 2, VM_precache_pic); + + s = PRVM_G_STRING(OFS_PARM0); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); + VM_CheckEmptyString(prog, s); + + if(prog->argc >= 2) + { + int f = PRVM_G_FLOAT(OFS_PARM1); + if(f & PRECACHE_PIC_NOTPERSISTENT) + flags |= CACHEPICFLAG_NOTPERSISTENT; + //if(f & PRECACHE_PIC_NOCLAMP) + // flags |= CACHEPICFLAG_NOCLAMP; + if(f & PRECACHE_PIC_MIPMAP) + flags |= CACHEPICFLAG_MIPMAP; + } + + // AK Draw_CachePic is supposed to always return a valid pointer + if( Draw_CachePic_Flags(s, flags)->tex == r_texture_notexture ) + PRVM_G_INT(OFS_RETURN) = OFS_NULL; +} + +/* +========= +VM_freepic + +freepic(string s) +========= +*/ +void VM_freepic(prvm_prog_t *prog) +{ + const char *s; + + VM_SAFEPARMCOUNT(1,VM_freepic); + + s = PRVM_G_STRING(OFS_PARM0); + VM_CheckEmptyString(prog, s); + + Draw_FreePic(s); +} + +static void getdrawfontscale(prvm_prog_t *prog, float *sx, float *sy) +{ + vec3_t v; + *sx = *sy = 1; + VectorCopy(PRVM_drawglobalvector(drawfontscale), v); + if(VectorLength2(v) > 0) + { + *sx = v[0]; + *sy = v[1]; + } +} + +static dp_font_t *getdrawfont(prvm_prog_t *prog) +{ + int f = (int) PRVM_drawglobalfloat(drawfont); + if(f < 0 || f >= dp_fonts.maxsize) + return FONT_DEFAULT; + return &dp_fonts.f[f]; +} + +/* +========= +VM_drawcharacter + +float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawcharacter(prvm_prog_t *prog) +{ + prvm_vec_t *pos,*scale,*rgb; + char character; + int flag; + float sx, sy; + VM_SAFEPARMCOUNT(6,VM_drawcharacter); + + character = (char) PRVM_G_FLOAT(OFS_PARM1); + if(character == 0) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning(prog, "VM_drawcharacter: %s passed null character !\n",prog->name); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + scale = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + flag = (int)PRVM_G_FLOAT(OFS_PARM5); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(pos[2] || scale[2]) + VM_Warning(prog, "VM_drawcharacter: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale"))); + + if(!scale[0] || !scale[1]) + { + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning(prog, "VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y"); + return; + } + + getdrawfontscale(prog, &sx, &sy); + DrawQ_String_Scale(pos[0], pos[1], &character, 1, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog)); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawstring + +float drawstring(vector position, string text, vector scale, vector rgb, float alpha[, float flag]) +========= +*/ +void VM_drawstring(prvm_prog_t *prog) +{ + prvm_vec_t *pos,*scale,*rgb; + const char *string; + int flag = 0; + float sx, sy; + VM_SAFEPARMCOUNTRANGE(5,6,VM_drawstring); + + string = PRVM_G_STRING(OFS_PARM1); + pos = PRVM_G_VECTOR(OFS_PARM0); + scale = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + if (prog->argc >= 6) + flag = (int)PRVM_G_FLOAT(OFS_PARM5); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(!scale[0] || !scale[1]) + { + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning(prog, "VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y"); + return; + } + + if(pos[2] || scale[2]) + VM_Warning(prog, "VM_drawstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale"))); + + getdrawfontscale(prog, &sx, &sy); + DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog)); + //Font_DrawString(pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawcolorcodedstring + +float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) +/ +float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawcolorcodedstring(prvm_prog_t *prog) +{ + prvm_vec_t *pos, *scale; + const char *string; + int flag; + vec3_t rgb; + float sx, sy, alpha; + + VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring); + + if (prog->argc == 6) // full 6 parms, like normal drawstring + { + pos = PRVM_G_VECTOR(OFS_PARM0); + string = PRVM_G_STRING(OFS_PARM1); + scale = PRVM_G_VECTOR(OFS_PARM2); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), rgb); + alpha = PRVM_G_FLOAT(OFS_PARM4); + flag = (int)PRVM_G_FLOAT(OFS_PARM5); + } + else + { + pos = PRVM_G_VECTOR(OFS_PARM0); + string = PRVM_G_STRING(OFS_PARM1); + scale = PRVM_G_VECTOR(OFS_PARM2); + rgb[0] = 1.0; + rgb[1] = 1.0; + rgb[2] = 1.0; + alpha = PRVM_G_FLOAT(OFS_PARM3); + flag = (int)PRVM_G_FLOAT(OFS_PARM4); + } + + if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(!scale[0] || !scale[1]) + { + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning(prog, "VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y"); + return; + } + + if(pos[2] || scale[2]) + VM_Warning(prog, "VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale"))); + + getdrawfontscale(prog, &sx, &sy); + DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], alpha, flag, NULL, false, getdrawfont(prog)); + if (prog->argc == 6) // also return vector of last color + VectorCopy(DrawQ_Color, PRVM_G_VECTOR(OFS_RETURN)); + else + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_stringwidth + +float stringwidth(string text, float allowColorCodes, float size) +========= +*/ +void VM_stringwidth(prvm_prog_t *prog) +{ + const char *string; + vec2_t szv; + float mult; // sz is intended font size so we can later add freetype support, mult is font size multiplier in pixels per character cell + int colors; + float sx, sy; + size_t maxlen = 0; + VM_SAFEPARMCOUNTRANGE(2,3,VM_drawstring); + + getdrawfontscale(prog, &sx, &sy); + if(prog->argc == 3) + { + Vector2Copy(PRVM_G_VECTOR(OFS_PARM2), szv); + mult = 1; + } + else + { + // we want the width for 8x8 font size, divided by 8 + Vector2Set(szv, 8, 8); + mult = 0.125; + // to make sure snapping is turned off, ALWAYS use a nontrivial scale in this case + if(sx >= 0.9 && sx <= 1.1) + { + mult *= 2; + sx /= 2; + sy /= 2; + } + } + + string = PRVM_G_STRING(OFS_PARM0); + colors = (int)PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth_UntilWidth_TrackColors_Scale(string, &maxlen, szv[0], szv[1], sx, sy, NULL, !colors, getdrawfont(prog), 1000000000) * mult; +/* + if(prog->argc == 3) + { + mult = sz = PRVM_G_FLOAT(OFS_PARM2); + } + else + { + sz = 8; + mult = 1; + } + + string = PRVM_G_STRING(OFS_PARM0); + colors = (int)PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw +*/ +} + +/* +========= +VM_findfont + +float findfont(string s) +========= +*/ + +static float getdrawfontnum(const char *fontname) +{ + int i; + + for(i = 0; i < dp_fonts.maxsize; ++i) + if(!strcmp(dp_fonts.f[i].title, fontname)) + return i; + return -1; +} + +void VM_findfont(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1,VM_findfont); + PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0)); +} + +/* +========= +VM_loadfont + +float loadfont(string fontname, string fontmaps, string sizes, float slot) +========= +*/ + +void VM_loadfont(prvm_prog_t *prog) +{ + const char *fontname, *filelist, *sizes, *c, *cm; + char mainfont[MAX_QPATH]; + int i, numsizes; + float sz, scale, voffset; + dp_font_t *f; + + VM_SAFEPARMCOUNTRANGE(3,6,VM_loadfont); + + fontname = PRVM_G_STRING(OFS_PARM0); + if (!fontname[0]) + fontname = "default"; + + filelist = PRVM_G_STRING(OFS_PARM1); + if (!filelist[0]) + filelist = "gfx/conchars"; + + sizes = PRVM_G_STRING(OFS_PARM2); + if (!sizes[0]) + sizes = "10"; + + // find a font + f = NULL; + if (prog->argc >= 4) + { + i = PRVM_G_FLOAT(OFS_PARM3); + if (i >= 0 && i < dp_fonts.maxsize) + { + f = &dp_fonts.f[i]; + strlcpy(f->title, fontname, sizeof(f->title)); // replace name + } + } + if (!f) + f = FindFont(fontname, true); + if (!f) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; // something go wrong + } + + memset(f->fallbacks, 0, sizeof(f->fallbacks)); + memset(f->fallback_faces, 0, sizeof(f->fallback_faces)); + + // first font is handled "normally" + c = strchr(filelist, ':'); + cm = strchr(filelist, ','); + if(c && (!cm || c < cm)) + f->req_face = atoi(c+1); + else + { + f->req_face = 0; + c = cm; + } + if(!c || (c - filelist) > MAX_QPATH) + strlcpy(mainfont, filelist, sizeof(mainfont)); + else + { + memcpy(mainfont, filelist, c - filelist); + mainfont[c - filelist] = 0; + } + + // handle fallbacks + for(i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + c = strchr(filelist, ','); + if(!c) + break; + filelist = c + 1; + if(!*filelist) + break; + c = strchr(filelist, ':'); + cm = strchr(filelist, ','); + if(c && (!cm || c < cm)) + f->fallback_faces[i] = atoi(c+1); + else + { + f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index + c = cm; + } + if(!c || (c-filelist) > MAX_QPATH) + { + strlcpy(f->fallbacks[i], filelist, sizeof(mainfont)); + } + else + { + memcpy(f->fallbacks[i], filelist, c - filelist); + f->fallbacks[i][c - filelist] = 0; + } + } + + // handle sizes + for(i = 0; i < MAX_FONT_SIZES; ++i) + f->req_sizes[i] = -1; + for (numsizes = 0,c = sizes;;) + { + if (!COM_ParseToken_VM_Tokenize(&c, 0)) + break; + sz = atof(com_token); + // detect crap size + if (sz < 0.001f || sz > 1000.0f) + { + VM_Warning(prog, "VM_loadfont: crap size %s", com_token); + continue; + } + // check overflow + if (numsizes == MAX_FONT_SIZES) + { + VM_Warning(prog, "VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES); + break; + } + f->req_sizes[numsizes] = sz; + numsizes++; + } + + // additional scale/hoffset parms + scale = 1; + voffset = 0; + if (prog->argc >= 5) + { + scale = PRVM_G_FLOAT(OFS_PARM4); + if (scale <= 0) + scale = 1; + } + if (prog->argc >= 6) + voffset = PRVM_G_FLOAT(OFS_PARM5); + + // load + LoadFont(true, mainfont, f, scale, voffset); + + // return index of loaded font + PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f); +} + +/* +========= +VM_drawpic + +float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawpic(prvm_prog_t *prog) +{ + const char *picname; + prvm_vec_t *size, *pos, *rgb; + int flag = 0; + + VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic); + + picname = PRVM_G_STRING(OFS_PARM1); + VM_CheckEmptyString(prog, picname); + + // is pic cached ? no function yet for that + if(!1) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning(prog, "VM_drawpic: %s: %s not cached !\n", prog->name, picname); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + if (prog->argc >= 6) + flag = (int) PRVM_G_FLOAT(OFS_PARM5); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(pos[2] || size[2]) + VM_Warning(prog, "VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); + + DrawQ_Pic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_drawrotpic + +float drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawrotpic(prvm_prog_t *prog) +{ + const char *picname; + prvm_vec_t *size, *pos, *org, *rgb; + int flag; + + VM_SAFEPARMCOUNT(8,VM_drawrotpic); + + picname = PRVM_G_STRING(OFS_PARM1); + VM_CheckEmptyString(prog, picname); + + // is pic cached ? no function yet for that + if(!1) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning(prog, "VM_drawrotpic: %s: %s not cached !\n", prog->name, picname); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM2); + org = PRVM_G_VECTOR(OFS_PARM3); + rgb = PRVM_G_VECTOR(OFS_PARM5); + flag = (int) PRVM_G_FLOAT(OFS_PARM7); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(pos[2] || size[2] || org[2]) + VM_Warning(prog, "VM_drawrotpic: z value from pos/size/org discarded\n"); + + DrawQ_RotPic(pos[0], pos[1], Draw_CachePic_Flags(picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_drawsubpic + +float drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag) + +========= +*/ +void VM_drawsubpic(prvm_prog_t *prog) +{ + const char *picname; + prvm_vec_t *size, *pos, *rgb, *srcPos, *srcSize, alpha; + int flag; + + VM_SAFEPARMCOUNT(8,VM_drawsubpic); + + picname = PRVM_G_STRING(OFS_PARM2); + VM_CheckEmptyString(prog, picname); + + // is pic cached ? no function yet for that + if(!1) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning(prog, "VM_drawsubpic: %s: %s not cached !\n", prog->name, picname); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM1); + srcPos = PRVM_G_VECTOR(OFS_PARM3); + srcSize = PRVM_G_VECTOR(OFS_PARM4); + rgb = PRVM_G_VECTOR(OFS_PARM5); + alpha = PRVM_G_FLOAT(OFS_PARM6); + flag = (int) PRVM_G_FLOAT(OFS_PARM7); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(pos[2] || size[2]) + VM_Warning(prog, "VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); + + DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), + size[0], size[1], + srcPos[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0] + srcSize[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0] + srcSize[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha, + flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawfill + +float drawfill(vector position, vector size, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawfill(prvm_prog_t *prog) +{ + prvm_vec_t *size, *pos, *rgb; + int flag; + + VM_SAFEPARMCOUNT(5,VM_drawfill); + + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM1); + rgb = PRVM_G_VECTOR(OFS_PARM2); + flag = (int) PRVM_G_FLOAT(OFS_PARM4); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning(prog, "VM_drawfill: %s: wrong DRAWFLAG %i !\n",prog->name,flag); + return; + } + + if(pos[2] || size[2]) + VM_Warning(prog, "VM_drawfill: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); + + DrawQ_Fill(pos[0], pos[1], size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawsetcliparea + +drawsetcliparea(float x, float y, float width, float height) +========= +*/ +void VM_drawsetcliparea(prvm_prog_t *prog) +{ + float x,y,w,h; + VM_SAFEPARMCOUNT(4,VM_drawsetcliparea); + + x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid_conwidth.integer); + y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid_conheight.integer); + w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid_conwidth.integer - x)); + h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid_conheight.integer - y)); + + DrawQ_SetClipArea(x, y, w, h); +} + +/* +========= +VM_drawresetcliparea + +drawresetcliparea() +========= +*/ +void VM_drawresetcliparea(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_drawresetcliparea); + + DrawQ_ResetClipArea(); +} + +/* +========= +VM_getimagesize + +vector getimagesize(string pic) +========= +*/ +void VM_getimagesize(prvm_prog_t *prog) +{ + const char *p; + cachepic_t *pic; + + VM_SAFEPARMCOUNT(1,VM_getimagesize); + + p = PRVM_G_STRING(OFS_PARM0); + VM_CheckEmptyString(prog, p); + + pic = Draw_CachePic_Flags (p, CACHEPICFLAG_NOTPERSISTENT); + if( pic->tex == r_texture_notexture ) + { + PRVM_G_VECTOR(OFS_RETURN)[0] = 0; + PRVM_G_VECTOR(OFS_RETURN)[1] = 0; + } + else + { + PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width; + PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height; + } + PRVM_G_VECTOR(OFS_RETURN)[2] = 0; +} + +/* +========= +VM_keynumtostring + +string keynumtostring(float keynum) +========= +*/ +void VM_keynumtostring (prvm_prog_t *prog) +{ + char tinystr[2]; + VM_SAFEPARMCOUNT(1, VM_keynumtostring); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0), tinystr, sizeof(tinystr))); +} + +/* +========= +VM_findkeysforcommand + +string findkeysforcommand(string command, float bindmap) + +the returned string is an altstring +========= +*/ +#define FKFC_NUMKEYS 5 +void M_FindKeysForCommand(const char *command, int *keys); +void VM_findkeysforcommand(prvm_prog_t *prog) +{ + const char *cmd; + char ret[VM_STRINGTEMP_LENGTH]; + int keys[FKFC_NUMKEYS]; + int i; + int bindmap; + char vabuf[1024]; + + VM_SAFEPARMCOUNTRANGE(1, 2, VM_findkeysforcommand); + + cmd = PRVM_G_STRING(OFS_PARM0); + if(prog->argc == 2) + bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1); + else + bindmap = 0; // consistent to "bind" + + VM_CheckEmptyString(prog, cmd); + + Key_FindKeysForCommand(cmd, keys, FKFC_NUMKEYS, bindmap); + + ret[0] = 0; + for(i = 0; i < FKFC_NUMKEYS; i++) + strlcat(ret, va(vabuf, sizeof(vabuf), " \'%i\'", keys[i]), sizeof(ret)); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ret); +} + +/* +========= +VM_stringtokeynum + +float stringtokeynum(string key) +========= +*/ +void VM_stringtokeynum (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT( 1, VM_keynumtostring ); + + PRVM_G_FLOAT(OFS_RETURN) = Key_StringToKeynum(PRVM_G_STRING(OFS_PARM0)); +} + +/* +========= +VM_getkeybind + +string getkeybind(float key, float bindmap) +========= +*/ +void VM_getkeybind (prvm_prog_t *prog) +{ + int bindmap; + VM_SAFEPARMCOUNTRANGE(1, 2, VM_CL_getkeybind); + if(prog->argc == 2) + bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1); + else + bindmap = 0; // consistent to "bind" + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap)); +} + +/* +========= +VM_setkeybind + +float setkeybind(float key, string cmd, float bindmap) +========= +*/ +void VM_setkeybind (prvm_prog_t *prog) +{ + int bindmap; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_setkeybind); + if(prog->argc == 3) + bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM2), MAX_BINDMAPS-1); + else + bindmap = 0; // consistent to "bind" + + PRVM_G_FLOAT(OFS_RETURN) = 0; + if(Key_SetBinding((int)PRVM_G_FLOAT(OFS_PARM0), bindmap, PRVM_G_STRING(OFS_PARM1))) + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_getbindmap + +vector getbindmaps() +========= +*/ +void VM_getbindmaps (prvm_prog_t *prog) +{ + int fg, bg; + VM_SAFEPARMCOUNT(0, VM_CL_getbindmap); + Key_GetBindMap(&fg, &bg); + PRVM_G_VECTOR(OFS_RETURN)[0] = fg; + PRVM_G_VECTOR(OFS_RETURN)[1] = bg; + PRVM_G_VECTOR(OFS_RETURN)[2] = 0; +} + +/* +========= +VM_setbindmap + +float setbindmaps(vector bindmap) +========= +*/ +void VM_setbindmaps (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_CL_setbindmap); + PRVM_G_FLOAT(OFS_RETURN) = 0; + if(PRVM_G_VECTOR(OFS_PARM0)[2] == 0) + if(Key_SetBindMap((int)PRVM_G_VECTOR(OFS_PARM0)[0], (int)PRVM_G_VECTOR(OFS_PARM0)[1])) + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +// CL_Video interface functions + +/* +======================== +VM_cin_open + +float cin_open(string file, string name) +======================== +*/ +void VM_cin_open(prvm_prog_t *prog) +{ + const char *file; + const char *name; + + VM_SAFEPARMCOUNT( 2, VM_cin_open ); + + file = PRVM_G_STRING( OFS_PARM0 ); + name = PRVM_G_STRING( OFS_PARM1 ); + + VM_CheckEmptyString(prog, file ); + VM_CheckEmptyString(prog, name ); + + if( CL_OpenVideo( file, name, MENUOWNER, "" ) ) + PRVM_G_FLOAT( OFS_RETURN ) = 1; + else + PRVM_G_FLOAT( OFS_RETURN ) = 0; +} + +/* +======================== +VM_cin_close + +void cin_close(string name) +======================== +*/ +void VM_cin_close(prvm_prog_t *prog) +{ + const char *name; + + VM_SAFEPARMCOUNT( 1, VM_cin_close ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString(prog, name ); + + CL_CloseVideo( CL_GetVideoByName( name ) ); +} + +/* +======================== +VM_cin_setstate +void cin_setstate(string name, float type) +======================== +*/ +void VM_cin_setstate(prvm_prog_t *prog) +{ + const char *name; + clvideostate_t state; + clvideo_t *video; + + VM_SAFEPARMCOUNT( 2, VM_cin_netstate ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString(prog, name ); + + state = (clvideostate_t)((int)PRVM_G_FLOAT( OFS_PARM1 )); + + video = CL_GetVideoByName( name ); + if( video && state > CLVIDEO_UNUSED && state < CLVIDEO_STATECOUNT ) + CL_SetVideoState( video, state ); +} + +/* +======================== +VM_cin_getstate + +float cin_getstate(string name) +======================== +*/ +void VM_cin_getstate(prvm_prog_t *prog) +{ + const char *name; + clvideo_t *video; + + VM_SAFEPARMCOUNT( 1, VM_cin_getstate ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString(prog, name ); + + video = CL_GetVideoByName( name ); + if( video ) + PRVM_G_FLOAT( OFS_RETURN ) = (int)video->state; + else + PRVM_G_FLOAT( OFS_RETURN ) = 0; +} + +/* +======================== +VM_cin_restart + +void cin_restart(string name) +======================== +*/ +void VM_cin_restart(prvm_prog_t *prog) +{ + const char *name; + clvideo_t *video; + + VM_SAFEPARMCOUNT( 1, VM_cin_restart ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString(prog, name ); + + video = CL_GetVideoByName( name ); + if( video ) + CL_RestartVideo( video ); +} + +/* +======================== +VM_gecko_create + +float[bool] gecko_create( string name ) +======================== +*/ +void VM_gecko_create(prvm_prog_t *prog) { + // REMOVED + PRVM_G_FLOAT( OFS_RETURN ) = 0; +} + +/* +======================== +VM_gecko_destroy + +void gecko_destroy( string name ) +======================== +*/ +void VM_gecko_destroy(prvm_prog_t *prog) { + // REMOVED +} + +/* +======================== +VM_gecko_navigate + +void gecko_navigate( string name, string URI ) +======================== +*/ +void VM_gecko_navigate(prvm_prog_t *prog) { + // REMOVED +} + +/* +======================== +VM_gecko_keyevent + +float[bool] gecko_keyevent( string name, float key, float eventtype ) +======================== +*/ +void VM_gecko_keyevent(prvm_prog_t *prog) { + // REMOVED + PRVM_G_FLOAT( OFS_RETURN ) = 0; +} + +/* +======================== +VM_gecko_movemouse + +void gecko_mousemove( string name, float x, float y ) +======================== +*/ +void VM_gecko_movemouse(prvm_prog_t *prog) { + // REMOVED +} + + +/* +======================== +VM_gecko_resize + +void gecko_resize( string name, float w, float h ) +======================== +*/ +void VM_gecko_resize(prvm_prog_t *prog) { + // REMOVED +} + + +/* +======================== +VM_gecko_get_texture_extent + +vector gecko_get_texture_extent( string name ) +======================== +*/ +void VM_gecko_get_texture_extent(prvm_prog_t *prog) { + // REMOVED + PRVM_G_VECTOR(OFS_RETURN)[0] = 0; + PRVM_G_VECTOR(OFS_RETURN)[1] = 0; +} + + + +/* +============== +VM_makevectors + +Writes new values for v_forward, v_up, and v_right based on angles +void makevectors(vector angle) +============== +*/ +void VM_makevectors (prvm_prog_t *prog) +{ + vec3_t angles, forward, right, up; + VM_SAFEPARMCOUNT(1, VM_makevectors); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), angles); + AngleVectors(angles, forward, right, up); + VectorCopy(forward, PRVM_gameglobalvector(v_forward)); + VectorCopy(right, PRVM_gameglobalvector(v_right)); + VectorCopy(up, PRVM_gameglobalvector(v_up)); +} + +/* +============== +VM_vectorvectors + +Writes new values for v_forward, v_up, and v_right based on the given forward vector +vectorvectors(vector) +============== +*/ +void VM_vectorvectors (prvm_prog_t *prog) +{ + vec3_t forward, right, up; + VM_SAFEPARMCOUNT(1, VM_vectorvectors); + VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), forward); + VectorVectors(forward, right, up); + VectorCopy(forward, PRVM_gameglobalvector(v_forward)); + VectorCopy(right, PRVM_gameglobalvector(v_right)); + VectorCopy(up, PRVM_gameglobalvector(v_up)); +} + +/* +======================== +VM_drawline + +void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags) +======================== +*/ +void VM_drawline (prvm_prog_t *prog) +{ + prvm_vec_t *c1, *c2, *rgb; + float alpha, width; + unsigned char flags; + + VM_SAFEPARMCOUNT(6, VM_drawline); + width = PRVM_G_FLOAT(OFS_PARM0); + c1 = PRVM_G_VECTOR(OFS_PARM1); + c2 = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + alpha = PRVM_G_FLOAT(OFS_PARM4); + flags = (int)PRVM_G_FLOAT(OFS_PARM5); + DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags); +} + +// float(float number, float quantity) bitshift (EXT_BITSHIFT) +void VM_bitshift (prvm_prog_t *prog) +{ + prvm_int_t n1, n2; + VM_SAFEPARMCOUNT(2, VM_bitshift); + + n1 = (prvm_int_t)fabs((prvm_vec_t)((prvm_int_t)PRVM_G_FLOAT(OFS_PARM0))); + n2 = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM1); + if(!n1) + PRVM_G_FLOAT(OFS_RETURN) = n1; + else + if(n2 < 0) + PRVM_G_FLOAT(OFS_RETURN) = (n1 >> -n2); + else + PRVM_G_FLOAT(OFS_RETURN) = (n1 << n2); +} + +//////////////////////////////////////// +// AltString functions +//////////////////////////////////////// + +/* +======================== +VM_altstr_count + +float altstr_count(string) +======================== +*/ +void VM_altstr_count(prvm_prog_t *prog) +{ + const char *altstr, *pos; + int count; + + VM_SAFEPARMCOUNT( 1, VM_altstr_count ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + //VM_CheckEmptyString(prog, altstr ); + + for( count = 0, pos = altstr ; *pos ; pos++ ) { + if( *pos == '\\' ) { + if( !*++pos ) { + break; + } + } else if( *pos == '\'' ) { + count++; + } + } + + PRVM_G_FLOAT( OFS_RETURN ) = (prvm_vec_t) (count / 2); +} + +/* +======================== +VM_altstr_prepare + +string altstr_prepare(string) +======================== +*/ +void VM_altstr_prepare(prvm_prog_t *prog) +{ + char *out; + const char *instr, *in; + int size; + char outstr[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT( 1, VM_altstr_prepare ); + + instr = PRVM_G_STRING( OFS_PARM0 ); + + for( out = outstr, in = instr, size = sizeof(outstr) - 1 ; size && *in ; size--, in++, out++ ) + if( *in == '\'' ) { + *out++ = '\\'; + *out = '\''; + size--; + } else + *out = *in; + *out = 0; + + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, outstr ); +} + +/* +======================== +VM_altstr_get + +string altstr_get(string, float) +======================== +*/ +void VM_altstr_get(prvm_prog_t *prog) +{ + const char *altstr, *pos; + char *out; + int count, size; + char outstr[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT( 2, VM_altstr_get ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + + count = (int)PRVM_G_FLOAT( OFS_PARM1 ); + count = count * 2 + 1; + + for( pos = altstr ; *pos && count ; pos++ ) + if( *pos == '\\' ) { + if( !*++pos ) + break; + } else if( *pos == '\'' ) + count--; + + if( !*pos ) { + PRVM_G_INT( OFS_RETURN ) = 0; + return; + } + + for( out = outstr, size = sizeof(outstr) - 1 ; size && *pos ; size--, pos++, out++ ) + if( *pos == '\\' ) { + if( !*++pos ) + break; + *out = *pos; + size--; + } else if( *pos == '\'' ) + break; + else + *out = *pos; + + *out = 0; + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, outstr ); +} + +/* +======================== +VM_altstr_set + +string altstr_set(string altstr, float num, string set) +======================== +*/ +void VM_altstr_set(prvm_prog_t *prog) +{ + int num; + const char *altstr, *str; + const char *in; + char *out; + char outstr[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT( 3, VM_altstr_set ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + + num = (int)PRVM_G_FLOAT( OFS_PARM1 ); + + str = PRVM_G_STRING( OFS_PARM2 ); + + out = outstr; + for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ ) + if( *in == '\\' ) { + if( !*++in ) { + break; + } + } else if( *in == '\'' ) { + num--; + } + + // copy set in + for( ; *str; *out++ = *str++ ); + // now jump over the old content + for( ; *in ; in++ ) + if( *in == '\'' || (*in == '\\' && !*++in) ) + break; + + strlcpy(out, in, outstr + sizeof(outstr) - out); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, outstr ); +} + +/* +======================== +VM_altstr_ins +insert after num +string altstr_ins(string altstr, float num, string set) +======================== +*/ +void VM_altstr_ins(prvm_prog_t *prog) +{ + int num; + const char *set; + const char *in; + char *out; + char outstr[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(3, VM_altstr_ins); + + in = PRVM_G_STRING( OFS_PARM0 ); + num = (int)PRVM_G_FLOAT( OFS_PARM1 ); + set = PRVM_G_STRING( OFS_PARM2 ); + + out = outstr; + for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ ) + if( *in == '\\' ) { + if( !*++in ) { + break; + } + } else if( *in == '\'' ) { + num--; + } + + *out++ = '\''; + for( ; *set ; *out++ = *set++ ); + *out++ = '\''; + + strlcpy(out, in, outstr + sizeof(outstr) - out); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, outstr ); +} + + +//////////////////////////////////////// +// BufString functions +//////////////////////////////////////// +//[515]: string buffers support + +static size_t stringbuffers_sortlength; + +static void BufStr_Expand(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex) +{ + if (stringbuffer->max_strings <= strindex) + { + char **oldstrings = stringbuffer->strings; + stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128); + while (stringbuffer->max_strings <= strindex) + stringbuffer->max_strings *= 2; + stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0])); + if (stringbuffer->num_strings > 0) + memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0])); + if (oldstrings) + Mem_Free(oldstrings); + } +} + +static void BufStr_Shrink(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer) +{ + // reduce num_strings if there are empty string slots at the end + while (stringbuffer->num_strings > 0 && stringbuffer->strings[stringbuffer->num_strings - 1] == NULL) + stringbuffer->num_strings--; + + // if empty, free the string pointer array + if (stringbuffer->num_strings == 0) + { + stringbuffer->max_strings = 0; + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + stringbuffer->strings = NULL; + } +} + +static int BufStr_SortStringsUP (const void *in1, const void *in2) +{ + const char *a, *b; + a = *((const char **) in1); + b = *((const char **) in2); + if(!a || !a[0]) return 1; + if(!b || !b[0]) return -1; + return strncmp(a, b, stringbuffers_sortlength); +} + +static int BufStr_SortStringsDOWN (const void *in1, const void *in2) +{ + const char *a, *b; + a = *((const char **) in1); + b = *((const char **) in2); + if(!a || !a[0]) return 1; + if(!b || !b[0]) return -1; + return strncmp(b, a, stringbuffers_sortlength); +} + +prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, int flags, char *format) +{ + prvm_stringbuffer_t *stringbuffer; + int i; + + if (bufindex < 0) + return NULL; + + // find buffer with wanted index + if (bufindex < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray)) + { + if ( (stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, bufindex)) ) + { + if (stringbuffer->flags & STRINGBUFFER_TEMP) + stringbuffer->flags = flags; // created but has not been used yet + return stringbuffer; + } + return NULL; + } + + // allocate new buffer with wanted index + while(1) + { + stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray); + stringbuffer->flags = STRINGBUFFER_TEMP; + for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++); + if (i == bufindex) + { + stringbuffer->flags = flags; // mark as used + break; + } + } + return stringbuffer; +} + +void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str) +{ + size_t alloclen; + + if (!stringbuffer || strindex < 0) + return; + + BufStr_Expand(prog, stringbuffer, strindex); + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); + if (stringbuffer->strings[strindex]) + Mem_Free(stringbuffer->strings[strindex]); + stringbuffer->strings[strindex] = NULL; + + if (str) + { + // not the NULL string! + alloclen = strlen(str) + 1; + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], str, alloclen); + } + + BufStr_Shrink(prog, stringbuffer); +} + +void BufStr_Del(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer) +{ + int i; + + if (!stringbuffer) + return; + + for (i = 0;i < stringbuffer->num_strings;i++) + if (stringbuffer->strings[i]) + Mem_Free(stringbuffer->strings[i]); + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + if(stringbuffer->origin) + PRVM_Free((char *)stringbuffer->origin); + Mem_ExpandableArray_FreeRecord(&prog->stringbuffersarray, stringbuffer); +} + +void BufStr_Flush(prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + int i, numbuffers; + + numbuffers = Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); + for (i = 0; i < numbuffers; i++) + if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) ) + BufStr_Del(prog, stringbuffer); + Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64); +} + +/* +======================== +VM_buf_create +creates new buffer, and returns it's index, returns -1 if failed +float buf_create(prvm_prog_t *prog) = #460; +float newbuf(string format, float flags) = #460; +======================== +*/ + +void VM_buf_create (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + int i; + + VM_SAFEPARMCOUNTRANGE(0, 2, VM_buf_create); + + // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string" + if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string")) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray); + for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++); + stringbuffer->origin = PRVM_AllocationOrigin(prog); + // optional flags parm + if (prog->argc >= 2) + stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & STRINGBUFFER_QCFLAGS; + PRVM_G_FLOAT(OFS_RETURN) = i; +} + + + +/* +======================== +VM_buf_del +deletes buffer and all strings in it +void buf_del(float bufhandle) = #461; +======================== +*/ +void VM_buf_del (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNT(1, VM_buf_del); + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if (stringbuffer) + BufStr_Del(prog, stringbuffer); + else + { + VM_Warning(prog, "VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } +} + +/* +======================== +VM_buf_getsize +how many strings are stored in buffer +float buf_getsize(float bufhandle) = #462; +======================== +*/ +void VM_buf_getsize (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNT(1, VM_buf_getsize); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning(prog, "VM_buf_getsize: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + else + PRVM_G_FLOAT(OFS_RETURN) = stringbuffer->num_strings; +} + +/* +======================== +VM_buf_copy +copy all content from one buffer to another, make sure it exists +void buf_copy(float bufhandle_from, float bufhandle_to) = #463; +======================== +*/ +void VM_buf_copy (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *srcstringbuffer, *dststringbuffer; + int i; + VM_SAFEPARMCOUNT(2, VM_buf_copy); + + srcstringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!srcstringbuffer) + { + VM_Warning(prog, "VM_buf_copy: invalid source buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + i = (int)PRVM_G_FLOAT(OFS_PARM1); + if(i == (int)PRVM_G_FLOAT(OFS_PARM0)) + { + VM_Warning(prog, "VM_buf_copy: source == destination (%i) in %s\n", i, prog->name); + return; + } + dststringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!dststringbuffer) + { + VM_Warning(prog, "VM_buf_copy: invalid destination buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name); + return; + } + + for (i = 0;i < dststringbuffer->num_strings;i++) + if (dststringbuffer->strings[i]) + Mem_Free(dststringbuffer->strings[i]); + if (dststringbuffer->strings) + Mem_Free(dststringbuffer->strings); + *dststringbuffer = *srcstringbuffer; + if (dststringbuffer->max_strings) + dststringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(dststringbuffer->strings[0]) * dststringbuffer->max_strings); + + for (i = 0;i < dststringbuffer->num_strings;i++) + { + if (srcstringbuffer->strings[i]) + { + size_t stringlen; + stringlen = strlen(srcstringbuffer->strings[i]) + 1; + dststringbuffer->strings[i] = (char *)Mem_Alloc(prog->progs_mempool, stringlen); + memcpy(dststringbuffer->strings[i], srcstringbuffer->strings[i], stringlen); + } + } +} + +/* +======================== +VM_buf_sort +sort buffer by beginnings of strings (cmplength defaults it's length) +"backward == TRUE" means that sorting goes upside-down +void buf_sort(float bufhandle, float cmplength, float backward) = #464; +======================== +*/ +void VM_buf_sort (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNT(3, VM_buf_sort); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_buf_sort: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + if(stringbuffer->num_strings <= 0) + { + VM_Warning(prog, "VM_buf_sort: tried to sort empty buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + stringbuffers_sortlength = (int)PRVM_G_FLOAT(OFS_PARM1); + if(stringbuffers_sortlength <= 0) + stringbuffers_sortlength = 0x7FFFFFFF; + + if(!PRVM_G_FLOAT(OFS_PARM2)) + qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsUP); + else + qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsDOWN); + + BufStr_Shrink(prog, stringbuffer); +} + +/* +======================== +VM_buf_implode +concantenates all buffer string into one with "glue" separator and returns it as tempstring +string buf_implode(float bufhandle, string glue) = #465; +======================== +*/ +void VM_buf_implode (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + char k[VM_STRINGTEMP_LENGTH]; + const char *sep; + int i; + size_t l; + VM_SAFEPARMCOUNT(2, VM_buf_implode); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + if(!stringbuffer) + { + VM_Warning(prog, "VM_buf_implode: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + if(!stringbuffer->num_strings) + return; + sep = PRVM_G_STRING(OFS_PARM1); + k[0] = 0; + for(l = i = 0;i < stringbuffer->num_strings;i++) + { + if(stringbuffer->strings[i]) + { + l += (i > 0 ? strlen(sep) : 0) + strlen(stringbuffer->strings[i]); + if (l >= sizeof(k) - 1) + break; + strlcat(k, sep, sizeof(k)); + strlcat(k, stringbuffer->strings[i], sizeof(k)); + } + } + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, k); +} + +/* +======================== +VM_bufstr_get +get a string from buffer, returns tempstring, dont str_unzone it! +string bufstr_get(float bufhandle, float string_index) = #465; +======================== +*/ +void VM_bufstr_get (prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + int strindex; + VM_SAFEPARMCOUNT(2, VM_bufstr_get); + + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + strindex = (int)PRVM_G_FLOAT(OFS_PARM1); + if (strindex < 0) + { + // VM_Warning(prog, "VM_bufstr_get: invalid string index %i used in %s\n", strindex, prog->name); + return; + } + if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex]) + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, stringbuffer->strings[strindex]); +} + +/* +======================== +VM_bufstr_set +copies a string into selected slot of buffer +void bufstr_set(float bufhandle, float string_index, string str) = #466; +======================== +*/ +void VM_bufstr_set (prvm_prog_t *prog) +{ + int strindex; + prvm_stringbuffer_t *stringbuffer; + const char *news; + + VM_SAFEPARMCOUNT(3, VM_bufstr_set); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_set: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + strindex = (int)PRVM_G_FLOAT(OFS_PARM1); + if(strindex < 0 || strindex >= 1000000) // huge number of strings + { + VM_Warning(prog, "VM_bufstr_set: invalid string index %i used in %s\n", strindex, prog->name); + return; + } + + news = PRVM_G_STRING(OFS_PARM2); + BufStr_Set(prog, stringbuffer, strindex, news); +} + +/* +======================== +VM_bufstr_add +adds string to buffer in first free slot and returns its index +"order == TRUE" means that string will be added after last "full" slot +float bufstr_add(float bufhandle, string str, float order) = #467; +======================== +*/ +void VM_bufstr_add (prvm_prog_t *prog) +{ + int order, strindex; + prvm_stringbuffer_t *stringbuffer; + const char *string; + size_t alloclen; + + VM_SAFEPARMCOUNT(3, VM_bufstr_add); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + PRVM_G_FLOAT(OFS_RETURN) = -1; + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_add: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + if(!PRVM_G_INT(OFS_PARM1)) // NULL string + { + VM_Warning(prog, "VM_bufstr_add: can not add an empty string to buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + string = PRVM_G_STRING(OFS_PARM1); + order = (int)PRVM_G_FLOAT(OFS_PARM2); + if(order) + strindex = stringbuffer->num_strings; + else + for (strindex = 0;strindex < stringbuffer->num_strings;strindex++) + if (stringbuffer->strings[strindex] == NULL) + break; + + BufStr_Expand(prog, stringbuffer, strindex); + + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); + alloclen = strlen(string) + 1; + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], string, alloclen); + + PRVM_G_FLOAT(OFS_RETURN) = strindex; +} + +/* +======================== +VM_bufstr_free +delete string from buffer +void bufstr_free(float bufhandle, float string_index) = #468; +======================== +*/ +void VM_bufstr_free (prvm_prog_t *prog) +{ + int i; + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNT(2, VM_bufstr_free); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + i = (int)PRVM_G_FLOAT(OFS_PARM1); + if(i < 0) + { + VM_Warning(prog, "VM_bufstr_free: invalid string index %i used in %s\n", i, prog->name); + return; + } + + if (i < stringbuffer->num_strings) + { + if(stringbuffer->strings[i]) + Mem_Free(stringbuffer->strings[i]); + stringbuffer->strings[i] = NULL; + } + + BufStr_Shrink(prog, stringbuffer); +} + +/* +======================== +VM_buf_loadfile +load a file into string buffer, return 0 or 1 +float buf_loadfile(string filename, float bufhandle) = #535; +======================== +*/ +void VM_buf_loadfile(prvm_prog_t *prog) +{ + size_t alloclen; + prvm_stringbuffer_t *stringbuffer; + char string[VM_STRINGTEMP_LENGTH]; + int filenum, strindex, c, end; + const char *filename; + char vabuf[1024]; + + VM_SAFEPARMCOUNT(2, VM_buf_loadfile); + + // get file + filename = PRVM_G_STRING(OFS_PARM0); + for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++) + if (prog->openfiles[filenum] == NULL) + break; + prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false); + if (prog->openfiles[filenum] == NULL) + prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false); + if (prog->openfiles[filenum] == NULL) + { + if (developer_extra.integer) + VM_Warning(prog, "VM_buf_loadfile: failed to open file %s in %s\n", filename, prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // get string buffer + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM1)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_buf_loadfile: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // read file (append to the end of buffer) + strindex = stringbuffer->num_strings; + while(1) + { + // read line + end = 0; + for (;;) + { + c = FS_Getc(prog->openfiles[filenum]); + if (c == '\r' || c == '\n' || c < 0) + break; + if (end < VM_STRINGTEMP_LENGTH - 1) + string[end++] = c; + } + string[end] = 0; + // remove \n following \r + if (c == '\r') + { + c = FS_Getc(prog->openfiles[filenum]); + if (c != '\n') + FS_UnGetc(prog->openfiles[filenum], (unsigned char)c); + } + // add and continue + if (c >= 0 || end) + { + BufStr_Expand(prog, stringbuffer, strindex); + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); + alloclen = strlen(string) + 1; + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], string, alloclen); + strindex = stringbuffer->num_strings; + } + else + break; + } + + // close file + FS_Close(prog->openfiles[filenum]); + prog->openfiles[filenum] = NULL; + if (prog->openfiles_origin[filenum]) + PRVM_Free((char *)prog->openfiles_origin[filenum]); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +======================== +VM_buf_writefile +writes stringbuffer to a file, returns 0 or 1 +float buf_writefile(float filehandle, float bufhandle, [, float startpos, float numstrings]) = #468; +======================== +*/ + +void VM_buf_writefile(prvm_prog_t *prog) +{ + int filenum, strindex, strnum, strlength; + prvm_stringbuffer_t *stringbuffer; + + VM_SAFEPARMCOUNTRANGE(2, 4, VM_buf_writefile); + + // get file + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning(prog, "VM_buf_writefile: invalid file handle %i used in %s\n", filenum, prog->name); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning(prog, "VM_buf_writefile: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name); + return; + } + + // get string buffer + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM1)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_buf_writefile: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // get start and end parms + if (prog->argc > 3) + { + strindex = (int)PRVM_G_FLOAT(OFS_PARM2); + strnum = (int)PRVM_G_FLOAT(OFS_PARM3); + } + else if (prog->argc > 2) + { + strindex = (int)PRVM_G_FLOAT(OFS_PARM2); + strnum = stringbuffer->num_strings - strindex; + } + else + { + strindex = 0; + strnum = stringbuffer->num_strings; + } + if (strindex < 0 || strindex >= stringbuffer->num_strings) + { + VM_Warning(prog, "VM_buf_writefile: wrong start string index %i used in %s\n", strindex, prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + if (strnum < 0) + { + VM_Warning(prog, "VM_buf_writefile: wrong strings count %i used in %s\n", strnum, prog->name); + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // write + while(strindex < stringbuffer->num_strings && strnum) + { + if (stringbuffer->strings[strindex]) + { + if ((strlength = strlen(stringbuffer->strings[strindex]))) + FS_Write(prog->openfiles[filenum], stringbuffer->strings[strindex], strlength); + FS_Write(prog->openfiles[filenum], "\n", 1); + } + strindex++; + strnum--; + } + + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +#define MATCH_AUTO 0 +#define MATCH_WHOLE 1 +#define MATCH_LEFT 2 +#define MATCH_RIGHT 3 +#define MATCH_MIDDLE 4 +#define MATCH_PATTERN 5 + +static const char *detect_match_rule(char *pattern, int *matchrule) +{ + char *ppos, *qpos; + int patternlength; + + patternlength = strlen(pattern); + ppos = strchr(pattern, '*'); + qpos = strchr(pattern, '?'); + // has ? - pattern + if (qpos) + { + *matchrule = MATCH_PATTERN; + return pattern; + } + // has * - left, mid, right or pattern + if (ppos) + { + // starts with * - may be right/mid or pattern + if ((ppos - pattern) == 0) + { + ppos = strchr(pattern+1, '*'); + // *something + if (!ppos) + { + *matchrule = MATCH_RIGHT; + return pattern+1; + } + // *something* + if ((ppos - pattern) == patternlength) + { + *matchrule = MATCH_MIDDLE; + *ppos = 0; + return pattern+1; + } + // *som*thing + *matchrule = MATCH_PATTERN; + return pattern; + } + // end with * - left + if ((ppos - pattern) == patternlength) + { + *matchrule = MATCH_LEFT; + *ppos = 0; + return pattern; + } + // som*thing + *matchrule = MATCH_PATTERN; + return pattern; + } + // have no wildcards - whole string + *matchrule = MATCH_WHOLE; + return pattern; +} + +// todo: support UTF8 +static qboolean match_rule(const char *string, int max_string, const char *pattern, int patternlength, int rule) +{ + const char *mid; + + if (rule == 1) + return !strncmp(string, pattern, max_string) ? true : false; + if (rule == 2) + return !strncmp(string, pattern, patternlength) ? true : false; + if (rule == 3) + { + mid = strstr(string, pattern); + return mid && !*(mid+patternlength); + } + if (rule == 4) + return strstr(string, pattern) ? true : false; + // pattern + return matchpattern_with_separator(string, pattern, false, "", false) ? true : false; +} + +/* +======================== +VM_bufstr_find +find an index of bufstring matching rule +float bufstr_find(float bufhandle, string match, float matchrule, float startpos, float step) = #468; +======================== +*/ + +void VM_bufstr_find(prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + char string[VM_STRINGTEMP_LENGTH]; + int matchrule, matchlen, i, step; + const char *match; + + VM_SAFEPARMCOUNTRANGE(3, 5, VM_bufstr_find); + + PRVM_G_FLOAT(OFS_RETURN) = -1; + + // get string buffer + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_find: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + + // get pattern/rule + matchrule = (int)PRVM_G_FLOAT(OFS_PARM2); + if (matchrule < 0 && matchrule > 5) + { + VM_Warning(prog, "VM_bufstr_find: invalid match rule %i in %s\n", matchrule, prog->name); + return; + } + if (matchrule) + match = PRVM_G_STRING(OFS_PARM1); + else + { + strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string)); + match = detect_match_rule(string, &matchrule); + } + matchlen = strlen(match); + + // find + i = (prog->argc > 3) ? (int)PRVM_G_FLOAT(OFS_PARM3) : 0; + step = (prog->argc > 4) ? (int)PRVM_G_FLOAT(OFS_PARM4) : 1; + while(i < stringbuffer->num_strings) + { + if (stringbuffer->strings[i] && match_rule(stringbuffer->strings[i], VM_STRINGTEMP_LENGTH, match, matchlen, matchrule)) + { + PRVM_G_FLOAT(OFS_RETURN) = i; + break; + } + i += step; + } +} + +/* +======================== +VM_matchpattern +float matchpattern(string s, string pattern, float matchrule, float startpos) = #468; +======================== +*/ +void VM_matchpattern(prvm_prog_t *prog) +{ + const char *s, *match; + char string[VM_STRINGTEMP_LENGTH]; + int matchrule, l; + + VM_SAFEPARMCOUNTRANGE(2, 4, VM_matchpattern); + + s = PRVM_G_STRING(OFS_PARM0); + + // get pattern/rule + matchrule = (int)PRVM_G_FLOAT(OFS_PARM2); + if (matchrule < 0 && matchrule > 5) + { + VM_Warning(prog, "VM_bufstr_find: invalid match rule %i in %s\n", matchrule, prog->name); + return; + } + if (matchrule) + match = PRVM_G_STRING(OFS_PARM1); + else + { + strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string)); + match = detect_match_rule(string, &matchrule); + } + + // offset + l = strlen(match); + if (prog->argc > 3) + s += max(0, min((unsigned int)PRVM_G_FLOAT(OFS_PARM3), strlen(s)-1)); + + // match + PRVM_G_FLOAT(OFS_RETURN) = match_rule(s, VM_STRINGTEMP_LENGTH, match, l, matchrule); +} + +/* +======================== +VM_buf_cvarlist +======================== +*/ + +void VM_buf_cvarlist(prvm_prog_t *prog) +{ + cvar_t *cvar; + const char *partial, *antipartial; + size_t len, antilen; + size_t alloclen; + qboolean ispattern, antiispattern; + int n; + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_buf_cvarlist); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning(prog, "VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + + partial = PRVM_G_STRING(OFS_PARM1); + if(!partial) + len = 0; + else + len = strlen(partial); + + if(prog->argc == 3) + antipartial = PRVM_G_STRING(OFS_PARM2); + else + antipartial = NULL; + if(!antipartial) + antilen = 0; + else + antilen = strlen(antipartial); + + for (n = 0;n < stringbuffer->num_strings;n++) + if (stringbuffer->strings[n]) + Mem_Free(stringbuffer->strings[n]); + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + stringbuffer->strings = NULL; + + ispattern = partial && (strchr(partial, '*') || strchr(partial, '?')); + antiispattern = antipartial && (strchr(antipartial, '*') || strchr(antipartial, '?')); + + n = 0; + for(cvar = cvar_vars; cvar; cvar = cvar->next) + { + if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len))) + continue; + + if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen))) + continue; + + ++n; + } + + stringbuffer->max_strings = stringbuffer->num_strings = n; + if (stringbuffer->max_strings) + stringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(stringbuffer->strings[0]) * stringbuffer->max_strings); + + n = 0; + for(cvar = cvar_vars; cvar; cvar = cvar->next) + { + if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len))) + continue; + + if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen))) + continue; + + alloclen = strlen(cvar->name) + 1; + stringbuffer->strings[n] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[n], cvar->name, alloclen); + + ++n; + } +} + + + + +//============= + +/* +============== +VM_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void VM_changeyaw (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + // this is called (VERY HACKISHLY) by VM_SV_MoveToGoal, so it can not use any + // parameters because they are the parameters to VM_SV_MoveToGoal, not this + //VM_SAFEPARMCOUNT(0, VM_changeyaw); + + ent = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "changeyaw: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "changeyaw: can not modify free entity\n"); + return; + } + current = PRVM_gameedictvector(ent, angles)[1]; + current = ANGLEMOD(current); + ideal = PRVM_gameedictfloat(ent, ideal_yaw); + speed = PRVM_gameedictfloat(ent, 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; + } + + current += move; + PRVM_gameedictvector(ent, angles)[1] = ANGLEMOD(current); +} + +/* +============== +VM_changepitch +============== +*/ +void VM_changepitch (prvm_prog_t *prog) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + VM_SAFEPARMCOUNT(1, VM_changepitch); + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning(prog, "changepitch: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "changepitch: can not modify free entity\n"); + return; + } + current = PRVM_gameedictvector(ent, angles)[0]; + current = ANGLEMOD(current); + ideal = PRVM_gameedictfloat(ent, idealpitch); + speed = PRVM_gameedictfloat(ent, 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; + } + + current += move; + PRVM_gameedictvector(ent, angles)[0] = ANGLEMOD(current); +} + + +void VM_uncolorstring (prvm_prog_t *prog) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1, VM_uncolorstring); + szString = PRVM_G_STRING(OFS_PARM0); + COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), TRUE); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString); + +} + +// #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS) +//strstr, without generating a new string. Use in conjunction with FRIK_FILE's substring for more similar strstr. +void VM_strstrofs (prvm_prog_t *prog) +{ + const char *instr, *match; + int firstofs; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strstrofs); + instr = PRVM_G_STRING(OFS_PARM0); + match = PRVM_G_STRING(OFS_PARM1); + firstofs = (prog->argc > 2)?(int)PRVM_G_FLOAT(OFS_PARM2):0; + firstofs = u8_bytelen(instr, firstofs); + + if (firstofs && (firstofs < 0 || firstofs > (int)strlen(instr))) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + + match = strstr(instr+firstofs, match); + if (!match) + PRVM_G_FLOAT(OFS_RETURN) = -1; + else + PRVM_G_FLOAT(OFS_RETURN) = u8_strnlen(instr, match-instr); +} + +//#222 string(string s, float index) str2chr (FTE_STRINGS) +void VM_str2chr (prvm_prog_t *prog) +{ + const char *s; + Uchar ch; + int index; + VM_SAFEPARMCOUNT(2, VM_str2chr); + s = PRVM_G_STRING(OFS_PARM0); + index = u8_bytelen(s, (int)PRVM_G_FLOAT(OFS_PARM1)); + + if((unsigned)index < strlen(s)) + { + if (utf8_enable.integer) + ch = u8_getchar_noendptr(s + index); + else + ch = (unsigned char)s[index]; + PRVM_G_FLOAT(OFS_RETURN) = ch; + } + else + PRVM_G_FLOAT(OFS_RETURN) = 0; +} + +//#223 string(float c, ...) chr2str (FTE_STRINGS) +void VM_chr2str (prvm_prog_t *prog) +{ + /* + char t[9]; + int i; + VM_SAFEPARMCOUNTRANGE(0, 8, VM_chr2str); + for(i = 0;i < prog->argc && i < (int)sizeof(t) - 1;i++) + t[i] = (unsigned char)PRVM_G_FLOAT(OFS_PARM0+i*3); + t[i] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t); + */ + char t[9 * 4 + 1]; + int i; + size_t len = 0; + VM_SAFEPARMCOUNTRANGE(0, 8, VM_chr2str); + for(i = 0; i < prog->argc && len < sizeof(t)-1; ++i) + len += u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0+i*3), t + len, sizeof(t)-1); + t[len] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t); +} + +static int chrconv_number(int i, int base, int conv) +{ + i -= base; + switch (conv) + { + default: + case 5: + case 6: + case 0: + break; + case 1: + base = '0'; + break; + case 2: + base = '0'+128; + break; + case 3: + base = '0'-30; + break; + case 4: + base = '0'+128-30; + break; + } + return i + base; +} +static int chrconv_punct(int i, int base, int conv) +{ + i -= base; + switch (conv) + { + default: + case 0: + break; + case 1: + base = 0; + break; + case 2: + base = 128; + break; + } + return i + base; +} + +static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int charnum) +{ + //convert case and colour seperatly... + + i -= baset + basec; + switch (convt) + { + default: + case 0: + break; + case 1: + baset = 0; + break; + case 2: + baset = 128; + break; + + case 5: + case 6: + baset = 128*((charnum&1) == (convt-5)); + break; + } + + switch (convc) + { + default: + case 0: + break; + case 1: + basec = 'a'; + break; + case 2: + basec = 'A'; + break; + } + return i + basec + baset; +} +// #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS) +//bulk convert a string. change case or colouring. +void VM_strconv (prvm_prog_t *prog) +{ + int ccase, redalpha, rednum, len, i; + unsigned char resbuf[VM_STRINGTEMP_LENGTH]; + unsigned char *result = resbuf; + + VM_SAFEPARMCOUNTRANGE(3, 8, VM_strconv); + + ccase = (int) PRVM_G_FLOAT(OFS_PARM0); //0 same, 1 lower, 2 upper + redalpha = (int) PRVM_G_FLOAT(OFS_PARM1); //0 same, 1 white, 2 red, 5 alternate, 6 alternate-alternate + rednum = (int) PRVM_G_FLOAT(OFS_PARM2); //0 same, 1 white, 2 red, 3 redspecial, 4 whitespecial, 5 alternate, 6 alternate-alternate + VM_VarString(prog, 3, (char *) resbuf, sizeof(resbuf)); + len = strlen((char *) resbuf); + + for (i = 0; i < len; i++, result++) //should this be done backwards? + { + if (*result >= '0' && *result <= '9') //normal numbers... + *result = chrconv_number(*result, '0', rednum); + else if (*result >= '0'+128 && *result <= '9'+128) + *result = chrconv_number(*result, '0'+128, rednum); + else if (*result >= '0'+128-30 && *result <= '9'+128-30) + *result = chrconv_number(*result, '0'+128-30, rednum); + else if (*result >= '0'-30 && *result <= '9'-30) + *result = chrconv_number(*result, '0'-30, rednum); + + else if (*result >= 'a' && *result <= 'z') //normal numbers... + *result = chrchar_alpha(*result, 'a', 0, ccase, redalpha, i); + else if (*result >= 'A' && *result <= 'Z') //normal numbers... + *result = chrchar_alpha(*result, 'A', 0, ccase, redalpha, i); + else if (*result >= 'a'+128 && *result <= 'z'+128) //normal numbers... + *result = chrchar_alpha(*result, 'a', 128, ccase, redalpha, i); + else if (*result >= 'A'+128 && *result <= 'Z'+128) //normal numbers... + *result = chrchar_alpha(*result, 'A', 128, ccase, redalpha, i); + + else if ((*result & 127) < 16 || !redalpha) //special chars.. + *result = *result; + else if (*result < 128) + *result = chrconv_punct(*result, 0, redalpha); + else + *result = chrconv_punct(*result, 128, redalpha); + } + *result = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, (char *) resbuf); +} + +// #225 string(float chars, string s, ...) strpad (FTE_STRINGS) +void VM_strpad (prvm_prog_t *prog) +{ + char src[VM_STRINGTEMP_LENGTH]; + char destbuf[VM_STRINGTEMP_LENGTH]; + int pad; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_strpad); + pad = (int) PRVM_G_FLOAT(OFS_PARM0); + VM_VarString(prog, 1, src, sizeof(src)); + + // note: < 0 = left padding, > 0 = right padding, + // this is reverse logic of printf! + dpsnprintf(destbuf, sizeof(destbuf), "%*s", -pad, src); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, destbuf); +} + +// #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS) +//uses qw style \key\value strings +void VM_infoadd (prvm_prog_t *prog) +{ + const char *info, *key; + char value[VM_STRINGTEMP_LENGTH]; + char temp[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_infoadd); + info = PRVM_G_STRING(OFS_PARM0); + key = PRVM_G_STRING(OFS_PARM1); + VM_VarString(prog, 2, value, sizeof(value)); + + strlcpy(temp, info, VM_STRINGTEMP_LENGTH); + + InfoString_SetValue(temp, VM_STRINGTEMP_LENGTH, key, value); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, temp); +} + +// #227 string(string info, string key) infoget (FTE_STRINGS) +//uses qw style \key\value strings +void VM_infoget (prvm_prog_t *prog) +{ + const char *info; + const char *key; + char value[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(2, VM_infoget); + info = PRVM_G_STRING(OFS_PARM0); + key = PRVM_G_STRING(OFS_PARM1); + + InfoString_GetValue(info, key, value, VM_STRINGTEMP_LENGTH); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, value); +} + +//#228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +// also float(string s1, string s2) strcmp (FRIK_FILE) +void VM_strncmp (prvm_prog_t *prog) +{ + const char *s1, *s2; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncmp); + s1 = PRVM_G_STRING(OFS_PARM0); + s2 = PRVM_G_STRING(OFS_PARM1); + if (prog->argc > 2) + { + PRVM_G_FLOAT(OFS_RETURN) = strncmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2)); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = strcmp(s1, s2); + } +} + +// #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) +// #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +void VM_strncasecmp (prvm_prog_t *prog) +{ + const char *s1, *s2; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncasecmp); + s1 = PRVM_G_STRING(OFS_PARM0); + s2 = PRVM_G_STRING(OFS_PARM1); + if (prog->argc > 2) + { + PRVM_G_FLOAT(OFS_RETURN) = strncasecmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2)); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = strcasecmp(s1, s2); + } +} + +// #494 float(float caseinsensitive, string s, ...) crc16 +void VM_crc16(prvm_prog_t *prog) +{ + float insensitive; + char s[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2, 8, VM_crc16); + insensitive = PRVM_G_FLOAT(OFS_PARM0); + VM_VarString(prog, 1, s, sizeof(s)); + PRVM_G_FLOAT(OFS_RETURN) = (unsigned short) ((insensitive ? CRC_Block_CaseInsensitive : CRC_Block) ((unsigned char *) s, strlen(s))); +} + +// #639 float(string digest, string data, ...) digest_hex +void VM_digest_hex(prvm_prog_t *prog) +{ + const char *digest; + + char out[32]; + char outhex[65]; + int outlen; + + char s[VM_STRINGTEMP_LENGTH]; + int len; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_digest_hex); + digest = PRVM_G_STRING(OFS_PARM0); + if(!digest) + digest = ""; + VM_VarString(prog, 1, s, sizeof(s)); + len = strlen(s); + + outlen = 0; + + if(!strcmp(digest, "MD4")) + { + outlen = 16; + mdfour((unsigned char *) out, (unsigned char *) s, len); + } + else if(!strcmp(digest, "SHA256") && Crypto_Available()) + { + outlen = 32; + sha256((unsigned char *) out, (unsigned char *) s, len); + } + // no warning needed on mismatch - we return string_null to QC + + if(outlen) + { + int i; + static const char *hexmap = "0123456789abcdef"; + for(i = 0; i < outlen; ++i) + { + outhex[2*i] = hexmap[(out[i] >> 4) & 15]; + outhex[2*i+1] = hexmap[(out[i] >> 0) & 15]; + } + outhex[2*i] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outhex); + } + else + PRVM_G_INT(OFS_RETURN) = 0; +} + +void VM_wasfreed (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_wasfreed); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICT(OFS_PARM0)->priv.required->free; +} + +void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace) +{ + PRVM_gameglobalfloat(trace_allsolid) = trace->allsolid; + PRVM_gameglobalfloat(trace_startsolid) = trace->startsolid; + PRVM_gameglobalfloat(trace_fraction) = trace->fraction; + PRVM_gameglobalfloat(trace_inwater) = trace->inwater; + PRVM_gameglobalfloat(trace_inopen) = trace->inopen; + VectorCopy(trace->endpos, PRVM_gameglobalvector(trace_endpos)); + VectorCopy(trace->plane.normal, PRVM_gameglobalvector(trace_plane_normal)); + PRVM_gameglobalfloat(trace_plane_dist) = trace->plane.dist; + PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts); + PRVM_gameglobalfloat(trace_dpstartcontents) = trace->startsupercontents; + PRVM_gameglobalfloat(trace_dphitcontents) = trace->hitsupercontents; + PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = trace->hitq3surfaceflags; + PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(prog, trace->hittexture->name) : 0; +} + +void VM_ClearTraceGlobals(prvm_prog_t *prog) +{ + // clean up all trace globals when leaving the VM (anti-triggerbot safeguard) + PRVM_gameglobalfloat(trace_allsolid) = 0; + PRVM_gameglobalfloat(trace_startsolid) = 0; + PRVM_gameglobalfloat(trace_fraction) = 0; + PRVM_gameglobalfloat(trace_inwater) = 0; + PRVM_gameglobalfloat(trace_inopen) = 0; + VectorClear(PRVM_gameglobalvector(trace_endpos)); + VectorClear(PRVM_gameglobalvector(trace_plane_normal)); + PRVM_gameglobalfloat(trace_plane_dist) = 0; + PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_gameglobalfloat(trace_dpstartcontents) = 0; + PRVM_gameglobalfloat(trace_dphitcontents) = 0; + PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = 0; + PRVM_gameglobalstring(trace_dphittexturename) = 0; +} + +//============= + +void VM_Cmd_Init(prvm_prog_t *prog) +{ + // only init the stuff for the current prog + VM_Files_Init(prog); + VM_Search_Init(prog); +} + +void VM_Cmd_Reset(prvm_prog_t *prog) +{ + CL_PurgeOwner( MENUOWNER ); + VM_Search_Reset(prog); + VM_Files_CloseAll(prog); +} + +// #510 string(string input, ...) uri_escape (DP_QC_URI_ESCAPE) +// does URI escaping on a string (replace evil stuff by %AB escapes) +void VM_uri_escape (prvm_prog_t *prog) +{ + char src[VM_STRINGTEMP_LENGTH]; + char dest[VM_STRINGTEMP_LENGTH]; + char *p, *q; + static const char *hex = "0123456789ABCDEF"; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_escape); + VM_VarString(prog, 0, src, sizeof(src)); + + for(p = src, q = dest; *p && q < dest + sizeof(dest) - 3; ++p) + { + if((*p >= 'A' && *p <= 'Z') + || (*p >= 'a' && *p <= 'z') + || (*p >= '0' && *p <= '9') + || (*p == '-') || (*p == '_') || (*p == '.') + || (*p == '!') || (*p == '~') + || (*p == '\'') || (*p == '(') || (*p == ')')) + *q++ = *p; + else + { + *q++ = '%'; + *q++ = hex[(*(unsigned char *)p >> 4) & 0xF]; + *q++ = hex[ *(unsigned char *)p & 0xF]; + } + } + *q++ = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest); +} + +// #510 string(string input, ...) uri_unescape (DP_QC_URI_ESCAPE) +// does URI unescaping on a string (get back the evil stuff) +void VM_uri_unescape (prvm_prog_t *prog) +{ + char src[VM_STRINGTEMP_LENGTH]; + char dest[VM_STRINGTEMP_LENGTH]; + char *p, *q; + int hi, lo; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_unescape); + VM_VarString(prog, 0, src, sizeof(src)); + + for(p = src, q = dest; *p; ) // no need to check size, because unescape can't expand + { + if(*p == '%') + { + if(p[1] >= '0' && p[1] <= '9') + hi = p[1] - '0'; + else if(p[1] >= 'a' && p[1] <= 'f') + hi = p[1] - 'a' + 10; + else if(p[1] >= 'A' && p[1] <= 'F') + hi = p[1] - 'A' + 10; + else + goto nohex; + if(p[2] >= '0' && p[2] <= '9') + lo = p[2] - '0'; + else if(p[2] >= 'a' && p[2] <= 'f') + lo = p[2] - 'a' + 10; + else if(p[2] >= 'A' && p[2] <= 'F') + lo = p[2] - 'A' + 10; + else + goto nohex; + if(hi != 0 || lo != 0) // don't unescape NUL bytes + *q++ = (char) (hi * 0x10 + lo); + p += 3; + continue; + } + +nohex: + // otherwise: + *q++ = *p++; + } + *q++ = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest); +} + +// #502 string(string filename) whichpack (DP_QC_WHICHPACK) +// returns the name of the pack containing a file, or "" if it is not in any pack (but local or non-existant) +void VM_whichpack (prvm_prog_t *prog) +{ + const char *fn, *pack; + + VM_SAFEPARMCOUNT(1, VM_whichpack); + fn = PRVM_G_STRING(OFS_PARM0); + pack = FS_WhichPack(fn); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, pack ? pack : ""); +} + +typedef struct +{ + prvm_prog_t *prog; + double starttime; + float id; + char buffer[MAX_INPUTLINE]; + char posttype[128]; + unsigned char *postdata; // free when uri_to_prog_t is freed + size_t postlen; + char *sigdata; // free when uri_to_prog_t is freed + size_t siglen; +} +uri_to_prog_t; + +static void uri_to_string_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + prvm_prog_t *prog; + uri_to_prog_t *handle = (uri_to_prog_t *) cbdata; + + prog = handle->prog; + if(!prog->loaded) + { + // curl reply came too late... so just drop it + if(handle->postdata) + Z_Free(handle->postdata); + if(handle->sigdata) + Z_Free(handle->sigdata); + Z_Free(handle); + return; + } + + if((prog->starttime == handle->starttime) && (PRVM_allfunction(URI_Get_Callback))) + { + if(length_received >= sizeof(handle->buffer)) + length_received = sizeof(handle->buffer) - 1; + handle->buffer[length_received] = 0; + + PRVM_G_FLOAT(OFS_PARM0) = handle->id; + PRVM_G_FLOAT(OFS_PARM1) = status; + PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(prog, handle->buffer); + prog->ExecuteProgram(prog, PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing"); + } + + if(handle->postdata) + Z_Free(handle->postdata); + if(handle->sigdata) + Z_Free(handle->sigdata); + Z_Free(handle); +} + +// uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned +// returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string +void VM_uri_get (prvm_prog_t *prog) +{ + const char *url; + float id; + qboolean ret; + uri_to_prog_t *handle; + const char *posttype = NULL; + const char *postseparator = NULL; + int poststringbuffer = -1; + int postkeyid = -1; + const char *query_string = NULL; + size_t lq; + + if(!PRVM_allfunction(URI_Get_Callback)) + prog->error_cmd("uri_get called by %s without URI_Get_Callback defined", prog->name); + + VM_SAFEPARMCOUNTRANGE(2, 6, VM_uri_get); + + url = PRVM_G_STRING(OFS_PARM0); + id = PRVM_G_FLOAT(OFS_PARM1); + if(prog->argc >= 3) + posttype = PRVM_G_STRING(OFS_PARM2); + if(prog->argc >= 4) + postseparator = PRVM_G_STRING(OFS_PARM3); + if(prog->argc >= 5) + poststringbuffer = PRVM_G_FLOAT(OFS_PARM4); + if(prog->argc >= 6) + postkeyid = PRVM_G_FLOAT(OFS_PARM5); + handle = (uri_to_prog_t *) Z_Malloc(sizeof(*handle)); // this can't be the prog's mem pool, as curl may call the callback later! + + query_string = strchr(url, '?'); + if(query_string) + ++query_string; + lq = query_string ? strlen(query_string) : 0; + + handle->prog = prog; + handle->starttime = prog->starttime; + handle->id = id; + if(postseparator && posttype && *posttype) + { + size_t l = strlen(postseparator); + if(poststringbuffer >= 0) + { + size_t ltotal; + int i; + // "implode" + prvm_stringbuffer_t *stringbuffer; + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, poststringbuffer); + if(!stringbuffer) + { + VM_Warning(prog, "uri_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); + return; + } + ltotal = 0; + for(i = 0;i < stringbuffer->num_strings;i++) + { + if(i > 0) + ltotal += l; + if(stringbuffer->strings[i]) + ltotal += strlen(stringbuffer->strings[i]); + } + handle->postdata = (unsigned char *)Z_Malloc(ltotal + 1 + lq); + handle->postlen = ltotal; + ltotal = 0; + for(i = 0;i < stringbuffer->num_strings;i++) + { + if(i > 0) + { + memcpy(handle->postdata + ltotal, postseparator, l); + ltotal += l; + } + if(stringbuffer->strings[i]) + { + memcpy(handle->postdata + ltotal, stringbuffer->strings[i], strlen(stringbuffer->strings[i])); + ltotal += strlen(stringbuffer->strings[i]); + } + } + if(ltotal != handle->postlen) + prog->error_cmd("%s: string buffer content size mismatch, possible overrun", prog->name); + } + else + { + handle->postdata = (unsigned char *)Z_Malloc(l + 1 + lq); + handle->postlen = l; + memcpy(handle->postdata, postseparator, l); + } + handle->postdata[handle->postlen] = 0; + if(query_string) + memcpy(handle->postdata + handle->postlen + 1, query_string, lq); + if(postkeyid >= 0) + { + // POST: we sign postdata \0 query string + size_t ll; + handle->sigdata = (char *)Z_Malloc(8192); + strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192); + l = strlen(handle->sigdata); + handle->siglen = Crypto_SignDataDetached(handle->postdata, handle->postlen + 1 + lq, postkeyid, handle->sigdata + l, 8192 - l); + if(!handle->siglen) + { + Z_Free(handle->sigdata); + handle->sigdata = NULL; + goto out1; + } + ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1); + if(!ll) + { + Z_Free(handle->sigdata); + handle->sigdata = NULL; + goto out1; + } + handle->siglen = l + ll; + handle->sigdata[handle->siglen] = 0; + } +out1: + strlcpy(handle->posttype, posttype, sizeof(handle->posttype)); + ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, handle->posttype, handle->postdata, handle->postlen, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle); + } + else + { + if(postkeyid >= 0 && query_string) + { + // GET: we sign JUST the query string + size_t l, ll; + handle->sigdata = (char *)Z_Malloc(8192); + strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192); + l = strlen(handle->sigdata); + handle->siglen = Crypto_SignDataDetached(query_string, lq, postkeyid, handle->sigdata + l, 8192 - l); + if(!handle->siglen) + { + Z_Free(handle->sigdata); + handle->sigdata = NULL; + goto out2; + } + ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1); + if(!ll) + { + Z_Free(handle->sigdata); + handle->sigdata = NULL; + goto out2; + } + handle->siglen = l + ll; + handle->sigdata[handle->siglen] = 0; + } +out2: + handle->postdata = NULL; + handle->postlen = 0; + ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, NULL, NULL, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle); + } + if(ret) + { + PRVM_G_INT(OFS_RETURN) = 1; + } + else + { + if(handle->postdata) + Z_Free(handle->postdata); + if(handle->sigdata) + Z_Free(handle->sigdata); + Z_Free(handle); + PRVM_G_INT(OFS_RETURN) = 0; + } +} + +void VM_netaddress_resolve (prvm_prog_t *prog) +{ + const char *ip; + char normalized[128]; + int port; + lhnetaddress_t addr; + + VM_SAFEPARMCOUNTRANGE(1, 2, VM_netaddress_resolve); + + ip = PRVM_G_STRING(OFS_PARM0); + port = 0; + if(prog->argc > 1) + port = (int) PRVM_G_FLOAT(OFS_PARM1); + + if(LHNETADDRESS_FromString(&addr, ip, port) && LHNETADDRESS_ToString(&addr, normalized, sizeof(normalized), prog->argc > 1)) + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, normalized); + else + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ""); +} + +//string(prvm_prog_t *prog) getextresponse = #624; // returns the next extResponse packet that was sent to this client +void VM_CL_getextresponse (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_argv); + + if (cl_net_extresponse_count <= 0) + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + else + { + int first; + --cl_net_extresponse_count; + first = (cl_net_extresponse_last + NET_EXTRESPONSE_MAX - cl_net_extresponse_count) % NET_EXTRESPONSE_MAX; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cl_net_extresponse[first]); + } +} + +void VM_SV_getextresponse (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0,VM_argv); + + if (sv_net_extresponse_count <= 0) + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + else + { + int first; + --sv_net_extresponse_count; + first = (sv_net_extresponse_last + NET_EXTRESPONSE_MAX - sv_net_extresponse_count) % NET_EXTRESPONSE_MAX; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, sv_net_extresponse[first]); + } +} + +/* +========= +Common functions between menu.dat and clsprogs +========= +*/ + +//#349 float() isdemo +void VM_CL_isdemo (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_isdemo); + PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback; +} + +//#355 float() videoplaying +void VM_CL_videoplaying (prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(0, VM_CL_videoplaying); + PRVM_G_FLOAT(OFS_RETURN) = cl_videoplaying; +} + +/* +========= +VM_M_callfunction + + callfunction(...,string function_name) +Extension: pass +========= +*/ +void VM_callfunction(prvm_prog_t *prog) +{ + mfunction_t *func; + const char *s; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_callfunction); + + s = PRVM_G_STRING(OFS_PARM0+(prog->argc - 1)*3); + + VM_CheckEmptyString(prog, s); + + func = PRVM_ED_FindFunction(prog, s); + + if(!func) + prog->error_cmd("VM_callfunciton: function %s not found !", s); + else if (func->first_statement < 0) + { + // negative statements are built in functions + int builtinnumber = -func->first_statement; + prog->xfunction->builtinsprofile++; + if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber]) + prog->builtins[builtinnumber](prog); + else + prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name); + } + else if(func - prog->functions > 0) + { + prog->argc--; + prog->ExecuteProgram(prog, func - prog->functions,""); + prog->argc++; + } +} + +/* +========= +VM_isfunction + +float isfunction(string function_name) +========= +*/ +void VM_isfunction(prvm_prog_t *prog) +{ + mfunction_t *func; + const char *s; + + VM_SAFEPARMCOUNT(1, VM_isfunction); + + s = PRVM_G_STRING(OFS_PARM0); + + VM_CheckEmptyString(prog, s); + + func = PRVM_ED_FindFunction(prog, s); + + if(!func) + PRVM_G_FLOAT(OFS_RETURN) = false; + else + PRVM_G_FLOAT(OFS_RETURN) = true; +} + +/* +========= +VM_sprintf + +string sprintf(string format, ...) +========= +*/ + +void VM_sprintf(prvm_prog_t *prog) +{ + const char *s, *s0; + char outbuf[MAX_INPUTLINE]; + char *o = outbuf, *end = outbuf + sizeof(outbuf), *err; + const char *p; + int argpos = 1; + int width, precision, thisarg, flags; + char formatbuf[16]; + char *f; + int isfloat; + static prvm_int_t dummyivec[3] = {0, 0, 0}; + static prvm_vec_t dummyvec[3] = {0, 0, 0}; + char vabuf[1024]; + +#define PRINTF_ALTERNATE 1 +#define PRINTF_ZEROPAD 2 +#define PRINTF_LEFT 4 +#define PRINTF_SPACEPOSITIVE 8 +#define PRINTF_SIGNPOSITIVE 16 + + formatbuf[0] = '%'; + + s = PRVM_G_STRING(OFS_PARM0); + +#define GETARG_FLOAT(a) (((a)>=1 && (a)argc) ? (PRVM_G_FLOAT(OFS_PARM0 + 3 * (a))) : 0) +#define GETARG_VECTOR(a) (((a)>=1 && (a)argc) ? (PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec) +#define GETARG_INT(a) (((a)>=1 && (a)argc) ? (PRVM_G_INT(OFS_PARM0 + 3 * (a))) : 0) +#define GETARG_INTVECTOR(a) (((a)>=1 && (a)argc) ? ((prvm_int_t*) PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec) +#define GETARG_STRING(a) (((a)>=1 && (a)argc) ? (PRVM_G_STRING(OFS_PARM0 + 3 * (a))) : "") + + for(;;) + { + s0 = s; + switch(*s) + { + case 0: + goto finished; + case '%': + ++s; + + if(*s == '%') + goto verbatim; + + // complete directive format: + // %3$*1$.*2$ld + + width = -1; + precision = -1; + thisarg = -1; + flags = 0; + isfloat = -1; + + // is number following? + if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err) + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + if(*err == '$') + { + thisarg = width; + width = -1; + s = err + 1; + } + else + { + if(*s == '0') + { + flags |= PRINTF_ZEROPAD; + if(width == 0) + width = -1; // it was just a flag + } + s = err; + } + } + + if(width < 0) + { + for(;;) + { + switch(*s) + { + case '#': flags |= PRINTF_ALTERNATE; break; + case '0': flags |= PRINTF_ZEROPAD; break; + case '-': flags |= PRINTF_LEFT; break; + case ' ': flags |= PRINTF_SPACEPOSITIVE; break; + case '+': flags |= PRINTF_SIGNPOSITIVE; break; + default: + goto noflags; + } + ++s; + } +noflags: + if(*s == '*') + { + ++s; + if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err || *err != '$') + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + s = err + 1; + } + else + width = argpos++; + width = GETARG_FLOAT(width); + if(width < 0) + { + flags |= PRINTF_LEFT; + width = -width; + } + } + else if(*s >= '0' && *s <= '9') + { + width = strtol(s, &err, 10); + if(!err) + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + s = err; + if(width < 0) + { + flags |= PRINTF_LEFT; + width = -width; + } + } + // otherwise width stays -1 + } + + if(*s == '.') + { + ++s; + if(*s == '*') + { + ++s; + if(*s >= '0' && *s <= '9') + { + precision = strtol(s, &err, 10); + if(!err || *err != '$') + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + s = err + 1; + } + else + precision = argpos++; + precision = GETARG_FLOAT(precision); + } + else if(*s >= '0' && *s <= '9') + { + precision = strtol(s, &err, 10); + if(!err) + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + s = err; + } + else + { + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + } + + for(;;) + { + switch(*s) + { + case 'h': isfloat = 1; break; + case 'l': isfloat = 0; break; + case 'L': isfloat = 0; break; + case 'j': break; + case 'z': break; + case 't': break; + default: + goto nolength; + } + ++s; + } +nolength: + + // now s points to the final directive char and is no longer changed + if(isfloat < 0) + { + if(*s == 'i') + isfloat = 0; + else + isfloat = 1; + } + + if(thisarg < 0) + thisarg = argpos++; + + if(o < end - 1) + { + f = &formatbuf[1]; + if(*s != 's' && *s != 'c') + if(flags & PRINTF_ALTERNATE) *f++ = '#'; + if(flags & PRINTF_ZEROPAD) *f++ = '0'; + if(flags & PRINTF_LEFT) *f++ = '-'; + if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' '; + if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+'; + *f++ = '*'; + if(precision >= 0) + { + *f++ = '.'; + *f++ = '*'; + } + if(*s == 'd' || *s == 'i' || *s == 'o' || *s == 'u' || *s == 'x' || *s == 'X') + { + // make it use a good integer type + for(p = INT_LOSSLESS_FORMAT_SIZE; *p; ) + *f++ = *p++; + } + *f++ = *s; + *f++ = 0; + + if(width < 0) // not set + width = 0; + + switch(*s) + { + case 'd': case 'i': + if(precision < 0) // not set + o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_INT(thisarg)))); + else + o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_INT(thisarg)))); + break; + case 'o': case 'u': case 'x': case 'X': + if(precision < 0) // not set + o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_INT(thisarg)))); + else + o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_INT(thisarg)))); + break; + case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': + if(precision < 0) // not set + o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg))); + else + o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg))); + break; + case 'v': case 'V': + f[-2] += 'g' - 'v'; + if(precision < 0) // not set + o += dpsnprintf(o, end - o, va(vabuf, sizeof(vabuf), "%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf), + width, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]), + width, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]), + width, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2]) + ); + else + o += dpsnprintf(o, end - o, va(vabuf, sizeof(vabuf), "%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf), + width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]), + width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]), + width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2]) + ); + break; + case 'c': + if(flags & PRINTF_ALTERNATE) + { + if(precision < 0) // not set + o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg))); + else + o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg))); + } + else + { + unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)); + char charbuf16[16]; + const char *buf = u8_encodech(c, NULL, charbuf16); + if(!buf) + buf = ""; + if(precision < 0) // not set + precision = end - o - 1; + o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision); + } + break; + case 's': + if(flags & PRINTF_ALTERNATE) + { + if(precision < 0) // not set + o += dpsnprintf(o, end - o, formatbuf, width, GETARG_STRING(thisarg)); + else + o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg)); + } + else + { + if(precision < 0) // not set + precision = end - o - 1; + if(flags & PRINTF_SIGNPOSITIVE) + o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision); + else + o += u8_strpad_colorcodes(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision); + } + break; + default: + VM_Warning(prog, "VM_sprintf: invalid directive in %s: %s\n", prog->name, s0); + goto finished; + } + } + ++s; + break; + default: +verbatim: + if(o < end - 1) + *o++ = *s++; + break; + } + } +finished: + *o = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outbuf); +} + + +// surface querying + +static dp_model_t *getmodel(prvm_prog_t *prog, prvm_edict_t *ed) +{ + if (prog == SVVM_prog) + return SV_GetModelFromEdict(ed); + else if (prog == CLVM_prog) + return CL_GetModelFromEdict(ed); + else + return NULL; +} + +typedef struct +{ + unsigned int progid; + dp_model_t *model; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + skeleton_t *skeleton_p; + skeleton_t skeleton; + float *data_vertex3f; + float *data_svector3f; + float *data_tvector3f; + float *data_normal3f; + int max_vertices; + float *buf_vertex3f; + float *buf_svector3f; + float *buf_tvector3f; + float *buf_normal3f; +} +animatemodel_cache_t; +static animatemodel_cache_t animatemodel_cache; + +static void animatemodel(prvm_prog_t *prog, dp_model_t *model, prvm_edict_t *ed) +{ + skeleton_t *skeleton; + int skeletonindex = -1; + qboolean need = false; + if(!(model->surfmesh.isanimated && model->AnimateVertices)) + { + animatemodel_cache.data_vertex3f = model->surfmesh.data_vertex3f; + animatemodel_cache.data_svector3f = model->surfmesh.data_svector3f; + animatemodel_cache.data_tvector3f = model->surfmesh.data_tvector3f; + animatemodel_cache.data_normal3f = model->surfmesh.data_normal3f; + return; + } + if(animatemodel_cache.progid != prog->id) + memset(&animatemodel_cache, 0, sizeof(animatemodel_cache)); + need |= (animatemodel_cache.model != model); + VM_GenerateFrameGroupBlend(prog, ed->priv.server->framegroupblend, ed); + VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model, PRVM_serverglobalfloat(time)); + need |= (memcmp(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend))) != 0; + skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1; + if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)) + skeleton = NULL; + need |= (animatemodel_cache.skeleton_p != skeleton); + if(skeleton) + need |= (memcmp(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton))) != 0; + if(!need) + return; + if(model->surfmesh.num_vertices > animatemodel_cache.max_vertices) + { + animatemodel_cache.max_vertices = model->surfmesh.num_vertices * 2; + if(animatemodel_cache.buf_vertex3f) Mem_Free(animatemodel_cache.buf_vertex3f); + if(animatemodel_cache.buf_svector3f) Mem_Free(animatemodel_cache.buf_svector3f); + if(animatemodel_cache.buf_tvector3f) Mem_Free(animatemodel_cache.buf_tvector3f); + if(animatemodel_cache.buf_normal3f) Mem_Free(animatemodel_cache.buf_normal3f); + animatemodel_cache.buf_vertex3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices); + animatemodel_cache.buf_svector3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices); + animatemodel_cache.buf_tvector3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices); + animatemodel_cache.buf_normal3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices); + } + animatemodel_cache.data_vertex3f = animatemodel_cache.buf_vertex3f; + animatemodel_cache.data_svector3f = animatemodel_cache.buf_svector3f; + animatemodel_cache.data_tvector3f = animatemodel_cache.buf_tvector3f; + animatemodel_cache.data_normal3f = animatemodel_cache.buf_normal3f; + VM_UpdateEdictSkeleton(prog, ed, model, ed->priv.server->frameblend); + model->AnimateVertices(model, ed->priv.server->frameblend, &ed->priv.server->skeleton, animatemodel_cache.data_vertex3f, animatemodel_cache.data_normal3f, animatemodel_cache.data_svector3f, animatemodel_cache.data_tvector3f); + animatemodel_cache.progid = prog->id; + animatemodel_cache.model = model; + memcpy(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend)); + animatemodel_cache.skeleton_p = skeleton; + if(skeleton) + memcpy(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton)); +} + +static void getmatrix(prvm_prog_t *prog, prvm_edict_t *ed, matrix4x4_t *out) +{ + if (prog == SVVM_prog) + SV_GetEntityMatrix(prog, ed, out, false); + else if (prog == CLVM_prog) + CL_GetEntityMatrix(prog, ed, out, false); + else + *out = identitymatrix; +} + +static void applytransform_forward(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + getmatrix(prog, ed, &m); + Matrix4x4_Transform(&m, in, out); +} + +static void applytransform_forward_direction(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + getmatrix(prog, ed, &m); + Matrix4x4_Transform3x3(&m, in, out); +} + +static void applytransform_inverted(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m, n; + getmatrix(prog, ed, &m); + Matrix4x4_Invert_Full(&n, &m); + Matrix4x4_Transform3x3(&n, in, out); +} + +static void applytransform_forward_normal(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out) +{ + matrix4x4_t m; + float p[4]; + getmatrix(prog, ed, &m); + Matrix4x4_TransformPositivePlane(&m, in[0], in[1], in[2], 0, p); + VectorCopy(p, out); +} + +static void clippointtosurface(prvm_prog_t *prog, prvm_edict_t *ed, dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out) +{ + int i, j, k; + float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist; + const int *e; + animatemodel(prog, model, ed); + bestdist = 1000000000; + VectorCopy(p, out); + for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3) + { + // clip original point to each triangle of the surface and find the + // triangle that is closest + v[0] = animatemodel_cache.data_vertex3f + e[0] * 3; + v[1] = animatemodel_cache.data_vertex3f + e[1] * 3; + v[2] = animatemodel_cache.data_vertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], facenormal); + VectorNormalize(facenormal); + offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal); + VectorMA(p, offsetdist, facenormal, temp); + for (j = 0, k = 2;j < 3;k = j, j++) + { + VectorSubtract(v[k], v[j], edgenormal); + CrossProduct(edgenormal, facenormal, sidenormal); + VectorNormalize(sidenormal); + offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal); + if (offsetdist < 0) + VectorMA(temp, offsetdist, sidenormal, temp); + } + dist = VectorDistance2(temp, p); + if (bestdist > dist) + { + bestdist = dist; + VectorCopy(temp, out); + } + } +} + +static msurface_t *getsurface(dp_model_t *model, int surfacenum) +{ + if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces) + return NULL; + return model->data_surfaces + surfacenum + model->firstmodelsurface; +} + + +//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434; +void VM_getsurfacenumpoints(prvm_prog_t *prog) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_getsurfacenumpoints); + // return 0 if no such surface + if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + // note: this (incorrectly) assumes it is a simple polygon + PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices; +} +//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435; +void VM_getsurfacepoint(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int pointnum; + vec3_t result; + VM_SAFEPARMCOUNT(3, VM_getsurfacepoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + // note: this (incorrectly) assumes it is a simple polygon + pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (pointnum < 0 || pointnum >= surface->num_vertices) + return; + animatemodel(prog, model, ed); + applytransform_forward(prog, &(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); +} +//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +// float SPA_POSITION = 0; +// float SPA_S_AXIS = 1; +// float SPA_T_AXIS = 2; +// float SPA_R_AXIS = 3; // same as SPA_NORMAL +// float SPA_TEXCOORDS0 = 4; +// float SPA_LIGHTMAP0_TEXCOORDS = 5; +// float SPA_LIGHTMAP0_COLOR = 6; +void VM_getsurfacepointattribute(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int pointnum; + int attributetype; + vec3_t result; + + VM_SAFEPARMCOUNT(4, VM_getsurfacepoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + pointnum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (pointnum < 0 || pointnum >= surface->num_vertices) + return; + attributetype = (int) PRVM_G_FLOAT(OFS_PARM3); + + animatemodel(prog, model, ed); + + switch( attributetype ) { + // float SPA_POSITION = 0; + case 0: + applytransform_forward(prog, &(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + // float SPA_S_AXIS = 1; + case 1: + applytransform_forward_direction(prog, &(animatemodel_cache.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + // float SPA_T_AXIS = 2; + case 2: + applytransform_forward_direction(prog, &(animatemodel_cache.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + // float SPA_R_AXIS = 3; // same as SPA_NORMAL + case 3: + applytransform_forward_direction(prog, &(animatemodel_cache.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + // float SPA_TEXCOORDS0 = 4; + case 4: { + float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2]; + result[0] = texcoord[0]; + result[1] = texcoord[1]; + result[2] = 0.0f; + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + } + // float SPA_LIGHTMAP0_TEXCOORDS = 5; + case 5: { + float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2]; + result[0] = texcoord[0]; + result[1] = texcoord[1]; + result[2] = 0.0f; + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); + break; + } + // float SPA_LIGHTMAP0_COLOR = 6; + case 6: + // ignore alpha for now.. + VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN)); + break; + default: + VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f ); + break; + } +} +//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436; +void VM_getsurfacenormal(prvm_prog_t *prog) +{ + dp_model_t *model; + msurface_t *surface; + vec3_t normal; + vec3_t result; + VM_SAFEPARMCOUNT(2, VM_getsurfacenormal); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + // note: this only returns the first triangle, so it doesn't work very + // well for curved surfaces or arbitrary meshes + animatemodel(prog, model, PRVM_G_EDICT(OFS_PARM0)); + TriangleNormal((animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex), (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 3, (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal); + applytransform_forward_normal(prog, normal, PRVM_G_EDICT(OFS_PARM0), result); + VectorNormalize(result); + VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN)); +} +//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437; +void VM_getsurfacetexture(prvm_prog_t *prog) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_getsurfacetexture); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, surface->texture->name); +} +//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438; +void VM_getsurfacenearpoint(prvm_prog_t *prog) +{ + int surfacenum, best; + vec3_t clipped, p; + vec_t dist, bestdist; + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + vec3_t point; + VM_SAFEPARMCOUNT(2, VM_getsurfacenearpoint); + PRVM_G_FLOAT(OFS_RETURN) = -1; + ed = PRVM_G_EDICT(OFS_PARM0); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), point); + + if (!ed || ed->priv.server->free) + return; + model = getmodel(prog, ed); + if (!model || !model->num_surfaces) + return; + + animatemodel(prog, model, ed); + + applytransform_inverted(prog, point, ed, p); + best = -1; + bestdist = 1000000000; + for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++) + { + surface = model->data_surfaces + surfacenum + model->firstmodelsurface; + // first see if the nearest point on the surface's box is closer than the previous match + clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0]; + clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1]; + clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2]; + dist = VectorLength2(clipped); + if (dist < bestdist) + { + // it is, check the nearest point on the actual geometry + clippointtosurface(prog, ed, model, surface, p, clipped); + VectorSubtract(clipped, p, clipped); + dist += VectorLength2(clipped); + if (dist < bestdist) + { + // that's closer too, store it as the best match + best = surfacenum; + bestdist = dist; + } + } + } + PRVM_G_FLOAT(OFS_RETURN) = best; +} +//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; +void VM_getsurfaceclippedpoint(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + vec3_t p, out, inp; + VM_SAFEPARMCOUNT(3, VM_te_getsurfaceclippedpoint); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + animatemodel(prog, model, ed); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), inp); + applytransform_inverted(prog, inp, ed, p); + clippointtosurface(prog, ed, model, surface, p, out); + VectorAdd(out, PRVM_serveredictvector(ed, origin), PRVM_G_VECTOR(OFS_RETURN)); +} + +//PF_getsurfacenumtriangles, // #??? float(entity e, float s) getsurfacenumtriangles = #???; +void VM_getsurfacenumtriangles(prvm_prog_t *prog) +{ + dp_model_t *model; + msurface_t *surface; + VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumtriangles); + // return 0 if no such surface + if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + + PRVM_G_FLOAT(OFS_RETURN) = surface->num_triangles; +} +//PF_getsurfacetriangle, // #??? vector(entity e, float s, float n) getsurfacetriangle = #???; +void VM_getsurfacetriangle(prvm_prog_t *prog) +{ + const vec3_t d = {-1, -1, -1}; + prvm_edict_t *ed; + dp_model_t *model; + msurface_t *surface; + int trinum; + VM_SAFEPARMCOUNT(3, VM_SV_getsurfacetriangle); + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1)))) + return; + trinum = (int)PRVM_G_FLOAT(OFS_PARM2); + if (trinum < 0 || trinum >= surface->num_triangles) + return; + // FIXME: implement rotation/scaling + VectorMA(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], surface->num_firstvertex, d, PRVM_G_VECTOR(OFS_RETURN)); +} + +// +// physics builtins +// + +#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(prog, ed, f); else World_Physics_ApplyCmd(ed, f) + +static edict_odefunc_t *VM_physics_newstackfunction(prvm_prog_t *prog, prvm_edict_t *ed, edict_odefunc_t *f) +{ + edict_odefunc_t *newfunc, *func; + + newfunc = (edict_odefunc_t *)Mem_Alloc(prog->progs_mempool, sizeof(edict_odefunc_t)); + memcpy(newfunc, f, sizeof(edict_odefunc_t)); + newfunc->next = NULL; + if (!ed->priv.server->ode_func) + ed->priv.server->ode_func = newfunc; + else + { + for (func = ed->priv.server->ode_func; func->next; func = func->next); + func->next = newfunc; + } + return newfunc; +} + +// void(entity e, float physics_enabled) physics_enable = #; +void VM_physics_enable(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + edict_odefunc_t f; + + VM_SAFEPARMCOUNT(2, VM_physics_enable); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!ed) + { + if (developer.integer > 0) + VM_Warning(prog, "VM_physics_enable: null entity!\n"); + return; + } + // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer + if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS) + { + VM_Warning(prog, "VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n"); + return; + } + f.type = PRVM_G_FLOAT(OFS_PARM1) == 0 ? ODEFUNC_DISABLE : ODEFUNC_ENABLE; + VM_physics_ApplyCmd(ed, &f); +} + +// void(entity e, vector force, vector relative_ofs) physics_addforce = #; +void VM_physics_addforce(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + edict_odefunc_t f; + + VM_SAFEPARMCOUNT(3, VM_physics_addforce); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!ed) + { + if (developer.integer > 0) + VM_Warning(prog, "VM_physics_addforce: null entity!\n"); + return; + } + // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer + if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS) + { + VM_Warning(prog, "VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n"); + return; + } + f.type = ODEFUNC_FORCE; + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), f.v2); + VM_physics_ApplyCmd(ed, &f); +} + +// void(entity e, vector torque) physics_addtorque = #; +void VM_physics_addtorque(prvm_prog_t *prog) +{ + prvm_edict_t *ed; + edict_odefunc_t f; + + VM_SAFEPARMCOUNT(2, VM_physics_addtorque); + ed = PRVM_G_EDICT(OFS_PARM0); + if (!ed) + { + if (developer.integer > 0) + VM_Warning(prog, "VM_physics_addtorque: null entity!\n"); + return; + } + // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer + if (PRVM_serveredictfloat(ed, movetype) != MOVETYPE_PHYSICS) + { + VM_Warning(prog, "VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n"); + return; + } + f.type = ODEFUNC_TORQUE; + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1); + VM_physics_ApplyCmd(ed, &f); +} diff --git a/app/jni/prvm_cmds.h b/app/jni/prvm_cmds.h new file mode 100644 index 0000000..e21a393 --- /dev/null +++ b/app/jni/prvm_cmds.h @@ -0,0 +1,487 @@ + +#ifndef PRVM_CMDS_H +#define PRVM_CMDS_H + +// AK +// Basically every vm builtin cmd should be in here. +// All 3 builtin and extension lists can be found here +// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds +// also applies here + + +/* +============================================================================ +common cmd list: +================= + + checkextension(string) + error(...[string]) + objerror(...[string) + print(...[strings]) + bprint(...[string]) + sprint(float clientnum,...[string]) + centerprint(...[string]) +vector normalize(vector) +float vlen(vector) +float vectoyaw(vector) +vector vectoangles(vector) +float random() + cmd(string) + float cvar (string) + cvar_set (string,string) + dprint(...[string]) +string ftos(float) +float fabs(float) +string vtos(vector) +string etos(entity) +float stof(...[string]) +entity spawn() + remove(entity e) +entity find(entity start, .string field, string match) + +entity findfloat(entity start, .float field, float match) +entity findentity(entity start, .entity field, entity match) + +entity findchain(.string field, string match) + +entity findchainfloat(.string field, float match) +entity findchainentity(.string field, entity match) + +string precache_file(string) +string precache_sound (string sample) + coredump() + traceon() + traceoff() + eprint(entity e) +float rint(float) +float floor(float) +float ceil(float) +entity nextent(entity) +float sin(float) +float cos(float) +float sqrt(float) +vector randomvec() +float registercvar (string name, string value, float flags) +float min(float a, float b, ...[float]) +float max(float a, float b, ...[float]) +float bound(float min, float value, float max) +float pow(float a, float b) + copyentity(entity src, entity dst) +float fopen(string filename, float mode) + fclose(float fhandle) +string fgets(float fhandle) + fputs(float fhandle, string s) +float strlen(string s) +string strcat(string,string,...[string]) +string substring(string s, float start, float length) +vector stov(string s) +string strzone(string s) + strunzone(string s) +float tokenize(string s) +string argv(float n) +float isserver() +float clientcount() +float clientstate() + clientcommand(float client, string s) (for client and menu) + changelevel(string map) + localsound(string sample) +vector getmousepos() +float gettime() + loadfromdata(string data) + loadfromfile(string file) + parseentitydata(entity ent, string data) +float mod(float val, float m) +const string cvar_string (string) +float cvar_type (string) + crash() + stackdump() + +float search_begin(string pattern, float caseinsensitive, float quiet) +void search_end(float handle) +float search_getsize(float handle) +string search_getfilename(float handle, float num) + +string chr(float ascii) + +float itof(intt ent) +entity ftoe(float num) + +-------will be removed soon---------- +float altstr_count(string) +string altstr_prepare(string) +string altstr_get(string,float) +string altstr_set(string altstr, float num, string set) +string altstr_ins(string altstr, float num, string set) +-------------------------------------- + +entity findflags(entity start, .float field, float match) +entity findchainflags(.float field, float match) + +const string VM_cvar_defstring (string) + +perhaps only : Menu : WriteMsg +=============================== + + WriteByte(float data, float dest, float desto) + WriteChar(float data, float dest, float desto) + WriteShort(float data, float dest, float desto) + WriteLong(float data, float dest, float desto) + WriteAngle(float data, float dest, float desto) + WriteCoord(float data, float dest, float desto) + WriteString(string data, float dest, float desto) + WriteEntity(entity data, float dest, float desto) + +Client & Menu : draw functions & video functions (& gecko functions) +=================================================== + +float iscachedpic(string pic) +string precache_pic(string pic) + freepic(string s) +float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) +float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) +float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) +float stringwidth(string text, float handleColors) +float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) +float drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag) +float drawfill(vector position, vector size, vector rgb, float alpha, float flag) + drawsetcliparea(float x, float y, float width, float height) + drawresetcliparea() +vector getimagesize(string pic) + +float cin_open(string file, string name) +void cin_close(string name) +void cin_setstate(string name, float type) +float cin_getstate(string name) +void cin_restart(string name) + +float[bool] gecko_create( string name ) +void gecko_destroy( string name ) +void gecko_navigate( string name, string URI ) +float[bool] gecko_keyevent( string name, float key, float eventtype ) +void gecko_mousemove( string name, float x, float y ) + +============================================================================== +menu cmd list: +=============== + + setkeydest(float dest) +float getkeydest() + setmousetarget(float target) +float getmousetarget() + + callfunction(...,string function_name) + writetofile(float fhandle, entity ent) +float isfunction(string function_name) +vector getresolution(float number) +string keynumtostring(float keynum) +string findkeysforcommand(string command) +float getserverliststat(float type) +string getserverliststring(float fld, float hostnr) + +float stringtokeynum(string key) + + resetserverlistmasks() + setserverlistmaskstring(float mask, float fld, string str) + setserverlistmasknumber(float mask, float fld, float num, float op) + resortserverlist() + setserverlistsort(float field, float descending) + refreshserverlist() +float getserverlistnumber(float fld, float hostnr) +float getserverlistindexforkey(string key) + addwantedserverlistkey(string key) +*/ + +#include "quakedef.h" +#include "progdefs.h" +#include "progsvm.h" +#include "clprogdefs.h" +#include "mprogdefs.h" + +#include "cl_video.h" + +//============================================================================ +// nice helper macros + +#ifndef VM_NOPARMCHECK +#define VM_SAFEPARMCOUNTRANGE(p1,p2,f) if(prog->argc < p1 || prog->argc > p2) prog->error_cmd(#f " wrong parameter count %i (" #p1 " to " #p2 " expected ) !", prog->argc) +#define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) prog->error_cmd(#f " wrong parameter count %i (" #p " expected ) !", prog->argc) +#else +#define VM_SAFEPARMCOUNTRANGE(p1,p2,f) +#define VM_SAFEPARMCOUNT(p,f) +#endif + +#define VM_RETURN_EDICT(e) (prog->globals.ip[OFS_RETURN] = PRVM_EDICT_TO_PROG(e)) + +#define VM_STRINGTEMP_LENGTH MAX_INPUTLINE + +// init code +void PR_Cmd_Init(void); + +// builtins and other general functions + +void VM_CheckEmptyString (prvm_prog_t *prog, const char *s); +void VM_VarString(prvm_prog_t *prog, int first, char *out, int outlength); + +void VM_checkextension (prvm_prog_t *prog); +void VM_error (prvm_prog_t *prog); +void VM_objerror (prvm_prog_t *prog); +void VM_print (prvm_prog_t *prog); +void VM_bprint (prvm_prog_t *prog); +void VM_sprint (prvm_prog_t *prog); +void VM_centerprint (prvm_prog_t *prog); +void VM_normalize (prvm_prog_t *prog); +void VM_vlen (prvm_prog_t *prog); +void VM_vectoyaw (prvm_prog_t *prog); +void VM_vectoangles (prvm_prog_t *prog); +void VM_random (prvm_prog_t *prog); +void VM_localsound(prvm_prog_t *prog); +void VM_break (prvm_prog_t *prog); +void VM_localcmd (prvm_prog_t *prog); +void VM_cvar (prvm_prog_t *prog); +void VM_cvar_string(prvm_prog_t *prog); +void VM_cvar_type (prvm_prog_t *prog); +void VM_cvar_defstring (prvm_prog_t *prog); +void VM_cvar_set (prvm_prog_t *prog); +void VM_dprint (prvm_prog_t *prog); +void VM_ftos (prvm_prog_t *prog); +void VM_fabs (prvm_prog_t *prog); +void VM_vtos (prvm_prog_t *prog); +void VM_etos (prvm_prog_t *prog); +void VM_stof(prvm_prog_t *prog); +void VM_itof(prvm_prog_t *prog); +void VM_ftoe(prvm_prog_t *prog); +void VM_strftime(prvm_prog_t *prog); +void VM_spawn (prvm_prog_t *prog); +void VM_remove (prvm_prog_t *prog); +void VM_find (prvm_prog_t *prog); +void VM_findfloat (prvm_prog_t *prog); +void VM_findchain (prvm_prog_t *prog); +void VM_findchainfloat (prvm_prog_t *prog); +void VM_findflags (prvm_prog_t *prog); +void VM_findchainflags (prvm_prog_t *prog); +void VM_precache_file (prvm_prog_t *prog); +void VM_precache_sound (prvm_prog_t *prog); +void VM_coredump (prvm_prog_t *prog); + +void VM_stackdump (prvm_prog_t *prog); +void VM_crash(prvm_prog_t *prog); // REMOVE IT +void VM_traceon (prvm_prog_t *prog); +void VM_traceoff (prvm_prog_t *prog); +void VM_eprint (prvm_prog_t *prog); +void VM_rint (prvm_prog_t *prog); +void VM_floor (prvm_prog_t *prog); +void VM_ceil (prvm_prog_t *prog); +void VM_nextent (prvm_prog_t *prog); + +void VM_changelevel (prvm_prog_t *prog); +void VM_sin (prvm_prog_t *prog); +void VM_cos (prvm_prog_t *prog); +void VM_sqrt (prvm_prog_t *prog); +void VM_randomvec (prvm_prog_t *prog); +void VM_registercvar (prvm_prog_t *prog); +void VM_min (prvm_prog_t *prog); +void VM_max (prvm_prog_t *prog); +void VM_bound (prvm_prog_t *prog); +void VM_pow (prvm_prog_t *prog); +void VM_log (prvm_prog_t *prog); +void VM_asin (prvm_prog_t *prog); +void VM_acos (prvm_prog_t *prog); +void VM_atan (prvm_prog_t *prog); +void VM_atan2 (prvm_prog_t *prog); +void VM_tan (prvm_prog_t *prog); + +void VM_Files_Init(prvm_prog_t *prog); +void VM_Files_CloseAll(prvm_prog_t *prog); + +void VM_fopen(prvm_prog_t *prog); +void VM_fclose(prvm_prog_t *prog); +void VM_fgets(prvm_prog_t *prog); +void VM_fputs(prvm_prog_t *prog); +void VM_writetofile(prvm_prog_t *prog); // only used by menu + +void VM_strlen(prvm_prog_t *prog); +void VM_strcat(prvm_prog_t *prog); +void VM_substring(prvm_prog_t *prog); +void VM_stov(prvm_prog_t *prog); +void VM_strzone(prvm_prog_t *prog); +void VM_strunzone(prvm_prog_t *prog); + +// KrimZon - DP_QC_ENTITYDATA +void VM_numentityfields(prvm_prog_t *prog); +void VM_entityfieldname(prvm_prog_t *prog); +void VM_entityfieldtype(prvm_prog_t *prog); +void VM_getentityfieldstring(prvm_prog_t *prog); +void VM_putentityfieldstring(prvm_prog_t *prog); + +// DRESK - String Length (not counting color codes) +void VM_strlennocol(prvm_prog_t *prog); +// DRESK - Decolorized String +void VM_strdecolorize(prvm_prog_t *prog); +// DRESK - String Uppercase and Lowercase Support +void VM_strtolower(prvm_prog_t *prog); +void VM_strtoupper(prvm_prog_t *prog); + +void VM_clcommand (prvm_prog_t *prog); + +void VM_tokenize (prvm_prog_t *prog); +void VM_tokenizebyseparator (prvm_prog_t *prog); +void VM_argv (prvm_prog_t *prog); + +void VM_isserver(prvm_prog_t *prog); +void VM_clientcount(prvm_prog_t *prog); +void VM_clientstate(prvm_prog_t *prog); +// not used at the moment -> not included in the common list +void VM_getostype(prvm_prog_t *prog); +void VM_getmousepos(prvm_prog_t *prog); +void VM_gettime(prvm_prog_t *prog); +void VM_getsoundtime(prvm_prog_t *prog); +void VM_soundlength(prvm_prog_t *prog); +void VM_loadfromdata(prvm_prog_t *prog); +void VM_parseentitydata(prvm_prog_t *prog); +void VM_loadfromfile(prvm_prog_t *prog); +void VM_modulo(prvm_prog_t *prog); + +void VM_search_begin(prvm_prog_t *prog); +void VM_search_end(prvm_prog_t *prog); +void VM_search_getsize(prvm_prog_t *prog); +void VM_search_getfilename(prvm_prog_t *prog); +void VM_chr(prvm_prog_t *prog); +void VM_iscachedpic(prvm_prog_t *prog); +void VM_precache_pic(prvm_prog_t *prog); +void VM_freepic(prvm_prog_t *prog); +void VM_drawcharacter(prvm_prog_t *prog); +void VM_drawstring(prvm_prog_t *prog); +void VM_drawcolorcodedstring(prvm_prog_t *prog); +void VM_stringwidth(prvm_prog_t *prog); +void VM_drawpic(prvm_prog_t *prog); +void VM_drawrotpic(prvm_prog_t *prog); +void VM_drawsubpic(prvm_prog_t *prog); +void VM_drawfill(prvm_prog_t *prog); +void VM_drawsetcliparea(prvm_prog_t *prog); +void VM_drawresetcliparea(prvm_prog_t *prog); +void VM_getimagesize(prvm_prog_t *prog); + +void VM_findfont(prvm_prog_t *prog); +void VM_loadfont(prvm_prog_t *prog); + +void VM_makevectors (prvm_prog_t *prog); +void VM_vectorvectors (prvm_prog_t *prog); + +void VM_keynumtostring (prvm_prog_t *prog); +void VM_getkeybind (prvm_prog_t *prog); +void VM_findkeysforcommand (prvm_prog_t *prog); +void VM_stringtokeynum (prvm_prog_t *prog); +void VM_setkeybind (prvm_prog_t *prog); +void VM_getbindmaps (prvm_prog_t *prog); +void VM_setbindmaps (prvm_prog_t *prog); + +void VM_cin_open(prvm_prog_t *prog); +void VM_cin_close(prvm_prog_t *prog); +void VM_cin_setstate(prvm_prog_t *prog); +void VM_cin_getstate(prvm_prog_t *prog); +void VM_cin_restart(prvm_prog_t *prog); + +void VM_gecko_create(prvm_prog_t *prog); +void VM_gecko_destroy(prvm_prog_t *prog); +void VM_gecko_navigate(prvm_prog_t *prog); +void VM_gecko_keyevent(prvm_prog_t *prog); +void VM_gecko_movemouse(prvm_prog_t *prog); +void VM_gecko_resize(prvm_prog_t *prog); +void VM_gecko_get_texture_extent(prvm_prog_t *prog); + +void VM_drawline (prvm_prog_t *prog); + +void VM_bitshift (prvm_prog_t *prog); + +void VM_altstr_count(prvm_prog_t *prog); +void VM_altstr_prepare(prvm_prog_t *prog); +void VM_altstr_get(prvm_prog_t *prog); +void VM_altstr_set(prvm_prog_t *prog); +void VM_altstr_ins(prvm_prog_t *prog); + +void VM_buf_create(prvm_prog_t *prog); +void VM_buf_del (prvm_prog_t *prog); +void VM_buf_getsize (prvm_prog_t *prog); +void VM_buf_copy (prvm_prog_t *prog); +void VM_buf_sort (prvm_prog_t *prog); +void VM_buf_implode (prvm_prog_t *prog); +void VM_bufstr_get (prvm_prog_t *prog); +void VM_bufstr_set (prvm_prog_t *prog); +void VM_bufstr_add (prvm_prog_t *prog); +void VM_bufstr_free (prvm_prog_t *prog); + +void VM_buf_loadfile(prvm_prog_t *prog); +void VM_buf_writefile(prvm_prog_t *prog); +void VM_bufstr_find(prvm_prog_t *prog); +void VM_matchpattern(prvm_prog_t *prog); + +void VM_changeyaw (prvm_prog_t *prog); +void VM_changepitch (prvm_prog_t *prog); + +void VM_uncolorstring (prvm_prog_t *prog); + +void VM_strstrofs (prvm_prog_t *prog); +void VM_str2chr (prvm_prog_t *prog); +void VM_chr2str (prvm_prog_t *prog); +void VM_strconv (prvm_prog_t *prog); +void VM_strpad (prvm_prog_t *prog); +void VM_infoadd (prvm_prog_t *prog); +void VM_infoget (prvm_prog_t *prog); +void VM_strncmp (prvm_prog_t *prog); +void VM_strncmp (prvm_prog_t *prog); +void VM_strncasecmp (prvm_prog_t *prog); +void VM_registercvar (prvm_prog_t *prog); +void VM_wasfreed (prvm_prog_t *prog); + +void VM_strreplace (prvm_prog_t *prog); +void VM_strireplace (prvm_prog_t *prog); + +void VM_crc16(prvm_prog_t *prog); +void VM_digest_hex(prvm_prog_t *prog); + +void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace); +void VM_ClearTraceGlobals(prvm_prog_t *prog); + +void VM_uri_escape (prvm_prog_t *prog); +void VM_uri_unescape (prvm_prog_t *prog); +void VM_whichpack (prvm_prog_t *prog); + +void VM_etof (prvm_prog_t *prog); +void VM_uri_get (prvm_prog_t *prog); +void VM_netaddress_resolve (prvm_prog_t *prog); + +void VM_tokenize_console (prvm_prog_t *prog); +void VM_argv_start_index (prvm_prog_t *prog); +void VM_argv_end_index (prvm_prog_t *prog); + +void VM_buf_cvarlist(prvm_prog_t *prog); +void VM_cvar_description(prvm_prog_t *prog); + +void VM_CL_getextresponse (prvm_prog_t *prog); +void VM_SV_getextresponse (prvm_prog_t *prog); + +// Common functions between menu.dat and clsprogs +void VM_CL_isdemo (prvm_prog_t *prog); +void VM_CL_videoplaying (prvm_prog_t *prog); + +void VM_isfunction(prvm_prog_t *prog); +void VM_callfunction(prvm_prog_t *prog); + +void VM_sprintf(prvm_prog_t *prog); + +void VM_getsurfacenumpoints(prvm_prog_t *prog); +void VM_getsurfacepoint(prvm_prog_t *prog); +void VM_getsurfacepointattribute(prvm_prog_t *prog); +void VM_getsurfacenormal(prvm_prog_t *prog); +void VM_getsurfacetexture(prvm_prog_t *prog); +void VM_getsurfacenearpoint(prvm_prog_t *prog); +void VM_getsurfaceclippedpoint(prvm_prog_t *prog); +void VM_getsurfacenumtriangles(prvm_prog_t *prog); +void VM_getsurfacetriangle(prvm_prog_t *prog); + +// physics builtins +void VM_physics_enable(prvm_prog_t *prog); +void VM_physics_addforce(prvm_prog_t *prog); +void VM_physics_addtorque(prvm_prog_t *prog); + +#endif diff --git a/app/jni/prvm_edict.c b/app/jni/prvm_edict.c new file mode 100644 index 0000000..191197f --- /dev/null +++ b/app/jni/prvm_edict.c @@ -0,0 +1,3381 @@ +/* +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. + +*/ +// AK new vm + +#include "quakedef.h" +#include "progsvm.h" +#include "csprogs.h" + +prvm_prog_t prvm_prog_list[PRVM_PROG_MAX]; + +int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4}; + +prvm_eval_t prvm_badvalue; // used only for error returns + +cvar_t prvm_language = {CVAR_SAVE, "prvm_language", "", "when set, loads progs.dat.LANGUAGENAME.po for string translations; when set to dump, progs.dat.pot is written from the strings in the progs"}; +// LordHavoc: prints every opcode as it executes - warning: this is significant spew +cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"}; +// LordHavoc: counts usage of each QuakeC statement +cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"}; +cvar_t prvm_timeprofiling = {0, "prvm_timeprofiling", "0", "counts how long each function has been executed, these counts are displayed in prvm_profile output (if enabled)"}; +cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"}; +cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"}; +cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"}; +cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"}; +cvar_t prvm_breakpointdump = {0, "prvm_breakpointdump", "0", "write a savegame on breakpoint to breakpoint-server.dmp"}; +cvar_t prvm_reuseedicts_startuptime = {0, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"}; +cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"}; + +static double prvm_reuseedicts_always_allow = 0; +qboolean prvm_runawaycheck = true; + +//============================================================================ +// mempool handling + +/* +=============== +PRVM_MEM_Alloc +=============== +*/ +static void PRVM_MEM_Alloc(prvm_prog_t *prog) +{ + int i; + + // reserve space for the null entity aka world + // check bound of max_edicts + prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts); + prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts); + + // edictprivate_size has to be min as big prvm_edict_private_t + prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t)); + + // alloc edicts + prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t)); + + // alloc edict private space + prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size); + + // alloc edict fields + prog->entityfieldsarea = prog->entityfields * prog->max_edicts; + prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t)); + + // set edict pointers + for(i = 0; i < prog->max_edicts; i++) + { + prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size); + prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields; + } +} + +/* +=============== +PRVM_MEM_IncreaseEdicts +=============== +*/ +void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog) +{ + int i; + + if(prog->max_edicts >= prog->limit_edicts) + return; + + prog->begin_increase_edicts(prog); + + // increase edicts + prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts); + + prog->entityfieldsarea = prog->entityfields * prog->max_edicts; + prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(prvm_vec_t)); + prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size); + + //set e and v pointers + for(i = 0; i < prog->max_edicts; i++) + { + prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size); + prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields; + } + + prog->end_increase_edicts(prog); +} + +//============================================================================ +// normal prvm + +int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field) +{ + ddef_t *d; + d = PRVM_ED_FindField(prog, field); + if (!d) + return -1; + return d->ofs; +} + +int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *global) +{ + ddef_t *d; + d = PRVM_ED_FindGlobal(prog, global); + if (!d) + return -1; + return d->ofs; +} + +func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *function) +{ + mfunction_t *f; + f = PRVM_ED_FindFunction(prog, function); + if (!f) + return 0; + return (func_t)(f - prog->functions); +} + +/* +================= +PRVM_ProgFromString +================= +*/ +prvm_prog_t *PRVM_ProgFromString(const char *str) +{ + if (!strcmp(str, "server")) + return SVVM_prog; + if (!strcmp(str, "client")) + return CLVM_prog; + if (!strcmp(str, "menu")) + return MVM_prog; + return NULL; +} + +/* +================= +PRVM_FriendlyProgFromString +================= +*/ +prvm_prog_t *PRVM_FriendlyProgFromString(const char *str) +{ + prvm_prog_t *prog = PRVM_ProgFromString(str); + if (!prog) + { + Con_Printf("%s: unknown program name\n", str); + return NULL; + } + if (!prog->loaded) + { + Con_Printf("%s: program is not loaded\n", str); + return NULL; + } + return prog; +} + +/* +================= +PRVM_ED_ClearEdict + +Sets everything to NULL +================= +*/ +void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e) +{ + memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); + e->priv.required->free = false; + + // AK: Let the init_edict function determine if something needs to be initialized + prog->init_edict(prog, e); +} + +const char *PRVM_AllocationOrigin(prvm_prog_t *prog) +{ + char *buf = NULL; + if(prog->leaktest_active) + if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame + { + buf = (char *)PRVM_Alloc(128); + PRVM_ShortStackTrace(prog, buf, 128); + } + return buf; +} + +/* +================= +PRVM_ED_CanAlloc + +Returns if this particular edict could get allocated by PRVM_ED_Alloc +================= +*/ +qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e) +{ + if(!e->priv.required->free) + return false; + if(prvm_reuseedicts_always_allow == realtime) + return true; + if(realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer) + return false; // never allow reuse in same frame (causes networking trouble) + if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value) + return true; + if(realtime > e->priv.required->freetime + 1) + return true; + return false; // entity slot still blocked because the entity was freed less than one second ago +} + +/* +================= +PRVM_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. +================= +*/ +prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *e; + + // the client qc dont need maxclients + // thus it doesnt need to use svs.maxclients + // AK: changed i=svs.maxclients+1 + // AK: changed so the edict 0 wont spawn -> used as reserved/world entity + // although the menu/client has no world + for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++) + { + e = PRVM_EDICT_NUM(i); + if(PRVM_ED_CanAlloc(prog, e)) + { + PRVM_ED_ClearEdict (prog, e); + e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog); + return e; + } + } + + if (i == prog->limit_edicts) + prog->error_cmd("%s: PRVM_ED_Alloc: no free edicts", prog->name); + + prog->num_edicts++; + if (prog->num_edicts >= prog->max_edicts) + PRVM_MEM_IncreaseEdicts(prog); + + e = PRVM_EDICT_NUM(i); + PRVM_ED_ClearEdict(prog, e); + + e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog); + + return e; +} + +/* +================= +PRVM_ED_Free + +Marks the edict as free +FIXME: walk all entities and NULL out references to this entity +================= +*/ +void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed) +{ + // dont delete the null entity (world) or reserved edicts + if (ed - prog->edicts <= prog->reserved_edicts) + return; + + prog->free_edict(prog, ed); + + ed->priv.required->free = true; + ed->priv.required->freetime = realtime; + if(ed->priv.required->allocation_origin) + { + Mem_Free((char *)ed->priv.required->allocation_origin); + ed->priv.required->allocation_origin = NULL; + } +} + +//=========================================================================== + +/* +============ +PRVM_ED_GlobalAtOfs +============ +*/ +static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs) +{ + ddef_t *def; + int i; + + for (i = 0;i < prog->numglobaldefs;i++) + { + def = &prog->globaldefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FieldAtOfs +============ +*/ +ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs) +{ + ddef_t *def; + int i; + + for (i = 0;i < prog->numfielddefs;i++) + { + def = &prog->fielddefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FindField +============ +*/ +ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name) +{ + ddef_t *def; + int i; + + for (i = 0;i < prog->numfielddefs;i++) + { + def = &prog->fielddefs[i]; + if (!strcmp(PRVM_GetString(prog, def->s_name), name)) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FindGlobal +============ +*/ +ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name) +{ + ddef_t *def; + int i; + + for (i = 0;i < prog->numglobaldefs;i++) + { + def = &prog->globaldefs[i]; + if (!strcmp(PRVM_GetString(prog, def->s_name), name)) + return def; + } + return NULL; +} + + +/* +============ +PRVM_ED_FindFunction +============ +*/ +mfunction_t *PRVM_ED_FindFunction (prvm_prog_t *prog, const char *name) +{ + mfunction_t *func; + int i; + + for (i = 0;i < prog->numfunctions;i++) + { + func = &prog->functions[i]; + if (!strcmp(PRVM_GetString(prog, func->s_name), name)) + return func; + } + return NULL; +} + + +/* +============ +PRVM_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength) +{ + ddef_t *def; + mfunction_t *f; + int n; + + type = (etype_t)((int) type & ~DEF_SAVEGLOBAL); + + switch (type) + { + case ev_string: + strlcpy (line, PRVM_GetString (prog, val->string), linelength); + break; + case ev_entity: + n = val->edict; + if (n < 0 || n >= prog->max_edicts) + dpsnprintf (line, linelength, "entity %i (invalid!)", n); + else + dpsnprintf (line, linelength, "entity %i", n); + break; + case ev_function: + f = prog->functions + val->function; + dpsnprintf (line, linelength, "%s()", PRVM_GetString(prog, f->s_name)); + break; + case ev_field: + def = PRVM_ED_FieldAtOfs ( prog, val->_int ); + dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name)); + break; + case ev_void: + dpsnprintf (line, linelength, "void"); + break; + case ev_float: + // LordHavoc: changed from %5.1f to %10.4f + dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float); + break; + case ev_vector: + // LordHavoc: changed from %5.1f to %10.4f + dpsnprintf (line, linelength, "'" VECTOR_LOSSLESS_FORMAT "'", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + dpsnprintf (line, linelength, "pointer"); + break; + default: + dpsnprintf (line, linelength, "bad type %i", (int) type); + break; + } + + return line; +} + +/* +============ +PRVM_UglyValueString + +Returns a string describing *data in a type specific manner +Easier to parse than PR_ValueString +============= +*/ +char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength) +{ + int i; + const char *s; + ddef_t *def; + mfunction_t *f; + + type = (etype_t)((int)type & ~DEF_SAVEGLOBAL); + + switch (type) + { + case ev_string: + // Parse the string a bit to turn special characters + // (like newline, specifically) into escape codes, + // this fixes saving games from various mods + s = PRVM_GetString (prog, val->string); + for (i = 0;i < (int)linelength - 2 && *s;) + { + if (*s == '\n') + { + line[i++] = '\\'; + line[i++] = 'n'; + } + else if (*s == '\r') + { + line[i++] = '\\'; + line[i++] = 'r'; + } + else if (*s == '\\') + { + line[i++] = '\\'; + line[i++] = '\\'; + } + else if (*s == '"') + { + line[i++] = '\\'; + line[i++] = '"'; + } + else + line[i++] = *s; + s++; + } + line[i] = '\0'; + break; + case ev_entity: + dpsnprintf (line, linelength, "%i", val->edict); + break; + case ev_function: + f = prog->functions + val->function; + strlcpy (line, PRVM_GetString (prog, f->s_name), linelength); + break; + case ev_field: + def = PRVM_ED_FieldAtOfs ( prog, val->_int ); + dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name)); + break; + case ev_void: + dpsnprintf (line, linelength, "void"); + break; + case ev_float: + dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float); + break; + case ev_vector: + dpsnprintf (line, linelength, VECTOR_LOSSLESS_FORMAT, val->vector[0], val->vector[1], val->vector[2]); + break; + default: + dpsnprintf (line, linelength, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PRVM_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t linelength) +{ + char *s; + //size_t i; + ddef_t *def; + prvm_eval_t *val; + char valuebuf[MAX_INPUTLINE]; + + val = (prvm_eval_t *)&prog->globals.fp[ofs]; + def = PRVM_ED_GlobalAtOfs(prog, ofs); + if (!def) + dpsnprintf (line, linelength, "GLOBAL%i", ofs); + else + { + s = PRVM_ValueString (prog, (etype_t)def->type, val, valuebuf, sizeof(valuebuf)); + dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s); + } + + //i = strlen(line); + //for ( ; i<20 ; i++) + // strcat (line," "); + //strcat (line," "); + + return line; +} + +char *PRVM_GlobalStringNoContents (prvm_prog_t *prog, int ofs, char *line, size_t linelength) +{ + //size_t i; + ddef_t *def; + + def = PRVM_ED_GlobalAtOfs(prog, ofs); + if (!def) + dpsnprintf (line, linelength, "GLOBAL%i", ofs); + else + dpsnprintf (line, linelength, "%s", PRVM_GetString(prog, def->s_name)); + + //i = strlen(line); + //for ( ; i<20 ; i++) + // strcat (line," "); + //strcat (line," "); + + return line; +} + + +/* +============= +PRVM_ED_Print + +For debugging +============= +*/ +// LordHavoc: optimized this to print out much more quickly (tempstring) +// LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print) +void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname) +{ + size_t l; + ddef_t *d; + prvm_eval_t *val; + int i, j; + const char *name; + int type; + char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers + char valuebuf[MAX_INPUTLINE]; + + if (ed->priv.required->free) + { + Con_Printf("%s: FREE\n",prog->name); + return; + } + + tempstring[0] = 0; + dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", prog->name, PRVM_NUM_FOR_EDICT(ed)); + for (i = 1;i < prog->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(prog, d->s_name); + if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z')) + continue; // skip _x, _y, _z vars + + // Check Field Name Wildcard + if(wildcard_fieldname) + if( !matchpattern(name, wildcard_fieldname, 1) ) + // Didn't match; skip + continue; + + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; jivector[j]) + break; + if (j == prvm_type_size[type]) + continue; + + if (strlen(name) > sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strlcat(tempstring, name, sizeof(tempstring)); + for (l = strlen(name);l < 14;l++) + strlcat(tempstring, " ", sizeof(tempstring)); + strlcat(tempstring, " ", sizeof(tempstring)); + + name = PRVM_ValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)); + if (strlen(name) > sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strlcat(tempstring, name, sizeof(tempstring)); + strlcat(tempstring, "\n", sizeof(tempstring)); + if (strlen(tempstring) >= sizeof(tempstring)/2) + { + Con_Print(tempstring); + tempstring[0] = 0; + } + } + if (tempstring[0]) + Con_Print(tempstring); +} + +/* +============= +PRVM_ED_Write + +For savegames +============= +*/ +extern cvar_t developer_entityparsing; +void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed) +{ + ddef_t *d; + prvm_eval_t *val; + int i, j; + const char *name; + int type; + char vabuf[1024]; + char valuebuf[MAX_INPUTLINE]; + + FS_Print(f, "{\n"); + + if (ed->priv.required->free) + { + FS_Print(f, "}\n"); + return; + } + + for (i = 1;i < prog->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(prog, d->s_name); + + if(developer_entityparsing.integer) + Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name); + + //if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z')) + if(strlen(name) > 1 && name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?) + + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jivector[j]) + break; + if (j == prvm_type_size[type]) + continue; + + FS_Printf(f,"\"%s\" ",name); + prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_Write, ent=%d, name=%s", i, name); + FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf))); + prog->statestring = NULL; + } + + FS_Print(f, "}\n"); +} + +void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname) +{ + PRVM_ED_Print(prog, PRVM_EDICT_NUM(ent), wildcard_fieldname); +} + +/* +============= +PRVM_ED_PrintEdicts_f + +For debugging, prints all the entities in the current server +============= +*/ +void PRVM_ED_PrintEdicts_f (void) +{ + prvm_prog_t *prog; + int i; + const char *wildcard_fieldname; + + if(Cmd_Argc() < 2 || Cmd_Argc() > 3) + { + Con_Print("prvm_edicts \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + if( Cmd_Argc() == 3) + wildcard_fieldname = Cmd_Argv(2); + else + wildcard_fieldname = NULL; + + Con_Printf("%s: %i entities\n", prog->name, prog->num_edicts); + for (i=0 ; inum_edicts ; i++) + PRVM_ED_PrintNum (prog, i, wildcard_fieldname); +} + +/* +============= +PRVM_ED_PrintEdict_f + +For debugging, prints a single edict +============= +*/ +static void PRVM_ED_PrintEdict_f (void) +{ + prvm_prog_t *prog; + int i; + const char *wildcard_fieldname; + + if(Cmd_Argc() < 3 || Cmd_Argc() > 4) + { + Con_Print("prvm_edict \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + i = atoi (Cmd_Argv(2)); + if (i >= prog->num_edicts) + { + Con_Print("Bad edict number\n"); + return; + } + if( Cmd_Argc() == 4) + // Optional Wildcard Provided + wildcard_fieldname = Cmd_Argv(3); + else + // Use All + wildcard_fieldname = NULL; + PRVM_ED_PrintNum (prog, i, wildcard_fieldname); +} + +/* +============= +PRVM_ED_Count + +For debugging +============= +*/ +// 2 possibilities : 1. just displaying the active edict count +// 2. making a function pointer [x] +static void PRVM_ED_Count_f (void) +{ + prvm_prog_t *prog; + + if(Cmd_Argc() != 2) + { + Con_Print("prvm_count \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + prog->count_edicts(prog); +} + +/* +============================================================================== + + ARCHIVING GLOBALS + +FIXME: need to tag constants, doesn't really work +============================================================================== +*/ + +/* +============= +PRVM_ED_WriteGlobals +============= +*/ +void PRVM_ED_WriteGlobals (prvm_prog_t *prog, qfile_t *f) +{ + ddef_t *def; + int i; + const char *name; + int type; + char vabuf[1024]; + char valuebuf[MAX_INPUTLINE]; + + FS_Print(f,"{\n"); + for (i = 0;i < prog->numglobaldefs;i++) + { + def = &prog->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 = PRVM_GetString(prog, def->s_name); + + if(developer_entityparsing.integer) + Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name); + + prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_WriteGlobals, name=%s", name); + FS_Printf(f,"\"%s\" ", name); + FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.fp[def->ofs], valuebuf, sizeof(valuebuf))); + prog->statestring = NULL; + } + FS_Print(f,"}\n"); +} + +/* +============= +PRVM_ED_ParseGlobals +============= +*/ +void PRVM_ED_ParseGlobals (prvm_prog_t *prog, const char *data) +{ + char keyname[MAX_INPUTLINE]; + ddef_t *key; + + while (1) + { + // parse key + if (!COM_ParseToken_Simple(&data, false, false, true)) + prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace"); + if (com_token[0] == '}') + break; + + if (developer_entityparsing.integer) + Con_Printf("Key: \"%s\"", com_token); + + strlcpy (keyname, com_token, sizeof(keyname)); + + // parse value + if (!COM_ParseToken_Simple(&data, false, true, true)) + prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace"); + + if (developer_entityparsing.integer) + Con_Printf(" \"%s\"\n", com_token); + + if (com_token[0] == '}') + prog->error_cmd("PRVM_ED_ParseGlobals: closing brace without data"); + + key = PRVM_ED_FindGlobal (prog, keyname); + if (!key) + { + Con_DPrintf("'%s' is not a global on %s\n", keyname, prog->name); + continue; + } + + if (!PRVM_ED_ParseEpair(prog, NULL, key, com_token, true)) + prog->error_cmd("PRVM_ED_ParseGlobals: parse error"); + } +} + +//============================================================================ + + +/* +============= +PRVM_ED_ParseEval + +Can parse either fields or globals +returns false if error +============= +*/ +qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash) +{ + int i, l; + char *new_p; + ddef_t *def; + prvm_eval_t *val; + mfunction_t *func; + + if (ent) + val = (prvm_eval_t *)(ent->fields.fp + key->ofs); + else + val = (prvm_eval_t *)(prog->globals.fp + key->ofs); + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + l = (int)strlen(s) + 1; + val->string = PRVM_AllocString(prog, l, &new_p); + for (i = 0;i < l;i++) + { + if (s[i] == '\\' && s[i+1] && parsebackslash) + { + i++; + if (s[i] == 'n') + *new_p++ = '\n'; + else if (s[i] == 'r') + *new_p++ = '\r'; + else + *new_p++ = s[i]; + } + else + *new_p++ = s[i]; + } + break; + + case ev_float: + while (*s && ISWHITESPACE(*s)) + s++; + val->_float = atof(s); + break; + + case ev_vector: + for (i = 0;i < 3;i++) + { + while (*s && ISWHITESPACE(*s)) + s++; + if (!*s) + break; + val->vector[i] = atof(s); + while (!ISWHITESPACE(*s)) + s++; + if (!*s) + break; + } + break; + + case ev_entity: + while (*s && ISWHITESPACE(*s)) + s++; + i = atoi(s); + if (i >= prog->limit_edicts) + Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, prog->limit_edicts, prog->name); + while (i >= prog->max_edicts) + PRVM_MEM_IncreaseEdicts(prog); + // if IncreaseEdicts was called the base pointer needs to be updated + if (ent) + val = (prvm_eval_t *)(ent->fields.fp + key->ofs); + val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i)); + break; + + case ev_field: + if (*s != '.') + { + Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, prog->name); + return false; + } + def = PRVM_ED_FindField(prog, s + 1); + if (!def) + { + Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, prog->name); + return false; + } + val->_int = def->ofs; + break; + + case ev_function: + func = PRVM_ED_FindFunction(prog, s); + if (!func) + { + Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, prog->name); + return false; + } + val->function = func - prog->functions; + break; + + default: + Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(prog, key->s_name), prog->name); + return false; + } + return true; +} + +/* +============= +PRVM_GameCommand_f + +Console command to send a string to QC function GameCommand of the +indicated progs + +Usage: + sv_cmd adminmsg 3 "do not teamkill" + cl_cmd someclientcommand + menu_cmd somemenucommand + +All progs can support this extension; sg calls it in server QC, cg in client +QC, mg in menu QC. +============= +*/ +static void PRVM_GameCommand(const char *whichprogs, const char *whichcmd) +{ + prvm_prog_t *prog; + if(Cmd_Argc() < 1) + { + Con_Printf("%s text...\n", whichcmd); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(whichprogs))) + return; + + if(!PRVM_allfunction(GameCommand)) + { + Con_Printf("%s program do not support GameCommand!\n", whichprogs); + } + else + { + int restorevm_tempstringsbuf_cursize; + const char *s; + + s = Cmd_Args(); + + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s ? s : ""); + prog->ExecuteProgram(prog, PRVM_allfunction(GameCommand), "QC function GameCommand is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } +} +static void PRVM_GameCommand_Server_f(void) +{ + PRVM_GameCommand("server", "sv_cmd"); +} +static void PRVM_GameCommand_Client_f(void) +{ + PRVM_GameCommand("client", "cl_cmd"); +} +static void PRVM_GameCommand_Menu_f(void) +{ + PRVM_GameCommand("menu", "menu_cmd"); +} + +/* +============= +PRVM_ED_EdictGet_f + +Console command to load a field of a specified edict +============= +*/ +static void PRVM_ED_EdictGet_f(void) +{ + prvm_prog_t *prog; + prvm_edict_t *ed; + ddef_t *key; + const char *s; + prvm_eval_t *v; + char valuebuf[MAX_INPUTLINE]; + + if(Cmd_Argc() != 4 && Cmd_Argc() != 5) + { + Con_Print("prvm_edictget []\n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2))); + + if((key = PRVM_ED_FindField(prog, Cmd_Argv(3))) == 0) + { + Con_Printf("Key %s not found !\n", Cmd_Argv(3)); + goto fail; + } + + v = (prvm_eval_t *)(ed->fields.fp + key->ofs); + s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf)); + if(Cmd_Argc() == 5) + { + cvar_t *cvar = Cvar_FindVar(Cmd_Argv(4)); + if (cvar && cvar->flags & CVAR_READONLY) + { + Con_Printf("prvm_edictget: %s is read-only\n", cvar->name); + goto fail; + } + Cvar_Get(Cmd_Argv(4), s, 0, NULL); + } + else + Con_Printf("%s\n", s); + +fail: + ; +} + +static void PRVM_ED_GlobalGet_f(void) +{ + prvm_prog_t *prog; + ddef_t *key; + const char *s; + prvm_eval_t *v; + char valuebuf[MAX_INPUTLINE]; + + if(Cmd_Argc() != 3 && Cmd_Argc() != 4) + { + Con_Print("prvm_globalget []\n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + key = PRVM_ED_FindGlobal(prog, Cmd_Argv(2)); + if(!key) + { + Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) ); + goto fail; + } + + v = (prvm_eval_t *) &prog->globals.fp[key->ofs]; + s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf)); + if(Cmd_Argc() == 4) + { + cvar_t *cvar = Cvar_FindVar(Cmd_Argv(3)); + if (cvar && cvar->flags & CVAR_READONLY) + { + Con_Printf("prvm_globalget: %s is read-only\n", cvar->name); + goto fail; + } + Cvar_Get(Cmd_Argv(3), s, 0, NULL); + } + else + Con_Printf("%s\n", s); + +fail: + ; +} + +/* +============= +PRVM_ED_EdictSet_f + +Console command to set a field of a specified edict +============= +*/ +static void PRVM_ED_EdictSet_f(void) +{ + prvm_prog_t *prog; + prvm_edict_t *ed; + ddef_t *key; + + if(Cmd_Argc() != 5) + { + Con_Print("prvm_edictset \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2))); + + if((key = PRVM_ED_FindField(prog, Cmd_Argv(3))) == 0) + Con_Printf("Key %s not found !\n", Cmd_Argv(3)); + else + PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(4), true); +} + +/* +==================== +PRVM_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. +==================== +*/ +const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_t *ent) +{ + ddef_t *key; + qboolean anglehack; + qboolean init; + char keyname[256]; + size_t n; + + init = false; + +// go through all the dictionary pairs + while (1) + { + // parse key + if (!COM_ParseToken_Simple(&data, false, false, true)) + prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace"); + if (developer_entityparsing.integer) + Con_Printf("Key: \"%s\"", com_token); + if (com_token[0] == '}') + break; + + // anglehack is to allow QuakeEd to write single scalar angles + // and allow them to be turned into vectors. (FIXME...) + if (!strcmp(com_token, "angle")) + { + strlcpy (com_token, "angles", sizeof(com_token)); + anglehack = true; + } + else + anglehack = false; + + // FIXME: change light to _light to get rid of this hack + if (!strcmp(com_token, "light")) + strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def + + strlcpy (keyname, com_token, sizeof(keyname)); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + if (!COM_ParseToken_Simple(&data, false, false, true)) + prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace"); + if (developer_entityparsing.integer) + Con_Printf(" \"%s\"\n", com_token); + + if (com_token[0] == '}') + prog->error_cmd("PRVM_ED_ParseEdict: closing brace without data"); + + init = true; + + // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp) + if (!keyname[0]) + continue; + +// keynames with a leading underscore are used for utility comments, +// and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + key = PRVM_ED_FindField (prog, keyname); + if (!key) + { + Con_DPrintf("%s: '%s' is not a field\n", prog->name, keyname); + continue; + } + + if (anglehack) + { + char temp[32]; + strlcpy (temp, com_token, sizeof(temp)); + dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp); + } + + if (!PRVM_ED_ParseEpair(prog, ent, key, com_token, strcmp(keyname, "wad") != 0)) + prog->error_cmd("PRVM_ED_ParseEdict: parse error"); + } + + if (!init) + ent->priv.required->free = true; + + return data; +} + + +/* +================ +PRVM_ED_LoadFromFile + +The entities are directly placed in the array, rather than allocated with +PRVM_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 PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves. +================ +*/ +void PRVM_ED_LoadFromFile (prvm_prog_t *prog, const char *data) +{ + prvm_edict_t *ent; + int parsed, inhibited, spawned, died; + const char *funcname; + mfunction_t *func; + char vabuf[1024]; + + parsed = 0; + inhibited = 0; + spawned = 0; + died = 0; + + prvm_reuseedicts_always_allow = realtime; + +// parse ents + while (1) + { +// parse the opening brace + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; + if (com_token[0] != '{') + prog->error_cmd("PRVM_ED_LoadFromFile: %s: found %s when expecting {", prog->name, com_token); + + // CHANGED: this is not conform to PR_LoadFromFile + if(prog->loadintoworld) + { + prog->loadintoworld = false; + ent = PRVM_EDICT_NUM(0); + } + else + ent = PRVM_ED_Alloc(prog); + + // clear it + if (ent != prog->edicts) // hack + memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); + + data = PRVM_ED_ParseEdict (prog, data, ent); + parsed++; + + // remove the entity ? + if(!prog->load_edict(prog, ent)) + { + PRVM_ED_Free(prog, ent); + inhibited++; + continue; + } + + if (PRVM_serverfunction(SV_OnEntityPreSpawnFunction)) + { + // self = ent + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing"); + } + + if(ent->priv.required->free) + { + inhibited++; + continue; + } + +// +// immediately call spawn function, but only if there is a self global and a classname +// + if(!ent->priv.required->free) + { + if (!PRVM_alledictstring(ent, classname)) + { + Con_Print("No classname for:\n"); + PRVM_ED_Print(prog, ent, NULL); + PRVM_ED_Free (prog, ent); + continue; + } + + // look for the spawn function + funcname = PRVM_GetString(prog, PRVM_alledictstring(ent, classname)); + func = PRVM_ED_FindFunction (prog, va(vabuf, sizeof(vabuf), "spawnfunc_%s", funcname)); + if(!func) + if(!PRVM_allglobalfloat(require_spawnfunc_prefix)) + func = PRVM_ED_FindFunction (prog, funcname); + + if (!func) + { + // check for OnEntityNoSpawnFunction + if (PRVM_serverfunction(SV_OnEntityNoSpawnFunction)) + { + // self = ent + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityNoSpawnFunction), "QC function SV_OnEntityNoSpawnFunction is missing"); + } + else + { + if (developer.integer > 0) // don't confuse non-developers with errors + { + Con_Print("No spawn function for:\n"); + PRVM_ED_Print(prog, ent, NULL); + } + PRVM_ED_Free (prog, ent); + continue; // not included in "inhibited" count + } + } + else + { + // self = ent + PRVM_serverglobalfloat(time) = sv.time; + PRVM_allglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, func - prog->functions, ""); + } + } + + if(!ent->priv.required->free) + if (PRVM_serverfunction(SV_OnEntityPostSpawnFunction)) + { + // self = ent + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing"); + } + + spawned++; + if (ent->priv.required->free) + died++; + } + + Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", prog->name, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died); + + prvm_reuseedicts_always_allow = 0; +} + +static void PRVM_FindOffsets(prvm_prog_t *prog) +{ + // field and global searches use -1 for NULL + memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets)); + memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets)); + // function searches use 0 for NULL + memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets)); +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) prog->fieldoffsets.x = PRVM_ED_FindFieldOffset(prog, #x); +#define PRVM_DECLARE_global(x) prog->globaloffsets.x = PRVM_ED_FindGlobalOffset(prog, #x); +#define PRVM_DECLARE_function(x) prog->funcoffsets.x = PRVM_ED_FindFunctionOffset(prog, #x); +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +} + +// not used +/* +typedef struct dpfield_s +{ + int type; + char *string; +} +dpfield_t; + +#define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t)) + +dpfield_t dpfields[] = +{ +}; +*/ + +/* +=============== +PRVM_ResetProg +=============== +*/ + +#define PO_HASHSIZE 16384 +typedef struct po_string_s +{ + char *key, *value; + struct po_string_s *nextonhashchain; +} +po_string_t; +typedef struct po_s +{ + po_string_t *hashtable[PO_HASHSIZE]; +} +po_t; +static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize) +{ + for(;;) + { + switch(*in) + { + case 0: + *out++ = 0; + return; + case '\a': if(outsize >= 2) { *out++ = '\\'; *out++ = 'a'; outsize -= 2; } break; + case '\b': if(outsize >= 2) { *out++ = '\\'; *out++ = 'b'; outsize -= 2; } break; + case '\t': if(outsize >= 2) { *out++ = '\\'; *out++ = 't'; outsize -= 2; } break; + case '\r': if(outsize >= 2) { *out++ = '\\'; *out++ = 'r'; outsize -= 2; } break; + case '\n': if(outsize >= 2) { *out++ = '\\'; *out++ = 'n'; outsize -= 2; } break; + case '\\': if(outsize >= 2) { *out++ = '\\'; *out++ = '\\'; outsize -= 2; } break; + case '"': if(outsize >= 2) { *out++ = '\\'; *out++ = '"'; outsize -= 2; } break; + default: + if(*in >= 0 && *in <= 0x1F) + { + if(outsize >= 4) + { + *out++ = '\\'; + *out++ = '0' + ((*in & 0700) >> 6); + *out++ = '0' + ((*in & 0070) >> 3); + *out++ = '0' + (*in & 0007) ; + outsize -= 4; + } + } + else + { + if(outsize >= 1) + { + *out++ = *in; + outsize -= 1; + } + } + break; + } + ++in; + } +} +static void PRVM_PO_ParseString(char *out, const char *in, size_t outsize) +{ + for(;;) + { + switch(*in) + { + case 0: + *out++ = 0; + return; + case '\\': + ++in; + switch(*in) + { + case 'a': if(outsize > 0) { *out++ = '\a'; --outsize; } break; + case 'b': if(outsize > 0) { *out++ = '\b'; --outsize; } break; + case 't': if(outsize > 0) { *out++ = '\t'; --outsize; } break; + case 'r': if(outsize > 0) { *out++ = '\r'; --outsize; } break; + case 'n': if(outsize > 0) { *out++ = '\n'; --outsize; } break; + case '\\': if(outsize > 0) { *out++ = '\\'; --outsize; } break; + case '"': if(outsize > 0) { *out++ = '"'; --outsize; } break; + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': + if(outsize > 0) + *out = *in - '0'; + ++in; + if(*in >= '0' && *in <= '7') + { + if(outsize > 0) + *out = (*out << 3) | (*in - '0'); + ++in; + } + if(*in >= '0' && *in <= '7') + { + if(outsize > 0) + *out = (*out << 3) | (*in - '0'); + ++in; + } + --in; + if(outsize > 0) + { + ++out; + --outsize; + } + break; + default: + if(outsize > 0) { *out++ = *in; --outsize; } + break; + } + break; + default: + if(outsize > 0) + { + *out++ = *in; + --outsize; + } + break; + } + ++in; + } +} +static po_t *PRVM_PO_Load(const char *filename, mempool_t *pool) +{ + po_t *po; + const char *p, *q; + int mode; + char inbuf[MAX_INPUTLINE]; + char decodedbuf[MAX_INPUTLINE]; + size_t decodedpos; + int hashindex; + po_string_t thisstr; + const char *buf = (const char *) FS_LoadFile(filename, pool, true, NULL); + + if(!buf) + return NULL; + + memset(&thisstr, 0, sizeof(thisstr)); // hush compiler warning + + po = (po_t *)Mem_Alloc(pool, sizeof(*po)); + memset(po, 0, sizeof(*po)); + + p = buf; + while(*p) + { + if(*p == '#') + { + // skip to newline + p = strchr(p, '\n'); + if(!p) + break; + ++p; + continue; + } + if(*p == '\r' || *p == '\n') + { + ++p; + continue; + } + if(!strncmp(p, "msgid \"", 7)) + { + mode = 0; + p += 6; + } + else if(!strncmp(p, "msgstr \"", 8)) + { + mode = 1; + p += 7; + } + else + { + p = strchr(p, '\n'); + if(!p) + break; + ++p; + continue; + } + decodedpos = 0; + while(*p == '"') + { + ++p; + q = strchr(p, '\n'); + if(!q) + break; + if(*(q-1) == '\r') + --q; + if(*(q-1) != '"') + break; + if((size_t)(q - p) >= (size_t) sizeof(inbuf)) + break; + strlcpy(inbuf, p, q - p); // not - 1, because this adds a NUL + PRVM_PO_ParseString(decodedbuf + decodedpos, inbuf, sizeof(decodedbuf) - decodedpos); + decodedpos += strlen(decodedbuf + decodedpos); + if(*q == '\r') + ++q; + if(*q == '\n') + ++q; + p = q; + } + if(mode == 0) + { + if(thisstr.key) + Mem_Free(thisstr.key); + thisstr.key = (char *)Mem_Alloc(pool, decodedpos + 1); + memcpy(thisstr.key, decodedbuf, decodedpos + 1); + } + else if(decodedpos > 0 && thisstr.key) // skip empty translation results + { + thisstr.value = (char *)Mem_Alloc(pool, decodedpos + 1); + memcpy(thisstr.value, decodedbuf, decodedpos + 1); + hashindex = CRC_Block((const unsigned char *) thisstr.key, strlen(thisstr.key)) % PO_HASHSIZE; + thisstr.nextonhashchain = po->hashtable[hashindex]; + po->hashtable[hashindex] = (po_string_t *)Mem_Alloc(pool, sizeof(thisstr)); + memcpy(po->hashtable[hashindex], &thisstr, sizeof(thisstr)); + memset(&thisstr, 0, sizeof(thisstr)); + } + } + + Mem_Free((char *) buf); + return po; +} +static const char *PRVM_PO_Lookup(po_t *po, const char *str) +{ + int hashindex = CRC_Block((const unsigned char *) str, strlen(str)) % PO_HASHSIZE; + po_string_t *p = po->hashtable[hashindex]; + while(p) + { + if(!strcmp(str, p->key)) + return p->value; + p = p->nextonhashchain; + } + return NULL; +} +static void PRVM_PO_Destroy(po_t *po) +{ + int i; + for(i = 0; i < PO_HASHSIZE; ++i) + { + po_string_t *p = po->hashtable[i]; + while(p) + { + po_string_t *q = p; + p = p->nextonhashchain; + Mem_Free(q->key); + Mem_Free(q->value); + Mem_Free(q); + } + } + Mem_Free(po); +} + +void PRVM_LeakTest(prvm_prog_t *prog); +void PRVM_Prog_Reset(prvm_prog_t *prog) +{ + if (prog->loaded) + { + PRVM_LeakTest(prog); + prog->reset_cmd(prog); + Mem_FreePool(&prog->progs_mempool); + if(prog->po) + PRVM_PO_Destroy((po_t *) prog->po); + } + memset(prog,0,sizeof(prvm_prog_t)); + prog->break_statement = -1; + prog->watch_global_type = ev_void; + prog->watch_field_type = ev_void; +} + +/* +=============== +PRVM_LoadLNO +=============== +*/ +static void PRVM_LoadLNO( prvm_prog_t *prog, const char *progname ) { + fs_offset_t filesize; + unsigned char *lno; + unsigned int *header; + char filename[512]; + + FS_StripExtension( progname, filename, sizeof( filename ) ); + strlcat( filename, ".lno", sizeof( filename ) ); + + lno = FS_LoadFile( filename, tempmempool, false, &filesize ); + if( !lno ) { + return; + } + +/* + SafeWrite (h, &lnotype, sizeof(int)); + SafeWrite (h, &version, sizeof(int)); + SafeWrite (h, &numglobaldefs, sizeof(int)); + SafeWrite (h, &numpr_globals, sizeof(int)); + SafeWrite (h, &numfielddefs, sizeof(int)); + SafeWrite (h, &numstatements, sizeof(int)); + SafeWrite (h, statement_linenums, numstatements*sizeof(int)); +*/ + if ((unsigned int)filesize < (6 + prog->progs_numstatements) * sizeof(int)) + { + Mem_Free(lno); + return; + } + + header = (unsigned int *) lno; + if( header[ 0 ] == *(unsigned int *) "LNOF" && + LittleLong( header[ 1 ] ) == 1 && + (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs_numglobaldefs && + (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs_numglobals && + (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs_numfielddefs && + (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs_numstatements ) + { + prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) ); + memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs_numstatements * sizeof( int ) ); + } + Mem_Free( lno ); +} + +/* +=============== +PRVM_LoadProgs +=============== +*/ +static void PRVM_UpdateBreakpoints(prvm_prog_t *prog); +void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global) +{ + int i; + dprograms_t *dprograms; + dstatement_t *instatements; + ddef_t *infielddefs; + ddef_t *inglobaldefs; + int *inglobals; + dfunction_t *infunctions; + char *instrings; + fs_offset_t filesize; + int requiredglobalspace; + opcode_t op; + int a; + int b; + int c; + union + { + unsigned int i; + float f; + } + u; + unsigned int d; + char vabuf[1024]; + + if (prog->loaded) + prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name ); + + Host_LockSession(); // all progs can use the session cvar + Crypto_LoadKeys(); // all progs might use the keys at init time + + if (data) + { + dprograms = (dprograms_t *) data; + filesize = size; + } + else + dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize); + if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t)) + prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name); + // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file + + prog->profiletime = Sys_DirtyTime(); + prog->starttime = realtime; + + Con_DPrintf("%s programs occupy %iK.\n", prog->name, (int)(filesize/1024)); + + requiredglobalspace = 0; + for (i = 0;i < numrequiredglobals;i++) + requiredglobalspace += required_global[i].type == ev_vector ? 3 : 1; + + prog->filecrc = CRC_Block((unsigned char *)dprograms, filesize); + +// byte swap the header + prog->progs_version = LittleLong(dprograms->version); + prog->progs_crc = LittleLong(dprograms->crc); + if (prog->progs_version != PROG_VERSION) + prog->error_cmd("%s: %s has wrong version number (%i should be %i)", prog->name, filename, prog->progs_version, PROG_VERSION); + instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements)); + prog->progs_numstatements = LittleLong(dprograms->numstatements); + inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs)); + prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs); + infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs)); + prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs); + infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions)); + prog->progs_numfunctions = LittleLong(dprograms->numfunctions); + instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings)); + prog->progs_numstrings = LittleLong(dprograms->numstrings); + inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals)); + prog->progs_numglobals = LittleLong(dprograms->numglobals); + prog->progs_entityfields = LittleLong(dprograms->entityfields); + + prog->numstatements = prog->progs_numstatements; + prog->numglobaldefs = prog->progs_numglobaldefs; + prog->numfielddefs = prog->progs_numfielddefs; + prog->numfunctions = prog->progs_numfunctions; + prog->numstrings = prog->progs_numstrings; + prog->numglobals = prog->progs_numglobals; + prog->entityfields = prog->progs_entityfields; + + if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize) + prog->error_cmd("%s: %s strings go past end of file", prog->name, filename); + prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings); + memcpy(prog->strings, instrings, prog->progs_numstrings); + prog->stringssize = prog->progs_numstrings; + + prog->numknownstrings = 0; + prog->maxknownstrings = 0; + prog->knownstrings = NULL; + prog->knownstrings_freeable = NULL; + + Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64); + + // we need to expand the globaldefs and fielddefs to include engine defs + prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t)); + prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t)); + // + 2 is because of an otherwise occurring overrun in RETURN instruction + // when trying to return the last or second-last global + // (RETURN always returns a vector, there is no RETURN_F instruction) + prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t)); + // we need to convert the statements to our memory format + prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t)); + // allocate space for profiling statement usage + prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile)); + // functions need to be converted to the memory format + prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions); + + for (i = 0;i < prog->progs_numfunctions;i++) + { + prog->functions[i].first_statement = LittleLong(infunctions[i].first_statement); + prog->functions[i].parm_start = LittleLong(infunctions[i].parm_start); + prog->functions[i].s_name = LittleLong(infunctions[i].s_name); + prog->functions[i].s_file = LittleLong(infunctions[i].s_file); + prog->functions[i].numparms = LittleLong(infunctions[i].numparms); + prog->functions[i].locals = LittleLong(infunctions[i].locals); + memcpy(prog->functions[i].parm_size, infunctions[i].parm_size, sizeof(infunctions[i].parm_size)); + if(prog->functions[i].first_statement >= prog->numstatements) + prog->error_cmd("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, prog->name); + // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size + } + + // copy the globaldefs to the new globaldefs list + for (i=0 ; inumglobaldefs ; i++) + { + prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type); + prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs); + prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name); + // TODO bounds check ofs, s_name + } + + // append the required globals + for (i = 0;i < numrequiredglobals;i++) + { + prog->globaldefs[prog->numglobaldefs].type = required_global[i].type; + prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals; + prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(prog, required_global[i].name); + if (prog->globaldefs[prog->numglobaldefs].type == ev_vector) + prog->numglobals += 3; + else + prog->numglobals++; + prog->numglobaldefs++; + } + + // copy the progs fields to the new fields list + for (i = 0;i < prog->numfielddefs;i++) + { + prog->fielddefs[i].type = LittleShort(infielddefs[i].type); + if (prog->fielddefs[i].type & DEF_SAVEGLOBAL) + prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name); + prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs); + prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name); + // TODO bounds check ofs, s_name + } + + // append the required fields + for (i = 0;i < numrequiredfields;i++) + { + prog->fielddefs[prog->numfielddefs].type = required_field[i].type; + prog->fielddefs[prog->numfielddefs].ofs = prog->entityfields; + prog->fielddefs[prog->numfielddefs].s_name = PRVM_SetEngineString(prog, required_field[i].name); + if (prog->fielddefs[prog->numfielddefs].type == ev_vector) + prog->entityfields += 3; + else + prog->entityfields++; + prog->numfielddefs++; + } + + // LordHavoc: TODO: reorder globals to match engine struct + // LordHavoc: TODO: reorder fields to match engine struct +#define remapglobal(index) (index) +#define remapfield(index) (index) + + // copy globals + // FIXME: LordHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type + for (i = 0;i < prog->progs_numglobals;i++) + { + u.i = LittleLong(inglobals[i]); + // most globals are 0, we only need to deal with the ones that are not + if (u.i) + { + d = u.i & 0xFF800000; + if ((d == 0xFF800000) || (d == 0)) + { + // Looks like an integer (expand to int64) + prog->globals.ip[remapglobal(i)] = u.i; + } + else + { + // Looks like a float (expand to double) + prog->globals.fp[remapglobal(i)] = u.f; + } + } + } + + // LordHavoc: TODO: support 32bit progs statement formats + // copy, remap globals in statements, bounds check + for (i = 0;i < prog->progs_numstatements;i++) + { + op = (opcode_t)LittleShort(instatements[i].op); + a = (unsigned short)LittleShort(instatements[i].a); + b = (unsigned short)LittleShort(instatements[i].b); + c = (unsigned short)LittleShort(instatements[i].c); + switch (op) + { + case OP_IF: + case OP_IFNOT: + b = (short)b; + if (a >= prog->progs_numglobals || b + i < 0 || b + i >= prog->progs_numstatements) + prog->error_cmd("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, prog->name); + prog->statements[i].op = op; + prog->statements[i].operand[0] = remapglobal(a); + prog->statements[i].operand[1] = -1; + prog->statements[i].operand[2] = -1; + prog->statements[i].jumpabsolute = i + b; + break; + case OP_GOTO: + a = (short)a; + if (a + i < 0 || a + i >= prog->progs_numstatements) + prog->error_cmd("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, prog->name); + prog->statements[i].op = op; + prog->statements[i].operand[0] = -1; + prog->statements[i].operand[1] = -1; + prog->statements[i].operand[2] = -1; + prog->statements[i].jumpabsolute = i + a; + break; + default: + Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, prog->name); + // global global global + case OP_ADD_F: + case OP_ADD_V: + case OP_SUB_F: + case OP_SUB_V: + case OP_MUL_F: + case OP_MUL_V: + case OP_MUL_FV: + case OP_MUL_VF: + case OP_DIV_F: + case OP_BITAND: + case OP_BITOR: + case OP_GE: + case OP_LE: + case OP_GT: + case OP_LT: + case OP_AND: + case OP_OR: + case OP_EQ_F: + case OP_EQ_V: + case OP_EQ_S: + case OP_EQ_E: + case OP_EQ_FNC: + case OP_NE_F: + case OP_NE_V: + case OP_NE_S: + case OP_NE_E: + case OP_NE_FNC: + case OP_ADDRESS: + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + case OP_LOAD_V: + if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals) + prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d)", i); + prog->statements[i].op = op; + prog->statements[i].operand[0] = remapglobal(a); + prog->statements[i].operand[1] = remapglobal(b); + prog->statements[i].operand[2] = remapglobal(c); + prog->statements[i].jumpabsolute = -1; + break; + // global none global + case OP_NOT_F: + case OP_NOT_V: + case OP_NOT_S: + case OP_NOT_FNC: + case OP_NOT_ENT: + if (a >= prog->progs_numglobals || c >= prog->progs_numglobals) + prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name); + prog->statements[i].op = op; + prog->statements[i].operand[0] = remapglobal(a); + prog->statements[i].operand[1] = -1; + prog->statements[i].operand[2] = remapglobal(c); + prog->statements[i].jumpabsolute = -1; + break; + // 2 globals + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: + case OP_STOREP_S: + case OP_STOREP_FNC: + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: + case OP_STORE_S: + case OP_STORE_FNC: + case OP_STATE: + case OP_STOREP_V: + case OP_STORE_V: + if (a >= prog->progs_numglobals || b >= prog->progs_numglobals) + prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name); + prog->statements[i].op = op; + prog->statements[i].operand[0] = remapglobal(a); + prog->statements[i].operand[1] = remapglobal(b); + prog->statements[i].operand[2] = -1; + prog->statements[i].jumpabsolute = -1; + break; + // 1 global + 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: + case OP_DONE: + case OP_RETURN: + if ( a >= prog->progs_numglobals) + prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name); + prog->statements[i].op = op; + prog->statements[i].operand[0] = remapglobal(a); + prog->statements[i].operand[1] = -1; + prog->statements[i].operand[2] = -1; + prog->statements[i].jumpabsolute = -1; + break; + } + } + if(prog->numstatements < 1) + { + prog->error_cmd("PRVM_LoadProgs: empty program in %s", prog->name); + } + else switch(prog->statements[prog->numstatements - 1].op) + { + case OP_RETURN: + case OP_GOTO: + case OP_DONE: + break; + default: + prog->error_cmd("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", prog->name); + break; + } + + // we're done with the file now + if(!data) + Mem_Free(dprograms); + dprograms = NULL; + + // check required functions + for(i=0 ; i < numrequiredfunc ; i++) + if(PRVM_ED_FindFunction(prog, required_func[i]) == 0) + prog->error_cmd("%s: %s not found in %s",prog->name, required_func[i], filename); + + PRVM_LoadLNO(prog, filename); + + PRVM_Init_Exec(prog); + + if(*prvm_language.string) + // in CSQC we really shouldn't be able to change how stuff works... sorry for now + // later idea: include a list of authorized .po file checksums with the csprogs + { + qboolean deftrans = prog == CLVM_prog; + const char *realfilename = (prog != CLVM_prog ? filename : csqc_progname.string); + if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method! + { + for (i=0 ; inumglobaldefs ; i++) + { + const char *name; + name = PRVM_GetString(prog, prog->globaldefs[i].s_name); + if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + if(name && !strncmp(name, "dotranslate_", 12)) + { + deftrans = false; + break; + } + } + } + if(!strcmp(prvm_language.string, "dump")) + { + qfile_t *f = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.pot", realfilename), "w", false); + Con_Printf("Dumping to %s.pot\n", realfilename); + if(f) + { + for (i=0 ; inumglobaldefs ; i++) + { + const char *name; + name = PRVM_GetString(prog, prog->globaldefs[i].s_name); + if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12))) + if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + { + prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs); + const char *value = PRVM_GetString(prog, val->string); + if(*value) + { + char buf[MAX_INPUTLINE]; + PRVM_PO_UnparseString(buf, value, sizeof(buf)); + FS_Printf(f, "msgid \"%s\"\nmsgstr \"\"\n\n", buf); + } + } + } + FS_Close(f); + } + } + else + { + po_t *po = PRVM_PO_Load(va(vabuf, sizeof(vabuf), "%s.%s.po", realfilename, prvm_language.string), prog->progs_mempool); + if(po) + { + for (i=0 ; inumglobaldefs ; i++) + { + const char *name; + name = PRVM_GetString(prog, prog->globaldefs[i].s_name); + if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12))) + if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + { + prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs); + const char *value = PRVM_GetString(prog, val->string); + if(*value) + { + value = PRVM_PO_Lookup(po, value); + if(value) + val->string = PRVM_SetEngineString(prog, value); + } + } + } + } + } + } + + for (i=0 ; inumglobaldefs ; i++) + { + const char *name; + name = PRVM_GetString(prog, prog->globaldefs[i].s_name); + //Con_Printf("found var %s\n", name); + if(name + && !strncmp(name, "autocvar_", 9) + && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z')) + ) + { + prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs); + cvar_t *cvar = Cvar_FindVar(name + 9); + //Con_Printf("PRVM_LoadProgs: autocvar global %s in %s, processing...\n", name, prog->name); + if(!cvar) + { + const char *value; + char buf[64]; + Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, prog->name); + switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) + { + case ev_float: + if((float)((int)(val->_float)) == val->_float) + dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float)); + else + dpsnprintf(buf, sizeof(buf), "%.9g", val->_float); + value = buf; + break; + case ev_vector: + dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf; + break; + case ev_string: + value = PRVM_GetString(prog, val->string); + break; + default: + Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name); + goto fail; + } + cvar = Cvar_Get(name + 9, value, 0, NULL); + if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string) + { + val->string = PRVM_SetEngineString(prog, cvar->string); + cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string; + } + if(!cvar) + prog->error_cmd("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, prog->name); + cvar->globaldefindex_progid[prog - prvm_prog_list] = prog->id; + cvar->globaldefindex[prog - prvm_prog_list] = i; + } + else if((cvar->flags & CVAR_PRIVATE) == 0) + { + // MUST BE SYNCED WITH cvar.c Cvar_Set + int j; + const char *s; + switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) + { + case ev_float: + val->_float = cvar->value; + break; + case ev_vector: + s = cvar->string; + VectorClear(val->vector); + for (j = 0;j < 3;j++) + { + while (*s && ISWHITESPACE(*s)) + s++; + if (!*s) + break; + val->vector[j] = atof(s); + while (!ISWHITESPACE(*s)) + s++; + if (!*s) + break; + } + break; + case ev_string: + val->string = PRVM_SetEngineString(prog, cvar->string); + cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string; + break; + default: + Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name); + goto fail; + } + cvar->globaldefindex_progid[prog - prvm_prog_list] = prog->id; + cvar->globaldefindex[prog - prvm_prog_list] = i; + } + else + Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, prog->name); + } +fail: + ; + } + + prog->loaded = TRUE; + + PRVM_UpdateBreakpoints(prog); + + // set flags & ddef_ts in prog + + prog->flag = 0; + + PRVM_FindOffsets(prog); + + prog->init_cmd(prog); + + // init mempools + PRVM_MEM_Alloc(prog); +} + + +static void PRVM_Fields_f (void) +{ + prvm_prog_t *prog; + int i, j, ednum, used, usedamount; + int *counts; + char tempstring[MAX_INPUTLINE], tempstring2[260]; + const char *name; + prvm_edict_t *ed; + ddef_t *d; + prvm_eval_t *val; + + // TODO + /* + if (!sv.active) + { + Con_Print("no progs loaded\n"); + return; + } + */ + + if(Cmd_Argc() != 2) + { + Con_Print("prvm_fields \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int)); + for (ednum = 0;ednum < prog->max_edicts;ednum++) + { + ed = PRVM_EDICT_NUM(ednum); + if (ed->priv.required->free) + continue; + for (i = 1;i < prog->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(prog, d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + val = (prvm_eval_t *)(ed->fields.fp + d->ofs); + // if the value is still all 0, skip the field + for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++) + { + if (val->ivector[j]) + { + counts[i]++; + break; + } + } + } + } + used = 0; + usedamount = 0; + tempstring[0] = 0; + for (i = 0;i < prog->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(prog, d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + switch(d->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + strlcat(tempstring, "string ", sizeof(tempstring)); + break; + case ev_entity: + strlcat(tempstring, "entity ", sizeof(tempstring)); + break; + case ev_function: + strlcat(tempstring, "function ", sizeof(tempstring)); + break; + case ev_field: + strlcat(tempstring, "field ", sizeof(tempstring)); + break; + case ev_void: + strlcat(tempstring, "void ", sizeof(tempstring)); + break; + case ev_float: + strlcat(tempstring, "float ", sizeof(tempstring)); + break; + case ev_vector: + strlcat(tempstring, "vector ", sizeof(tempstring)); + break; + case ev_pointer: + strlcat(tempstring, "pointer ", sizeof(tempstring)); + break; + default: + dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL); + strlcat(tempstring, tempstring2, sizeof(tempstring)); + break; + } + if (strlen(name) > sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strlcat(tempstring, name, sizeof(tempstring)); + for (j = (int)strlen(name);j < 25;j++) + strlcat(tempstring, " ", sizeof(tempstring)); + dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]); + strlcat(tempstring, tempstring2, sizeof(tempstring)); + strlcat(tempstring, "\n", sizeof(tempstring)); + if (strlen(tempstring) >= sizeof(tempstring)/2) + { + Con_Print(tempstring); + tempstring[0] = 0; + } + if (counts[i]) + { + used++; + usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL]; + } + } + Mem_Free(counts); + Con_Printf("%s: %i entity fields (%i in use), totalling %i bytes per edict (%i in use), %i edicts allocated, %i bytes total spent on edict fields (%i needed)\n", prog->name, prog->entityfields, used, prog->entityfields * 4, usedamount * 4, prog->max_edicts, prog->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts); +} + +static void PRVM_Globals_f (void) +{ + prvm_prog_t *prog; + int i; + const char *wildcard; + int numculled; + numculled = 0; + // TODO + /*if (!sv.active) + { + Con_Print("no progs loaded\n"); + return; + }*/ + if(Cmd_Argc () < 2 || Cmd_Argc() > 3) + { + Con_Print("prvm_globals \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + if( Cmd_Argc() == 3) + wildcard = Cmd_Argv(2); + else + wildcard = NULL; + + Con_Printf("%s :", prog->name); + + for (i = 0;i < prog->numglobaldefs;i++) + { + if(wildcard) + if( !matchpattern( PRVM_GetString(prog, prog->globaldefs[i].s_name), wildcard, 1) ) + { + numculled++; + continue; + } + Con_Printf("%s\n", PRVM_GetString(prog, prog->globaldefs[i].s_name)); + } + Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->numglobals, numculled, prog->numglobals * 4); +} + +/* +=============== +PRVM_Global +=============== +*/ +static void PRVM_Global_f(void) +{ + prvm_prog_t *prog; + ddef_t *global; + char valuebuf[MAX_INPUTLINE]; + if( Cmd_Argc() != 3 ) { + Con_Printf( "prvm_global \n" ); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) ); + if( !global ) + Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) ); + else + Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( prog, (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs), valuebuf, sizeof(valuebuf) ) ); +} + +/* +=============== +PRVM_GlobalSet +=============== +*/ +static void PRVM_GlobalSet_f(void) +{ + prvm_prog_t *prog; + ddef_t *global; + if( Cmd_Argc() != 4 ) { + Con_Printf( "prvm_globalset \n" ); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) ); + if( !global ) + Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) ); + else + PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(3), true ); +} + +/* +====================== +Break- and Watchpoints +====================== +*/ +typedef struct +{ + char break_statement[256]; + char watch_global[256]; + int watch_edict; + char watch_field[256]; +} +debug_data_t; +static debug_data_t debug_data[PRVM_PROG_MAX]; + +void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text) +{ + char vabuf[1024]; + Con_Printf("PRVM_Breakpoint: %s\n", text); + PRVM_PrintState(prog, stack_index); + if (prvm_breakpointdump.integer) + Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name)); +} + +void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n) +{ + size_t sz = sizeof(prvm_vec_t) * ((type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1); + if (memcmp(o, n, sz)) + { + char buf[1024]; + char valuebuf_o[128]; + char valuebuf_n[128]; + PRVM_UglyValueString(prog, type, o, valuebuf_o, sizeof(valuebuf_o)); + PRVM_UglyValueString(prog, type, n, valuebuf_n, sizeof(valuebuf_n)); + dpsnprintf(buf, sizeof(buf), "%s: %s -> %s", text, valuebuf_o, valuebuf_n); + PRVM_Breakpoint(prog, stack_index, buf); + memcpy(o, n, sz); + } +} + +static void PRVM_UpdateBreakpoints(prvm_prog_t *prog) +{ + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + if (!prog->loaded) + return; + if (debug->break_statement[0]) + { + if (debug->break_statement[0] >= '0' && debug->break_statement[0] <= '9') + { + prog->break_statement = atoi(debug->break_statement); + prog->break_stack_index = 0; + } + else + { + mfunction_t *func; + func = PRVM_ED_FindFunction (prog, debug->break_statement); + if (!func) + { + Con_Printf("%s progs: no function or statement named %s to break on!\n", prog->name, debug->break_statement); + prog->break_statement = -1; + } + else + { + prog->break_statement = func->first_statement; + prog->break_stack_index = 1; + } + } + if (prog->break_statement >= -1) + Con_Printf("%s progs: breakpoint is at statement %d\n", prog->name, prog->break_statement); + } + else + prog->break_statement = -1; + + if (debug->watch_global[0]) + { + ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global ); + if( !global ) + { + Con_Printf( "%s progs: no global named '%s' to watch!\n", prog->name, debug->watch_global ); + prog->watch_global_type = ev_void; + } + else + { + size_t sz = sizeof(prvm_vec_t) * ((global->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1); + prog->watch_global = global->ofs; + prog->watch_global_type = (etype_t)global->type; + memcpy(&prog->watch_global_value, PRVM_GLOBALFIELDVALUE(prog->watch_global), sz); + } + if (prog->watch_global_type != ev_void) + Con_Printf("%s progs: global watchpoint is at global index %d\n", prog->name, prog->watch_global); + } + else + prog->watch_global_type = ev_void; + + if (debug->watch_field[0]) + { + ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field ); + if( !field ) + { + Con_Printf( "%s progs: no field named '%s' to watch!\n", prog->name, debug->watch_field ); + prog->watch_field_type = ev_void; + } + else + { + size_t sz = sizeof(prvm_vec_t) * ((field->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1); + prog->watch_edict = debug->watch_edict; + prog->watch_field = field->ofs; + prog->watch_field_type = (etype_t)field->type; + if (prog->watch_edict < prog->num_edicts) + memcpy(&prog->watch_edictfield_value, PRVM_EDICTFIELDVALUE(PRVM_EDICT_NUM(prog->watch_edict), prog->watch_field), sz); + else + memset(&prog->watch_edictfield_value, 0, sz); + } + if (prog->watch_edict != ev_void) + Con_Printf("%s progs: edict field watchpoint is at edict %d field index %d\n", prog->name, prog->watch_edict, prog->watch_field); + } + else + prog->watch_field_type = ev_void; +} + +static void PRVM_Breakpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->break_statement[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 3 ) { + Con_Printf( "prvm_breakpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + strlcpy(debug->break_statement, Cmd_Argv(2), sizeof(debug->break_statement)); + } + PRVM_UpdateBreakpoints(prog); +} + +static void PRVM_GlobalWatchpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_global[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 3 ) { + Con_Printf( "prvm_globalwatchpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + strlcpy(debug->watch_global, Cmd_Argv(2), sizeof(debug->watch_global)); + } + PRVM_UpdateBreakpoints(prog); +} + +static void PRVM_EdictWatchpoint_f(void) +{ + prvm_prog_t *prog; + + if( Cmd_Argc() == 2 ) { + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_field[0] = 0; + } + PRVM_UpdateBreakpoints(prog); + return; + } + if( Cmd_Argc() != 4 ) { + Con_Printf( "prvm_edictwatchpoint \n" ); + return; + } + + if (!(prog = PRVM_ProgFromString(Cmd_Argv(1)))) + return; + + { + debug_data_t *debug = &debug_data[prog - prvm_prog_list]; + debug->watch_edict = atoi(Cmd_Argv(2)); + strlcpy(debug->watch_field, Cmd_Argv(3), sizeof(debug->watch_field)); + } + PRVM_UpdateBreakpoints(prog); +} + +/* +=============== +PRVM_Init +=============== +*/ +void PRVM_Init (void) +{ + Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls"); + Cmd_AddCommand ("prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)"); + Cmd_AddCommand ("prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console"); + Cmd_AddCommand ("prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console"); + Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)"); + Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); + + Cmd_AddCommand ("prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint"); + Cmd_AddCommand ("prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + Cmd_AddCommand ("prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + + Cvar_RegisterVariable (&prvm_language); + Cvar_RegisterVariable (&prvm_traceqc); + Cvar_RegisterVariable (&prvm_statementprofiling); + Cvar_RegisterVariable (&prvm_timeprofiling); + Cvar_RegisterVariable (&prvm_backtraceforwarnings); + Cvar_RegisterVariable (&prvm_leaktest); + Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames); + Cvar_RegisterVariable (&prvm_errordump); + Cvar_RegisterVariable (&prvm_breakpointdump); + Cvar_RegisterVariable (&prvm_reuseedicts_startuptime); + Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe); + + // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!) + prvm_runawaycheck = !COM_CheckParm("-norunaway"); + + //VM_Cmd_Init(); +} + +/* +=============== +PRVM_InitProg +=============== +*/ +void PRVM_Prog_Init(prvm_prog_t *prog) +{ + PRVM_Prog_Reset(prog); + prog->leaktest_active = prvm_leaktest.integer != 0; +} + +// LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons +unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline) +{ + prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline); + return 0; +} + +#define PRVM_KNOWNSTRINGBASE 0x40000000 + +const char *PRVM_GetString(prvm_prog_t *prog, int num) +{ + if (num < 0) + { + // invalid + VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num); + return ""; + } + else if (num < prog->stringssize) + { + // constant string from progs.dat + return prog->strings + num; + } + else if (num <= prog->stringssize + prog->tempstringsbuf.maxsize) + { + // tempstring returned by engine to QC (becomes invalid after returning to engine) + num -= prog->stringssize; + if (num < prog->tempstringsbuf.cursize) + return (char *)prog->tempstringsbuf.data + num; + else + { + VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize); + return ""; + } + } + else if (num & PRVM_KNOWNSTRINGBASE) + { + // allocated string + num = num - PRVM_KNOWNSTRINGBASE; + if (num >= 0 && num < prog->numknownstrings) + { + if (!prog->knownstrings[num]) + { + VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num); + return ""; + } + return prog->knownstrings[num]; + } + else + { + VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings); + return ""; + } + } + else + { + // invalid string offset + VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize); + return ""; + } +} + +const char *PRVM_ChangeEngineString(prvm_prog_t *prog, int i, const char *s) +{ + const char *old; + i = i - PRVM_KNOWNSTRINGBASE; + if(i < 0 || i >= prog->numknownstrings) + prog->error_cmd("PRVM_ChangeEngineString: s is not an engine string"); + old = prog->knownstrings[i]; + prog->knownstrings[i] = s; + return old; +} + +int PRVM_SetEngineString(prvm_prog_t *prog, const char *s) +{ + int i; + if (!s) + return 0; + if (s >= prog->strings && s <= prog->strings + prog->stringssize) + prog->error_cmd("PRVM_SetEngineString: s in prog->strings area"); + // if it's in the tempstrings area, use a reserved range + // (otherwise we'd get millions of useless string offsets cluttering the database) + if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize) + return prog->stringssize + (s - (char *)prog->tempstringsbuf.data); + // see if it's a known string address + for (i = 0;i < prog->numknownstrings;i++) + if (prog->knownstrings[i] == s) + return PRVM_KNOWNSTRINGBASE + i; + // new unknown engine string + if (developer_insane.integer) + Con_DPrintf("new engine string %p = \"%s\"\n", s, s); + for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + const unsigned char *oldstrings_freeable = prog->knownstrings_freeable; + const char **oldstrings_origin = prog->knownstrings_origin; + prog->maxknownstrings += 128; + prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char)); + if(prog->leaktest_active) + prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + if (prog->numknownstrings) + { + memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char)); + if(prog->leaktest_active) + memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *)); + } + } + prog->numknownstrings++; + } + prog->firstfreeknownstring = i + 1; + prog->knownstrings[i] = s; + prog->knownstrings_freeable[i] = false; + if(prog->leaktest_active) + prog->knownstrings_origin[i] = NULL; + return PRVM_KNOWNSTRINGBASE + i; +} + +// temp string handling + +// all tempstrings go into this buffer consecutively, and it is reset +// whenever PRVM_ExecuteProgram returns to the engine +// (technically each PRVM_ExecuteProgram call saves the cursize value and +// restores it on return, so multiple recursive calls can share the same +// buffer) +// the buffer size is automatically grown as needed + +int PRVM_SetTempString(prvm_prog_t *prog, const char *s) +{ + int size; + char *t; + if (!s) + return 0; + size = (int)strlen(s) + 1; + if (developer_insane.integer) + Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", prog->tempstringsbuf.cursize, size); + if (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size) + { + sizebuf_t old = prog->tempstringsbuf; + if (prog->tempstringsbuf.cursize + size >= 1<<28) + prog->error_cmd("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", prog->tempstringsbuf.cursize, size); + prog->tempstringsbuf.maxsize = max(prog->tempstringsbuf.maxsize, 65536); + while (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size) + prog->tempstringsbuf.maxsize *= 2; + if (prog->tempstringsbuf.maxsize != old.maxsize || prog->tempstringsbuf.data == NULL) + { + Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, prog->tempstringsbuf.maxsize/1024); + prog->tempstringsbuf.data = (unsigned char *) Mem_Alloc(prog->progs_mempool, prog->tempstringsbuf.maxsize); + if (old.cursize) + memcpy(prog->tempstringsbuf.data, old.data, old.cursize); + if (old.data) + Mem_Free(old.data); + } + } + t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize; + memcpy(t, s, size); + prog->tempstringsbuf.cursize += size; + return PRVM_SetEngineString(prog, t); +} + +int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer) +{ + int i; + if (!bufferlength) + return 0; + for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + const unsigned char *oldstrings_freeable = prog->knownstrings_freeable; + const char **oldstrings_origin = prog->knownstrings_origin; + prog->maxknownstrings += 128; + prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char)); + if(prog->leaktest_active) + prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + if (prog->numknownstrings) + { + memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char)); + if(prog->leaktest_active) + memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *)); + } + if (oldstrings) + Mem_Free((char **)oldstrings); + if (oldstrings_freeable) + Mem_Free((unsigned char *)oldstrings_freeable); + if (oldstrings_origin) + Mem_Free((char **)oldstrings_origin); + } + prog->numknownstrings++; + } + prog->firstfreeknownstring = i + 1; + prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength); + prog->knownstrings_freeable[i] = true; + if(prog->leaktest_active) + prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog); + if (pointer) + *pointer = (char *)(prog->knownstrings[i]); + return PRVM_KNOWNSTRINGBASE + i; +} + +void PRVM_FreeString(prvm_prog_t *prog, int num) +{ + if (num == 0) + prog->error_cmd("PRVM_FreeString: attempt to free a NULL string"); + else if (num >= 0 && num < prog->stringssize) + prog->error_cmd("PRVM_FreeString: attempt to free a constant string"); + else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings) + { + num = num - PRVM_KNOWNSTRINGBASE; + if (!prog->knownstrings[num]) + prog->error_cmd("PRVM_FreeString: attempt to free a non-existent or already freed string"); + if (!prog->knownstrings_freeable[num]) + prog->error_cmd("PRVM_FreeString: attempt to free a string owned by the engine"); + PRVM_Free((char *)prog->knownstrings[num]); + if(prog->leaktest_active) + if(prog->knownstrings_origin[num]) + PRVM_Free((char *)prog->knownstrings_origin[num]); + prog->knownstrings[num] = NULL; + prog->knownstrings_freeable[num] = false; + prog->firstfreeknownstring = min(prog->firstfreeknownstring, num); + } + else + prog->error_cmd("PRVM_FreeString: invalid string offset %i", num); +} + +static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string) +{ + int i, j; + + for (i = 0;i < prog->numglobaldefs;i++) + { + ddef_t *d = &prog->globaldefs[i]; + if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string) + continue; + if(string == PRVM_GLOBALFIELDSTRING(d->ofs)) + return true; + } + + for(j = 0; j < prog->num_edicts; ++j) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(j); + if (ed->priv.required->free) + continue; + for (i=0; inumfielddefs; ++i) + { + ddef_t *d = &prog->fielddefs[i]; + if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string) + continue; + if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs)) + return true; + } + } + + return false; +} + +static qboolean PRVM_IsEdictRelevant(prvm_prog_t *prog, prvm_edict_t *edict) +{ + char vabuf[1024]; + char vabuf2[1024]; + if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts) + return true; // world or clients + if (prog == SVVM_prog) + { + if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger? + return true; + if(PRVM_serveredictfloat(edict, modelindex)) // visible ent? + return true; + if(PRVM_serveredictfloat(edict, effects)) // particle effect? + return true; + if(PRVM_serveredictfunction(edict, think)) // has a think function? + if(PRVM_serveredictfloat(edict, nextthink) > 0) // that actually will eventually run? + return true; + if(PRVM_serveredictfloat(edict, takedamage)) + return true; + if(*prvm_leaktest_ignore_classnames.string) + { + if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_serveredictstring(edict, classname))))) + return true; + } + } + else if (prog == CLVM_prog) + { + // TODO someone add more stuff here + if(PRVM_clientedictfloat(edict, entnum)) // csqc networked + return true; + if(PRVM_clientedictfloat(edict, modelindex)) // visible ent? + return true; + if(PRVM_clientedictfloat(edict, effects)) // particle effect? + return true; + if(PRVM_clientedictfunction(edict, think)) // has a think function? + if(PRVM_clientedictfloat(edict, nextthink) > 0) // that actually will eventually run? + return true; + if(*prvm_leaktest_ignore_classnames.string) + { + if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_clientedictstring(edict, classname))))) + return true; + } + } + else + { + // menu prog does not have classnames + } + return false; +} + +static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, int mark) +{ + int i, j; + int edictnum = PRVM_NUM_FOR_EDICT(edict); + const char *targetname = NULL; + + if (prog == SVVM_prog) + targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname)); + + if(targetname) + if(!*targetname) // "" + targetname = NULL; + + if(mark == 0) + { + for (i = 0;i < prog->numglobaldefs;i++) + { + ddef_t *d = &prog->globaldefs[i]; + if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) + continue; + if(edictnum == PRVM_GLOBALFIELDEDICT(d->ofs)) + return true; + } + } + + for(j = 0; j < prog->num_edicts; ++j) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(j); + if (ed->priv.required->mark < mark) + continue; + if(ed == edict) + continue; + if(targetname) + { + const char *target = PRVM_GetString(prog, PRVM_serveredictstring(ed, target)); + if(target) + if(!strcmp(target, targetname)) + return true; + } + for (i=0; inumfielddefs; ++i) + { + ddef_t *d = &prog->fielddefs[i]; + if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity) + continue; + if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs)) + return true; + } + } + + return false; +} + +static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog) +{ + int j; + qboolean found_new; + int stage; + + for(j = 0; j < prog->num_edicts; ++j) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(j); + if(ed->priv.required->free) + continue; + ed->priv.required->mark = PRVM_IsEdictRelevant(prog, ed) ? 1 : 0; + } + + stage = 1; + do + { + found_new = false; + for(j = 0; j < prog->num_edicts; ++j) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(j); + if(ed->priv.required->free) + continue; + if(ed->priv.required->mark) + continue; + if(PRVM_IsEdictReferenced(prog, ed, stage)) + { + ed->priv.required->mark = stage + 1; + found_new = true; + } + } + ++stage; + } + while(found_new); + Con_DPrintf("leak check used %d stages to find all references\n", stage); +} + +void PRVM_LeakTest(prvm_prog_t *prog) +{ + int i, j; + qboolean leaked = false; + + if(!prog->leaktest_active) + return; + + // 1. Strings + for (i = 0; i < prog->numknownstrings; ++i) + { + if(prog->knownstrings[i]) + if(prog->knownstrings_freeable[i]) + if(prog->knownstrings_origin[i]) + if(!PRVM_IsStringReferenced(prog, PRVM_KNOWNSTRINGBASE + i)) + { + Con_Printf("Unreferenced string found!\n Value: %s\n Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]); + leaked = true; + } + } + + // 2. Edicts + PRVM_MarkReferencedEdicts(prog); + for(j = 0; j < prog->num_edicts; ++j) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(j); + if(ed->priv.required->free) + continue; + if(!ed->priv.required->mark) + if(ed->priv.required->allocation_origin) + { + Con_Printf("Unreferenced edict found!\n Allocated at: %s\n", ed->priv.required->allocation_origin); + PRVM_ED_Print(prog, ed, NULL); + Con_Print("\n"); + leaked = true; + } + + ed->priv.required->mark = 0; // clear marks again when done + } + + for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i) + { + prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i); + if(stringbuffer) + if(stringbuffer->origin) + { + Con_Printf("Open string buffer handle found!\n Allocated at: %s\n", stringbuffer->origin); + leaked = true; + } + } + + for(i = 0; i < PRVM_MAX_OPENFILES; ++i) + { + if(prog->openfiles[i]) + if(prog->openfiles_origin[i]) + { + Con_Printf("Open file handle found!\n Allocated at: %s\n", prog->openfiles_origin[i]); + leaked = true; + } + } + + for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i) + { + if(prog->opensearches[i]) + if(prog->opensearches_origin[i]) + { + Con_Printf("Open search handle found!\n Allocated at: %s\n", prog->opensearches_origin[i]); + leaked = true; + } + } + + if(!leaked) + Con_Printf("Congratulations. No leaks found.\n"); +} diff --git a/app/jni/prvm_exec.c b/app/jni/prvm_exec.c new file mode 100644 index 0000000..823c2d3 --- /dev/null +++ b/app/jni/prvm_exec.c @@ -0,0 +1,983 @@ +/* +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 "progsvm.h" + +const char *prvm_opnames[] = +{ +"^5DONE", + +"MUL_F", +"MUL_V", +"MUL_FV", +"MUL_VF", + +"DIV", + +"ADD_F", +"ADD_V", + +"SUB_F", +"SUB_V", + +"^2EQ_F", +"^2EQ_V", +"^2EQ_S", +"^2EQ_E", +"^2EQ_FNC", + +"^2NE_F", +"^2NE_V", +"^2NE_S", +"^2NE_E", +"^2NE_FNC", + +"^2LE", +"^2GE", +"^2LT", +"^2GT", + +"^6FIELD_F", +"^6FIELD_V", +"^6FIELD_S", +"^6FIELD_ENT", +"^6FIELD_FLD", +"^6FIELD_FNC", + +"^1ADDRESS", + +"STORE_F", +"STORE_V", +"STORE_S", +"STORE_ENT", +"STORE_FLD", +"STORE_FNC", + +"^1STOREP_F", +"^1STOREP_V", +"^1STOREP_S", +"^1STOREP_ENT", +"^1STOREP_FLD", +"^1STOREP_FNC", + +"^5RETURN", + +"^2NOT_F", +"^2NOT_V", +"^2NOT_S", +"^2NOT_ENT", +"^2NOT_FNC", + +"^5IF", +"^5IFNOT", + +"^3CALL0", +"^3CALL1", +"^3CALL2", +"^3CALL3", +"^3CALL4", +"^3CALL5", +"^3CALL6", +"^3CALL7", +"^3CALL8", + +"^1STATE", + +"^5GOTO", + +"^2AND", +"^2OR", + +"BITAND", +"BITOR" +}; + + + +//============================================================================= + +/* +================= +PRVM_PrintStatement +================= +*/ +extern cvar_t prvm_statementprofiling; +extern cvar_t prvm_timeprofiling; +static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) +{ + size_t i; + int opnum = (int)(s - prog->statements); + char valuebuf[MAX_INPUTLINE]; + + Con_Printf("s%i: ", opnum); + if( prog->statement_linenums ) + Con_Printf( "%s:%i: ", PRVM_GetString( prog, prog->xfunction->s_file ), prog->statement_linenums[ opnum ] ); + + if (prvm_statementprofiling.integer) + Con_Printf("%7.0f ", prog->statement_profile[s - prog->statements]); + + if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0])) + { + Con_Printf("%s ", prvm_opnames[s->op]); + i = strlen(prvm_opnames[s->op]); + // don't count a preceding color tag when padding the name + if (prvm_opnames[s->op][0] == STRING_COLOR_TAG) + i -= 2; + for ( ; i<10 ; i++) + Con_Print(" "); + } + if (s->operand[0] >= 0) Con_Printf( "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf))); + if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf))); + if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf))); + if (s->jumpabsolute >= 0) Con_Printf(", statement %i", s->jumpabsolute); + Con_Print("\n"); +} + +void PRVM_PrintFunctionStatements (prvm_prog_t *prog, const char *name) +{ + int i, firststatement, endstatement; + mfunction_t *func; + func = PRVM_ED_FindFunction (prog, name); + if (!func) + { + Con_Printf("%s progs: no function named %s\n", prog->name, name); + return; + } + firststatement = func->first_statement; + if (firststatement < 0) + { + Con_Printf("%s progs: function %s is builtin #%i\n", prog->name, name, -firststatement); + return; + } + + // find the end statement + endstatement = prog->numstatements; + for (i = 0;i < prog->numfunctions;i++) + if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement) + endstatement = prog->functions[i].first_statement; + + // now print the range of statements + Con_Printf("%s progs: disassembly of function %s (statements %i-%i, locals %i-%i):\n", prog->name, name, firststatement, endstatement, func->parm_start, func->parm_start + func->locals - 1); + prog->xfunction = func; + for (i = firststatement;i < endstatement;i++) + { + PRVM_PrintStatement(prog, prog->statements + i); + prog->statement_profile[i] = 0; + } +} + +/* +============ +PRVM_PrintFunction_f + +============ +*/ +void PRVM_PrintFunction_f (void) +{ + prvm_prog_t *prog; + if (Cmd_Argc() != 3) + { + Con_Printf("usage: prvm_printfunction \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + PRVM_PrintFunctionStatements(prog, Cmd_Argv(2)); +} + +/* +============ +PRVM_StackTrace +============ +*/ +void PRVM_StackTrace (prvm_prog_t *prog) +{ + mfunction_t *f; + int i; + + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + for (i = prog->depth;i > 0;i--) + { + f = prog->stack[i].f; + + if (!f) + Con_Print("\n"); + else + { + if (prog->statement_linenums) + Con_Printf("%12s:%i : %s : statement %i\n", PRVM_GetString(prog, f->s_file), prog->statement_linenums[prog->stack[i].s], PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + else + Con_Printf("%12s : %s : statement %i\n", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement); + } + } +} + +void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize) +{ + mfunction_t *f; + int i; + char vabuf[1024]; + + if(prog) + { + dpsnprintf(buf, bufsize, "(%s) ", prog->name); + } + else + { + strlcpy(buf, "", bufsize); + return; + } + + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + for (i = prog->depth;i > 0;i--) + { + f = prog->stack[i].f; + + if(strlcat(buf, + f + ? va(vabuf, sizeof(vabuf), "%s:%s(%i) ", PRVM_GetString(prog, f->s_file), PRVM_GetString(prog, f->s_name), prog->stack[i].s - f->first_statement) + : " ", + bufsize + ) >= bufsize) + break; + } +} + + +static void PRVM_CallProfile (prvm_prog_t *prog) +{ + mfunction_t *f, *best; + int i; + double max; + double sum; + double newprofiletime; + + Con_Printf( "%s Call Profile:\n", prog->name ); + + sum = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; inumfunctions ; i++) + { + f = &prog->functions[i]; + if (max < f->totaltime) + { + max = f->totaltime; + best = f; + } + } + if (best) + { + sum += best->totaltime; + Con_Printf("%9.4f %s\n", best->totaltime, PRVM_GetString(prog, best->s_name)); + best->totaltime = 0; + } + } while (best); + + newprofiletime = Sys_DirtyTime(); + Con_Printf("Total time since last profile reset: %9.4f\n", newprofiletime - prog->profiletime); + Con_Printf(" - used by QC code of this VM: %9.4f\n", sum); + + prog->profiletime = newprofiletime; +} + +void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby) +{ + mfunction_t *f, *best; + int i, num; + double max; + + if(!prvm_timeprofiling.integer) + mintime *= 10000000; // count each statement as about 0.1µs + + if(prvm_timeprofiling.integer) + Con_Printf( "%s Profile:\n[CallCount] [Time] [BuiltinTm] [Statement] [BuiltinCt] [TimeTotal] [StmtTotal] [BltnTotal] [self]\n", prog->name ); + // 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 12345678901 123.45% + else + Con_Printf( "%s Profile:\n[CallCount] [Statement] [BuiltinCt] [StmtTotal] [BltnTotal] [self]\n", prog->name ); + // 12345678901 12345678901 12345678901 12345678901 12345678901 123.45% + + num = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; inumfunctions ; i++) + { + f = &prog->functions[i]; + if(prvm_timeprofiling.integer) + { + if(sortby) + { + if(f->first_statement < 0) + { + if (max < f->tprofile) + { + max = f->tprofile; + best = f; + } + } + else + { + if (max < f->tprofile_total) + { + max = f->tprofile_total; + best = f; + } + } + } + else + { + if (max < f->tprofile + f->tbprofile) + { + max = f->tprofile + f->tbprofile; + best = f; + } + } + } + else + { + if(sortby) + { + if (max < f->profile_total + f->builtinsprofile_total + f->callcount) + { + max = f->profile_total + f->builtinsprofile_total + f->callcount; + best = f; + } + } + else + { + if (max < f->profile + f->builtinsprofile + f->callcount) + { + max = f->profile + f->builtinsprofile + f->callcount; + best = f; + } + } + } + } + if (best) + { + if (num < maxfunctions && max > mintime) + { + if(prvm_timeprofiling.integer) + { + if (best->first_statement < 0) + Con_Printf("%11.0f %11.6f ------------- builtin ------------- %11.6f ----------- builtin ----------- %s\n", best->callcount, best->tprofile, best->tprofile, PRVM_GetString(prog, best->s_name)); + // %11.6f 12345678901 12345678901 12345678901 %11.6f 12345678901 12345678901 123.45% + else + Con_Printf("%11.0f %11.6f %11.6f %11.0f %11.0f %11.6f %11.0f %11.0f %6.2f%% %s\n", best->callcount, best->tprofile, best->tbprofile, best->profile, best->builtinsprofile, best->tprofile_total, best->profile_total, best->builtinsprofile_total, (best->tprofile_total > 0) ? ((best->tprofile) * 100.0 / (best->tprofile_total)) : -99.99, PRVM_GetString(prog, best->s_name)); + } + else + { + if (best->first_statement < 0) + Con_Printf("%11.0f ----------------------- builtin ----------------------- %s\n", best->callcount, PRVM_GetString(prog, best->s_name)); + // 12345678901 12345678901 12345678901 12345678901 123.45% + else + Con_Printf("%11.0f %11.0f %11.0f %11.0f %11.0f %6.2f%% %s\n", best->callcount, best->profile, best->builtinsprofile, best->profile_total, best->builtinsprofile_total, (best->profile + best->builtinsprofile) * 100.0 / (best->profile_total + best->builtinsprofile_total), PRVM_GetString(prog, best->s_name)); + } + } + num++; + best->profile = 0; + best->tprofile = 0; + best->tbprofile = 0; + best->builtinsprofile = 0; + best->profile_total = 0; + best->tprofile_total = 0; + best->builtinsprofile_total = 0; + best->callcount = 0; + } + } while (best); +} + +/* +============ +PRVM_CallProfile_f + +============ +*/ +void PRVM_CallProfile_f (void) +{ + prvm_prog_t *prog; + if (Cmd_Argc() != 2) + { + Con_Print("prvm_callprofile \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + PRVM_CallProfile(prog); +} + +/* +============ +PRVM_Profile_f + +============ +*/ +void PRVM_Profile_f (void) +{ + prvm_prog_t *prog; + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_profile \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + PRVM_Profile(prog, howmany, 0, 0); +} + +void PRVM_ChildProfile_f (void) +{ + prvm_prog_t *prog; + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_childprofile \n"); + return; + } + + if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1)))) + return; + + PRVM_Profile(prog, howmany, 0, 1); +} + +void PRVM_PrintState(prvm_prog_t *prog, int stack_index) +{ + int i; + mfunction_t *func = prog->xfunction; + int st = prog->xstatement; + if (stack_index > 0 && stack_index <= prog->depth) + { + func = prog->stack[prog->depth - stack_index].f; + st = prog->stack[prog->depth - stack_index].s; + } + if (prog->statestring) + { + Con_Printf("Caller-provided information: %s\n", prog->statestring); + } + if (func) + { + for (i = -7; i <= 0;i++) + if (st + i >= func->first_statement) + PRVM_PrintStatement(prog, prog->statements + st + i); + } + PRVM_StackTrace(prog); +} + +extern cvar_t prvm_errordump; +void PRVM_Crash(prvm_prog_t *prog) +{ + char vabuf[1024]; + if (prog == NULL) + return; + if (!prog->loaded) + return; + + PRVM_serverfunction(SV_Shutdown) = 0; // don't call SV_Shutdown on crash + + if( prog->depth > 0 ) + { + Con_Printf("QuakeC crash report for %s:\n", prog->name); + PRVM_PrintState(prog, 0); + } + + if(prvm_errordump.integer) + { + // make a savegame + Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "crash-%s.dmp", prog->name)); + } + + // dump the stack so host_error can shutdown functions + prog->depth = 0; + prog->localstack_used = 0; + + // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?) + prog->tempstringsbuf.cursize = 0; + + // reset the prog pointer + prog = NULL; +} + +/* +============================================================================ +PRVM_ExecuteProgram + +The interpretation main loop +============================================================================ +*/ + +/* +==================== +PRVM_EnterFunction + +Returns the new program statement counter +==================== +*/ +static int PRVM_EnterFunction (prvm_prog_t *prog, mfunction_t *f) +{ + int i, j, c, o; + + if (!f) + prog->error_cmd("PRVM_EnterFunction: NULL function in %s", prog->name); + + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + prog->stack[prog->depth].profile_acc = -f->profile; + prog->stack[prog->depth].tprofile_acc = -f->tprofile + -f->tbprofile; + prog->stack[prog->depth].builtinsprofile_acc = -f->builtinsprofile; + prog->depth++; + if (prog->depth >=PRVM_MAX_STACK_DEPTH) + prog->error_cmd("stack overflow"); + +// save off any locals that the new function steps on + c = f->locals; + if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE) + prog->error_cmd("PRVM_ExecuteProgram: locals stack overflow in %s", prog->name); + + for (i=0 ; i < c ; i++) + prog->localstack[prog->localstack_used+i] = prog->globals.ip[f->parm_start + i]; + prog->localstack_used += c; + +// copy parameters + o = f->parm_start; + for (i=0 ; inumparms ; i++) + { + for (j=0 ; jparm_size[i] ; j++) + { + prog->globals.ip[o] = prog->globals.ip[OFS_PARM0+i*3+j]; + o++; + } + } + + ++f->recursion; + prog->xfunction = f; + return f->first_statement - 1; // offset the s++ +} + +/* +==================== +PRVM_LeaveFunction +==================== +*/ +static int PRVM_LeaveFunction (prvm_prog_t *prog) +{ + int i, c; + mfunction_t *f; + + if (prog->depth <= 0) + prog->error_cmd("prog stack underflow in %s", prog->name); + + if (!prog->xfunction) + prog->error_cmd("PR_LeaveFunction: NULL function in %s", prog->name); +// restore locals from the stack + c = prog->xfunction->locals; + prog->localstack_used -= c; + if (prog->localstack_used < 0) + prog->error_cmd("PRVM_ExecuteProgram: locals stack underflow in %s", prog->name); + + for (i=0 ; i < c ; i++) + prog->globals.ip[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; + +// up stack + prog->depth--; + f = prog->xfunction; + --f->recursion; + prog->xfunction = prog->stack[prog->depth].f; + prog->stack[prog->depth].profile_acc += f->profile; + prog->stack[prog->depth].tprofile_acc += f->tprofile + f->tbprofile; + prog->stack[prog->depth].builtinsprofile_acc += f->builtinsprofile; + if(prog->depth > 0) + { + prog->stack[prog->depth-1].profile_acc += prog->stack[prog->depth].profile_acc; + prog->stack[prog->depth-1].tprofile_acc += prog->stack[prog->depth].tprofile_acc; + prog->stack[prog->depth-1].builtinsprofile_acc += prog->stack[prog->depth].builtinsprofile_acc; + } + if(!f->recursion) + { + // if f is already on the call stack... + // we cannot add this profile data to it now + // or we would add it more than once + // so, let's only add to the function's profile if it is the outermost call + f->profile_total += prog->stack[prog->depth].profile_acc; + f->tprofile_total += prog->stack[prog->depth].tprofile_acc; + f->builtinsprofile_total += prog->stack[prog->depth].builtinsprofile_acc; + } + + return prog->stack[prog->depth].s; +} + +void PRVM_Init_Exec(prvm_prog_t *prog) +{ + // dump the stack + prog->depth = 0; + prog->localstack_used = 0; + // reset the string table + // nothing here yet +} + +#define OPA ((prvm_eval_t *)&prog->globals.fp[st->operand[0]]) +#define OPB ((prvm_eval_t *)&prog->globals.fp[st->operand[1]]) +#define OPC ((prvm_eval_t *)&prog->globals.fp[st->operand[2]]) +extern cvar_t prvm_traceqc; +extern cvar_t prvm_statementprofiling; +extern qboolean prvm_runawaycheck; + +#ifdef PROFILING +/* +==================== +MVM_ExecuteProgram +==================== +*/ +void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) +{ + mstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; + + calltime = Sys_DirtyTime(); + + if (!fnum || fnum >= (unsigned int)prog->numfunctions) + { + if (PRVM_allglobaledict(self)) + PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL); + prog->error_cmd("MVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction(prog, f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + starttm = calltime; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0) + { +#define PRVMSLOWINTERPRETER 1 + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMSLOWINTERPRETER + } + else + { + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } + } + +cleanup: + if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("MVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; + f->totaltime += tm; + + if (prog == SVVM_prog) + SV_FlushBroadcastMessages(); +} + +/* +==================== +CLVM_ExecuteProgram +==================== +*/ +void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) +{ + mstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; + + calltime = Sys_DirtyTime(); + + if (!fnum || fnum >= (unsigned int)prog->numfunctions) + { + if (PRVM_allglobaledict(self)) + PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL); + prog->error_cmd("CLVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction(prog, f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + starttm = calltime; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0) + { +#define PRVMSLOWINTERPRETER 1 + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMSLOWINTERPRETER + } + else + { + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } + } + +cleanup: + if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("CLVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; + f->totaltime += tm; + + if (prog == SVVM_prog) + SV_FlushBroadcastMessages(); +} +#endif + +/* +==================== +SVVM_ExecuteProgram +==================== +*/ +#ifdef PROFILING +void SVVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) +#else +void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessage) +#endif +{ + mstatement_t *st, *startst; + mfunction_t *f, *newf; + prvm_edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + int restorevm_tempstringsbuf_cursize; + double calltime; + double tm, starttm; + prvm_vec_t tempfloat; + // these may become out of date when a builtin is called, and are updated accordingly + prvm_vec_t *cached_edictsfields = prog->edictsfields; + unsigned int cached_entityfields = prog->entityfields; + unsigned int cached_entityfields_3 = prog->entityfields - 3; + unsigned int cached_entityfieldsarea = prog->entityfieldsarea; + unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + unsigned int cached_max_edicts = prog->max_edicts; + // these do not change + mstatement_t *cached_statements = prog->statements; + qboolean cached_allowworldwrites = prog->allowworldwrites; + unsigned int cached_flag = prog->flag; + + calltime = Sys_DirtyTime(); + + if (!fnum || fnum >= (unsigned int)prog->numfunctions) + { + if (PRVM_allglobaledict(self)) + PRVM_ED_Print(prog, PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self)), NULL); + prog->error_cmd("SVVM_ExecuteProgram: %s", errormessage); + } + + f = &prog->functions[fnum]; + + // after executing this function, delete all tempstrings it created + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + + prog->trace = prvm_traceqc.integer; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + +// make a stack frame + st = &prog->statements[PRVM_EnterFunction(prog, f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + starttm = calltime; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + if (prvm_statementprofiling.integer || prog->trace || prog->watch_global >= 0 || prog->watch_edict >= 0 || prog->break_statement >= 0) + { +#define PRVMSLOWINTERPRETER 1 + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } +#undef PRVMSLOWINTERPRETER + } + else + { + if (prvm_timeprofiling.integer) + { +#define PRVMTIMEPROFILING 1 +#include "prvm_execprogram.h" +#undef PRVMTIMEPROFILING + } + else + { +#include "prvm_execprogram.h" + } + } + +cleanup: + if (developer_insane.integer && prog->tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize) + Con_DPrintf("SVVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog, prog->functions[fnum].s_name), prog->tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize); + // delete tempstrings created by this function + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + + tm = Sys_DirtyTime() - calltime;if (tm < 0 || tm >= 1800) tm = 0; + f->totaltime += tm; + + if (prog == SVVM_prog) + SV_FlushBroadcastMessages(); +} diff --git a/app/jni/prvm_execprogram.h b/app/jni/prvm_execprogram.h new file mode 100644 index 0000000..02b444b --- /dev/null +++ b/app/jni/prvm_execprogram.h @@ -0,0 +1,744 @@ +#ifdef PRVMTIMEPROFILING +#define PreError() \ + prog->xstatement = st - cached_statements; \ + tm = Sys_DirtyTime(); \ + prog->xfunction->profile += (st - startst); \ + prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; +#else +#define PreError() \ + prog->xstatement = st - cached_statements; \ + prog->xfunction->profile += (st - startst); +#endif + +// This code isn't #ifdef/#define protectable, don't try. + +#if PRVMSLOWINTERPRETER + { + if (prog->watch_global_type != ev_void) + { + prvm_eval_t *f = PRVM_GLOBALFIELDVALUE(prog->watch_global); + prog->xstatement = st + 1 - cached_statements; + PRVM_Watchpoint(prog, 1, "Global watchpoint hit by engine", prog->watch_global_type, &prog->watch_global_value, f); + } + if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts) + { + prvm_eval_t *f = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field); + prog->xstatement = st + 1 - cached_statements; + PRVM_Watchpoint(prog, 1, "Entityfield watchpoint hit by engine", prog->watch_field_type, &prog->watch_edictfield_value, f); + } + } +#endif + + while (1) + { + st++; + +#if PRVMSLOWINTERPRETER + if (prog->trace) + PRVM_PrintStatement(prog, st); + prog->statement_profile[st - cached_statements]++; + if (prog->break_statement >= 0) + if ((st - cached_statements) == prog->break_statement) + { + prog->xstatement = st - cached_statements; + PRVM_Breakpoint(prog, prog->break_stack_index, "Breakpoint hit"); + } +#endif + + switch (st->op) + { + case OP_ADD_F: + OPC->_float = OPA->_float + OPB->_float; + break; + case OP_ADD_V: + OPC->vector[0] = OPA->vector[0] + OPB->vector[0]; + OPC->vector[1] = OPA->vector[1] + OPB->vector[1]; + OPC->vector[2] = OPA->vector[2] + OPB->vector[2]; + break; + case OP_SUB_F: + OPC->_float = OPA->_float - OPB->_float; + break; + case OP_SUB_V: + OPC->vector[0] = OPA->vector[0] - OPB->vector[0]; + OPC->vector[1] = OPA->vector[1] - OPB->vector[1]; + OPC->vector[2] = OPA->vector[2] - OPB->vector[2]; + break; + case OP_MUL_F: + OPC->_float = OPA->_float * OPB->_float; + break; + case OP_MUL_V: + OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2]; + break; + case OP_MUL_FV: + tempfloat = OPA->_float; + OPC->vector[0] = tempfloat * OPB->vector[0]; + OPC->vector[1] = tempfloat * OPB->vector[1]; + OPC->vector[2] = tempfloat * OPB->vector[2]; + break; + case OP_MUL_VF: + tempfloat = OPB->_float; + OPC->vector[0] = tempfloat * OPA->vector[0]; + OPC->vector[1] = tempfloat * OPA->vector[1]; + OPC->vector[2] = tempfloat * OPA->vector[2]; + break; + case OP_DIV_F: + if( OPB->_float != 0.0f ) + { + OPC->_float = OPA->_float / OPB->_float; + } + else + { + if (developer.integer) + { + prog->xfunction->profile += (st - startst); + startst = st; + prog->xstatement = st - cached_statements; + VM_Warning(prog, "Attempted division by zero in %s\n", prog->name ); + } + OPC->_float = 0.0f; + } + break; + case OP_BITAND: + OPC->_float = (prvm_int_t)OPA->_float & (prvm_int_t)OPB->_float; + break; + case OP_BITOR: + OPC->_float = (prvm_int_t)OPA->_float | (prvm_int_t)OPB->_float; + break; + case OP_GE: + OPC->_float = OPA->_float >= OPB->_float; + break; + case OP_LE: + OPC->_float = OPA->_float <= OPB->_float; + break; + case OP_GT: + OPC->_float = OPA->_float > OPB->_float; + break; + case OP_LT: + OPC->_float = OPA->_float < OPB->_float; + break; + case OP_AND: + OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) && FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add AND_I to be used by fteqcc for anything not a float + break; + case OP_OR: + OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) || FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add OR_I to be used by fteqcc for anything not a float + break; + case OP_NOT_F: + OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int); + break; + case OP_NOT_V: + OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]; + break; + case OP_NOT_S: + OPC->_float = !OPA->string || !*PRVM_GetString(prog, OPA->string); + break; + case OP_NOT_FNC: + OPC->_float = !OPA->function; + break; + case OP_NOT_ENT: + OPC->_float = (OPA->edict == 0); + break; + case OP_EQ_F: + OPC->_float = OPA->_float == OPB->_float; + break; + case OP_EQ_V: + OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]); + break; + case OP_EQ_S: + OPC->_float = !strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string)); + break; + case OP_EQ_E: + OPC->_float = OPA->_int == OPB->_int; + break; + case OP_EQ_FNC: + OPC->_float = OPA->function == OPB->function; + break; + case OP_NE_F: + OPC->_float = OPA->_float != OPB->_float; + break; + case OP_NE_V: + OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]); + break; + case OP_NE_S: + OPC->_float = strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string)); + break; + case OP_NE_E: + OPC->_float = OPA->_int != OPB->_int; + break; + case OP_NE_FNC: + OPC->_float = OPA->function != OPB->function; + break; + + //================== + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: // integers + case OP_STORE_S: + case OP_STORE_FNC: // pointers + OPB->_int = OPA->_int; + break; + case OP_STORE_V: + OPB->ivector[0] = OPA->ivector[0]; + OPB->ivector[1] = OPA->ivector[1]; + OPB->ivector[2] = OPA->ivector[2]; + break; + + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: // integers + case OP_STOREP_S: + case OP_STOREP_FNC: // pointers + if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields) + { + if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea) + { + PreError(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; + } + if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites) + { + prog->xstatement = st - cached_statements; + VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name); + } + } + ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + ptr->_int = OPA->_int; + break; + case OP_STOREP_V: + if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3) + { + if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3) + { + PreError(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; + } + if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites) + { + prog->xstatement = st - cached_statements; + VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name); + } + } + ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + ptr->ivector[0] = OPA->ivector[0]; + ptr->ivector[1] = OPA->ivector[1]; + ptr->ivector[2] = OPA->ivector[2]; + break; + + case OP_ADDRESS: + if ((prvm_uint_t)OPA->edict >= cached_max_edicts) + { + PreError(); + prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name); + goto cleanup; + } + if ((prvm_uint_t)OPB->_int >= cached_entityfields) + { + PreError(); + prog->error_cmd("%s attempted to address an invalid field (%i) in an edict", prog->name, (int)OPB->_int); + goto cleanup; + } +#if 0 + if (OPA->edict == 0 && !cached_allowworldwrites) + { + PreError(); + prog->error_cmd("forbidden assignment to null/world entity in %s", prog->name); + goto cleanup; + } +#endif + OPC->_int = OPA->edict * cached_entityfields + OPB->_int; + break; + + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + if ((prvm_uint_t)OPA->edict >= cached_max_edicts) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name); + goto cleanup; + } + if ((prvm_uint_t)OPB->_int >= cached_entityfields) + { + PreError(); + prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->_int = ((prvm_eval_t *)(ed->fields.ip + OPB->_int))->_int; + break; + + case OP_LOAD_V: + if ((prvm_uint_t)OPA->edict >= cached_max_edicts) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name); + goto cleanup; + } + if ((prvm_uint_t)OPB->_int > cached_entityfields_3) + { + PreError(); + prog->error_cmd("%s attempted to read an invalid field in an edict (%i)", prog->name, (int)OPB->_int); + goto cleanup; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + ptr = (prvm_eval_t *)(ed->fields.ip + OPB->_int); + OPC->ivector[0] = ptr->ivector[0]; + OPC->ivector[1] = ptr->ivector[1]; + OPC->ivector[2] = ptr->ivector[2]; + break; + + //================== + + case OP_IFNOT: + if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int)) + // TODO add an "int-if", and change this one to OPA->_float + // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) + // and entity, string, field values can never have that value + { + prog->xfunction->profile += (st - startst); + st = cached_statements + st->jumpabsolute - 1; // offset the st++ + startst = st; + // no bounds check needed, it is done when loading progs + if (++jumpcount == 10000000 && prvm_runawaycheck) + { + prog->xstatement = st - cached_statements; + PRVM_Profile(prog, 1<<30, 1000000, 0); + prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); + } + } + break; + + case OP_IF: + if(FLOAT_IS_TRUE_FOR_INT(OPA->_int)) + // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float + // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) + // and entity, string, field values can never have that value + { + prog->xfunction->profile += (st - startst); + st = cached_statements + st->jumpabsolute - 1; // offset the st++ + startst = st; + // no bounds check needed, it is done when loading progs + if (++jumpcount == 10000000 && prvm_runawaycheck) + { + prog->xstatement = st - cached_statements; + PRVM_Profile(prog, 1<<30, 0.01, 0); + prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); + } + } + break; + + case OP_GOTO: + prog->xfunction->profile += (st - startst); + st = cached_statements + st->jumpabsolute - 1; // offset the st++ + startst = st; + // no bounds check needed, it is done when loading progs + if (++jumpcount == 10000000 && prvm_runawaycheck) + { + prog->xstatement = st - cached_statements; + PRVM_Profile(prog, 1<<30, 0.01, 0); + prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); + } + 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: +#ifdef PRVMTIMEPROFILING + tm = Sys_DirtyTime(); + prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; + starttm = tm; +#endif + prog->xfunction->profile += (st - startst); + startst = st; + prog->xstatement = st - cached_statements; + prog->argc = st->op - OP_CALL0; + if (!OPA->function) + prog->error_cmd("NULL function in %s", prog->name); + + if(!OPA->function || OPA->function < 0 || OPA->function >= prog->numfunctions) + { + PreError(); + prog->error_cmd("%s CALL outside the program", prog->name); + goto cleanup; + } + + newf = &prog->functions[OPA->function]; + newf->callcount++; + + if (newf->first_statement < 0) + { + // negative first_statement values are built in functions + int builtinnumber = -newf->first_statement; + prog->xfunction->builtinsprofile++; + if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber]) + { + prog->builtins[builtinnumber](prog); +#ifdef PRVMTIMEPROFILING + tm = Sys_DirtyTime(); + newf->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; + prog->xfunction->tbprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; + starttm = tm; +#endif + // builtins may cause ED_Alloc() to be called, update cached variables + cached_edictsfields = prog->edictsfields; + cached_entityfields = prog->entityfields; + cached_entityfields_3 = prog->entityfields - 3; + cached_entityfieldsarea = prog->entityfieldsarea; + cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; + cached_entityfieldsarea_3 = prog->entityfieldsarea - 3; + cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3; + cached_max_edicts = prog->max_edicts; + // these do not change + //cached_statements = prog->statements; + //cached_allowworldwrites = prog->allowworldwrites; + //cached_flag = prog->flag; + // if prog->trace changed we need to change interpreter path + if (prog->trace != cachedpr_trace) + goto chooseexecprogram; + } + else + prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name); + } + else + st = cached_statements + PRVM_EnterFunction(prog, newf); + startst = st; + break; + + case OP_DONE: + case OP_RETURN: +#ifdef PRVMTIMEPROFILING + tm = Sys_DirtyTime(); + prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; + starttm = tm; +#endif + prog->xfunction->profile += (st - startst); + prog->xstatement = st - cached_statements; + + prog->globals.ip[OFS_RETURN ] = prog->globals.ip[st->operand[0] ]; + prog->globals.ip[OFS_RETURN+1] = prog->globals.ip[st->operand[0]+1]; + prog->globals.ip[OFS_RETURN+2] = prog->globals.ip[st->operand[0]+2]; + + st = cached_statements + PRVM_LeaveFunction(prog); + startst = st; + if (prog->depth <= exitdepth) + goto cleanup; // all done + break; + + case OP_STATE: + if(cached_flag & PRVM_OP_STATE) + { + ed = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self)); + PRVM_gameedictfloat(ed,nextthink) = PRVM_gameglobalfloat(time) + 0.1; + PRVM_gameedictfloat(ed,frame) = OPA->_float; + PRVM_gameedictfunction(ed,think) = OPB->function; + } + else + { + PreError(); + prog->xstatement = st - cached_statements; + prog->error_cmd("OP_STATE not supported by %s", prog->name); + } + break; + +// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized +/* + case OP_ADD_I: + OPC->_int = OPA->_int + OPB->_int; + break; + case OP_ADD_IF: + OPC->_int = OPA->_int + (prvm_int_t) OPB->_float; + break; + case OP_ADD_FI: + OPC->_float = OPA->_float + (prvm_vec_t) OPB->_int; + break; + case OP_SUB_I: + OPC->_int = OPA->_int - OPB->_int; + break; + case OP_SUB_IF: + OPC->_int = OPA->_int - (prvm_int_t) OPB->_float; + break; + case OP_SUB_FI: + OPC->_float = OPA->_float - (prvm_vec_t) OPB->_int; + break; + case OP_MUL_I: + OPC->_int = OPA->_int * OPB->_int; + break; + case OP_MUL_IF: + OPC->_int = OPA->_int * (prvm_int_t) OPB->_float; + break; + case OP_MUL_FI: + OPC->_float = OPA->_float * (prvm_vec_t) OPB->_int; + break; + case OP_MUL_VI: + OPC->vector[0] = (prvm_vec_t) OPB->_int * OPA->vector[0]; + OPC->vector[1] = (prvm_vec_t) OPB->_int * OPA->vector[1]; + OPC->vector[2] = (prvm_vec_t) OPB->_int * OPA->vector[2]; + break; + case OP_DIV_VF: + { + float temp = 1.0f / OPB->_float; + OPC->vector[0] = temp * OPA->vector[0]; + OPC->vector[1] = temp * OPA->vector[1]; + OPC->vector[2] = temp * OPA->vector[2]; + } + break; + case OP_DIV_I: + OPC->_int = OPA->_int / OPB->_int; + break; + case OP_DIV_IF: + OPC->_int = OPA->_int / (prvm_int_t) OPB->_float; + break; + case OP_DIV_FI: + OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int; + break; + case OP_CONV_IF: + OPC->_float = OPA->_int; + break; + case OP_CONV_FI: + OPC->_int = OPA->_float; + break; + case OP_BITAND_I: + OPC->_int = OPA->_int & OPB->_int; + break; + case OP_BITOR_I: + OPC->_int = OPA->_int | OPB->_int; + break; + case OP_BITAND_IF: + OPC->_int = OPA->_int & (prvm_int_t)OPB->_float; + break; + case OP_BITOR_IF: + OPC->_int = OPA->_int | (prvm_int_t)OPB->_float; + break; + case OP_BITAND_FI: + OPC->_float = (prvm_int_t)OPA->_float & OPB->_int; + break; + case OP_BITOR_FI: + OPC->_float = (prvm_int_t)OPA->_float | OPB->_int; + break; + case OP_GE_I: + OPC->_float = OPA->_int >= OPB->_int; + break; + case OP_LE_I: + OPC->_float = OPA->_int <= OPB->_int; + break; + case OP_GT_I: + OPC->_float = OPA->_int > OPB->_int; + break; + case OP_LT_I: + OPC->_float = OPA->_int < OPB->_int; + break; + case OP_AND_I: + OPC->_float = OPA->_int && OPB->_int; + break; + case OP_OR_I: + OPC->_float = OPA->_int || OPB->_int; + break; + case OP_GE_IF: + OPC->_float = (prvm_vec_t)OPA->_int >= OPB->_float; + break; + case OP_LE_IF: + OPC->_float = (prvm_vec_t)OPA->_int <= OPB->_float; + break; + case OP_GT_IF: + OPC->_float = (prvm_vec_t)OPA->_int > OPB->_float; + break; + case OP_LT_IF: + OPC->_float = (prvm_vec_t)OPA->_int < OPB->_float; + break; + case OP_AND_IF: + OPC->_float = (prvm_vec_t)OPA->_int && OPB->_float; + break; + case OP_OR_IF: + OPC->_float = (prvm_vec_t)OPA->_int || OPB->_float; + break; + case OP_GE_FI: + OPC->_float = OPA->_float >= (prvm_vec_t)OPB->_int; + break; + case OP_LE_FI: + OPC->_float = OPA->_float <= (prvm_vec_t)OPB->_int; + break; + case OP_GT_FI: + OPC->_float = OPA->_float > (prvm_vec_t)OPB->_int; + break; + case OP_LT_FI: + OPC->_float = OPA->_float < (prvm_vec_t)OPB->_int; + break; + case OP_AND_FI: + OPC->_float = OPA->_float && (prvm_vec_t)OPB->_int; + break; + case OP_OR_FI: + OPC->_float = OPA->_float || (prvm_vec_t)OPB->_int; + break; + case OP_NOT_I: + OPC->_float = !OPA->_int; + break; + case OP_EQ_I: + OPC->_float = OPA->_int == OPB->_int; + break; + case OP_EQ_IF: + OPC->_float = (prvm_vec_t)OPA->_int == OPB->_float; + break; + case OP_EQ_FI: + OPC->_float = OPA->_float == (prvm_vec_t)OPB->_int; + break; + case OP_NE_I: + OPC->_float = OPA->_int != OPB->_int; + break; + case OP_NE_IF: + OPC->_float = (prvm_vec_t)OPA->_int != OPB->_float; + break; + case OP_NE_FI: + OPC->_float = OPA->_float != (prvm_vec_t)OPB->_int; + break; + case OP_STORE_I: + OPB->_int = OPA->_int; + break; + case OP_STOREP_I: +#if PRBOUNDSCHECK + if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize) + { + PreError(); + prog->error_cmd("%s Progs attempted to write to an out of bounds edict", prog->name); + goto cleanup; + } +#endif + ptr = (prvm_eval_t *)(prog->edictsfields + OPB->_int); + ptr->_int = OPA->_int; + break; + case OP_LOAD_I: +#if PRBOUNDSCHECK + if (OPA->edict < 0 || OPA->edict >= prog->max_edicts) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name); + goto cleanup; + } + if (OPB->_int < 0 || OPB->_int >= progs->entityfields) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an invalid field in an edict", prog->name); + goto cleanup; + } +#endif + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->_int = ((prvm_eval_t *)((int *)ed->v + OPB->_int))->_int; + break; + + case OP_GSTOREP_I: + case OP_GSTOREP_F: + case OP_GSTOREP_ENT: + case OP_GSTOREP_FLD: // integers + case OP_GSTOREP_S: + case OP_GSTOREP_FNC: // pointers +#if PRBOUNDSCHECK + if (OPB->_int < 0 || OPB->_int >= pr_globaldefs) + { + PreError(); + prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name); + goto cleanup; + } +#endif + pr_iglobals[OPB->_int] = OPA->_int; + break; + case OP_GSTOREP_V: +#if PRBOUNDSCHECK + if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs) + { + PreError(); + prog->error_cmd("%s Progs attempted to write to an invalid indexed global", prog->name); + goto cleanup; + } +#endif + pr_iglobals[OPB->_int ] = OPA->ivector[0]; + pr_iglobals[OPB->_int+1] = OPA->ivector[1]; + pr_iglobals[OPB->_int+2] = OPA->ivector[2]; + break; + + case OP_GADDRESS: + i = OPA->_int + (prvm_int_t) OPB->_float; +#if PRBOUNDSCHECK + if (i < 0 || i >= pr_globaldefs) + { + PreError(); + prog->error_cmd("%s Progs attempted to address an out of bounds global", prog->name); + goto cleanup; + } +#endif + OPC->_int = pr_iglobals[i]; + break; + + case OP_GLOAD_I: + case OP_GLOAD_F: + case OP_GLOAD_FLD: + case OP_GLOAD_ENT: + case OP_GLOAD_S: + case OP_GLOAD_FNC: +#if PRBOUNDSCHECK + if (OPA->_int < 0 || OPA->_int >= pr_globaldefs) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name); + goto cleanup; + } +#endif + OPC->_int = pr_iglobals[OPA->_int]; + break; + + case OP_GLOAD_V: +#if PRBOUNDSCHECK + if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs) + { + PreError(); + prog->error_cmd("%s Progs attempted to read an invalid indexed global", prog->name); + goto cleanup; + } +#endif + OPC->ivector[0] = pr_iglobals[OPA->_int ]; + OPC->ivector[1] = pr_iglobals[OPA->_int+1]; + OPC->ivector[2] = pr_iglobals[OPA->_int+2]; + break; + + case OP_BOUNDCHECK: + if (OPA->_int < 0 || OPA->_int >= st->b) + { + PreError(); + prog->error_cmd("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", prog->name, st->b, st->c); + goto cleanup; + } + break; + +*/ + + default: + PreError(); + prog->error_cmd("Bad opcode %i in %s", st->op, prog->name); + goto cleanup; + } +#if PRVMSLOWINTERPRETER + { + if (prog->watch_global_type != ev_void) + { + prvm_eval_t *f = PRVM_GLOBALFIELDVALUE(prog->watch_global); + prog->xstatement = st - cached_statements; + PRVM_Watchpoint(prog, 0, "Global watchpoint hit", prog->watch_global_type, &prog->watch_global_value, f); + } + if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts) + { + prvm_eval_t *f = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field); + prog->xstatement = st - cached_statements; + PRVM_Watchpoint(prog, 0, "Entityfield watchpoint hit", prog->watch_field_type, &prog->watch_edictfield_value, f); + } + } +#endif + } + +#undef PreError diff --git a/app/jni/prvm_offsets.h b/app/jni/prvm_offsets.h new file mode 100644 index 0000000..440b3e4 --- /dev/null +++ b/app/jni/prvm_offsets.h @@ -0,0 +1,850 @@ +PRVM_DECLARE_clientfieldedict(aiment) +PRVM_DECLARE_clientfieldedict(chain) +PRVM_DECLARE_clientfieldedict(enemy) +PRVM_DECLARE_clientfieldedict(groundentity) +PRVM_DECLARE_clientfieldedict(owner) +PRVM_DECLARE_clientfieldedict(tag_entity) +PRVM_DECLARE_clientfieldfloat(alpha) +PRVM_DECLARE_clientfieldfloat(bouncefactor) +PRVM_DECLARE_clientfieldfloat(bouncestop) +PRVM_DECLARE_clientfieldfloat(colormap) +PRVM_DECLARE_clientfieldfloat(dphitcontentsmask) +PRVM_DECLARE_clientfieldfloat(drawmask) +PRVM_DECLARE_clientfieldfloat(effects) +PRVM_DECLARE_clientfieldfloat(entnum) +PRVM_DECLARE_clientfieldfloat(flags) +PRVM_DECLARE_clientfieldfloat(frame) +PRVM_DECLARE_clientfieldfloat(frame1time) +PRVM_DECLARE_clientfieldfloat(frame2) +PRVM_DECLARE_clientfieldfloat(frame2time) +PRVM_DECLARE_clientfieldfloat(frame3) +PRVM_DECLARE_clientfieldfloat(frame3time) +PRVM_DECLARE_clientfieldfloat(frame4) +PRVM_DECLARE_clientfieldfloat(frame4time) +PRVM_DECLARE_clientfieldfloat(gravity) +PRVM_DECLARE_clientfieldfloat(ideal_yaw) +PRVM_DECLARE_clientfieldfloat(idealpitch) +PRVM_DECLARE_clientfieldfloat(geomtype) +PRVM_DECLARE_clientfieldfloat(jointtype) +PRVM_DECLARE_clientfieldfloat(forcetype) +PRVM_DECLARE_clientfieldfloat(lerpfrac) +PRVM_DECLARE_clientfieldfloat(lerpfrac3) +PRVM_DECLARE_clientfieldfloat(lerpfrac4) +PRVM_DECLARE_clientfieldfloat(mass) +PRVM_DECLARE_clientfieldvector(massofs) +PRVM_DECLARE_clientfieldfloat(friction) +PRVM_DECLARE_clientfieldfloat(maxcontacts) +PRVM_DECLARE_clientfieldfloat(erp) +PRVM_DECLARE_clientfieldfloat(modelindex) +PRVM_DECLARE_clientfieldfloat(movetype) +PRVM_DECLARE_clientfieldfloat(nextthink) +PRVM_DECLARE_clientfieldfloat(pitch_speed) +PRVM_DECLARE_clientfieldfloat(pmove_flags) +PRVM_DECLARE_clientfieldfloat(renderflags) +PRVM_DECLARE_clientfieldfloat(scale) +PRVM_DECLARE_clientfieldvector(modelscale_vec) +PRVM_DECLARE_clientfieldfloat(shadertime) +PRVM_DECLARE_clientfieldfloat(skeletonindex) +PRVM_DECLARE_clientfieldfloat(skin) +PRVM_DECLARE_clientfieldfloat(solid) +PRVM_DECLARE_clientfieldfloat(tag_index) +PRVM_DECLARE_clientfieldfloat(userwavefunc_param0) +PRVM_DECLARE_clientfieldfloat(userwavefunc_param1) +PRVM_DECLARE_clientfieldfloat(userwavefunc_param2) +PRVM_DECLARE_clientfieldfloat(userwavefunc_param3) +PRVM_DECLARE_clientfieldfloat(yaw_speed) +PRVM_DECLARE_clientfieldfunction(blocked) +PRVM_DECLARE_clientfieldfunction(camera_transform) +PRVM_DECLARE_clientfieldfunction(predraw) +PRVM_DECLARE_clientfieldfunction(think) +PRVM_DECLARE_clientfieldfunction(touch) +PRVM_DECLARE_clientfieldfunction(use) +PRVM_DECLARE_clientfieldstring(classname) +PRVM_DECLARE_clientfieldstring(message) +PRVM_DECLARE_clientfieldstring(model) +PRVM_DECLARE_clientfieldstring(netname) +PRVM_DECLARE_clientfieldvector(absmax) +PRVM_DECLARE_clientfieldvector(absmin) +PRVM_DECLARE_clientfieldvector(angles) +PRVM_DECLARE_clientfieldvector(avelocity) +PRVM_DECLARE_clientfieldvector(colormod) +PRVM_DECLARE_clientfieldvector(glowmod) +PRVM_DECLARE_clientfieldvector(maxs) +PRVM_DECLARE_clientfieldvector(mins) +PRVM_DECLARE_clientfieldvector(movedir) +PRVM_DECLARE_clientfieldvector(oldorigin) +PRVM_DECLARE_clientfieldvector(origin) +PRVM_DECLARE_clientfieldvector(size) +PRVM_DECLARE_clientfieldvector(velocity) +PRVM_DECLARE_clientfieldvector(modellight_ambient) +PRVM_DECLARE_clientfieldvector(modellight_diffuse) +PRVM_DECLARE_clientfieldvector(modellight_dir) +PRVM_DECLARE_clientfunction(CSQC_ConsoleCommand) +PRVM_DECLARE_clientfunction(CSQC_Ent_Remove) +PRVM_DECLARE_clientfunction(CSQC_Ent_Spawn) +PRVM_DECLARE_clientfunction(CSQC_Ent_Update) +PRVM_DECLARE_clientfunction(CSQC_Event) +PRVM_DECLARE_clientfunction(CSQC_Event_Sound) +PRVM_DECLARE_clientfunction(CSQC_Init) +PRVM_DECLARE_clientfunction(CSQC_InputEvent) +PRVM_DECLARE_clientfunction(CSQC_Parse_CenterPrint) +PRVM_DECLARE_clientfunction(CSQC_Parse_Print) +PRVM_DECLARE_clientfunction(CSQC_Parse_StuffCmd) +PRVM_DECLARE_clientfunction(CSQC_Parse_TempEntity) +PRVM_DECLARE_clientfunction(CSQC_Shutdown) +PRVM_DECLARE_clientfunction(CSQC_UpdateView) +PRVM_DECLARE_clientfunction(GameCommand) +PRVM_DECLARE_clientfunction(URI_Get_Callback) +PRVM_DECLARE_clientglobaledict(other) +PRVM_DECLARE_clientglobaledict(self) +PRVM_DECLARE_clientglobaledict(trace_ent) +PRVM_DECLARE_clientglobaledict(world) +PRVM_DECLARE_clientglobalfloat(clientcommandframe) +PRVM_DECLARE_clientglobalfloat(coop) +PRVM_DECLARE_clientglobalfloat(deathmatch) +PRVM_DECLARE_clientglobalfloat(dmg_save) +PRVM_DECLARE_clientglobalfloat(dmg_take) +PRVM_DECLARE_clientglobalfloat(drawfont) +PRVM_DECLARE_clientglobalfloat(frametime) +PRVM_DECLARE_clientglobalfloat(gettaginfo_parent) +PRVM_DECLARE_clientglobalvector(getlight_ambient) +PRVM_DECLARE_clientglobalvector(getlight_diffuse) +PRVM_DECLARE_clientglobalvector(getlight_dir) +PRVM_DECLARE_clientglobalfloat(input_buttons) +PRVM_DECLARE_clientglobalfloat(input_timelength) +PRVM_DECLARE_clientglobalfloat(intermission) +PRVM_DECLARE_clientglobalfloat(maxclients) +PRVM_DECLARE_clientglobalfloat(movevar_accelerate) +PRVM_DECLARE_clientglobalfloat(movevar_airaccelerate) +PRVM_DECLARE_clientglobalfloat(movevar_entgravity) +PRVM_DECLARE_clientglobalfloat(movevar_friction) +PRVM_DECLARE_clientglobalfloat(movevar_gravity) +PRVM_DECLARE_clientglobalfloat(movevar_maxspeed) +PRVM_DECLARE_clientglobalfloat(movevar_spectatormaxspeed) +PRVM_DECLARE_clientglobalfloat(movevar_stopspeed) +PRVM_DECLARE_clientglobalfloat(movevar_wateraccelerate) +PRVM_DECLARE_clientglobalfloat(movevar_waterfriction) +PRVM_DECLARE_clientglobalfloat(particle_airfriction) +PRVM_DECLARE_clientglobalfloat(particle_alpha) +PRVM_DECLARE_clientglobalfloat(particle_alphafade) +PRVM_DECLARE_clientglobalfloat(particle_angle) +PRVM_DECLARE_clientglobalfloat(particle_blendmode) +PRVM_DECLARE_clientglobalfloat(particle_bounce) +PRVM_DECLARE_clientglobalfloat(particle_delaycollision) +PRVM_DECLARE_clientglobalfloat(particle_delayspawn) +PRVM_DECLARE_clientglobalfloat(particle_gravity) +PRVM_DECLARE_clientglobalfloat(particle_liquidfriction) +PRVM_DECLARE_clientglobalfloat(particle_orientation) +PRVM_DECLARE_clientglobalfloat(particle_originjitter) +PRVM_DECLARE_clientglobalfloat(particle_qualityreduction) +PRVM_DECLARE_clientglobalfloat(particle_size) +PRVM_DECLARE_clientglobalfloat(particle_sizeincrease) +PRVM_DECLARE_clientglobalfloat(particle_spin) +PRVM_DECLARE_clientglobalfloat(particle_stainalpha) +PRVM_DECLARE_clientglobalfloat(particle_stainsize) +PRVM_DECLARE_clientglobalfloat(particle_staintex) +PRVM_DECLARE_clientglobalfloat(particle_stretch) +PRVM_DECLARE_clientglobalfloat(particle_tex) +PRVM_DECLARE_clientglobalfloat(particle_time) +PRVM_DECLARE_clientglobalfloat(particle_type) +PRVM_DECLARE_clientglobalfloat(particle_velocityjitter) +PRVM_DECLARE_clientglobalfloat(particles_alphamax) +PRVM_DECLARE_clientglobalfloat(particles_alphamin) +PRVM_DECLARE_clientglobalfloat(player_localentnum) +PRVM_DECLARE_clientglobalfloat(player_localnum) +PRVM_DECLARE_clientglobalfloat(require_spawnfunc_prefix) +PRVM_DECLARE_clientglobalfloat(sb_showscores) +PRVM_DECLARE_clientglobalfloat(servercommandframe) +PRVM_DECLARE_clientglobalfloat(serverdeltatime) +PRVM_DECLARE_clientglobalfloat(serverprevtime) +PRVM_DECLARE_clientglobalfloat(servertime) +PRVM_DECLARE_clientglobalfloat(time) +PRVM_DECLARE_clientglobalfloat(trace_allsolid) +PRVM_DECLARE_clientglobalfloat(trace_dphitcontents) +PRVM_DECLARE_clientglobalfloat(trace_dphitq3surfaceflags) +PRVM_DECLARE_clientglobalfloat(trace_dpstartcontents) +PRVM_DECLARE_clientglobalfloat(trace_fraction) +PRVM_DECLARE_clientglobalfloat(trace_inopen) +PRVM_DECLARE_clientglobalfloat(trace_inwater) +PRVM_DECLARE_clientglobalfloat(trace_networkentity) +PRVM_DECLARE_clientglobalfloat(trace_plane_dist) +PRVM_DECLARE_clientglobalfloat(trace_startsolid) +PRVM_DECLARE_clientglobalfloat(transparent_offset) +PRVM_DECLARE_clientglobalstring(gettaginfo_name) +PRVM_DECLARE_clientglobalstring(mapname) +PRVM_DECLARE_clientglobalstring(trace_dphittexturename) +PRVM_DECLARE_clientglobalvector(dmg_origin) +PRVM_DECLARE_clientglobalvector(drawfontscale) +PRVM_DECLARE_clientglobalvector(gettaginfo_forward) +PRVM_DECLARE_clientglobalvector(gettaginfo_offset) +PRVM_DECLARE_clientglobalvector(gettaginfo_right) +PRVM_DECLARE_clientglobalvector(gettaginfo_up) +PRVM_DECLARE_clientglobalvector(input_angles) +PRVM_DECLARE_clientglobalvector(input_movevalues) +PRVM_DECLARE_clientglobalvector(particle_color1) +PRVM_DECLARE_clientglobalvector(particle_color2) +PRVM_DECLARE_clientglobalvector(particle_staincolor1) +PRVM_DECLARE_clientglobalvector(particle_staincolor2) +PRVM_DECLARE_clientglobalvector(particles_colormax) +PRVM_DECLARE_clientglobalvector(particles_colormin) +PRVM_DECLARE_clientglobalvector(pmove_inwater) +PRVM_DECLARE_clientglobalvector(pmove_maxs) +PRVM_DECLARE_clientglobalvector(pmove_mins) +PRVM_DECLARE_clientglobalvector(pmove_onground) +PRVM_DECLARE_clientglobalfloat(pmove_waterjumptime) +PRVM_DECLARE_clientglobalfloat(pmove_jump_held) +PRVM_DECLARE_clientglobalvector(pmove_org) +PRVM_DECLARE_clientglobalvector(pmove_vel) +PRVM_DECLARE_clientglobalvector(trace_endpos) +PRVM_DECLARE_clientglobalvector(trace_plane_normal) +PRVM_DECLARE_clientglobalvector(v_forward) +PRVM_DECLARE_clientglobalvector(v_right) +PRVM_DECLARE_clientglobalvector(v_up) +PRVM_DECLARE_clientglobalvector(view_angles) +PRVM_DECLARE_clientglobalvector(view_punchangle) +PRVM_DECLARE_clientglobalvector(view_punchvector) +PRVM_DECLARE_clientglobalfloat(sound_starttime) +PRVM_DECLARE_field(SendEntity) +PRVM_DECLARE_field(SendFlags) +PRVM_DECLARE_field(Version) +PRVM_DECLARE_field(absmax) +PRVM_DECLARE_field(absmin) +PRVM_DECLARE_field(aiment) +PRVM_DECLARE_field(alpha) +PRVM_DECLARE_field(ammo_cells) +PRVM_DECLARE_field(ammo_cells1) +PRVM_DECLARE_field(ammo_lava_nails) +PRVM_DECLARE_field(ammo_multi_rockets) +PRVM_DECLARE_field(ammo_nails) +PRVM_DECLARE_field(ammo_nails1) +PRVM_DECLARE_field(ammo_plasma) +PRVM_DECLARE_field(ammo_rockets) +PRVM_DECLARE_field(ammo_rockets1) +PRVM_DECLARE_field(ammo_shells) +PRVM_DECLARE_field(ammo_shells1) +PRVM_DECLARE_field(angles) +PRVM_DECLARE_field(armortype) +PRVM_DECLARE_field(armorvalue) +PRVM_DECLARE_field(avelocity) +PRVM_DECLARE_field(blocked) +PRVM_DECLARE_field(bouncefactor) +PRVM_DECLARE_field(bouncestop) +PRVM_DECLARE_field(button0) +PRVM_DECLARE_field(button1) +PRVM_DECLARE_field(button2) +PRVM_DECLARE_field(button3) +PRVM_DECLARE_field(button4) +PRVM_DECLARE_field(button5) +PRVM_DECLARE_field(button6) +PRVM_DECLARE_field(button7) +PRVM_DECLARE_field(button8) +PRVM_DECLARE_field(button9) +PRVM_DECLARE_field(button10) +PRVM_DECLARE_field(button11) +PRVM_DECLARE_field(button12) +PRVM_DECLARE_field(button13) +PRVM_DECLARE_field(button14) +PRVM_DECLARE_field(button15) +PRVM_DECLARE_field(button16) +PRVM_DECLARE_field(buttonchat) +PRVM_DECLARE_field(buttonuse) +PRVM_DECLARE_field(camera_transform) +PRVM_DECLARE_field(chain) +PRVM_DECLARE_field(classname) +PRVM_DECLARE_field(clientcamera) +PRVM_DECLARE_field(clientcolors) +PRVM_DECLARE_field(clientstatus) +PRVM_DECLARE_field(color) +PRVM_DECLARE_field(colormap) +PRVM_DECLARE_field(colormod) +PRVM_DECLARE_field(contentstransition) +PRVM_DECLARE_field(crypto_encryptmethod) +PRVM_DECLARE_field(crypto_idfp) +PRVM_DECLARE_field(crypto_keyfp) +PRVM_DECLARE_field(crypto_mykeyfp) +PRVM_DECLARE_field(crypto_signmethod) +PRVM_DECLARE_field(currentammo) +PRVM_DECLARE_field(cursor_active) +PRVM_DECLARE_field(cursor_screen) +PRVM_DECLARE_field(cursor_trace_endpos) +PRVM_DECLARE_field(cursor_trace_ent) +PRVM_DECLARE_field(cursor_trace_start) +PRVM_DECLARE_field(customizeentityforclient) +PRVM_DECLARE_field(deadflag) +PRVM_DECLARE_field(disableclientprediction) +PRVM_DECLARE_field(discardabledemo) +PRVM_DECLARE_field(dmg_inflictor) +PRVM_DECLARE_field(dmg_save) +PRVM_DECLARE_field(dmg_take) +PRVM_DECLARE_field(dphitcontentsmask) +PRVM_DECLARE_field(drawmask) +PRVM_DECLARE_field(drawonlytoclient) +PRVM_DECLARE_field(effects) +PRVM_DECLARE_field(enemy) +PRVM_DECLARE_field(entnum) +PRVM_DECLARE_field(exteriormodeltoclient) +PRVM_DECLARE_field(fixangle) +PRVM_DECLARE_field(flags) +PRVM_DECLARE_field(frags) +PRVM_DECLARE_field(frame) +PRVM_DECLARE_field(frame1time) +PRVM_DECLARE_field(frame2) +PRVM_DECLARE_field(frame2time) +PRVM_DECLARE_field(frame3) +PRVM_DECLARE_field(frame3time) +PRVM_DECLARE_field(frame4) +PRVM_DECLARE_field(frame4time) +PRVM_DECLARE_field(fullbright) +PRVM_DECLARE_field(glow_color) +PRVM_DECLARE_field(glow_size) +PRVM_DECLARE_field(glow_trail) +PRVM_DECLARE_field(glowmod) +PRVM_DECLARE_field(goalentity) +PRVM_DECLARE_field(gravity) +PRVM_DECLARE_field(groundentity) +PRVM_DECLARE_field(health) +PRVM_DECLARE_field(ideal_yaw) +PRVM_DECLARE_field(idealpitch) +PRVM_DECLARE_field(impulse) +PRVM_DECLARE_field(items) +PRVM_DECLARE_field(items2) +PRVM_DECLARE_field(geomtype) +PRVM_DECLARE_field(jointtype) +PRVM_DECLARE_field(forcetype) +PRVM_DECLARE_field(lerpfrac) +PRVM_DECLARE_field(lerpfrac3) +PRVM_DECLARE_field(lerpfrac4) +PRVM_DECLARE_field(light_lev) +PRVM_DECLARE_field(ltime) +PRVM_DECLARE_field(mass) +PRVM_DECLARE_field(massofs) +PRVM_DECLARE_field(friction) +PRVM_DECLARE_field(maxcontacts) +PRVM_DECLARE_field(erp) +PRVM_DECLARE_field(max_health) +PRVM_DECLARE_field(maxs) +PRVM_DECLARE_field(message) +PRVM_DECLARE_field(mins) +PRVM_DECLARE_field(model) +PRVM_DECLARE_field(modelflags) +PRVM_DECLARE_field(modelindex) +PRVM_DECLARE_field(movedir) +PRVM_DECLARE_field(movement) +PRVM_DECLARE_field(movetype) +PRVM_DECLARE_field(movetypesteplandevent) +PRVM_DECLARE_field(netaddress) +PRVM_DECLARE_field(netname) +PRVM_DECLARE_field(nextthink) +PRVM_DECLARE_field(nodrawtoclient) +PRVM_DECLARE_field(noise) +PRVM_DECLARE_field(noise1) +PRVM_DECLARE_field(noise2) +PRVM_DECLARE_field(noise3) +PRVM_DECLARE_field(oldorigin) +PRVM_DECLARE_field(origin) +PRVM_DECLARE_field(owner) +PRVM_DECLARE_field(pflags) +PRVM_DECLARE_field(ping) +PRVM_DECLARE_field(ping_movementloss) +PRVM_DECLARE_field(ping_packetloss) +PRVM_DECLARE_field(pitch_speed) +PRVM_DECLARE_field(playermodel) +PRVM_DECLARE_field(playerskin) +PRVM_DECLARE_field(pmodel) +PRVM_DECLARE_field(pmove_flags) +PRVM_DECLARE_field(predraw) +PRVM_DECLARE_field(punchangle) +PRVM_DECLARE_field(punchvector) +PRVM_DECLARE_field(renderamt) +PRVM_DECLARE_field(renderflags) +PRVM_DECLARE_field(scale) +PRVM_DECLARE_field(modelscale_vec) +PRVM_DECLARE_field(sendcomplexanimation) +PRVM_DECLARE_field(shadertime) +PRVM_DECLARE_field(size) +PRVM_DECLARE_field(skeletonindex) +PRVM_DECLARE_field(skin) +PRVM_DECLARE_field(solid) +PRVM_DECLARE_field(sounds) +PRVM_DECLARE_field(spawnflags) +PRVM_DECLARE_field(style) +PRVM_DECLARE_field(tag_entity) +PRVM_DECLARE_field(tag_index) +PRVM_DECLARE_field(takedamage) +PRVM_DECLARE_field(target) +PRVM_DECLARE_field(targetname) +PRVM_DECLARE_field(team) +PRVM_DECLARE_field(teleport_time) +PRVM_DECLARE_field(think) +PRVM_DECLARE_field(touch) +PRVM_DECLARE_field(traileffectnum) +PRVM_DECLARE_field(use) +PRVM_DECLARE_field(userwavefunc_param0) +PRVM_DECLARE_field(userwavefunc_param1) +PRVM_DECLARE_field(userwavefunc_param2) +PRVM_DECLARE_field(userwavefunc_param3) +PRVM_DECLARE_field(v_angle) +PRVM_DECLARE_field(velocity) +PRVM_DECLARE_field(modellight_ambient) +PRVM_DECLARE_field(modellight_diffuse) +PRVM_DECLARE_field(modellight_dir) +PRVM_DECLARE_field(view_ofs) +PRVM_DECLARE_field(viewmodelforclient) +PRVM_DECLARE_field(viewzoom) +PRVM_DECLARE_field(waterlevel) +PRVM_DECLARE_field(watertype) +PRVM_DECLARE_field(weapon) +PRVM_DECLARE_field(weaponframe) +PRVM_DECLARE_field(weaponmodel) +PRVM_DECLARE_field(yaw_speed) +PRVM_DECLARE_function(CSQC_ConsoleCommand) +PRVM_DECLARE_function(CSQC_Ent_Remove) +PRVM_DECLARE_function(CSQC_Ent_Spawn) +PRVM_DECLARE_function(CSQC_Ent_Update) +PRVM_DECLARE_function(CSQC_Event) +PRVM_DECLARE_function(CSQC_Event_Sound) +PRVM_DECLARE_function(CSQC_Init) +PRVM_DECLARE_function(CSQC_InputEvent) +PRVM_DECLARE_function(CSQC_Parse_CenterPrint) +PRVM_DECLARE_function(CSQC_Parse_Print) +PRVM_DECLARE_function(CSQC_Parse_StuffCmd) +PRVM_DECLARE_function(CSQC_Parse_TempEntity) +PRVM_DECLARE_function(CSQC_Shutdown) +PRVM_DECLARE_function(CSQC_UpdateView) +PRVM_DECLARE_function(ClientConnect) +PRVM_DECLARE_function(ClientDisconnect) +PRVM_DECLARE_function(ClientKill) +PRVM_DECLARE_function(EndFrame) +PRVM_DECLARE_function(GameCommand) +PRVM_DECLARE_function(PlayerPostThink) +PRVM_DECLARE_function(PlayerPreThink) +PRVM_DECLARE_function(PutClientInServer) +PRVM_DECLARE_function(RestoreGame) +PRVM_DECLARE_function(SV_ChangeTeam) +PRVM_DECLARE_function(SV_OnEntityNoSpawnFunction) +PRVM_DECLARE_function(SV_OnEntityPostSpawnFunction) +PRVM_DECLARE_function(SV_OnEntityPreSpawnFunction) +PRVM_DECLARE_function(SV_ParseClientCommand) +PRVM_DECLARE_function(SV_PausedTic) +PRVM_DECLARE_function(SV_PlayerPhysics) +PRVM_DECLARE_function(SV_Shutdown) +PRVM_DECLARE_function(SetChangeParms) +PRVM_DECLARE_function(SetNewParms) +PRVM_DECLARE_function(StartFrame) +PRVM_DECLARE_function(URI_Get_Callback) +PRVM_DECLARE_function(m_draw) +PRVM_DECLARE_function(m_init) +PRVM_DECLARE_function(m_keydown) +PRVM_DECLARE_function(m_keyup) +PRVM_DECLARE_function(m_newmap) +PRVM_DECLARE_function(m_shutdown) +PRVM_DECLARE_function(m_toggle) +PRVM_DECLARE_function(main) +PRVM_DECLARE_global(SV_InitCmd) +PRVM_DECLARE_global(clientcommandframe) +PRVM_DECLARE_global(coop) +PRVM_DECLARE_global(deathmatch) +PRVM_DECLARE_global(dmg_origin) +PRVM_DECLARE_global(dmg_save) +PRVM_DECLARE_global(dmg_take) +PRVM_DECLARE_global(drawfont) +PRVM_DECLARE_global(drawfontscale) +PRVM_DECLARE_global(force_retouch) +PRVM_DECLARE_global(found_secrets) +PRVM_DECLARE_global(frametime) +PRVM_DECLARE_global(gettaginfo_forward) +PRVM_DECLARE_global(gettaginfo_name) +PRVM_DECLARE_global(gettaginfo_offset) +PRVM_DECLARE_global(gettaginfo_parent) +PRVM_DECLARE_global(gettaginfo_right) +PRVM_DECLARE_global(gettaginfo_up) +PRVM_DECLARE_global(getlight_ambient) +PRVM_DECLARE_global(getlight_diffuse) +PRVM_DECLARE_global(getlight_dir) +PRVM_DECLARE_global(input_angles) +PRVM_DECLARE_global(input_buttons) +PRVM_DECLARE_global(input_movevalues) +PRVM_DECLARE_global(input_timelength) +PRVM_DECLARE_global(intermission) +PRVM_DECLARE_global(killed_monsters) +PRVM_DECLARE_global(mapname) +PRVM_DECLARE_global(maxclients) +PRVM_DECLARE_global(movevar_accelerate) +PRVM_DECLARE_global(movevar_airaccelerate) +PRVM_DECLARE_global(movevar_entgravity) +PRVM_DECLARE_global(movevar_friction) +PRVM_DECLARE_global(movevar_gravity) +PRVM_DECLARE_global(movevar_maxspeed) +PRVM_DECLARE_global(movevar_spectatormaxspeed) +PRVM_DECLARE_global(movevar_stopspeed) +PRVM_DECLARE_global(movevar_wateraccelerate) +PRVM_DECLARE_global(movevar_waterfriction) +PRVM_DECLARE_global(msg_entity) +PRVM_DECLARE_global(other) +PRVM_DECLARE_global(parm1) +PRVM_DECLARE_global(parm2) +PRVM_DECLARE_global(parm3) +PRVM_DECLARE_global(parm4) +PRVM_DECLARE_global(parm5) +PRVM_DECLARE_global(parm6) +PRVM_DECLARE_global(parm7) +PRVM_DECLARE_global(parm8) +PRVM_DECLARE_global(parm9) +PRVM_DECLARE_global(parm10) +PRVM_DECLARE_global(parm11) +PRVM_DECLARE_global(parm12) +PRVM_DECLARE_global(parm13) +PRVM_DECLARE_global(parm14) +PRVM_DECLARE_global(parm15) +PRVM_DECLARE_global(parm16) +PRVM_DECLARE_global(particle_airfriction) +PRVM_DECLARE_global(particle_alpha) +PRVM_DECLARE_global(particle_alphafade) +PRVM_DECLARE_global(particle_angle) +PRVM_DECLARE_global(particle_blendmode) +PRVM_DECLARE_global(particle_bounce) +PRVM_DECLARE_global(particle_color1) +PRVM_DECLARE_global(particle_color2) +PRVM_DECLARE_global(particle_delaycollision) +PRVM_DECLARE_global(particle_delayspawn) +PRVM_DECLARE_global(particle_gravity) +PRVM_DECLARE_global(particle_liquidfriction) +PRVM_DECLARE_global(particle_orientation) +PRVM_DECLARE_global(particle_originjitter) +PRVM_DECLARE_global(particle_qualityreduction) +PRVM_DECLARE_global(particle_size) +PRVM_DECLARE_global(particle_sizeincrease) +PRVM_DECLARE_global(particle_spin) +PRVM_DECLARE_global(particle_stainalpha) +PRVM_DECLARE_global(particle_staincolor1) +PRVM_DECLARE_global(particle_staincolor2) +PRVM_DECLARE_global(particle_stainsize) +PRVM_DECLARE_global(particle_staintex) +PRVM_DECLARE_global(particle_stretch) +PRVM_DECLARE_global(particle_tex) +PRVM_DECLARE_global(particle_time) +PRVM_DECLARE_global(particle_type) +PRVM_DECLARE_global(particle_velocityjitter) +PRVM_DECLARE_global(particles_alphamax) +PRVM_DECLARE_global(particles_alphamin) +PRVM_DECLARE_global(particles_colormax) +PRVM_DECLARE_global(particles_colormin) +PRVM_DECLARE_global(player_localentnum) +PRVM_DECLARE_global(player_localnum) +PRVM_DECLARE_global(pmove_inwater) +PRVM_DECLARE_global(pmove_maxs) +PRVM_DECLARE_global(pmove_mins) +PRVM_DECLARE_global(pmove_onground) +PRVM_DECLARE_global(pmove_waterjumptime) +PRVM_DECLARE_global(pmove_jump_held) +PRVM_DECLARE_global(pmove_org) +PRVM_DECLARE_global(pmove_vel) +PRVM_DECLARE_global(require_spawnfunc_prefix) +PRVM_DECLARE_global(sb_showscores) +PRVM_DECLARE_global(self) +PRVM_DECLARE_global(servercommandframe) +PRVM_DECLARE_global(serverdeltatime) +PRVM_DECLARE_global(serverflags) +PRVM_DECLARE_global(serverprevtime) +PRVM_DECLARE_global(servertime) +PRVM_DECLARE_global(teamplay) +PRVM_DECLARE_global(time) +PRVM_DECLARE_global(total_monsters) +PRVM_DECLARE_global(total_secrets) +PRVM_DECLARE_global(trace_allsolid) +PRVM_DECLARE_global(trace_dphitcontents) +PRVM_DECLARE_global(trace_dphitq3surfaceflags) +PRVM_DECLARE_global(trace_dphittexturename) +PRVM_DECLARE_global(trace_dpstartcontents) +PRVM_DECLARE_global(trace_endpos) +PRVM_DECLARE_global(trace_ent) +PRVM_DECLARE_global(trace_fraction) +PRVM_DECLARE_global(trace_inopen) +PRVM_DECLARE_global(trace_inwater) +PRVM_DECLARE_global(trace_networkentity) +PRVM_DECLARE_global(trace_plane_dist) +PRVM_DECLARE_global(trace_plane_normal) +PRVM_DECLARE_global(trace_startsolid) +PRVM_DECLARE_global(transparent_offset) +PRVM_DECLARE_global(v_forward) +PRVM_DECLARE_global(v_right) +PRVM_DECLARE_global(v_up) +PRVM_DECLARE_global(view_angles) +PRVM_DECLARE_global(view_punchangle) +PRVM_DECLARE_global(view_punchvector) +PRVM_DECLARE_global(world) +PRVM_DECLARE_global(worldstatus) +PRVM_DECLARE_global(sound_starttime) +PRVM_DECLARE_menufieldstring(classname) +PRVM_DECLARE_menufunction(GameCommand) +PRVM_DECLARE_menufunction(URI_Get_Callback) +PRVM_DECLARE_menufunction(m_draw) +PRVM_DECLARE_menufunction(m_init) +PRVM_DECLARE_menufunction(m_keydown) +PRVM_DECLARE_menufunction(m_keyup) +PRVM_DECLARE_menufunction(m_newmap) +PRVM_DECLARE_menufunction(m_shutdown) +PRVM_DECLARE_menufunction(m_toggle) +PRVM_DECLARE_menuglobaledict(self) +PRVM_DECLARE_menuglobalfloat(drawfont) +PRVM_DECLARE_menuglobalfloat(require_spawnfunc_prefix) +PRVM_DECLARE_menuglobalvector(drawfontscale) +PRVM_DECLARE_serverfieldedict(aiment) +PRVM_DECLARE_serverfieldedict(chain) +PRVM_DECLARE_serverfieldedict(clientcamera) +PRVM_DECLARE_serverfieldedict(cursor_trace_ent) +PRVM_DECLARE_serverfieldedict(dmg_inflictor) +PRVM_DECLARE_serverfieldedict(drawonlytoclient) +PRVM_DECLARE_serverfieldedict(enemy) +PRVM_DECLARE_serverfieldedict(exteriormodeltoclient) +PRVM_DECLARE_serverfieldedict(goalentity) +PRVM_DECLARE_serverfieldedict(groundentity) +PRVM_DECLARE_serverfieldedict(nodrawtoclient) +PRVM_DECLARE_serverfieldedict(owner) +PRVM_DECLARE_serverfieldedict(tag_entity) +PRVM_DECLARE_serverfieldedict(viewmodelforclient) +PRVM_DECLARE_serverfieldfloat(SendFlags) +PRVM_DECLARE_serverfieldfloat(Version) +PRVM_DECLARE_serverfieldfloat(alpha) +PRVM_DECLARE_serverfieldfloat(ammo_cells) +PRVM_DECLARE_serverfieldfloat(ammo_cells1) +PRVM_DECLARE_serverfieldfloat(ammo_lava_nails) +PRVM_DECLARE_serverfieldfloat(ammo_multi_rockets) +PRVM_DECLARE_serverfieldfloat(ammo_nails) +PRVM_DECLARE_serverfieldfloat(ammo_nails1) +PRVM_DECLARE_serverfieldfloat(ammo_plasma) +PRVM_DECLARE_serverfieldfloat(ammo_rockets) +PRVM_DECLARE_serverfieldfloat(ammo_rockets1) +PRVM_DECLARE_serverfieldfloat(ammo_shells) +PRVM_DECLARE_serverfieldfloat(ammo_shells1) +PRVM_DECLARE_serverfieldfloat(armortype) +PRVM_DECLARE_serverfieldfloat(armorvalue) +PRVM_DECLARE_serverfieldfloat(bouncefactor) +PRVM_DECLARE_serverfieldfloat(bouncestop) +PRVM_DECLARE_serverfieldfloat(button0) +PRVM_DECLARE_serverfieldfloat(button1) +PRVM_DECLARE_serverfieldfloat(button2) +PRVM_DECLARE_serverfieldfloat(button3) +PRVM_DECLARE_serverfieldfloat(button4) +PRVM_DECLARE_serverfieldfloat(button5) +PRVM_DECLARE_serverfieldfloat(button6) +PRVM_DECLARE_serverfieldfloat(button7) +PRVM_DECLARE_serverfieldfloat(button8) +PRVM_DECLARE_serverfieldfloat(button9) +PRVM_DECLARE_serverfieldfloat(button10) +PRVM_DECLARE_serverfieldfloat(button11) +PRVM_DECLARE_serverfieldfloat(button12) +PRVM_DECLARE_serverfieldfloat(button13) +PRVM_DECLARE_serverfieldfloat(button14) +PRVM_DECLARE_serverfieldfloat(button15) +PRVM_DECLARE_serverfieldfloat(button16) +PRVM_DECLARE_serverfieldfloat(buttonchat) +PRVM_DECLARE_serverfieldfloat(buttonuse) +PRVM_DECLARE_serverfieldfloat(clientcolors) +PRVM_DECLARE_serverfieldfloat(colormap) +PRVM_DECLARE_serverfieldfloat(currentammo) +PRVM_DECLARE_serverfieldfloat(cursor_active) +PRVM_DECLARE_serverfieldfloat(deadflag) +PRVM_DECLARE_serverfieldfloat(disableclientprediction) +PRVM_DECLARE_serverfieldfloat(discardabledemo) +PRVM_DECLARE_serverfieldfloat(dmg_save) +PRVM_DECLARE_serverfieldfloat(dmg_take) +PRVM_DECLARE_serverfieldfloat(dphitcontentsmask) +PRVM_DECLARE_serverfieldfloat(effects) +PRVM_DECLARE_serverfieldfloat(fixangle) +PRVM_DECLARE_serverfieldfloat(flags) +PRVM_DECLARE_serverfieldfloat(frags) +PRVM_DECLARE_serverfieldfloat(frame) +PRVM_DECLARE_serverfieldfloat(frame1time) +PRVM_DECLARE_serverfieldfloat(frame2) +PRVM_DECLARE_serverfieldfloat(frame2time) +PRVM_DECLARE_serverfieldfloat(frame3) +PRVM_DECLARE_serverfieldfloat(frame3time) +PRVM_DECLARE_serverfieldfloat(frame4) +PRVM_DECLARE_serverfieldfloat(frame4time) +PRVM_DECLARE_serverfieldfloat(fullbright) +PRVM_DECLARE_serverfieldfloat(glow_color) +PRVM_DECLARE_serverfieldfloat(glow_size) +PRVM_DECLARE_serverfieldfloat(glow_trail) +PRVM_DECLARE_serverfieldfloat(gravity) +PRVM_DECLARE_serverfieldfloat(health) +PRVM_DECLARE_serverfieldfloat(ideal_yaw) +PRVM_DECLARE_serverfieldfloat(idealpitch) +PRVM_DECLARE_serverfieldfloat(impulse) +PRVM_DECLARE_serverfieldfloat(items) +PRVM_DECLARE_serverfieldfloat(items2) +PRVM_DECLARE_serverfieldfloat(geomtype) +PRVM_DECLARE_serverfieldfloat(jointtype) +PRVM_DECLARE_serverfieldfloat(forcetype) +PRVM_DECLARE_serverfieldfloat(lerpfrac) +PRVM_DECLARE_serverfieldfloat(lerpfrac3) +PRVM_DECLARE_serverfieldfloat(lerpfrac4) +PRVM_DECLARE_serverfieldfloat(light_lev) +PRVM_DECLARE_serverfieldfloat(ltime) +PRVM_DECLARE_serverfieldfloat(mass) +PRVM_DECLARE_serverfieldvector(massofs) +PRVM_DECLARE_serverfieldfloat(friction) +PRVM_DECLARE_serverfieldfloat(maxcontacts) +PRVM_DECLARE_serverfieldfloat(erp) +PRVM_DECLARE_serverfieldfloat(max_health) +PRVM_DECLARE_serverfieldfloat(modelflags) +PRVM_DECLARE_serverfieldfloat(modelindex) +PRVM_DECLARE_serverfieldfloat(movetype) +PRVM_DECLARE_serverfieldfloat(nextthink) +PRVM_DECLARE_serverfieldfloat(pflags) +PRVM_DECLARE_serverfieldfloat(ping) +PRVM_DECLARE_serverfieldfloat(ping_movementloss) +PRVM_DECLARE_serverfieldfloat(ping_packetloss) +PRVM_DECLARE_serverfieldfloat(pitch_speed) +PRVM_DECLARE_serverfieldfloat(pmodel) +PRVM_DECLARE_serverfieldfloat(renderamt) +PRVM_DECLARE_serverfieldfloat(scale) +PRVM_DECLARE_serverfieldvector(modelscale_vec) +PRVM_DECLARE_serverfieldfloat(sendcomplexanimation) +PRVM_DECLARE_serverfieldfloat(skeletonindex) +PRVM_DECLARE_serverfieldfloat(skin) +PRVM_DECLARE_serverfieldfloat(solid) +PRVM_DECLARE_serverfieldfloat(sounds) +PRVM_DECLARE_serverfieldfloat(spawnflags) +PRVM_DECLARE_serverfieldfloat(style) +PRVM_DECLARE_serverfieldfloat(tag_index) +PRVM_DECLARE_serverfieldfloat(takedamage) +PRVM_DECLARE_serverfieldfloat(team) +PRVM_DECLARE_serverfieldfloat(teleport_time) +PRVM_DECLARE_serverfieldfloat(traileffectnum) +PRVM_DECLARE_serverfieldfloat(viewzoom) +PRVM_DECLARE_serverfieldfloat(waterlevel) +PRVM_DECLARE_serverfieldfloat(watertype) +PRVM_DECLARE_serverfieldfloat(weapon) +PRVM_DECLARE_serverfieldfloat(weaponframe) +PRVM_DECLARE_serverfieldfloat(yaw_speed) +PRVM_DECLARE_serverfieldfunction(SendEntity) +PRVM_DECLARE_serverfieldfunction(blocked) +PRVM_DECLARE_serverfieldfunction(camera_transform) +PRVM_DECLARE_serverfieldfunction(contentstransition) +PRVM_DECLARE_serverfieldfunction(customizeentityforclient) +PRVM_DECLARE_serverfieldfunction(movetypesteplandevent) +PRVM_DECLARE_serverfieldfunction(think) +PRVM_DECLARE_serverfieldfunction(touch) +PRVM_DECLARE_serverfieldfunction(use) +PRVM_DECLARE_serverfieldstring(classname) +PRVM_DECLARE_serverfieldstring(clientstatus) +PRVM_DECLARE_serverfieldstring(crypto_encryptmethod) +PRVM_DECLARE_serverfieldstring(crypto_idfp) +PRVM_DECLARE_serverfieldstring(crypto_keyfp) +PRVM_DECLARE_serverfieldstring(crypto_mykeyfp) +PRVM_DECLARE_serverfieldstring(crypto_signmethod) +PRVM_DECLARE_serverfieldstring(message) +PRVM_DECLARE_serverfieldstring(model) +PRVM_DECLARE_serverfieldstring(netaddress) +PRVM_DECLARE_serverfieldstring(netname) +PRVM_DECLARE_serverfieldstring(noise) +PRVM_DECLARE_serverfieldstring(noise1) +PRVM_DECLARE_serverfieldstring(noise2) +PRVM_DECLARE_serverfieldstring(noise3) +PRVM_DECLARE_serverfieldstring(playermodel) +PRVM_DECLARE_serverfieldstring(playerskin) +PRVM_DECLARE_serverfieldstring(target) +PRVM_DECLARE_serverfieldstring(targetname) +PRVM_DECLARE_serverfieldstring(weaponmodel) +PRVM_DECLARE_serverfieldvector(absmax) +PRVM_DECLARE_serverfieldvector(absmin) +PRVM_DECLARE_serverfieldvector(angles) +PRVM_DECLARE_serverfieldvector(avelocity) +PRVM_DECLARE_serverfieldvector(color) +PRVM_DECLARE_serverfieldvector(colormod) +PRVM_DECLARE_serverfieldvector(cursor_screen) +PRVM_DECLARE_serverfieldvector(cursor_trace_endpos) +PRVM_DECLARE_serverfieldvector(cursor_trace_start) +PRVM_DECLARE_serverfieldvector(glowmod) +PRVM_DECLARE_serverfieldvector(maxs) +PRVM_DECLARE_serverfieldvector(mins) +PRVM_DECLARE_serverfieldvector(movedir) +PRVM_DECLARE_serverfieldvector(movement) +PRVM_DECLARE_serverfieldvector(oldorigin) +PRVM_DECLARE_serverfieldvector(origin) +PRVM_DECLARE_serverfieldvector(punchangle) +PRVM_DECLARE_serverfieldvector(punchvector) +PRVM_DECLARE_serverfieldvector(size) +PRVM_DECLARE_serverfieldvector(v_angle) +PRVM_DECLARE_serverfieldvector(velocity) +PRVM_DECLARE_serverfieldvector(view_ofs) +PRVM_DECLARE_serverfunction(ClientConnect) +PRVM_DECLARE_serverfunction(ClientDisconnect) +PRVM_DECLARE_serverfunction(ClientKill) +PRVM_DECLARE_serverfunction(EndFrame) +PRVM_DECLARE_serverfunction(GameCommand) +PRVM_DECLARE_serverfunction(PlayerPostThink) +PRVM_DECLARE_serverfunction(PlayerPreThink) +PRVM_DECLARE_serverfunction(PutClientInServer) +PRVM_DECLARE_serverfunction(RestoreGame) +PRVM_DECLARE_serverfunction(SV_ChangeTeam) +PRVM_DECLARE_serverfunction(SV_OnEntityNoSpawnFunction) +PRVM_DECLARE_serverfunction(SV_OnEntityPostSpawnFunction) +PRVM_DECLARE_serverfunction(SV_OnEntityPreSpawnFunction) +PRVM_DECLARE_serverfunction(SV_ParseClientCommand) +PRVM_DECLARE_serverfunction(SV_PausedTic) +PRVM_DECLARE_serverfunction(SV_PlayerPhysics) +PRVM_DECLARE_serverfunction(SV_Shutdown) +PRVM_DECLARE_serverfunction(SetChangeParms) +PRVM_DECLARE_serverfunction(SetNewParms) +PRVM_DECLARE_serverfunction(StartFrame) +PRVM_DECLARE_serverfunction(URI_Get_Callback) +PRVM_DECLARE_serverfunction(main) +PRVM_DECLARE_serverglobaledict(msg_entity) +PRVM_DECLARE_serverglobaledict(other) +PRVM_DECLARE_serverglobaledict(self) +PRVM_DECLARE_serverglobaledict(trace_ent) +PRVM_DECLARE_serverglobaledict(world) +PRVM_DECLARE_serverglobalfloat(coop) +PRVM_DECLARE_serverglobalfloat(deathmatch) +PRVM_DECLARE_serverglobalfloat(force_retouch) +PRVM_DECLARE_serverglobalfloat(found_secrets) +PRVM_DECLARE_serverglobalfloat(frametime) +PRVM_DECLARE_serverglobalfloat(gettaginfo_parent) +PRVM_DECLARE_serverglobalfloat(killed_monsters) +PRVM_DECLARE_serverglobalfloat(parm1) +PRVM_DECLARE_serverglobalfloat(parm2) +PRVM_DECLARE_serverglobalfloat(parm3) +PRVM_DECLARE_serverglobalfloat(parm4) +PRVM_DECLARE_serverglobalfloat(parm5) +PRVM_DECLARE_serverglobalfloat(parm6) +PRVM_DECLARE_serverglobalfloat(parm7) +PRVM_DECLARE_serverglobalfloat(parm8) +PRVM_DECLARE_serverglobalfloat(parm9) +PRVM_DECLARE_serverglobalfloat(parm10) +PRVM_DECLARE_serverglobalfloat(parm11) +PRVM_DECLARE_serverglobalfloat(parm12) +PRVM_DECLARE_serverglobalfloat(parm13) +PRVM_DECLARE_serverglobalfloat(parm14) +PRVM_DECLARE_serverglobalfloat(parm15) +PRVM_DECLARE_serverglobalfloat(parm16) +PRVM_DECLARE_serverglobalfloat(require_spawnfunc_prefix) +PRVM_DECLARE_serverglobalfloat(serverflags) +PRVM_DECLARE_serverglobalfloat(teamplay) +PRVM_DECLARE_serverglobalfloat(time) +PRVM_DECLARE_serverglobalfloat(total_monsters) +PRVM_DECLARE_serverglobalfloat(total_secrets) +PRVM_DECLARE_serverglobalfloat(trace_allsolid) +PRVM_DECLARE_serverglobalfloat(trace_dphitcontents) +PRVM_DECLARE_serverglobalfloat(trace_dphitq3surfaceflags) +PRVM_DECLARE_serverglobalfloat(trace_dpstartcontents) +PRVM_DECLARE_serverglobalfloat(trace_fraction) +PRVM_DECLARE_serverglobalfloat(trace_inopen) +PRVM_DECLARE_serverglobalfloat(trace_inwater) +PRVM_DECLARE_serverglobalfloat(trace_plane_dist) +PRVM_DECLARE_serverglobalfloat(trace_startsolid) +PRVM_DECLARE_serverglobalstring(SV_InitCmd) +PRVM_DECLARE_serverglobalstring(gettaginfo_name) +PRVM_DECLARE_serverglobalstring(mapname) +PRVM_DECLARE_serverglobalstring(trace_dphittexturename) +PRVM_DECLARE_serverglobalstring(worldstatus) +PRVM_DECLARE_serverglobalvector(gettaginfo_forward) +PRVM_DECLARE_serverglobalvector(gettaginfo_offset) +PRVM_DECLARE_serverglobalvector(gettaginfo_right) +PRVM_DECLARE_serverglobalvector(gettaginfo_up) +PRVM_DECLARE_serverglobalvector(trace_endpos) +PRVM_DECLARE_serverglobalvector(trace_plane_normal) +PRVM_DECLARE_serverglobalvector(v_forward) +PRVM_DECLARE_serverglobalvector(v_right) +PRVM_DECLARE_serverglobalvector(v_up) diff --git a/app/jni/qtypes.h b/app/jni/qtypes.h new file mode 100644 index 0000000..e0ba637 --- /dev/null +++ b/app/jni/qtypes.h @@ -0,0 +1,65 @@ + +#ifndef QTYPES_H +#define QTYPES_H + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum qboolean_e {false, true} qboolean; +#else +typedef bool qboolean; +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef FALSE +#define FALSE false +#define TRUE true +#endif + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + +#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1400) +#define RESTRICT __restrict +#else +#define RESTRICT +#endif + +// LordHavoc: upgrade the prvm to double precision for better time values +// LordHavoc: to be enabled when bugs are worked out... +//#define PRVM_64 +#ifdef PRVM_64 +typedef double prvm_vec_t; +typedef long long prvm_int_t; +typedef unsigned long long prvm_uint_t; +#else +typedef float prvm_vec_t; +typedef int prvm_int_t; +typedef unsigned int prvm_uint_t; +#endif +typedef prvm_vec_t prvm_vec3_t[3]; + +#ifdef VEC_64 +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec2_t[2]; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; +typedef vec_t vec5_t[5]; +typedef vec_t vec6_t[6]; +typedef vec_t vec7_t[7]; +typedef vec_t vec8_t[8]; + +#endif diff --git a/app/jni/quakedef.h b/app/jni/quakedef.h new file mode 100644 index 0000000..2962cb4 --- /dev/null +++ b/app/jni/quakedef.h @@ -0,0 +1,550 @@ +/* +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 + +#ifndef QUAKEDEF_H +#define QUAKEDEF_H + +#if defined(__GNUC__) && (__GNUC__ > 2) +#define DP_FUNC_PRINTF(n) __attribute__ ((format (printf, n, n+1))) +#define DP_FUNC_PURE __attribute__ ((pure)) +#define DP_FUNC_NORETURN __attribute__ ((noreturn)) +#else +#define DP_FUNC_PRINTF(n) +#define DP_FUNC_PURE +#define DP_FUNC_NORETURN +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qtypes.h" + +extern const char *buildstring; +extern char engineversion[128]; + +#define GAMENAME "id1" + +#define MAX_NUM_ARGVS 50 + +#ifdef DP_SMALLMEMORY +#define MAX_INPUTLINE 1024 +#define CON_TEXTSIZE 16384 +#define CON_MAXLINES 256 +#define HIST_TEXTSIZE 2048 +#define HIST_MAXLINES 16 +#define MAX_ALIAS_NAME 32 +#define CMDBUFSIZE 131072 +#define MAX_ARGS 80 + +#define NET_MAXMESSAGE 65536 +#define MAX_PACKETFRAGMENT 1024 +#define MAX_EDICTS 4096 +#define MAX_MODELS 1024 +#define MAX_SOUNDS 1024 +#define MAX_LIGHTSTYLES 64 +#define MAX_STYLESTRING 16 +#define MAX_SCOREBOARD 32 +#define MAX_SCOREBOARDNAME 128 +#define MAX_USERINFO_STRING 196 +#define MAX_SERVERINFO_STRING 512 +#define MAX_LOCALINFO_STRING 1 // not actually used by DP servers +#define CL_MAX_USERCMDS 32 +#define CVAR_HASHSIZE 1024 +#define M_MAX_EDICTS 4096 +#define MAX_DEMOS 8 +#define MAX_DEMONAME 16 +#define MAX_SAVEGAMES 12 +#define SAVEGAME_COMMENT_LENGTH 39 +#define MAX_CLIENTNETWORKEYES 2 +#define MAX_LEVELNETWORKEYES 0 // no portal support +#define MAX_OCCLUSION_QUERIES 256 + +#define CRYPTO_HOSTKEY_HASHSIZE 256 +#define MAX_NETWM_ICON 1026 // one 32x32 + +#define MAX_WATERPLANES 2 +#define MAX_CUBEMAPS 1024 +#define MAX_EXPLOSIONS 8 +#define MAX_DLIGHTS 16 +#define MAX_CACHED_PICS 1024 // this is 144 bytes each (or 152 on 64bit) +#define CACHEPICHASHSIZE 256 +#define MAX_PARTICLEEFFECTNAME 256 +#define MAX_PARTICLEEFFECTINFO 1024 +#define MAX_PARTICLETEXTURES 256 +#define MAXCLVIDEOS 1 +#define MAX_DYNAMIC_TEXTURE_COUNT 2 +#define MAX_MAP_LEAFS 8192 + +#define MAXTRACKS 256 +#define MAX_DYNAMIC_CHANNELS 64 +#define MAX_CHANNELS 260 +#define MODLIST_TOTALSIZE 32 +#define MAX_FAVORITESERVERS 32 +#define MAX_DECALSYSTEM_QUEUE 64 +#define PAINTBUFFER_SIZE 512 +#define MAX_BINDMAPS 8 +#define MAX_PARTICLES_INITIAL 8192 +#define MAX_PARTICLES 8192 +#define MAX_DECALS_INITIAL 1024 +#define MAX_DECALS 1024 +#define MAX_ENITIES_INITIAL 256 +#define MAX_STATICENTITIES 256 +#define MAX_EFFECTS 16 +#define MAX_BEAMS 16 +#define MAX_TEMPENTITIES 256 +#define SERVERLIST_TOTALSIZE 1024 +#define SERVERLIST_ANDMASKCOUNT 5 +#define SERVERLIST_ORMASKCOUNT 5 +#else +#define MAX_INPUTLINE 16384 ///< maximum length of console commandline, QuakeC strings, and many other text processing buffers +#define CON_TEXTSIZE 1048576 ///< max scrollback buffer characters in console +#define CON_MAXLINES 16384 ///< max scrollback buffer lines in console +#define HIST_TEXTSIZE 262144 ///< max command history buffer characters in console +#define HIST_MAXLINES 4096 ///< max command history buffer lines in console +#define MAX_ALIAS_NAME 32 +#define CMDBUFSIZE 655360 ///< maximum script size that can be loaded by the exec command (8192 in Quake) +#define MAX_ARGS 80 ///< maximum number of parameters to a console command or alias + +#define NET_MAXMESSAGE 65536 ///< max reliable packet size (sent as multiple fragments of MAX_PACKETFRAGMENT) +#define MAX_PACKETFRAGMENT 1024 ///< max length of packet fragment +#define MAX_EDICTS 32768 ///< max number of objects in game world at once (32768 protocol limit) +#define MAX_MODELS 8192 ///< max number of models loaded at once (including during level transitions) +#define MAX_SOUNDS 4096 ///< max number of sounds loaded at once +#define MAX_LIGHTSTYLES 256 ///< max flickering light styles in level (note: affects savegame format) +#define MAX_STYLESTRING 64 ///< max length of flicker pattern for light style +#define MAX_SCOREBOARD 255 ///< max number of players in game at once (255 protocol limit) +#define MAX_SCOREBOARDNAME 128 ///< max length of player name in game +#define MAX_USERINFO_STRING 1280 ///< max length of infostring for PROTOCOL_QUAKEWORLD (196 in QuakeWorld) +#define MAX_SERVERINFO_STRING 1280 ///< max length of server infostring for PROTOCOL_QUAKEWORLD (512 in QuakeWorld) +#define MAX_LOCALINFO_STRING 32768 ///< max length of server-local infostring for PROTOCOL_QUAKEWORLD (32768 in QuakeWorld) +#define CL_MAX_USERCMDS 128 ///< max number of predicted input packets in queue +#define CVAR_HASHSIZE 65536 ///< number of hash buckets for accelerating cvar name lookups +#define M_MAX_EDICTS 32768 ///< max objects in menu vm +#define MAX_DEMOS 8 ///< max demos provided to demos command +#define MAX_DEMONAME 16 ///< max demo name length for demos command +#define MAX_SAVEGAMES 12 ///< max savegames listed in savegame menu +#define SAVEGAME_COMMENT_LENGTH 39 ///< max comment length of savegame in menu +#define MAX_CLIENTNETWORKEYES 16 ///< max number of locations that can be added to pvs when culling network entities (must be at least 2 for prediction) +#define MAX_LEVELNETWORKEYES 512 ///< max number of locations that can be added to pvs when culling network entities (must be at least 2 for prediction) +#define MAX_OCCLUSION_QUERIES 4096 ///< max number of GL_ARB_occlusion_query objects that can be used in one frame + +#define CRYPTO_HOSTKEY_HASHSIZE 8192 ///< number of hash buckets for accelerating host key lookups +#define MAX_NETWM_ICON 352822 // 16x16, 22x22, 24x24, 32x32, 48x48, 64x64, 128x128, 256x256, 512x512 + +#define MAX_WATERPLANES 16 ///< max number of water planes visible (each one causes additional view renders) +#define MAX_CUBEMAPS 1024 ///< max number of cubemap textures loaded for light filters +#define MAX_EXPLOSIONS 64 ///< max number of explosion shell effects active at once (not particle related) +#define MAX_DLIGHTS 256 ///< max number of dynamic lights (rocket flashes, etc) in scene at once +#define MAX_CACHED_PICS 1024 ///< max number of 2D pics loaded at once +#define CACHEPICHASHSIZE 256 ///< number of hash buckets for accelerating 2D pic name lookups +#define MAX_PARTICLEEFFECTNAME 256 ///< maximum number of unique names of particle effects (for particleeffectnum) +#define MAX_PARTICLEEFFECTINFO 4096 ///< maximum number of unique particle effects (each name may associate with several of these) +#define MAX_PARTICLETEXTURES 256 ///< maximum number of unique particle textures in the particle font +#define MAXCLVIDEOS 65 ///< maximum number of video streams being played back at once (1 is reserved for the playvideo command) +#define MAX_DYNAMIC_TEXTURE_COUNT 64 ///< maximum number of dynamic textures (web browsers, playvideo, etc) +#define MAX_MAP_LEAFS 65536 ///< maximum number of BSP leafs in world (8192 in Quake) + +#define MAXTRACKS 256 ///< max CD track index +// 0 to NUM_AMBIENTS - 1 = water, etc +// NUM_AMBIENTS to NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS - 1 = normal entity sounds +// NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS to total_channels = static sounds +#define MAX_DYNAMIC_CHANNELS 512 +#define MAX_CHANNELS 1028 +#define MODLIST_TOTALSIZE 256 +#define MAX_FAVORITESERVERS 256 +#define MAX_DECALSYSTEM_QUEUE 1024 +#define PAINTBUFFER_SIZE 2048 +#define MAX_BINDMAPS 8 +#define MAX_PARTICLES_INITIAL 8192 ///< initial allocation for cl.particles +#define MAX_PARTICLES 1048576 ///< upper limit on cl.particles size +#define MAX_DECALS_INITIAL 8192 ///< initial allocation for cl.decals +#define MAX_DECALS 1048576 ///< upper limit on cl.decals size +#define MAX_ENITIES_INITIAL 256 ///< initial size of cl.entities +#define MAX_STATICENTITIES 1024 ///< limit on size of cl.static_entities +#define MAX_EFFECTS 256 ///< limit on size of cl.effects +#define MAX_BEAMS 256 ///< limit on size of cl.beams +#define MAX_TEMPENTITIES 4096 ///< max number of temporary models visible per frame (certain sprite effects, certain types of CSQC entities also use this) +#define SERVERLIST_TOTALSIZE 2048 ///< max servers in the server list +#define SERVERLIST_ANDMASKCOUNT 16 ///< max items in server list AND mask +#define SERVERLIST_ORMASKCOUNT 16 ///< max items in server list OR mask +#endif + + +#define CMD_TOKENIZELENGTH (MAX_INPUTLINE + MAX_ARGS) ///< maximum tokenizable commandline length (counting trailing 0) + + +#define MAX_QPATH 128 ///< max length of a quake game pathname +#ifdef PATH_MAX +#define MAX_OSPATH PATH_MAX +#elif MAX_PATH +#define MAX_OSPATH MAX_PATH +#else +#define MAX_OSPATH 1024 ///< max length of a filesystem pathname +#endif + +#define ON_EPSILON 0.1 ///< point on plane side epsilon + +#define NET_MINRATE 1000 ///< limits "rate" and "sv_maxrate" cvars + +// +// stats are integers communicated to the client by the server +// +#define MAX_CL_STATS 256 +#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 +#define STAT_ITEMS 15 ///< FTE, DP +#define STAT_VIEWHEIGHT 16 ///< FTE, DP +//#define STAT_TIME 17 ///< FTE +//#define STAT_VIEW2 20 ///< FTE +#define STAT_VIEWZOOM 21 ///< DP +#define STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR 220 ///< DP +#define STAT_MOVEVARS_AIRCONTROL_PENALTY 221 ///< DP +#define STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW 222 ///< DP +#define STAT_MOVEVARS_AIRSTRAFEACCEL_QW 223 ///< DP +#define STAT_MOVEVARS_AIRCONTROL_POWER 224 ///< DP +#define STAT_MOVEFLAGS 225 ///< DP +#define STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL 226 ///< DP +#define STAT_MOVEVARS_WARSOWBUNNY_ACCEL 227 ///< DP +#define STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED 228 ///< DP +#define STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL 229 ///< DP +#define STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO 230 ///< DP +#define STAT_MOVEVARS_AIRSTOPACCELERATE 231 ///< DP +#define STAT_MOVEVARS_AIRSTRAFEACCELERATE 232 ///< DP +#define STAT_MOVEVARS_MAXAIRSTRAFESPEED 233 ///< DP +#define STAT_MOVEVARS_AIRCONTROL 234 ///< DP +#define STAT_FRAGLIMIT 235 ///< DP +#define STAT_TIMELIMIT 236 ///< DP +#define STAT_MOVEVARS_WALLFRICTION 237 ///< DP +#define STAT_MOVEVARS_FRICTION 238 ///< DP +#define STAT_MOVEVARS_WATERFRICTION 239 ///< DP +#define STAT_MOVEVARS_TICRATE 240 ///< DP +#define STAT_MOVEVARS_TIMESCALE 241 ///< DP +#define STAT_MOVEVARS_GRAVITY 242 ///< DP +#define STAT_MOVEVARS_STOPSPEED 243 ///< DP +#define STAT_MOVEVARS_MAXSPEED 244 ///< DP +#define STAT_MOVEVARS_SPECTATORMAXSPEED 245 ///< DP +#define STAT_MOVEVARS_ACCELERATE 246 ///< DP +#define STAT_MOVEVARS_AIRACCELERATE 247 ///< DP +#define STAT_MOVEVARS_WATERACCELERATE 248 ///< DP +#define STAT_MOVEVARS_ENTGRAVITY 249 ///< DP +#define STAT_MOVEVARS_JUMPVELOCITY 250 ///< DP +#define STAT_MOVEVARS_EDGEFRICTION 251 ///< DP +#define STAT_MOVEVARS_MAXAIRSPEED 252 ///< DP +#define STAT_MOVEVARS_STEPHEIGHT 253 ///< DP +#define STAT_MOVEVARS_AIRACCEL_QW 254 ///< DP +#define STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION 255 ///< DP + +// moveflags values +#define MOVEFLAG_VALID 0x80000000 +#define MOVEFLAG_Q2AIRACCELERATE 0x00000001 +#define MOVEFLAG_NOGRAVITYONGROUND 0x00000002 +#define MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE 0x00000004 + +// 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) + +//=========================================== +// AK nexuiz changed and added defines + +#define NEX_IT_UZI 1 +#define NEX_IT_SHOTGUN 2 +#define NEX_IT_GRENADE_LAUNCHER 4 +#define NEX_IT_ELECTRO 8 +#define NEX_IT_CRYLINK 16 +#define NEX_IT_NEX 32 +#define NEX_IT_HAGAR 64 +#define NEX_IT_ROCKET_LAUNCHER 128 +#define NEX_IT_SHELLS 256 +#define NEX_IT_BULLETS 512 +#define NEX_IT_ROCKETS 1024 +#define NEX_IT_CELLS 2048 +#define NEX_IT_LASER 4094 +#define NEX_IT_STRENGTH 8192 +#define NEX_IT_INVINCIBLE 16384 +#define NEX_IT_SPEED 32768 +#define NEX_IT_SLOWMO 65536 + +//=========================================== +//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<server packet. Demo +// playback will ignore this, but it may be useful to make DP sniff packets to +// debug protocol exploits. +#define DEMOMSG_CLIENT_TO_SERVER 0x80000000 + +// In Quake, any char in 0..32 counts as whitespace +//#define ISWHITESPACE(ch) ((unsigned char) ch <= (unsigned char) ' ') +#define ISWHITESPACE(ch) (!(ch) || (ch) == ' ' || (ch) == '\t' || (ch) == '\r' || (ch) == '\n') + +// This also includes extended characters, and ALL control chars +#define ISWHITESPACEORCONTROL(ch) ((signed char) (ch) <= (signed char) ' ') + + +#ifdef PRVM_64 +#define FLOAT_IS_TRUE_FOR_INT(x) ((x) & 0x7FFFFFFFFFFFFFFF) // also match "negative zero" doubles of value 0x8000000000000000 +#define FLOAT_LOSSLESS_FORMAT "%.17g" +#define VECTOR_LOSSLESS_FORMAT "%.17g %.17g %.17g" +#else +#define FLOAT_IS_TRUE_FOR_INT(x) ((x) & 0x7FFFFFFF) // also match "negative zero" floats of value 0x80000000 +#define FLOAT_LOSSLESS_FORMAT "%.9g" +#define VECTOR_LOSSLESS_FORMAT "%.9g %.9g %.9g" +#endif + +// originally this was _MSC_VER +// but here we want to test the system libc, which on win32 is borked, and NOT the compiler +#ifdef WIN32 +#define INT_LOSSLESS_FORMAT_SIZE "I64" +#define INT_LOSSLESS_FORMAT_CONVERT_S(x) ((__int64)(x)) +#define INT_LOSSLESS_FORMAT_CONVERT_U(x) ((unsigned __int64)(x)) +#else +#define INT_LOSSLESS_FORMAT_SIZE "j" +#define INT_LOSSLESS_FORMAT_CONVERT_S(x) ((intmax_t)(x)) +#define INT_LOSSLESS_FORMAT_CONVERT_U(x) ((uintmax_t)(x)) +#endif + +#endif + diff --git a/app/jni/r_explosion.c b/app/jni/r_explosion.c new file mode 100644 index 0000000..3c40edb --- /dev/null +++ b/app/jni/r_explosion.c @@ -0,0 +1,285 @@ +/* +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 "cl_collision.h" + +#ifdef MAX_EXPLOSIONS +#define EXPLOSIONGRID 8 +#define EXPLOSIONVERTS ((EXPLOSIONGRID+1)*(EXPLOSIONGRID+1)) +#define EXPLOSIONTRIS (EXPLOSIONGRID*EXPLOSIONGRID*2) + +static int numexplosions = 0; + +static float explosiontexcoord2f[EXPLOSIONVERTS][2]; +static unsigned short explosiontris[EXPLOSIONTRIS][3]; +static int explosionnoiseindex[EXPLOSIONVERTS]; +static vec3_t explosionpoint[EXPLOSIONVERTS]; + +typedef struct explosion_s +{ + float starttime; + float endtime; + float time; + float alpha; + float fade; + vec3_t origin; + vec3_t vert[EXPLOSIONVERTS]; + vec3_t vertvel[EXPLOSIONVERTS]; + qboolean clipping; +} +explosion_t; + +static explosion_t explosion[MAX_EXPLOSIONS]; + +static rtexture_t *explosiontexture; +//static rtexture_t *explosiontexturefog; + +static rtexturepool_t *explosiontexturepool; +#endif + +cvar_t r_explosionclip = {CVAR_SAVE, "r_explosionclip", "1", "enables collision detection for explosion shell (so that it flattens against walls and floors)"}; +#ifdef MAX_EXPLOSIONS +static cvar_t r_drawexplosions = {0, "r_drawexplosions", "1", "enables rendering of explosion shells (see also cl_particles_explosions_shell)"}; + +//extern qboolean r_loadfog; +static void r_explosion_start(void) +{ + int x, y; + static unsigned char noise1[128][128], noise2[128][128], noise3[128][128], data[128][128][4]; + explosiontexturepool = R_AllocTexturePool(); + explosiontexture = NULL; + //explosiontexturefog = NULL; + fractalnoise(&noise1[0][0], 128, 32); + fractalnoise(&noise2[0][0], 128, 4); + fractalnoise(&noise3[0][0], 128, 4); + for (y = 0;y < 128;y++) + { + for (x = 0;x < 128;x++) + { + int j, r, g, b, a; + j = (noise1[y][x] * noise2[y][x]) * 3 / 256 - 128; + r = (j * 512) / 256; + g = (j * 256) / 256; + b = (j * 128) / 256; + a = noise3[y][x] * 3 - 128; + data[y][x][2] = bound(0, r, 255); + data[y][x][1] = bound(0, g, 255); + data[y][x][0] = bound(0, b, 255); + data[y][x][3] = bound(0, a, 255); + } + } + explosiontexture = R_LoadTexture2D(explosiontexturepool, "explosiontexture", 128, 128, &data[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL); +// if (r_loadfog) +// { +// for (y = 0;y < 128;y++) +// for (x = 0;x < 128;x++) +// data[y][x][0] = data[y][x][1] = data[y][x][2] = 255; +// explosiontexturefog = R_LoadTexture2D(explosiontexturepool, "explosiontexture_fog", 128, 128, &data[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL); +// } + // note that explosions survive the restart +} + +static void r_explosion_shutdown(void) +{ + R_FreeTexturePool(&explosiontexturepool); +} + +static void r_explosion_newmap(void) +{ + numexplosions = 0; + memset(explosion, 0, sizeof(explosion)); +} + +static int R_ExplosionVert(int column, int row) +{ + int i; + float yaw, pitch; + // top and bottom rows are all one position... + if (row == 0 || row == EXPLOSIONGRID) + column = 0; + i = row * (EXPLOSIONGRID + 1) + column; + yaw = ((double) column / EXPLOSIONGRID) * M_PI * 2; + pitch = (((double) row / EXPLOSIONGRID) - 0.5) * M_PI; + explosionpoint[i][0] = cos(yaw) * cos(pitch); + explosionpoint[i][1] = sin(yaw) * cos(pitch); + explosionpoint[i][2] = 1 * -sin(pitch); + explosiontexcoord2f[i][0] = (float) column / (float) EXPLOSIONGRID; + explosiontexcoord2f[i][1] = (float) row / (float) EXPLOSIONGRID; + explosionnoiseindex[i] = (row % EXPLOSIONGRID) * EXPLOSIONGRID + (column % EXPLOSIONGRID); + return i; +} +#endif + +void R_Explosion_Init(void) +{ +#ifdef MAX_EXPLOSIONS + int i, x, y; + i = 0; + for (y = 0;y < EXPLOSIONGRID;y++) + { + for (x = 0;x < EXPLOSIONGRID;x++) + { + explosiontris[i][0] = R_ExplosionVert(x , y ); + explosiontris[i][1] = R_ExplosionVert(x + 1, y ); + explosiontris[i][2] = R_ExplosionVert(x , y + 1); + i++; + explosiontris[i][0] = R_ExplosionVert(x + 1, y ); + explosiontris[i][1] = R_ExplosionVert(x + 1, y + 1); + explosiontris[i][2] = R_ExplosionVert(x , y + 1); + i++; + } + } + +#endif + Cvar_RegisterVariable(&r_explosionclip); +#ifdef MAX_EXPLOSIONS + Cvar_RegisterVariable(&r_drawexplosions); + + R_RegisterModule("R_Explosions", r_explosion_start, r_explosion_shutdown, r_explosion_newmap, NULL, NULL); +#endif +} + +void R_NewExplosion(const vec3_t org) +{ +#ifdef MAX_EXPLOSIONS + int i, j; + float dist, n; + explosion_t *e; + trace_t trace; + unsigned char noise[EXPLOSIONGRID*EXPLOSIONGRID]; + fractalnoisequick(noise, EXPLOSIONGRID, 4); // adjust noise grid size according to explosion + for (i = 0, e = explosion;i < MAX_EXPLOSIONS;i++, e++) + { + if (!e->alpha) + { + numexplosions = max(numexplosions, i + 1); + e->starttime = cl.time; + e->endtime = cl.time + cl_explosions_lifetime.value; + e->time = e->starttime; + e->alpha = cl_explosions_alpha_start.value; + e->fade = (cl_explosions_alpha_start.value - cl_explosions_alpha_end.value) / cl_explosions_lifetime.value; + e->clipping = r_explosionclip.integer != 0; + VectorCopy(org, e->origin); + for (j = 0;j < EXPLOSIONVERTS;j++) + { + // calculate start origin and velocity + n = noise[explosionnoiseindex[j]] * (1.0f / 255.0f) + 0.5; + dist = n * cl_explosions_size_start.value; + VectorMA(e->origin, dist, explosionpoint[j], e->vert[j]); + dist = n * (cl_explosions_size_end.value - cl_explosions_size_start.value) / cl_explosions_lifetime.value; + VectorScale(explosionpoint[j], dist, e->vertvel[j]); + // clip start origin + if (e->clipping) + { + trace = CL_TraceLine(e->origin, e->vert[j], MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false); + VectorCopy(trace.endpos, e->vert[i]); + } + } + break; + } + } +#endif +} + +#ifdef MAX_EXPLOSIONS +static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int surfacelistindex = 0; + const int numtriangles = EXPLOSIONTRIS, numverts = EXPLOSIONVERTS; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + GL_DepthTest(true); + GL_CullFace(r_refdef.view.cullface_back); + R_EntityMatrix(&identitymatrix); + +// R_Mesh_ResetTextureState(); + R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1, false, false, false); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + const explosion_t *e = explosion + surfacelist[surfacelistindex]; + // FIXME: this can't properly handle r_refdef.view.colorscale > 1 + GL_Color(e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, 1); + R_Mesh_PrepareVertices_Generic_Arrays(numverts, e->vert[0], NULL, explosiontexcoord2f[0]); + R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, NULL, 0, explosiontris[0], NULL, 0); + } +} + +static void R_MoveExplosion(explosion_t *e) +{ + int i; + float dot, end[3], frametime; + trace_t trace; + + frametime = cl.time - e->time; + e->time = cl.time; + e->alpha = e->alpha - (e->fade * frametime); + if (e->alpha < 0 || cl.time > e->endtime) + { + e->alpha = 0; + return; + } + for (i = 0;i < EXPLOSIONVERTS;i++) + { + if (e->vertvel[i][0] || e->vertvel[i][1] || e->vertvel[i][2]) + { + VectorMA(e->vert[i], frametime, e->vertvel[i], end); + if (e->clipping) + { + trace = CL_TraceLine(e->vert[i], end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false); + if (trace.fraction < 1) + { + // clip velocity against the wall + dot = -DotProduct(e->vertvel[i], trace.plane.normal); + VectorMA(e->vertvel[i], dot, trace.plane.normal, e->vertvel[i]); + } + VectorCopy(trace.endpos, e->vert[i]); + } + else + VectorCopy(end, e->vert[i]); + } + } +} +#endif + +void R_DrawExplosions(void) +{ +#ifdef MAX_EXPLOSIONS + int i; + + if (!r_drawexplosions.integer) + return; + + for (i = 0;i < numexplosions;i++) + { + if (explosion[i].alpha) + { + R_MoveExplosion(&explosion[i]); + if (explosion[i].alpha) + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, explosion[i].origin, R_DrawExplosion_TransparentCallback, NULL, i, NULL); + } + } + while (numexplosions > 0 && explosion[i-1].alpha <= 0) + numexplosions--; +#endif +} + diff --git a/app/jni/r_lerpanim.c b/app/jni/r_lerpanim.c new file mode 100644 index 0000000..e69de29 diff --git a/app/jni/r_lerpanim.h b/app/jni/r_lerpanim.h new file mode 100644 index 0000000..e69de29 diff --git a/app/jni/r_lightning.c b/app/jni/r_lightning.c new file mode 100644 index 0000000..8568292 --- /dev/null +++ b/app/jni/r_lightning.c @@ -0,0 +1,327 @@ + +#include "quakedef.h" +#include "image.h" + +cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "4", "thickness of the lightning beam effect"}; +cvar_t r_lightningbeam_scroll = {CVAR_SAVE, "r_lightningbeam_scroll", "5", "speed of texture scrolling on the lightning beam effect"}; +cvar_t r_lightningbeam_repeatdistance = {CVAR_SAVE, "r_lightningbeam_repeatdistance", "128", "how far to stretch the texture along the lightning beam effect"}; +cvar_t r_lightningbeam_color_red = {CVAR_SAVE, "r_lightningbeam_color_red", "1", "color of the lightning beam effect"}; +cvar_t r_lightningbeam_color_green = {CVAR_SAVE, "r_lightningbeam_color_green", "1", "color of the lightning beam effect"}; +cvar_t r_lightningbeam_color_blue = {CVAR_SAVE, "r_lightningbeam_color_blue", "1", "color of the lightning beam effect"}; +cvar_t r_lightningbeam_qmbtexture = {CVAR_SAVE, "r_lightningbeam_qmbtexture", "0", "load the qmb textures/particles/lightning.pcx texture instead of generating one, can look better"}; + +skinframe_t *r_lightningbeamtexture; +skinframe_t *r_lightningbeamqmbtexture; + +int r_lightningbeamelement3i[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11}; +unsigned short r_lightningbeamelement3s[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11}; + +static void r_lightningbeams_start(void) +{ + r_lightningbeamtexture = NULL; + r_lightningbeamqmbtexture = NULL; +} + +static void r_lightningbeams_setupqmbtexture(void) +{ + r_lightningbeamqmbtexture = R_SkinFrame_LoadExternal("textures/particles/lightning.pcx", TEXF_ALPHA | TEXF_FORCELINEAR, false); + if (r_lightningbeamqmbtexture == NULL) + Cvar_SetValueQuick(&r_lightningbeam_qmbtexture, false); +} + +static void r_lightningbeams_setuptexture(void) +{ +#if 0 +#define BEAMWIDTH 128 +#define BEAMHEIGHT 64 +#define PATHPOINTS 8 + int i, j, px, py, nearestpathindex, imagenumber; + float particlex, particley, particlexv, particleyv, dx, dy, s, maxpathstrength; + unsigned char *pixels; + int *image; + struct lightningpathnode_s + { + float x, y, strength; + } + path[PATHPOINTS], temppath; + + image = Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * sizeof(int)); + pixels = Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * sizeof(unsigned char[4])); + + for (imagenumber = 0, maxpathstrength = 0.0339476;maxpathstrength < 0.5;imagenumber++, maxpathstrength += 0.01) + { + for (i = 0;i < PATHPOINTS;i++) + { + path[i].x = lhrandom(0, 1); + path[i].y = lhrandom(0.2, 0.8); + path[i].strength = lhrandom(0, 1); + } + for (i = 0;i < PATHPOINTS;i++) + { + for (j = i + 1;j < PATHPOINTS;j++) + { + if (path[j].x < path[i].x) + { + temppath = path[j]; + path[j] = path[i]; + path[i] = temppath; + } + } + } + particlex = path[0].x; + particley = path[0].y; + particlexv = lhrandom(0, 0.02); + particlexv = lhrandom(-0.02, 0.02); + memset(image, 0, BEAMWIDTH * BEAMHEIGHT * sizeof(int)); + for (i = 0;i < 65536;i++) + { + for (nearestpathindex = 0;nearestpathindex < PATHPOINTS;nearestpathindex++) + if (path[nearestpathindex].x > particlex) + break; + nearestpathindex %= PATHPOINTS; + dx = path[nearestpathindex].x + lhrandom(-0.01, 0.01);dx = bound(0, dx, 1) - particlex;if (dx < 0) dx += 1; + dy = path[nearestpathindex].y + lhrandom(-0.01, 0.01);dy = bound(0, dy, 1) - particley; + s = path[nearestpathindex].strength / sqrt(dx*dx+dy*dy); + particlexv = particlexv /* (1 - lhrandom(0.08, 0.12))*/ + dx * s; + particleyv = particleyv /* (1 - lhrandom(0.08, 0.12))*/ + dy * s; + particlex += particlexv * maxpathstrength;particlex -= (int) particlex; + particley += particleyv * maxpathstrength;particley = bound(0, particley, 1); + px = particlex * BEAMWIDTH; + py = particley * BEAMHEIGHT; + if (px >= 0 && py >= 0 && px < BEAMWIDTH && py < BEAMHEIGHT) + image[py*BEAMWIDTH+px] += 16; + } + + for (py = 0;py < BEAMHEIGHT;py++) + { + for (px = 0;px < BEAMWIDTH;px++) + { + pixels[(py*BEAMWIDTH+px)*4+2] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f); + pixels[(py*BEAMWIDTH+px)*4+1] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f); + pixels[(py*BEAMWIDTH+px)*4+0] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f); + pixels[(py*BEAMWIDTH+px)*4+3] = 255; + } + } + + Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "lightningbeam%i.tga", imagenumber), BEAMWIDTH, BEAMHEIGHT, pixels); + } + + r_lightningbeamtexture = R_LoadTexture2D(r_lightningbeamtexturepool, "lightningbeam", BEAMWIDTH, BEAMHEIGHT, pixels, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL); + + Mem_Free(pixels); + Mem_Free(image); +#else +#define BEAMWIDTH 64 +#define BEAMHEIGHT 128 + float r, g, b, intensity, fx, width, center; + int x, y; + unsigned char *data, *noise1, *noise2; + + data = (unsigned char *)Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * 4); + noise1 = (unsigned char *)Mem_Alloc(tempmempool, BEAMHEIGHT * BEAMHEIGHT); + noise2 = (unsigned char *)Mem_Alloc(tempmempool, BEAMHEIGHT * BEAMHEIGHT); + fractalnoise(noise1, BEAMHEIGHT, BEAMHEIGHT / 8); + fractalnoise(noise2, BEAMHEIGHT, BEAMHEIGHT / 16); + + for (y = 0;y < BEAMHEIGHT;y++) + { + width = 0.15;//((noise1[y * BEAMHEIGHT] * (1.0f / 256.0f)) * 0.1f + 0.1f); + center = (noise1[y * BEAMHEIGHT + (BEAMHEIGHT / 2)] / 256.0f) * (1.0f - width * 2.0f) + width; + for (x = 0;x < BEAMWIDTH;x++, fx++) + { + fx = (((float) x / BEAMWIDTH) - center) / width; + intensity = 1.0f - sqrt(fx * fx); + if (intensity > 0) + intensity = pow(intensity, 2) * ((noise2[y * BEAMHEIGHT + x] * (1.0f / 256.0f)) * 0.33f + 0.66f); + intensity = bound(0, intensity, 1); + r = intensity * 1.0f; + g = intensity * 1.0f; + b = intensity * 1.0f; + data[(y * BEAMWIDTH + x) * 4 + 2] = (unsigned char)(bound(0, r, 1) * 255.0f); + data[(y * BEAMWIDTH + x) * 4 + 1] = (unsigned char)(bound(0, g, 1) * 255.0f); + data[(y * BEAMWIDTH + x) * 4 + 0] = (unsigned char)(bound(0, b, 1) * 255.0f); + data[(y * BEAMWIDTH + x) * 4 + 3] = (unsigned char)255; + } + } + + r_lightningbeamtexture = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, BEAMWIDTH, BEAMHEIGHT, false); + Mem_Free(noise1); + Mem_Free(noise2); + Mem_Free(data); +#endif +} + +static void r_lightningbeams_shutdown(void) +{ + r_lightningbeamtexture = NULL; + r_lightningbeamqmbtexture = NULL; +} + +static void r_lightningbeams_newmap(void) +{ + if (r_lightningbeamtexture) + R_SkinFrame_MarkUsed(r_lightningbeamtexture); + if (r_lightningbeamqmbtexture) + R_SkinFrame_MarkUsed(r_lightningbeamqmbtexture); +} + +void R_LightningBeams_Init(void) +{ + Cvar_RegisterVariable(&r_lightningbeam_thickness); + Cvar_RegisterVariable(&r_lightningbeam_scroll); + Cvar_RegisterVariable(&r_lightningbeam_repeatdistance); + Cvar_RegisterVariable(&r_lightningbeam_color_red); + Cvar_RegisterVariable(&r_lightningbeam_color_green); + Cvar_RegisterVariable(&r_lightningbeam_color_blue); + Cvar_RegisterVariable(&r_lightningbeam_qmbtexture); + R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap, NULL, NULL); +} + +static void R_CalcLightningBeamPolygonVertex3f(float *v, const float *start, const float *end, const float *offset) +{ + // near right corner + VectorAdd (start, offset, (v + 0)); + // near left corner + VectorSubtract(start, offset, (v + 3)); + // far left corner + VectorSubtract(end , offset, (v + 6)); + // far right corner + VectorAdd (end , offset, (v + 9)); +} + +static void R_CalcLightningBeamPolygonTexCoord2f(float *tc, float t1, float t2) +{ + if (r_lightningbeam_qmbtexture.integer) + { + // near right corner + tc[0] = t1;tc[1] = 0; + // near left corner + tc[2] = t1;tc[3] = 1; + // far left corner + tc[4] = t2;tc[5] = 1; + // far right corner + tc[6] = t2;tc[7] = 0; + } + else + { + // near right corner + tc[0] = 0;tc[1] = t1; + // near left corner + tc[2] = 1;tc[3] = t1; + // far left corner + tc[4] = 1;tc[5] = t2; + // far right corner + tc[6] = 0;tc[7] = t2; + } +} + +float beamrepeatscale; + +static void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int surfacelistindex; + float vertex3f[12*3]; + float texcoord2f[12*2]; + + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1, 12, vertex3f, texcoord2f, NULL, NULL, NULL, NULL, 6, r_lightningbeamelement3i, r_lightningbeamelement3s, false, false); + + if (r_lightningbeam_qmbtexture.integer && r_lightningbeamqmbtexture == NULL) + r_lightningbeams_setupqmbtexture(); + if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL) + r_lightningbeams_setuptexture(); + + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + const beam_t *b = cl.beams + surfacelist[surfacelistindex]; + vec3_t beamdir, right, up, offset, start, end; + float length, t1, t2; + + CL_Beam_CalculatePositions(b, start, end); + + // calculate beam direction (beamdir) vector and beam length + // get difference vector + VectorSubtract(end, start, beamdir); + // find length of difference vector + length = sqrt(DotProduct(beamdir, beamdir)); + // calculate scale to make beamdir a unit vector (normalized) + t1 = 1.0f / length; + // scale beamdir so it is now normalized + VectorScale(beamdir, t1, beamdir); + + // calculate up vector such that it points toward viewer, and rotates around the beamdir + // get direction from start of beam to viewer + VectorSubtract(r_refdef.view.origin, start, up); + // remove the portion of the vector that moves along the beam + // (this leaves only a vector pointing directly away from the beam) + t1 = -DotProduct(up, beamdir); + VectorMA(up, t1, beamdir, up); + // generate right vector from forward and up, the result is unnormalized + CrossProduct(beamdir, up, right); + // now normalize the right vector and up vector + VectorNormalize(right); + VectorNormalize(up); + + // calculate T coordinate scrolling (start and end texcoord along the beam) + t1 = r_refdef.scene.time * -r_lightningbeam_scroll.value;// + beamrepeatscale * DotProduct(start, beamdir); + t1 = t1 - (int) t1; + t2 = t1 + beamrepeatscale * length; + + // the beam is 3 polygons in this configuration: + // * 2 + // * * + // 1****** + // * * + // * 3 + // they are showing different portions of the beam texture, creating an + // illusion of a beam that appears to curl around in 3D space + // (and realize that the whole polygon assembly orients itself to face + // the viewer) + + // polygon 1, verts 0-3 + VectorScale(right, r_lightningbeam_thickness.value, offset); + R_CalcLightningBeamPolygonVertex3f(vertex3f + 0, start, end, offset); + // polygon 2, verts 4-7 + VectorAdd(right, up, offset); + VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); + R_CalcLightningBeamPolygonVertex3f(vertex3f + 12, start, end, offset); + // polygon 3, verts 8-11 + VectorSubtract(right, up, offset); + VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset); + R_CalcLightningBeamPolygonVertex3f(vertex3f + 24, start, end, offset); + R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 0, t1, t2); + R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 8, t1 + 0.33, t2 + 0.33); + R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 16, t1 + 0.66, t2 + 0.66); + + // draw the 3 polygons as one batch of 6 triangles using the 12 vertices + R_DrawCustomSurface(r_lightningbeam_qmbtexture.integer ? r_lightningbeamqmbtexture : r_lightningbeamtexture, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 12, 0, 6, false, false); + } +} + +extern cvar_t cl_beams_polygons; +void R_DrawLightningBeams(void) +{ + int i; + beam_t *b; + + if (!cl_beams_polygons.integer) + return; + + beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value; + for (i = 0, b = cl.beams;i < cl.num_beams;i++, b++) + { + if (b->model && b->lightning) + { + vec3_t org, start, end, dir; + vec_t dist; + CL_Beam_CalculatePositions(b, start, end); + // calculate the nearest point on the line (beam) for depth sorting + VectorSubtract(end, start, dir); + dist = (DotProduct(r_refdef.view.origin, dir) - DotProduct(start, dir)) / (DotProduct(end, dir) - DotProduct(start, dir)); + dist = bound(0, dist, 1); + VectorLerp(start, dist, end, org); + // now we have the nearest point on the line, so sort with it + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL); + } + } +} + diff --git a/app/jni/r_modules.c b/app/jni/r_modules.c new file mode 100644 index 0000000..818637e --- /dev/null +++ b/app/jni/r_modules.c @@ -0,0 +1,134 @@ + +#include "quakedef.h" + +#define MAXRENDERMODULES 20 + +typedef struct rendermodule_s +{ + int active; // set by start, cleared by shutdown + const char *name; + void(*start)(void); + void(*shutdown)(void); + void(*newmap)(void); + void(*devicelost)(void); + void(*devicerestored)(void); +} +rendermodule_t; + +rendermodule_t rendermodule[MAXRENDERMODULES]; + +void R_Modules_Init(void) +{ + Cmd_AddCommand("r_restart", R_Modules_Restart, "restarts renderer"); +} + +void R_RegisterModule(const char *name, void(*start)(void), void(*shutdown)(void), void(*newmap)(void), void(*devicelost)(void), void(*devicerestored)(void)) +{ + int i; + for (i = 0;i < MAXRENDERMODULES;i++) + { + if (rendermodule[i].name == NULL) + break; + if (!strcmp(name, rendermodule[i].name)) + { + Con_Printf("R_RegisterModule: module \"%s\" registered twice\n", name); + return; + } + } + if (i >= MAXRENDERMODULES) + Sys_Error("R_RegisterModule: ran out of renderer module slots (%i)", MAXRENDERMODULES); + rendermodule[i].active = 0; + rendermodule[i].name = name; + rendermodule[i].start = start; + rendermodule[i].shutdown = shutdown; + rendermodule[i].newmap = newmap; + rendermodule[i].devicelost = devicelost; + rendermodule[i].devicerestored = devicerestored; +} + +void R_Modules_Start(void) +{ + int i; + for (i = 0;i < MAXRENDERMODULES;i++) + { + if (rendermodule[i].name == NULL) + continue; + if (rendermodule[i].active) + { + Con_Printf ("R_StartModules: module \"%s\" already active\n", rendermodule[i].name); + continue; + } + rendermodule[i].active = 1; + rendermodule[i].start(); + } +} + +void R_Modules_Shutdown(void) +{ + int i; + // shutdown in reverse + for (i = MAXRENDERMODULES - 1;i >= 0;i--) + { + if (rendermodule[i].name == NULL) + continue; + if (!rendermodule[i].active) + continue; + rendermodule[i].active = 0; + rendermodule[i].shutdown(); + } +} + +void R_Modules_Restart(void) +{ + Host_StartVideo(); + Con_Print("restarting renderer\n"); + R_Modules_Shutdown(); + R_Modules_Start(); +} + +void R_Modules_NewMap(void) +{ + int i; + R_SkinFrame_PrepareForPurge(); + for (i = 0;i < MAXRENDERMODULES;i++) + { + if (rendermodule[i].name == NULL) + continue; + if (!rendermodule[i].active) + continue; + rendermodule[i].newmap(); + } + R_SkinFrame_Purge(); +} + +void R_Modules_DeviceLost(void) +{ + int i; + for (i = 0;i < MAXRENDERMODULES;i++) + { + if (rendermodule[i].name == NULL) + continue; + if (!rendermodule[i].active) + continue; + if (!rendermodule[i].devicelost) + continue; + rendermodule[i].devicelost(); + } +} + + +void R_Modules_DeviceRestored(void) +{ + int i; + for (i = 0;i < MAXRENDERMODULES;i++) + { + if (rendermodule[i].name == NULL) + continue; + if (!rendermodule[i].active) + continue; + if (!rendermodule[i].devicerestored) + continue; + rendermodule[i].devicerestored(); + } +} + diff --git a/app/jni/r_modules.h b/app/jni/r_modules.h new file mode 100644 index 0000000..ad838d1 --- /dev/null +++ b/app/jni/r_modules.h @@ -0,0 +1,15 @@ + +#ifndef R_MODULES_H +#define R_MODULES_H + +void R_Modules_Init(void); +void R_RegisterModule(const char *name, void(*start)(void), void(*shutdown)(void), void(*newmap)(void), void(*devicelost)(void), void(*devicerestored)(void)); +void R_Modules_Start(void); +void R_Modules_Shutdown(void); +void R_Modules_NewMap(void); +void R_Modules_Restart(void); +void R_Modules_DeviceLost(void); +void R_Modules_DeviceRestored(void); + +#endif + diff --git a/app/jni/r_shadow.c b/app/jni/r_shadow.c new file mode 100644 index 0000000..727e7d4 --- /dev/null +++ b/app/jni/r_shadow.c @@ -0,0 +1,6919 @@ + +/* +Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows) +An extrusion of the lit faces, beginning at the original geometry and ending +further from the light source than the original geometry (presumably at least +as far as the light's radius, if the light has a radius at all), capped at +both front and back to avoid any problems (extrusion from dark faces also +works but has a different set of problems) + +This is normally rendered using Carmack's Reverse technique, in which +backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind +zbuffer (zfail) decrement the stencil, the result is a stencil value of zero +where shadows did not intersect the visible geometry, suitable as a stencil +mask for rendering lighting everywhere but shadow. + +In our case to hopefully avoid the Creative Labs patent, we draw the backfaces +as decrement and the frontfaces as increment, and we redefine the DepthFunc to +GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces +and zpass when infront (the patent draws where zpass with a GL_GEQUAL test), +additionally we clear stencil to 128 to avoid the need for the unclamped +incr/decr extension (not related to patent). + +Patent warning: +This algorithm may be covered by Creative's patent (US Patent #6384822), +however that patent is quite specific about increment on backfaces and +decrement on frontfaces where zpass with GL_GEQUAL depth test, which is +opposite this implementation and partially opposite Carmack's Reverse paper +(which uses GL_LESS, but increments on backfaces and decrements on frontfaces). + + + +Terminology: Stencil Light Volume (sometimes called Light Volumes) +Similar to a Stencil Shadow Volume, but inverted; rather than containing the +areas in shadow it contains the areas in light, this can only be built +quickly for certain limited cases (such as portal visibility from a point), +but is quite useful for some effects (sunlight coming from sky polygons is +one possible example, translucent occluders is another example). + + + +Terminology: Optimized Stencil Shadow Volume +A Stencil Shadow Volume that has been processed sufficiently to ensure it has +no duplicate coverage of areas (no need to shadow an area twice), often this +greatly improves performance but is an operation too costly to use on moving +lights (however completely optimal Stencil Light Volumes can be constructed +in some ideal cases). + + + +Terminology: Per Pixel Lighting (sometimes abbreviated PPL) +Per pixel evaluation of lighting equations, at a bare minimum this involves +DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence +vector and surface normal, using a texture of the surface bumps, called a +NormalMap) if supported by hardware; in our case there is support for cards +which are incapable of DOT3, the quality is quite poor however. Additionally +it is desirable to have specular evaluation per pixel, per vertex +normalization of specular halfangle vectors causes noticable distortion but +is unavoidable on hardware without GL_ARB_fragment_program or +GL_ARB_fragment_shader. + + + +Terminology: Normalization CubeMap +A cubemap containing normalized dot3-encoded (vectors of length 1 or less +encoded as RGB colors) for any possible direction, this technique allows per +pixel calculation of incidence vector for per pixel lighting purposes, which +would not otherwise be possible per pixel without GL_ARB_fragment_program or +GL_ARB_fragment_shader. + + + +Terminology: 2D+1D Attenuation Texturing +A very crude approximation of light attenuation with distance which results +in cylindrical light shapes which fade vertically as a streak (some games +such as Doom3 allow this to be rotated to be less noticable in specific +cases), the technique is simply modulating lighting by two 2D textures (which +can be the same) on different axes of projection (XY and Z, typically), this +is the second best technique available without 3D Attenuation Texturing, +GL_ARB_fragment_program or GL_ARB_fragment_shader technology. + + + +Terminology: 2D+1D Inverse Attenuation Texturing +A clever method described in papers on the Abducted engine, this has a squared +distance texture (bright on the outside, black in the middle), which is used +twice using GL_ADD blending, the result of this is used in an inverse modulate +(GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation +lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation +texturing). + + + +Terminology: 3D Attenuation Texturing +A slightly crude approximation of light attenuation with distance, its flaws +are limited radius and resolution (performance tradeoffs). + + + +Terminology: 3D Attenuation-Normalization Texturing +A 3D Attenuation Texture merged with a Normalization CubeMap, by making the +vectors shorter the lighting becomes darker, a very effective optimization of +diffuse lighting if 3D Attenuation Textures are already used. + + + +Terminology: Light Cubemap Filtering +A technique for modeling non-uniform light distribution according to +direction, for example a lantern may use a cubemap to describe the light +emission pattern of the cage around the lantern (as well as soot buildup +discoloring the light in certain areas), often also used for softened grate +shadows and light shining through a stained glass window (done crudely by +texturing the lighting with a cubemap), another good example would be a disco +light. This technique is used heavily in many games (Doom3 does not support +this however). + + + +Terminology: Light Projection Filtering +A technique for modeling shadowing of light passing through translucent +surfaces, allowing stained glass windows and other effects to be done more +elegantly than possible with Light Cubemap Filtering by applying an occluder +texture to the lighting combined with a stencil light volume to limit the lit +area, this technique is used by Doom3 for spotlights and flashlights, among +other things, this can also be used more generally to render light passing +through multiple translucent occluders in a scene (using a light volume to +describe the area beyond the occluder, and thus mask off rendering of all +other areas). + + + +Terminology: Doom3 Lighting +A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization +CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as +demonstrated by the game Doom3. +*/ + +#include "quakedef.h" +#include "r_shadow.h" +#include "cl_collision.h" +#include "portals.h" +#include "image.h" +#include "dpsoftrast.h" + +#ifdef SUPPORTD3D +#include +extern LPDIRECT3DDEVICE9 vid_d3d9dev; +#endif + +static void R_Shadow_EditLights_Init(void); + +typedef enum r_shadow_rendermode_e +{ + R_SHADOW_RENDERMODE_NONE, + R_SHADOW_RENDERMODE_ZPASS_STENCIL, + R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL, + R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE, + R_SHADOW_RENDERMODE_ZFAIL_STENCIL, + R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL, + R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE, + R_SHADOW_RENDERMODE_LIGHT_VERTEX, + R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN, + R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN, + R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN, + R_SHADOW_RENDERMODE_LIGHT_GLSL, + R_SHADOW_RENDERMODE_VISIBLEVOLUMES, + R_SHADOW_RENDERMODE_VISIBLELIGHTING, + R_SHADOW_RENDERMODE_SHADOWMAP2D +} +r_shadow_rendermode_t; + +typedef enum r_shadow_shadowmode_e +{ + R_SHADOW_SHADOWMODE_STENCIL, + R_SHADOW_SHADOWMODE_SHADOWMAP2D +} +r_shadow_shadowmode_t; + +r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; +r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE; +r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE; +r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE; +qboolean r_shadow_usingshadowmap2d; +qboolean r_shadow_usingshadowmaportho; +int r_shadow_shadowmapside; +float r_shadow_shadowmap_texturescale[2]; +float r_shadow_shadowmap_parameters[4]; +#if 0 +int r_shadow_drawbuffer; +int r_shadow_readbuffer; +#endif +int r_shadow_cullface_front, r_shadow_cullface_back; +GLuint r_shadow_fbo2d; +r_shadow_shadowmode_t r_shadow_shadowmode; +int r_shadow_shadowmapfilterquality; +int r_shadow_shadowmapdepthbits; +int r_shadow_shadowmapmaxsize; +qboolean r_shadow_shadowmapvsdct; +qboolean r_shadow_shadowmapsampler; +qboolean r_shadow_shadowmapshadowsampler; +int r_shadow_shadowmappcf; +int r_shadow_shadowmapborder; +matrix4x4_t r_shadow_shadowmapmatrix; +int r_shadow_lightscissor[4]; +qboolean r_shadow_usingdeferredprepass; +qboolean r_shadow_shadowmapdepthtexture; +int maxshadowtriangles; +int *shadowelements; + +int maxshadowvertices; +float *shadowvertex3f; + +int maxshadowmark; +int numshadowmark; +int *shadowmark; +int *shadowmarklist; +int shadowmarkcount; + +int maxshadowsides; +int numshadowsides; +unsigned char *shadowsides; +int *shadowsideslist; + +int maxvertexupdate; +int *vertexupdate; +int *vertexremap; +int vertexupdatenum; + +int r_shadow_buffer_numleafpvsbytes; +unsigned char *r_shadow_buffer_visitingleafpvs; +unsigned char *r_shadow_buffer_leafpvs; +int *r_shadow_buffer_leaflist; + +int r_shadow_buffer_numsurfacepvsbytes; +unsigned char *r_shadow_buffer_surfacepvs; +int *r_shadow_buffer_surfacelist; +unsigned char *r_shadow_buffer_surfacesides; + +int r_shadow_buffer_numshadowtrispvsbytes; +unsigned char *r_shadow_buffer_shadowtrispvs; +int r_shadow_buffer_numlighttrispvsbytes; +unsigned char *r_shadow_buffer_lighttrispvs; + +rtexturepool_t *r_shadow_texturepool; +rtexture_t *r_shadow_attenuationgradienttexture; +rtexture_t *r_shadow_attenuation2dtexture; +rtexture_t *r_shadow_attenuation3dtexture; +skinframe_t *r_shadow_lightcorona; +rtexture_t *r_shadow_shadowmap2ddepthbuffer; +rtexture_t *r_shadow_shadowmap2ddepthtexture; +rtexture_t *r_shadow_shadowmapvsdcttexture; +int r_shadow_shadowmapsize; // changes for each light based on distance +int r_shadow_shadowmaplod; // changes for each light based on distance + +GLuint r_shadow_prepassgeometryfbo; +GLuint r_shadow_prepasslightingdiffusespecularfbo; +GLuint r_shadow_prepasslightingdiffusefbo; +int r_shadow_prepass_width; +int r_shadow_prepass_height; +rtexture_t *r_shadow_prepassgeometrydepthbuffer; +rtexture_t *r_shadow_prepassgeometrynormalmaptexture; +rtexture_t *r_shadow_prepasslightingdiffusetexture; +rtexture_t *r_shadow_prepasslightingspeculartexture; + +// keep track of the provided framebuffer info +static int r_shadow_fb_fbo; +static rtexture_t *r_shadow_fb_depthtexture; +static rtexture_t *r_shadow_fb_colortexture; + +// lights are reloaded when this changes +char r_shadow_mapname[MAX_QPATH]; + +// used only for light filters (cubemaps) +rtexturepool_t *r_shadow_filters_texturepool; + +cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"}; +cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"}; +cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"}; +cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"}; +cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"}; +cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"}; +cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"}; +cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"}; +cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"}; +cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"}; +cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"}; +cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"}; +cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"}; +cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"}; +cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"}; +cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"}; +cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"}; +cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"}; +cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"}; +cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"}; +cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"}; +cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"}; +cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"}; +cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"}; +cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"}; +cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"}; +cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"}; +cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"}; +cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"}; +cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"}; +cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"}; +cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"}; +cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"}; +cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"}; +cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"}; +cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"}; +cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"}; +cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"}; +//cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"}; +//cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"}; +cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"}; +cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"}; +cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"}; +cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"}; +cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"}; +cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"}; +cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"}; +cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"}; +cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"}; +cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"}; +cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"}; +cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"}; +cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"}; +cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"}; +cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"}; +cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"}; +cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"}; +cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"}; +cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"}; +cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"}; +cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"}; +cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"}; +cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"}; +cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"}; +cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"}; +cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"}; +cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"}; +cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"}; +cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"}; +cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"}; +cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"}; +cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"}; +cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"}; +cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"}; +cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"}; +cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"}; +cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"}; +cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"}; +cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"}; +cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"}; +cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"}; +cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"}; +cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"}; +cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"}; +cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"}; +cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"}; +cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"}; +cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"}; +cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"}; +cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"}; +cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"}; +cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"}; +cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"}; +cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"}; +cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"}; +cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"}; +cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"}; +cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"}; +cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"}; + + +typedef struct r_shadow_bouncegrid_settings_s +{ + qboolean staticmode; + qboolean bounceanglediffuse; + qboolean directionalshading; + qboolean includedirectlighting; + float dlightparticlemultiplier; + qboolean hitmodels; + float lightradiusscale; + int maxbounce; + float particlebounceintensity; + float particleintensity; + int photons; + float spacing[3]; + int stablerandom; +} +r_shadow_bouncegrid_settings_t; + +r_shadow_bouncegrid_settings_t r_shadow_bouncegridsettings; +rtexture_t *r_shadow_bouncegridtexture; +matrix4x4_t r_shadow_bouncegridmatrix; +vec_t r_shadow_bouncegridintensity; +qboolean r_shadow_bouncegriddirectional; +static double r_shadow_bouncegridtime; +static int r_shadow_bouncegridresolution[3]; +static int r_shadow_bouncegridnumpixels; +static unsigned char *r_shadow_bouncegridpixels; +static float *r_shadow_bouncegridhighpixels; + +// note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error +#define ATTENTABLESIZE 256 +// 1D gradient, 2D circle and 3D sphere attenuation textures +#define ATTEN1DSIZE 32 +#define ATTEN2DSIZE 64 +#define ATTEN3DSIZE 32 + +static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias +static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale +static float r_shadow_attentable[ATTENTABLESIZE+1]; + +rtlight_t *r_shadow_compilingrtlight; +static memexpandablearray_t r_shadow_worldlightsarray; +dlight_t *r_shadow_selectedlight; +dlight_t r_shadow_bufferlight; +vec3_t r_editlights_cursorlocation; +qboolean r_editlights_lockcursor; + +extern int con_vislines; + +void R_Shadow_UncompileWorldLights(void); +void R_Shadow_ClearWorldLights(void); +void R_Shadow_SaveWorldLights(void); +void R_Shadow_LoadWorldLights(void); +void R_Shadow_LoadLightsFile(void); +void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void); +void R_Shadow_EditLights_Reload_f(void); +void R_Shadow_ValidateCvars(void); +static void R_Shadow_MakeTextures(void); + +#define EDLIGHTSPRSIZE 8 +skinframe_t *r_editlights_sprcursor; +skinframe_t *r_editlights_sprlight; +skinframe_t *r_editlights_sprnoshadowlight; +skinframe_t *r_editlights_sprcubemaplight; +skinframe_t *r_editlights_sprcubemapnoshadowlight; +skinframe_t *r_editlights_sprselection; + +static void R_Shadow_SetShadowMode(void) +{ + r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4); + r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20; + r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer; + r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0; + r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer; + r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16); + r_shadow_shadowmaplod = -1; + r_shadow_shadowmapsize = 0; + r_shadow_shadowmapsampler = false; + r_shadow_shadowmappcf = 0; + r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL; + if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object) + { + switch(vid.renderpath) + { + case RENDERPATH_GL20: + if(r_shadow_shadowmapfilterquality < 0) + { + if (!r_fb.usedepthtextures) + r_shadow_shadowmappcf = 1; + else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler) + { + r_shadow_shadowmapsampler = true; + r_shadow_shadowmappcf = 1; + } + else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) + r_shadow_shadowmappcf = 1; + else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa")) + r_shadow_shadowmappcf = 1; + else + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; + } + else + { + r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler; + switch (r_shadow_shadowmapfilterquality) + { + case 1: + break; + case 2: + r_shadow_shadowmappcf = 1; + break; + case 3: + r_shadow_shadowmappcf = 1; + break; + case 4: + r_shadow_shadowmappcf = 2; + break; + } + } + if (!r_fb.usedepthtextures) + r_shadow_shadowmapsampler = false; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + r_shadow_shadowmapsampler = false; + r_shadow_shadowmappcf = 1; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + } + } + + if(R_CompileShader_CheckStaticParms()) + R_GLSL_Restart_f(); +} + +qboolean R_Shadow_ShadowMappingEnabled(void) +{ + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + return true; + default: + return false; + } +} + +static void R_Shadow_FreeShadowMaps(void) +{ + R_Shadow_SetShadowMode(); + + R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d); + + r_shadow_fbo2d = 0; + + if (r_shadow_shadowmap2ddepthtexture) + R_FreeTexture(r_shadow_shadowmap2ddepthtexture); + r_shadow_shadowmap2ddepthtexture = NULL; + + if (r_shadow_shadowmap2ddepthbuffer) + R_FreeTexture(r_shadow_shadowmap2ddepthbuffer); + r_shadow_shadowmap2ddepthbuffer = NULL; + + if (r_shadow_shadowmapvsdcttexture) + R_FreeTexture(r_shadow_shadowmapvsdcttexture); + r_shadow_shadowmapvsdcttexture = NULL; +} + +static void r_shadow_start(void) +{ + // allocate vertex processing arrays + r_shadow_bouncegridpixels = NULL; + r_shadow_bouncegridhighpixels = NULL; + r_shadow_bouncegridnumpixels = 0; + r_shadow_bouncegridtexture = NULL; + r_shadow_bouncegriddirectional = false; + r_shadow_attenuationgradienttexture = NULL; + r_shadow_attenuation2dtexture = NULL; + r_shadow_attenuation3dtexture = NULL; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL; + r_shadow_shadowmap2ddepthtexture = NULL; + r_shadow_shadowmap2ddepthbuffer = NULL; + r_shadow_shadowmapvsdcttexture = NULL; + r_shadow_shadowmapmaxsize = 0; + r_shadow_shadowmapsize = 0; + r_shadow_shadowmaplod = 0; + r_shadow_shadowmapfilterquality = -1; + r_shadow_shadowmapdepthbits = 0; + r_shadow_shadowmapvsdct = false; + r_shadow_shadowmapsampler = false; + r_shadow_shadowmappcf = 0; + r_shadow_fbo2d = 0; + + R_Shadow_FreeShadowMaps(); + + r_shadow_texturepool = NULL; + r_shadow_filters_texturepool = NULL; + R_Shadow_ValidateCvars(); + R_Shadow_MakeTextures(); + maxshadowtriangles = 0; + shadowelements = NULL; + maxshadowvertices = 0; + shadowvertex3f = NULL; + maxvertexupdate = 0; + vertexupdate = NULL; + vertexremap = NULL; + vertexupdatenum = 0; + maxshadowmark = 0; + numshadowmark = 0; + shadowmark = NULL; + shadowmarklist = NULL; + shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + shadowsides = NULL; + shadowsideslist = NULL; + r_shadow_buffer_numleafpvsbytes = 0; + r_shadow_buffer_visitingleafpvs = NULL; + r_shadow_buffer_leafpvs = NULL; + r_shadow_buffer_leaflist = NULL; + r_shadow_buffer_numsurfacepvsbytes = 0; + r_shadow_buffer_surfacepvs = NULL; + r_shadow_buffer_surfacelist = NULL; + r_shadow_buffer_surfacesides = NULL; + r_shadow_buffer_numshadowtrispvsbytes = 0; + r_shadow_buffer_shadowtrispvs = NULL; + r_shadow_buffer_numlighttrispvsbytes = 0; + r_shadow_buffer_lighttrispvs = NULL; + + r_shadow_usingdeferredprepass = false; + r_shadow_prepass_width = r_shadow_prepass_height = 0; +} + +static void R_Shadow_FreeDeferred(void); +static void r_shadow_shutdown(void) +{ + CHECKGLERROR + R_Shadow_UncompileWorldLights(); + + R_Shadow_FreeShadowMaps(); + + r_shadow_usingdeferredprepass = false; + if (r_shadow_prepass_width) + R_Shadow_FreeDeferred(); + r_shadow_prepass_width = r_shadow_prepass_height = 0; + + CHECKGLERROR + r_shadow_bouncegridtexture = NULL; + r_shadow_bouncegridpixels = NULL; + r_shadow_bouncegridhighpixels = NULL; + r_shadow_bouncegridnumpixels = 0; + r_shadow_bouncegriddirectional = false; + r_shadow_attenuationgradienttexture = NULL; + r_shadow_attenuation2dtexture = NULL; + r_shadow_attenuation3dtexture = NULL; + R_FreeTexturePool(&r_shadow_texturepool); + R_FreeTexturePool(&r_shadow_filters_texturepool); + maxshadowtriangles = 0; + if (shadowelements) + Mem_Free(shadowelements); + shadowelements = NULL; + if (shadowvertex3f) + Mem_Free(shadowvertex3f); + shadowvertex3f = NULL; + maxvertexupdate = 0; + if (vertexupdate) + Mem_Free(vertexupdate); + vertexupdate = NULL; + if (vertexremap) + Mem_Free(vertexremap); + vertexremap = NULL; + vertexupdatenum = 0; + maxshadowmark = 0; + numshadowmark = 0; + if (shadowmark) + Mem_Free(shadowmark); + shadowmark = NULL; + if (shadowmarklist) + Mem_Free(shadowmarklist); + shadowmarklist = NULL; + shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + if (shadowsides) + Mem_Free(shadowsides); + shadowsides = NULL; + if (shadowsideslist) + Mem_Free(shadowsideslist); + shadowsideslist = NULL; + r_shadow_buffer_numleafpvsbytes = 0; + if (r_shadow_buffer_visitingleafpvs) + Mem_Free(r_shadow_buffer_visitingleafpvs); + r_shadow_buffer_visitingleafpvs = NULL; + if (r_shadow_buffer_leafpvs) + Mem_Free(r_shadow_buffer_leafpvs); + r_shadow_buffer_leafpvs = NULL; + if (r_shadow_buffer_leaflist) + Mem_Free(r_shadow_buffer_leaflist); + r_shadow_buffer_leaflist = NULL; + r_shadow_buffer_numsurfacepvsbytes = 0; + if (r_shadow_buffer_surfacepvs) + Mem_Free(r_shadow_buffer_surfacepvs); + r_shadow_buffer_surfacepvs = NULL; + if (r_shadow_buffer_surfacelist) + Mem_Free(r_shadow_buffer_surfacelist); + r_shadow_buffer_surfacelist = NULL; + if (r_shadow_buffer_surfacesides) + Mem_Free(r_shadow_buffer_surfacesides); + r_shadow_buffer_surfacesides = NULL; + r_shadow_buffer_numshadowtrispvsbytes = 0; + if (r_shadow_buffer_shadowtrispvs) + Mem_Free(r_shadow_buffer_shadowtrispvs); + r_shadow_buffer_numlighttrispvsbytes = 0; + if (r_shadow_buffer_lighttrispvs) + Mem_Free(r_shadow_buffer_lighttrispvs); +} + +static void r_shadow_newmap(void) +{ + if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL; + if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona); + if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor); + if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight); + if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); + if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); + if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); + if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection); + if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname))) + R_Shadow_EditLights_Reload_f(); +} + +void R_Shadow_Init(void) +{ + Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture); + Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap); + Cvar_RegisterVariable(&r_shadow_usebihculling); + Cvar_RegisterVariable(&r_shadow_usenormalmap); + Cvar_RegisterVariable(&r_shadow_debuglight); + Cvar_RegisterVariable(&r_shadow_deferred); + Cvar_RegisterVariable(&r_shadow_gloss); + Cvar_RegisterVariable(&r_shadow_gloss2intensity); + Cvar_RegisterVariable(&r_shadow_glossintensity); + Cvar_RegisterVariable(&r_shadow_glossexponent); + Cvar_RegisterVariable(&r_shadow_gloss2exponent); + Cvar_RegisterVariable(&r_shadow_glossexact); + Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias); + Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale); + Cvar_RegisterVariable(&r_shadow_lightintensityscale); + Cvar_RegisterVariable(&r_shadow_lightradiusscale); + Cvar_RegisterVariable(&r_shadow_projectdistance); + Cvar_RegisterVariable(&r_shadow_frontsidecasting); + Cvar_RegisterVariable(&r_shadow_realtime_dlight); + Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows); + Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling); + Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling); + Cvar_RegisterVariable(&r_shadow_realtime_world); + Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps); + Cvar_RegisterVariable(&r_shadow_realtime_world_shadows); + Cvar_RegisterVariable(&r_shadow_realtime_world_compile); + Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow); + Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp); + Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling); + Cvar_RegisterVariable(&r_shadow_scissor); + Cvar_RegisterVariable(&r_shadow_shadowmapping); + Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct); + Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality); + Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler); + Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits); + Cvar_RegisterVariable(&r_shadow_shadowmapping_precision); + Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize); + Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize); +// Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias); +// Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale); + Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize); + Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip); + Cvar_RegisterVariable(&r_shadow_shadowmapping_bias); + Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor); + Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset); + Cvar_RegisterVariable(&r_shadow_sortsurfaces); + Cvar_RegisterVariable(&r_shadow_polygonfactor); + Cvar_RegisterVariable(&r_shadow_polygonoffset); + Cvar_RegisterVariable(&r_shadow_texture3d); + Cvar_RegisterVariable(&r_shadow_bouncegrid); + Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse); + Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading); + Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier); + Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels); + Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting); + Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity); + Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale); + Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce); + Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity); + Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity); + Cvar_RegisterVariable(&r_shadow_bouncegrid_photons); + Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing); + Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom); + Cvar_RegisterVariable(&r_shadow_bouncegrid_static); + Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading); + Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale); + Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce); + Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons); + Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval); + Cvar_RegisterVariable(&r_shadow_bouncegrid_x); + Cvar_RegisterVariable(&r_shadow_bouncegrid_y); + Cvar_RegisterVariable(&r_shadow_bouncegrid_z); + Cvar_RegisterVariable(&r_coronas); + Cvar_RegisterVariable(&r_coronas_occlusionsizescale); + Cvar_RegisterVariable(&r_coronas_occlusionquery); + Cvar_RegisterVariable(&gl_flashblend); + Cvar_RegisterVariable(&gl_ext_separatestencil); + Cvar_RegisterVariable(&gl_ext_stenciltwoside); + R_Shadow_EditLights_Init(); + Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128); + maxshadowtriangles = 0; + shadowelements = NULL; + maxshadowvertices = 0; + shadowvertex3f = NULL; + maxvertexupdate = 0; + vertexupdate = NULL; + vertexremap = NULL; + vertexupdatenum = 0; + maxshadowmark = 0; + numshadowmark = 0; + shadowmark = NULL; + shadowmarklist = NULL; + shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + shadowsides = NULL; + shadowsideslist = NULL; + r_shadow_buffer_numleafpvsbytes = 0; + r_shadow_buffer_visitingleafpvs = NULL; + r_shadow_buffer_leafpvs = NULL; + r_shadow_buffer_leaflist = NULL; + r_shadow_buffer_numsurfacepvsbytes = 0; + r_shadow_buffer_surfacepvs = NULL; + r_shadow_buffer_surfacelist = NULL; + r_shadow_buffer_surfacesides = NULL; + r_shadow_buffer_shadowtrispvs = NULL; + r_shadow_buffer_lighttrispvs = NULL; + R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL); +} + +matrix4x4_t matrix_attenuationxyz = +{ + { + {0.5, 0.0, 0.0, 0.5}, + {0.0, 0.5, 0.0, 0.5}, + {0.0, 0.0, 0.5, 0.5}, + {0.0, 0.0, 0.0, 1.0} + } +}; + +matrix4x4_t matrix_attenuationz = +{ + { + {0.0, 0.0, 0.5, 0.5}, + {0.0, 0.0, 0.0, 0.5}, + {0.0, 0.0, 0.0, 0.5}, + {0.0, 0.0, 0.0, 1.0} + } +}; + +static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale) +{ + numvertices = ((numvertices + 255) & ~255) * vertscale; + numtriangles = ((numtriangles + 255) & ~255) * triscale; + // make sure shadowelements is big enough for this volume + if (maxshadowtriangles < numtriangles) + { + maxshadowtriangles = numtriangles; + if (shadowelements) + Mem_Free(shadowelements); + shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3])); + } + // make sure shadowvertex3f is big enough for this volume + if (maxshadowvertices < numvertices) + { + maxshadowvertices = numvertices; + if (shadowvertex3f) + Mem_Free(shadowvertex3f); + shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3])); + } +} + +static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles) +{ + int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255; + int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255; + int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255; + int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255; + if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes) + { + if (r_shadow_buffer_visitingleafpvs) + Mem_Free(r_shadow_buffer_visitingleafpvs); + if (r_shadow_buffer_leafpvs) + Mem_Free(r_shadow_buffer_leafpvs); + if (r_shadow_buffer_leaflist) + Mem_Free(r_shadow_buffer_leaflist); + r_shadow_buffer_numleafpvsbytes = numleafpvsbytes; + r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes); + r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes); + r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist)); + } + if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes) + { + if (r_shadow_buffer_surfacepvs) + Mem_Free(r_shadow_buffer_surfacepvs); + if (r_shadow_buffer_surfacelist) + Mem_Free(r_shadow_buffer_surfacelist); + if (r_shadow_buffer_surfacesides) + Mem_Free(r_shadow_buffer_surfacesides); + r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes; + r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes); + r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist)); + r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist)); + } + if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes) + { + if (r_shadow_buffer_shadowtrispvs) + Mem_Free(r_shadow_buffer_shadowtrispvs); + r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes; + r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes); + } + if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes) + { + if (r_shadow_buffer_lighttrispvs) + Mem_Free(r_shadow_buffer_lighttrispvs); + r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes; + r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes); + } +} + +void R_Shadow_PrepareShadowMark(int numtris) +{ + // make sure shadowmark is big enough for this volume + if (maxshadowmark < numtris) + { + maxshadowmark = numtris; + if (shadowmark) + Mem_Free(shadowmark); + if (shadowmarklist) + Mem_Free(shadowmarklist); + shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark)); + shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist)); + shadowmarkcount = 0; + } + shadowmarkcount++; + // if shadowmarkcount wrapped we clear the array and adjust accordingly + if (shadowmarkcount == 0) + { + shadowmarkcount = 1; + memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark)); + } + numshadowmark = 0; +} + +void R_Shadow_PrepareShadowSides(int numtris) +{ + if (maxshadowsides < numtris) + { + maxshadowsides = numtris; + if (shadowsides) + Mem_Free(shadowsides); + if (shadowsideslist) + Mem_Free(shadowsideslist); + shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides)); + shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist)); + } + numshadowsides = 0; +} + +static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris) +{ + int i, j; + int outtriangles = 0, outvertices = 0; + const int *element; + const float *vertex; + float ratio, direction[3], projectvector[3]; + + if (projectdirection) + VectorScale(projectdirection, projectdistance, projectvector); + else + VectorClear(projectvector); + + // create the vertices + if (projectdirection) + { + for (i = 0;i < numshadowmarktris;i++) + { + element = inelement3i + shadowmarktris[i] * 3; + for (j = 0;j < 3;j++) + { + if (vertexupdate[element[j]] != vertexupdatenum) + { + vertexupdate[element[j]] = vertexupdatenum; + vertexremap[element[j]] = outvertices; + vertex = invertex3f + element[j] * 3; + // project one copy of the vertex according to projectvector + VectorCopy(vertex, outvertex3f); + VectorAdd(vertex, projectvector, (outvertex3f + 3)); + outvertex3f += 6; + outvertices += 2; + } + } + } + } + else + { + for (i = 0;i < numshadowmarktris;i++) + { + element = inelement3i + shadowmarktris[i] * 3; + for (j = 0;j < 3;j++) + { + if (vertexupdate[element[j]] != vertexupdatenum) + { + vertexupdate[element[j]] = vertexupdatenum; + vertexremap[element[j]] = outvertices; + vertex = invertex3f + element[j] * 3; + // project one copy of the vertex to the sphere radius of the light + // (FIXME: would projecting it to the light box be better?) + VectorSubtract(vertex, projectorigin, direction); + ratio = projectdistance / VectorLength(direction); + VectorCopy(vertex, outvertex3f); + VectorMA(projectorigin, ratio, direction, (outvertex3f + 3)); + outvertex3f += 6; + outvertices += 2; + } + } + } + } + + if (r_shadow_frontsidecasting.integer) + { + for (i = 0;i < numshadowmarktris;i++) + { + int remappedelement[3]; + int markindex; + const int *neighbortriangle; + + markindex = shadowmarktris[i] * 3; + element = inelement3i + markindex; + neighbortriangle = inneighbor3i + markindex; + // output the front and back triangles + outelement3i[0] = vertexremap[element[0]]; + outelement3i[1] = vertexremap[element[1]]; + outelement3i[2] = vertexremap[element[2]]; + outelement3i[3] = vertexremap[element[2]] + 1; + outelement3i[4] = vertexremap[element[1]] + 1; + outelement3i[5] = vertexremap[element[0]] + 1; + + outelement3i += 6; + outtriangles += 2; + // output the sides (facing outward from this triangle) + if (shadowmark[neighbortriangle[0]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[1] = vertexremap[element[1]]; + outelement3i[0] = remappedelement[1]; + outelement3i[1] = remappedelement[0]; + outelement3i[2] = remappedelement[0] + 1; + outelement3i[3] = remappedelement[1]; + outelement3i[4] = remappedelement[0] + 1; + outelement3i[5] = remappedelement[1] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[1]] != shadowmarkcount) + { + remappedelement[1] = vertexremap[element[1]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[2]; + outelement3i[1] = remappedelement[1]; + outelement3i[2] = remappedelement[1] + 1; + outelement3i[3] = remappedelement[2]; + outelement3i[4] = remappedelement[1] + 1; + outelement3i[5] = remappedelement[2] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[2]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[0]; + outelement3i[1] = remappedelement[2]; + outelement3i[2] = remappedelement[2] + 1; + outelement3i[3] = remappedelement[0]; + outelement3i[4] = remappedelement[2] + 1; + outelement3i[5] = remappedelement[0] + 1; + + outelement3i += 6; + outtriangles += 2; + } + } + } + else + { + for (i = 0;i < numshadowmarktris;i++) + { + int remappedelement[3]; + int markindex; + const int *neighbortriangle; + + markindex = shadowmarktris[i] * 3; + element = inelement3i + markindex; + neighbortriangle = inneighbor3i + markindex; + // output the front and back triangles + outelement3i[0] = vertexremap[element[2]]; + outelement3i[1] = vertexremap[element[1]]; + outelement3i[2] = vertexremap[element[0]]; + outelement3i[3] = vertexremap[element[0]] + 1; + outelement3i[4] = vertexremap[element[1]] + 1; + outelement3i[5] = vertexremap[element[2]] + 1; + + outelement3i += 6; + outtriangles += 2; + // output the sides (facing outward from this triangle) + if (shadowmark[neighbortriangle[0]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[1] = vertexremap[element[1]]; + outelement3i[0] = remappedelement[0]; + outelement3i[1] = remappedelement[1]; + outelement3i[2] = remappedelement[1] + 1; + outelement3i[3] = remappedelement[0]; + outelement3i[4] = remappedelement[1] + 1; + outelement3i[5] = remappedelement[0] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[1]] != shadowmarkcount) + { + remappedelement[1] = vertexremap[element[1]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[1]; + outelement3i[1] = remappedelement[2]; + outelement3i[2] = remappedelement[2] + 1; + outelement3i[3] = remappedelement[1]; + outelement3i[4] = remappedelement[2] + 1; + outelement3i[5] = remappedelement[1] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (shadowmark[neighbortriangle[2]] != shadowmarkcount) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[2]; + outelement3i[1] = remappedelement[0]; + outelement3i[2] = remappedelement[0] + 1; + outelement3i[3] = remappedelement[2]; + outelement3i[4] = remappedelement[0] + 1; + outelement3i[5] = remappedelement[2] + 1; + + outelement3i += 6; + outtriangles += 2; + } + } + } + if (outnumvertices) + *outnumvertices = outvertices; + return outtriangles; +} + +static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris) +{ + int i, j, k; + int outtriangles = 0, outvertices = 0; + const int *element; + const float *vertex; + float ratio, direction[3], projectvector[3]; + qboolean side[4]; + + if (projectdirection) + VectorScale(projectdirection, projectdistance, projectvector); + else + VectorClear(projectvector); + + for (i = 0;i < numshadowmarktris;i++) + { + int remappedelement[3]; + int markindex; + const int *neighbortriangle; + + markindex = shadowmarktris[i] * 3; + neighbortriangle = inneighbor3i + markindex; + side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount; + side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount; + side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount; + if (side[0] + side[1] + side[2] == 0) + continue; + + side[3] = side[0]; + element = inelement3i + markindex; + + // create the vertices + for (j = 0;j < 3;j++) + { + if (side[j] + side[j+1] == 0) + continue; + k = element[j]; + if (vertexupdate[k] != vertexupdatenum) + { + vertexupdate[k] = vertexupdatenum; + vertexremap[k] = outvertices; + vertex = invertex3f + k * 3; + VectorCopy(vertex, outvertex3f); + if (projectdirection) + { + // project one copy of the vertex according to projectvector + VectorAdd(vertex, projectvector, (outvertex3f + 3)); + } + else + { + // project one copy of the vertex to the sphere radius of the light + // (FIXME: would projecting it to the light box be better?) + VectorSubtract(vertex, projectorigin, direction); + ratio = projectdistance / VectorLength(direction); + VectorMA(projectorigin, ratio, direction, (outvertex3f + 3)); + } + outvertex3f += 6; + outvertices += 2; + } + } + + // output the sides (facing outward from this triangle) + if (!side[0]) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[1] = vertexremap[element[1]]; + outelement3i[0] = remappedelement[1]; + outelement3i[1] = remappedelement[0]; + outelement3i[2] = remappedelement[0] + 1; + outelement3i[3] = remappedelement[1]; + outelement3i[4] = remappedelement[0] + 1; + outelement3i[5] = remappedelement[1] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (!side[1]) + { + remappedelement[1] = vertexremap[element[1]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[2]; + outelement3i[1] = remappedelement[1]; + outelement3i[2] = remappedelement[1] + 1; + outelement3i[3] = remappedelement[2]; + outelement3i[4] = remappedelement[1] + 1; + outelement3i[5] = remappedelement[2] + 1; + + outelement3i += 6; + outtriangles += 2; + } + if (!side[2]) + { + remappedelement[0] = vertexremap[element[0]]; + remappedelement[2] = vertexremap[element[2]]; + outelement3i[0] = remappedelement[0]; + outelement3i[1] = remappedelement[2]; + outelement3i[2] = remappedelement[2] + 1; + outelement3i[3] = remappedelement[0]; + outelement3i[4] = remappedelement[2] + 1; + outelement3i[5] = remappedelement[0] + 1; + + outelement3i += 6; + outtriangles += 2; + } + } + if (outnumvertices) + *outnumvertices = outvertices; + return outtriangles; +} + +void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs) +{ + int t, tend; + const int *e; + const float *v[3]; + float normal[3]; + if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs)) + return; + tend = firsttriangle + numtris; + if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs)) + { + // surface box entirely inside light box, no box cull + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)) + shadowmarklist[numshadowmark++] = t; + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3)) + shadowmarklist[numshadowmark++] = t; + } + } + else + { + // surface box not entirely inside light box, cull each triangle + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3; + v[1] = invertex3f + e[1] * 3; + v[2] = invertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0) + && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + shadowmarklist[numshadowmark++] = t; + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3; + v[1] = invertex3f + e[1] * 3; + v[2] = invertex3f + e[2] * 3; + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) + && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + shadowmarklist[numshadowmark++] = t; + } + } + } +} + +static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs) +{ +#if 1 + return false; +#else + if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer) + return false; + // check if the shadow volume intersects the near plane + // + // a ray between the eye and light origin may intersect the caster, + // indicating that the shadow may touch the eye location, however we must + // test the near plane (a polygon), not merely the eye location, so it is + // easiest to enlarge the caster bounding shape slightly for this. + // TODO + return true; +#endif +} + +void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs) +{ + int i, tris, outverts; + if (projectdistance < 0.1) + { + Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance); + return; + } + if (!numverts || !nummarktris) + return; + // make sure shadowelements is big enough for this volume + if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2) + R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8); + + if (maxvertexupdate < numverts) + { + maxvertexupdate = numverts; + if (vertexupdate) + Mem_Free(vertexupdate); + if (vertexremap) + Mem_Free(vertexremap); + vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int)); + vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int)); + vertexupdatenum = 0; + } + vertexupdatenum++; + if (vertexupdatenum == 0) + { + vertexupdatenum = 1; + memset(vertexupdate, 0, maxvertexupdate * sizeof(int)); + memset(vertexremap, 0, maxvertexupdate * sizeof(int)); + } + + for (i = 0;i < nummarktris;i++) + shadowmark[marktris[i]] = shadowmarkcount; + + if (r_shadow_compilingrtlight) + { + // if we're compiling an rtlight, capture the mesh + //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); + //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements); + tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); + Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements); + } + else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES) + { + tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); + R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); + } + else + { + // decide which type of shadow to generate and set stencil mode + R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs)); + // generate the sides or a solid volume, depending on type + if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE) + tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); + else + tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); + r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris; + r_refdef.stats[r_stat_lights_shadowtriangles] += tris; + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) + { + // increment stencil if frontface is infront of depthbuffer + GL_CullFace(r_refdef.view.cullface_front); + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); + // decrement stencil if backface is infront of depthbuffer + GL_CullFace(r_refdef.view.cullface_back); + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255); + } + else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL) + { + // decrement stencil if backface is behind depthbuffer + GL_CullFace(r_refdef.view.cullface_front); + R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255); + //Android hack + R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); + // increment stencil if frontface is behind depthbuffer + GL_CullFace(r_refdef.view.cullface_back); + R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255); + } + //R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); + } +} + +int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias) +{ + // p1, p2, p3 are in the cubemap's local coordinate system + // bias = border/(size - border) + int mask = 0x3F; + + float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<4) + | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<4) + | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + + dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<0) + | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<0) + | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + + dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<2) + | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<2) + | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + + return mask; +} + +static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias) +{ + vec3_t center, radius, lightcenter, lightradius, pmin, pmax; + float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2; + int mask = 0x3F; + + VectorSubtract(maxs, mins, radius); + VectorScale(radius, 0.5f, radius); + VectorAdd(mins, radius, center); + Matrix4x4_Transform(worldtolight, center, lightcenter); + Matrix4x4_Transform3x3(radiustolight, radius, lightradius); + VectorSubtract(lightcenter, lightradius, pmin); + VectorAdd(lightcenter, lightradius, pmax); + + dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<4) + | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<4) + | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + + dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<0) + | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<0) + | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + + dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<2) + | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<2) + | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + + return mask; +} + +#define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias) + +int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias) +{ + // p is in the cubemap's local coordinate system + // bias = border/(size - border) + float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn); + float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn); + float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn); + int mask = 0x3F; + if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2)); + if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2)); + if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4)); + if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4)); + if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0)); + if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0)); + return mask; +} + +static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border) +{ + int i; + vec3_t o, p, n; + int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 }; + float scale = (size - 2*border)/size, len; + float bias = border / (float)(size - border), dp, dn, ap, an; + // check if cone enclosing side would cross frustum plane + scale = 2 / (scale*scale + 2); + Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o); + for (i = 0;i < 5;i++) + { + if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125) + continue; + Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n); + len = scale*VectorLength2(n); + if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0); + if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2); + if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4); + } + if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125) + { + Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n); + len = scale*VectorLength2(n); + if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0); + if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2); + if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4); + } + // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results + // check if frustum corners/origin cross plane sides +#if 1 + // infinite version, assumes frustum corners merely give direction and extend to infinite distance + Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p); + dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn); + masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn); + masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn); + masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + for (i = 0;i < 4;i++) + { + Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n); + VectorSubtract(n, p, n); + dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2); + if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2); + dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4); + if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4); + dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn); + if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0); + if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0); + } +#else + // finite version, assumes corners are a finite distance from origin dependent on far plane + for (i = 0;i < 5;i++) + { + Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p); + dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn); + masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn); + masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn); + masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + } +#endif + return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5]; +} + +int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals) +{ + int t, tend; + const int *e; + const float *v[3]; + float normal[3]; + vec3_t p[3]; + float bias; + int mask, surfacemask = 0; + if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs)) + return 0; + bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder); + tend = firsttriangle + numtris; + if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs)) + { + // surface box entirely inside light box, no box cull + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + } + else + { + // surface box not entirely inside light box, cull each triangle + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0) + && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) + && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + } + return surfacemask; +} + +void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris) +{ + int i, j, outtriangles = 0; + int *outelement3i[6]; + if (!numverts || !numsidetris || !r_shadow_compilingrtlight) + return; + outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5]; + // make sure shadowelements is big enough for this mesh + if (maxshadowtriangles < outtriangles) + R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1); + + // compute the offset and size of the separate index lists for each cubemap side + outtriangles = 0; + for (i = 0;i < 6;i++) + { + outelement3i[i] = shadowelements + outtriangles * 3; + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles; + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i]; + outtriangles += sidetotals[i]; + } + + // gather up the (sparse) triangles into separate index lists for each cubemap side + for (i = 0;i < numsidetris;i++) + { + const int *element = elements + sidetris[i] * 3; + for (j = 0;j < 6;j++) + { + if (sides[i] & (1 << j)) + { + outelement3i[j][0] = element[0]; + outelement3i[j][1] = element[1]; + outelement3i[j][2] = element[2]; + outelement3i[j] += 3; + } + } + } + + Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements); +} + +static void R_Shadow_MakeTextures_MakeCorona(void) +{ + float dx, dy; + int x, y, a; + unsigned char pixels[32][32][4]; + for (y = 0;y < 32;y++) + { + dy = (y - 15.5f) * (1.0f / 16.0f); + for (x = 0;x < 32;x++) + { + dx = (x - 15.5f) * (1.0f / 16.0f); + a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2))); + a = bound(0, a, 255); + pixels[y][x][0] = a; + pixels[y][x][1] = a; + pixels[y][x][2] = a; + pixels[y][x][3] = 255; + } + } + r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false); +} + +static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z) +{ + float dist = sqrt(x*x+y*y+z*z); + float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways + return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101; +} + +static void R_Shadow_MakeTextures(void) +{ + int x, y, z; + float intensity, dist; + unsigned int *data; + R_Shadow_FreeShadowMaps(); + R_FreeTexturePool(&r_shadow_texturepool); + r_shadow_texturepool = R_AllocTexturePool(); + r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value; + r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value; + data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4); + // the table includes one additional value to avoid the need to clamp indexing due to minor math errors + for (x = 0;x <= ATTENTABLESIZE;x++) + { + dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375); + intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + r_shadow_attentable[x] = bound(0, intensity, 1); + } + // 1D gradient texture + for (x = 0;x < ATTEN1DSIZE;x++) + data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0); + r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL); + // 2D circle texture + for (y = 0;y < ATTEN2DSIZE;y++) + for (x = 0;x < ATTEN2DSIZE;x++) + data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0); + r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL); + // 3D sphere texture + if (r_shadow_texture3d.integer && vid.support.ext_texture_3d) + { + for (z = 0;z < ATTEN3DSIZE;z++) + for (y = 0;y < ATTEN3DSIZE;y++) + for (x = 0;x < ATTEN3DSIZE;x++) + data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375)); + r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL); + } + else + r_shadow_attenuation3dtexture = NULL; + Mem_Free(data); + + R_Shadow_MakeTextures_MakeCorona(); + + // Editor light sprites + r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + ".3............3." + "..5...2332...5.." + "...7.3....3.7..." + "....7......7...." + "...3.7....7.3..." + "..2...7..7...2.." + "..3..........3.." + "..3..........3.." + "..2...7..7...2.." + "...3.7....7.3..." + "....7......7...." + "...7.3....3.7..." + "..5...2332...5.." + ".3............3." + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......1111......" + "....11233211...." + "...1234554321..." + "...1356776531..." + "..124677776421.." + "..135777777531.." + "..135777777531.." + "..124677776421.." + "...1356776531..." + "...1234554321..." + "....11233211...." + "......1111......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......1111......" + "....11233211...." + "...1234554321..." + "...1356226531..." + "..12462..26421.." + "..1352....2531.." + "..1352....2531.." + "..12462..26421.." + "...1356226531..." + "...1234554321..." + "....11233211...." + "......1111......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......2772......" + "....27755772...." + "..277533335772.." + "..753333333357.." + "..777533335777.." + "..735775577537.." + "..733357753337.." + "..733337733337.." + "..753337733357.." + "..277537735772.." + "....27777772...." + "......2772......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......2772......" + "....27722772...." + "..2772....2772.." + "..72........27.." + "..7772....2777.." + "..7.27722772.7.." + "..7...2772...7.." + "..7....77....7.." + "..72...77...27.." + "..2772.77.2772.." + "....27777772...." + "......2772......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *) + "................" + ".777752..257777." + ".742........247." + ".72..........27." + ".7............7." + ".5............5." + ".2............2." + "................" + "................" + ".2............2." + ".5............5." + ".7............7." + ".72..........27." + ".742........247." + ".777752..257777." + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); +} + +void R_Shadow_ValidateCvars(void) +{ + if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d) + Cvar_SetValueQuick(&r_shadow_texture3d, 0); + if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil) + Cvar_SetValueQuick(&gl_ext_separatestencil, 0); + if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side) + Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0); +} + +void R_Shadow_RenderMode_Begin(void) +{ +#if 0 + GLint drawbuffer; + GLint readbuffer; +#endif + R_Shadow_ValidateCvars(); + + if (!r_shadow_attenuation2dtexture + || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer) + || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias + || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale) + R_Shadow_MakeTextures(); + + CHECKGLERROR + R_Mesh_ResetTextureState(); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthRange(0, 1); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); + GL_DepthTest(true); + GL_DepthMask(false); + GL_Color(0, 0, 0, 1); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + + r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; + + if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil) + { + r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL; + r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL; + } + else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side) + { + r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE; + r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE; + } + else + { + r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL; + r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL; + } + + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture) + r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN; + else if (r_textureunits.integer >= 3 && vid.texunits >= 3) + r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN; + else if (r_textureunits.integer >= 2 && vid.texunits >= 2) + r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN; + else + r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX; + break; + } + + CHECKGLERROR +#if 0 + qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR + qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR + r_shadow_drawbuffer = drawbuffer; + r_shadow_readbuffer = readbuffer; +#endif + r_shadow_cullface_front = r_refdef.view.cullface_front; + r_shadow_cullface_back = r_refdef.view.cullface_back; +} + +void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight) +{ + rsurface.rtlight = rtlight; +} + +void R_Shadow_RenderMode_Reset(void) +{ + R_Mesh_ResetTextureState(); + R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL); + R_SetViewport(&r_refdef.view.viewport); + GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]); + GL_DepthRange(0, 1); + GL_DepthTest(true); + GL_DepthMask(false); + GL_DepthFunc(GL_LEQUAL); + GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + r_refdef.view.cullface_front = r_shadow_cullface_front; + r_refdef.view.cullface_back = r_shadow_cullface_back; + GL_CullFace(r_refdef.view.cullface_back); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + R_SetupShader_Generic_NoTexture(false, false); + r_shadow_usingshadowmap2d = false; + r_shadow_usingshadowmaportho = false; + R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255); +} + +void R_Shadow_ClearStencil(void) +{ + GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128); + r_refdef.stats[r_stat_lights_clears]++; +} + +void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass) +{ + r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail; + if (r_shadow_rendermode == mode) + return; + R_Shadow_RenderMode_Reset(); + GL_DepthFunc(GL_LESS); + GL_ColorMask(0, 0, 0, 0); + GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR + GL_CullFace(GL_NONE); + R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model? + r_shadow_rendermode = mode; + switch(mode) + { + default: + break; + case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE: + case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL: + R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255); + break; + case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE: + case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL: + R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255); + break; + } +} + +static void R_Shadow_MakeVSDCT(void) +{ + // maps to a 2x3 texture rectangle with normalized coordinates + // +- + // XX + // YY + // ZZ + // stores abs(dir.xy), offset.xy/2.5 + unsigned char data[4*6] = + { + 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5> + 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5> + 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5> + 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5> + 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5> + 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5> + }; + r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL); +} + +static void R_Shadow_MakeShadowMap(int side, int size) +{ + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (r_shadow_shadowmap2ddepthtexture) return; + if (r_fb.usedepthtextures) + { + r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler); + r_shadow_shadowmap2ddepthbuffer = NULL; + r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL); + } + else + { + r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL); + r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16); + r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL); + } + break; + default: + return; + } +} + +static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size) +{ + float nearclip, farclip, bias; + r_viewport_t viewport; + int flipped; + GLuint fbo2d = 0; + float clearcolor[4]; + nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius; + farclip = 1.0f; + bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius; + r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias; + r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip); + r_shadow_shadowmapside = side; + r_shadow_shadowmapsize = size; + + r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder); + r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size; + R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done; + + // complex unrolled cube approach (more flexible) + if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture) + R_Shadow_MakeVSDCT(); + if (!r_shadow_shadowmap2ddepthtexture) + R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize); + fbo2d = r_shadow_fbo2d; + r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture); + r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture); + r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D; + + R_Mesh_ResetTextureState(); + R_Shadow_RenderMode_Reset(); + if (r_shadow_shadowmap2ddepthbuffer) + R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL); + else + R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL); + R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model? + GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value); + GL_DepthMask(true); + GL_DepthTest(true); + +init_done: + R_SetViewport(&viewport); + flipped = (side & 1) ^ (side >> 2); + r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front; + r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back; + if (r_shadow_shadowmap2ddepthbuffer) + { + // completely different meaning than in depthtexture approach + r_shadow_shadowmap_parameters[1] = 0; + r_shadow_shadowmap_parameters[3] = -bias; + } + Vector4Set(clearcolor, 1,1,1,1); + if (r_shadow_shadowmap2ddepthbuffer) + GL_ColorMask(1,1,1,1); + else + GL_ColorMask(0,0,0,0); + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + GL_CullFace(r_refdef.view.cullface_back); + // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once + if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask + { + // get tightest scissor rectangle that encloses all viewports in the clear mask + int x1 = clear & 0x15 ? 0 : size; + int x2 = clear & 0x2A ? 2 * size : size; + int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size); + int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size); + GL_Scissor(x1, y1, x2 - x1, y2 - y1); + if (clear) + { + if (r_shadow_shadowmap2ddepthbuffer) + GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0); + else + GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0); + } + } + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + // we invert the cull mode because we flip the projection matrix + // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided... + GL_CullFace(r_refdef.view.cullface_front); + // D3D considers it an error to use a scissor larger than the viewport... clear just this view + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + if (clear) + { + if (r_shadow_shadowmap2ddepthbuffer) + GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0); + else + GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0); + } + break; + } +} + +void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping) +{ + R_Mesh_ResetTextureState(); + if (transparent) + { + r_shadow_lightscissor[0] = r_refdef.view.viewport.x; + r_shadow_lightscissor[1] = r_refdef.view.viewport.y; + r_shadow_lightscissor[2] = r_refdef.view.viewport.width; + r_shadow_lightscissor[3] = r_refdef.view.viewport.height; + } + R_Shadow_RenderMode_Reset(); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + if (!transparent) + GL_DepthFunc(GL_EQUAL); + // do global setup needed for the chosen lighting mode + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL) + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0); + r_shadow_usingshadowmap2d = shadowmapping; + r_shadow_rendermode = r_shadow_lightingrendermode; + // only draw light where this geometry was already rendered AND the + // stencil is 128 (values other than this mean shadow) + if (stenciltest) + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255); + else + R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255); +} + +static const unsigned short bboxelements[36] = +{ + 5, 1, 3, 5, 3, 7, + 6, 2, 0, 6, 0, 4, + 7, 3, 2, 7, 2, 6, + 4, 0, 1, 4, 1, 5, + 4, 5, 7, 4, 7, 6, + 1, 0, 2, 1, 2, 3, +}; + +static const float bboxpoints[8][3] = +{ + {-1,-1,-1}, + { 1,-1,-1}, + {-1, 1,-1}, + { 1, 1,-1}, + {-1,-1, 1}, + { 1,-1, 1}, + {-1, 1, 1}, + { 1, 1, 1}, +}; + +void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping) +{ + int i; + float vertex3f[8*3]; + const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld; +// do global setup needed for the chosen lighting mode + R_Shadow_RenderMode_Reset(); + r_shadow_rendermode = r_shadow_lightingrendermode; + R_EntityMatrix(&identitymatrix); + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + // only draw light where this geometry was already rendered AND the + // stencil is 128 (values other than this mean shadow) + R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255); + if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0) + R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL); + else + R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL); + + r_shadow_usingshadowmap2d = shadowmapping; + + // render the lighting + R_SetupShader_DeferredLight(rsurface.rtlight); + for (i = 0;i < 8;i++) + Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3); + GL_ColorMask(1,1,1,1); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(true); + GL_DepthFunc(GL_GREATER); + GL_CullFace(r_refdef.view.cullface_back); + R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0); + R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); +} + +void R_Shadow_UpdateBounceGridTexture(void) +{ +#define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576 + dlight_t *light; + int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + int bouncecount; + int hitsupercontentsmask; + int maxbounce; + int numpixels; + int resolution[3]; + int shootparticles; + int shotparticles; + int photoncount; + int tex[3]; + trace_t cliptrace; + //trace_t cliptrace2; + //trace_t cliptrace3; + unsigned char *pixel; + unsigned char *pixels; + float *highpixel; + float *highpixels; + unsigned int lightindex; + unsigned int range; + unsigned int range1; + unsigned int range2; + unsigned int seed = (unsigned int)(realtime * 1000.0f); + vec3_t shotcolor; + vec3_t baseshotcolor; + vec3_t surfcolor; + vec3_t clipend; + vec3_t clipstart; + vec3_t clipdiff; + vec3_t ispacing; + vec3_t maxs; + vec3_t mins; + vec3_t size; + vec3_t spacing; + vec3_t lightcolor; + vec3_t steppos; + vec3_t stepdelta; + vec3_t cullmins, cullmaxs; + vec_t radius; + vec_t s; + vec_t lightintensity; + vec_t photonscaling; + vec_t photonresidual; + float m[16]; + float texlerp[2][3]; + float splatcolor[32]; + float pixelweight[8]; + float w; + int c[4]; + int pixelindex[8]; + int corner; + int pixelsperband; + int pixelband; + int pixelbands; + int numsteps; + int step; + int x, y, z; + rtlight_t *rtlight; + r_shadow_bouncegrid_settings_t settings; + qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel; + qboolean allowdirectionalshading = false; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + allowdirectionalshading = true; + if (!vid.support.ext_texture_3d) + return; + break; + case RENDERPATH_GLES2: + // for performance reasons, do not use directional shading on GLES devices + if (!vid.support.ext_texture_3d) + return; + break; + // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them... + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_SOFT: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + return; + } + + r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value; + + // see if there are really any lights to render... + if (enable && r_shadow_bouncegrid_static.integer) + { + enable = false; + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light || !(light->flags & flag)) + continue; + rtlight = &light->rtlight; + // when static, we skip styled lights because they tend to change... + if (rtlight->style > 0) + continue; + VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor); + if (!VectorLength2(lightcolor)) + continue; + enable = true; + break; + } + } + + if (!enable) + { + if (r_shadow_bouncegridtexture) + { + R_FreeTexture(r_shadow_bouncegridtexture); + r_shadow_bouncegridtexture = NULL; + } + if (r_shadow_bouncegridpixels) + Mem_Free(r_shadow_bouncegridpixels); + r_shadow_bouncegridpixels = NULL; + if (r_shadow_bouncegridhighpixels) + Mem_Free(r_shadow_bouncegridhighpixels); + r_shadow_bouncegridhighpixels = NULL; + r_shadow_bouncegridnumpixels = 0; + r_shadow_bouncegriddirectional = false; + return; + } + + // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters + memset(&settings, 0, sizeof(settings)); + settings.staticmode = r_shadow_bouncegrid_static.integer != 0; + settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0; + settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading; + settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value; + settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0; + settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2; + settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value); + settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer); + settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value; + settings.particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings.directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value); + settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer; + settings.spacing[0] = r_shadow_bouncegrid_spacing.value; + settings.spacing[1] = r_shadow_bouncegrid_spacing.value; + settings.spacing[2] = r_shadow_bouncegrid_spacing.value; + settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer; + + // bound the values for sanity + settings.photons = bound(1, settings.photons, 1048576); + settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f); + settings.maxbounce = bound(0, settings.maxbounce, 16); + settings.spacing[0] = bound(1, settings.spacing[0], 512); + settings.spacing[1] = bound(1, settings.spacing[1], 512); + settings.spacing[2] = bound(1, settings.spacing[2], 512); + + // get the spacing values + spacing[0] = settings.spacing[0]; + spacing[1] = settings.spacing[1]; + spacing[2] = settings.spacing[2]; + ispacing[0] = 1.0f / spacing[0]; + ispacing[1] = 1.0f / spacing[1]; + ispacing[2] = 1.0f / spacing[2]; + + // calculate texture size enclosing entire world bounds at the spacing + VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins); + VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs); + VectorSubtract(maxs, mins, size); + // now we can calculate the resolution we want + c[0] = (int)floor(size[0] / spacing[0] + 0.5f); + c[1] = (int)floor(size[1] / spacing[1] + 0.5f); + c[2] = (int)floor(size[2] / spacing[2] + 0.5f); + // figure out the exact texture size (honoring power of 2 if required) + c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d); + c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d); + c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d); + if (vid.support.arb_texture_non_power_of_two) + { + resolution[0] = c[0]; + resolution[1] = c[1]; + resolution[2] = c[2]; + } + else + { + for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ; + for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ; + for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ; + } + size[0] = spacing[0] * resolution[0]; + size[1] = spacing[1] * resolution[1]; + size[2] = spacing[2] * resolution[2]; + + // if dynamic we may or may not want to use the world bounds + // if the dynamic size is smaller than the world bounds, use it instead + if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2])) + { + // we know the resolution we want + c[0] = r_shadow_bouncegrid_x.integer; + c[1] = r_shadow_bouncegrid_y.integer; + c[2] = r_shadow_bouncegrid_z.integer; + // now we can calculate the texture size (power of 2 if required) + c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d); + c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d); + c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d); + if (vid.support.arb_texture_non_power_of_two) + { + resolution[0] = c[0]; + resolution[1] = c[1]; + resolution[2] = c[2]; + } + else + { + for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ; + for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ; + for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ; + } + size[0] = spacing[0] * resolution[0]; + size[1] = spacing[1] * resolution[1]; + size[2] = spacing[2] * resolution[2]; + // center the rendering on the view + mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0]; + mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1]; + mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2]; + } + + // recalculate the maxs in case the resolution was not satisfactory + VectorAdd(mins, size, maxs); + + // if all the settings seem identical to the previous update, return + if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings))) + return; + + // store the new settings + r_shadow_bouncegridsettings = settings; + + pixelbands = settings.directionalshading ? 8 : 1; + pixelsperband = resolution[0]*resolution[1]*resolution[2]; + numpixels = pixelsperband*pixelbands; + + // we're going to update the bouncegrid, update the matrix... + memset(m, 0, sizeof(m)); + m[0] = 1.0f / size[0]; + m[3] = -mins[0] * m[0]; + m[5] = 1.0f / size[1]; + m[7] = -mins[1] * m[5]; + m[10] = 1.0f / size[2]; + m[11] = -mins[2] * m[10]; + m[15] = 1.0f; + Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m); + // reallocate pixels for this update if needed... + if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels) + { + if (r_shadow_bouncegridtexture) + { + R_FreeTexture(r_shadow_bouncegridtexture); + r_shadow_bouncegridtexture = NULL; + } + r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4])); + r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4])); + } + r_shadow_bouncegridnumpixels = numpixels; + pixels = r_shadow_bouncegridpixels; + highpixels = r_shadow_bouncegridhighpixels; + x = pixelsperband*4; + for (pixelband = 0;pixelband < pixelbands;pixelband++) + { + if (pixelband == 1) + memset(pixels + pixelband * x, 128, x); + else + memset(pixels + pixelband * x, 0, x); + } + memset(highpixels, 0, numpixels * sizeof(float[4])); + // figure out what we want to interact with + if (settings.hitmodels) + hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK; + else + hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK; + maxbounce = settings.maxbounce; + // clear variables that produce warnings otherwise + memset(splatcolor, 0, sizeof(splatcolor)); + // iterate world rtlights + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + range1 = settings.staticmode ? 0 : r_refdef.scene.numlights; + range2 = range + range1; + photoncount = 0; + for (lightindex = 0;lightindex < range2;lightindex++) + { + if (lightindex < range) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + rtlight = &light->rtlight; + VectorClear(rtlight->photoncolor); + rtlight->photons = 0; + if (!(light->flags & flag)) + continue; + if (settings.staticmode) + { + // when static, we skip styled lights because they tend to change... + if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2) + continue; + } + } + else + { + rtlight = r_refdef.scene.lights[lightindex - range]; + VectorClear(rtlight->photoncolor); + rtlight->photons = 0; + } + // draw only visible lights (major speedup) + radius = rtlight->radius * settings.lightradiusscale; + cullmins[0] = rtlight->shadoworigin[0] - radius; + cullmins[1] = rtlight->shadoworigin[1] - radius; + cullmins[2] = rtlight->shadoworigin[2] - radius; + cullmaxs[0] = rtlight->shadoworigin[0] + radius; + cullmaxs[1] = rtlight->shadoworigin[1] + radius; + cullmaxs[2] = rtlight->shadoworigin[2] + radius; + if (R_CullBox(cullmins, cullmaxs)) + continue; + if (r_refdef.scene.worldmodel + && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs + && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs)) + continue; + w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale); + if (w * VectorLength2(rtlight->color) == 0.0f) + continue; + w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1); + VectorScale(rtlight->color, w, rtlight->photoncolor); + //if (!VectorLength2(rtlight->photoncolor)) + // continue; + // shoot particles from this light + // use a calculation for the number of particles that will not + // vary with lightstyle, otherwise we get randomized particle + // distribution, the seeded random is only consistent for a + // consistent number of particles on this light... + s = rtlight->radius; + lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale); + if (lightindex >= range) + lightintensity *= settings.dlightparticlemultiplier; + rtlight->photons = max(0.0f, lightintensity * s * s); + photoncount += rtlight->photons; + } + photonscaling = (float)settings.photons / max(1, photoncount); + photonresidual = 0.0f; + for (lightindex = 0;lightindex < range2;lightindex++) + { + if (lightindex < range) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + rtlight = &light->rtlight; + } + else + rtlight = r_refdef.scene.lights[lightindex - range]; + // skip a light with no photons + if (rtlight->photons == 0.0f) + continue; + // skip a light with no photon color) + if (VectorLength2(rtlight->photoncolor) == 0.0f) + continue; + photonresidual += rtlight->photons * photonscaling; + shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT); + if (!shootparticles) + continue; + photonresidual -= shootparticles; + radius = rtlight->radius * settings.lightradiusscale; + s = settings.particleintensity / shootparticles; + VectorScale(rtlight->photoncolor, s, baseshotcolor); + r_refdef.stats[r_stat_bouncegrid_lights]++; + r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles; + for (shotparticles = 0;shotparticles < shootparticles;shotparticles++) + { + if (settings.stablerandom > 0) + seed = lightindex * 11937 + shotparticles; + VectorCopy(baseshotcolor, shotcolor); + VectorCopy(rtlight->shadoworigin, clipstart); + if (settings.stablerandom < 0) + VectorRandom(clipend); + else + VectorCheeseRandom(clipend); + VectorMA(clipstart, radius, clipend, clipend); + for (bouncecount = 0;;bouncecount++) + { + r_refdef.stats[r_stat_bouncegrid_traces]++; + //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask); + //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask); + if (settings.staticmode) + { + // static mode fires a LOT of rays but none of them are identical, so they are not cached + cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true); + } + else + { + // dynamic mode fires many rays and most will match the cache from the previous frame + cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask); + } + if (bouncecount > 0 || settings.includedirectlighting) + { + // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ) + // accumulate average shotcolor + w = VectorLength(shotcolor); + splatcolor[ 0] = shotcolor[0]; + splatcolor[ 1] = shotcolor[1]; + splatcolor[ 2] = shotcolor[2]; + splatcolor[ 3] = 0.0f; + if (pixelbands > 1) + { + VectorSubtract(clipstart, cliptrace.endpos, clipdiff); + VectorNormalize(clipdiff); + // store bentnormal in case the shader has a use for it + splatcolor[ 4] = clipdiff[0] * w; + splatcolor[ 5] = clipdiff[1] * w; + splatcolor[ 6] = clipdiff[2] * w; + splatcolor[ 7] = w; + // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z) + splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]); + splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]); + splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]); + splatcolor[11] = 0.0f; + splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]); + splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]); + splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]); + splatcolor[15] = 0.0f; + splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]); + splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]); + splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]); + splatcolor[19] = 0.0f; + splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]); + splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]); + splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]); + splatcolor[23] = 0.0f; + splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]); + splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]); + splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]); + splatcolor[27] = 0.0f; + splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]); + splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]); + splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]); + splatcolor[31] = 0.0f; + } + // calculate the number of steps we need to traverse this distance + VectorSubtract(cliptrace.endpos, clipstart, stepdelta); + numsteps = (int)(VectorLength(stepdelta) * ispacing[0]); + numsteps = bound(1, numsteps, 1024); + w = 1.0f / numsteps; + VectorScale(stepdelta, w, stepdelta); + VectorMA(clipstart, 0.5f, stepdelta, steppos); + for (step = 0;step < numsteps;step++) + { + r_refdef.stats[r_stat_bouncegrid_splats]++; + // figure out which texture pixel this is in + texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f; + texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f; + texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f; + tex[0] = (int)floor(texlerp[1][0]); + tex[1] = (int)floor(texlerp[1][1]); + tex[2] = (int)floor(texlerp[1][2]); + if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2) + { + // it is within bounds... do the real work now + // calculate the lerp factors + texlerp[1][0] -= tex[0]; + texlerp[1][1] -= tex[1]; + texlerp[1][2] -= tex[2]; + texlerp[0][0] = 1.0f - texlerp[1][0]; + texlerp[0][1] = 1.0f - texlerp[1][1]; + texlerp[0][2] = 1.0f - texlerp[1][2]; + // calculate individual pixel indexes and weights + pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]); + pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]); + pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]); + pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]); + pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]); + pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]); + pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]); + pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]); + // update the 8 pixels... + for (pixelband = 0;pixelband < pixelbands;pixelband++) + { + for (corner = 0;corner < 8;corner++) + { + // calculate address for pixel + w = pixelweight[corner]; + pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4; + highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4; + // add to the high precision pixel color + highpixel[0] += (splatcolor[pixelband*4+0]*w); + highpixel[1] += (splatcolor[pixelband*4+1]*w); + highpixel[2] += (splatcolor[pixelband*4+2]*w); + highpixel[3] += (splatcolor[pixelband*4+3]*w); + // flag the low precision pixel as needing to be updated + pixel[3] = 255; + // advance to next band of coefficients + //pixel += pixelsperband*4; + //highpixel += pixelsperband*4; + } + } + } + VectorAdd(steppos, stepdelta, steppos); + } + } + if (cliptrace.fraction >= 1.0f) + break; + r_refdef.stats[r_stat_bouncegrid_hits]++; + if (bouncecount >= maxbounce) + break; + // scale down shot color by bounce intensity and texture color (or 50% if no texture reported) + // also clamp the resulting color to never add energy, even if the user requests extreme values + if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe) + VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor); + else + VectorSet(surfcolor, 0.5f, 0.5f, 0.5f); + VectorScale(surfcolor, settings.particlebounceintensity, surfcolor); + surfcolor[0] = min(surfcolor[0], 1.0f); + surfcolor[1] = min(surfcolor[1], 1.0f); + surfcolor[2] = min(surfcolor[2], 1.0f); + VectorMultiply(shotcolor, surfcolor, shotcolor); + if (VectorLength2(baseshotcolor) == 0.0f) + break; + r_refdef.stats[r_stat_bouncegrid_bounces]++; + if (settings.bounceanglediffuse) + { + // random direction, primarily along plane normal + s = VectorDistance(cliptrace.endpos, clipend); + if (settings.stablerandom < 0) + VectorRandom(clipend); + else + VectorCheeseRandom(clipend); + VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend); + VectorNormalize(clipend); + VectorScale(clipend, s, clipend); + } + else + { + // reflect the remaining portion of the line across plane normal + VectorSubtract(clipend, cliptrace.endpos, clipdiff); + VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend); + } + // calculate the new line start and end + VectorCopy(cliptrace.endpos, clipstart); + VectorAdd(clipstart, clipend, clipend); + } + } + } + // generate pixels array from highpixels array + // skip first and last columns, rows, and layers as these are blank + // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated + for (pixelband = 0;pixelband < pixelbands;pixelband++) + { + for (z = 1;z < resolution[2]-1;z++) + { + for (y = 1;y < resolution[1]-1;y++) + { + for (x = 1, pixelindex[0] = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 4*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 4) + { + // only convert pixels that were hit by photons + if (pixel[3] == 255) + { + // normalize the bentnormal... + if (pixelband == 1) + { + VectorNormalize(highpixel); + c[0] = (int)(highpixel[0]*128.0f+128.0f); + c[1] = (int)(highpixel[1]*128.0f+128.0f); + c[2] = (int)(highpixel[2]*128.0f+128.0f); + c[3] = (int)(highpixel[3]*128.0f+128.0f); + } + else + { + c[0] = (int)(highpixel[0]*256.0f); + c[1] = (int)(highpixel[1]*256.0f); + c[2] = (int)(highpixel[2]*256.0f); + c[3] = (int)(highpixel[3]*256.0f); + } + pixel[2] = (unsigned char)bound(0, c[0], 255); + pixel[1] = (unsigned char)bound(0, c[1], 255); + pixel[0] = (unsigned char)bound(0, c[2], 255); + pixel[3] = (unsigned char)bound(0, c[3], 255); + } + } + } + } + } + if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2] && r_shadow_bouncegriddirectional == settings.directionalshading) + R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands); + else + { + VectorCopy(resolution, r_shadow_bouncegridresolution); + r_shadow_bouncegriddirectional = settings.directionalshading; + if (r_shadow_bouncegridtexture) + R_FreeTexture(r_shadow_bouncegridtexture); + r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL); + } + r_shadow_bouncegridtime = realtime; +} + +void R_Shadow_RenderMode_VisibleShadowVolumes(void) +{ + R_Shadow_RenderMode_Reset(); + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthRange(0, 1); + GL_DepthTest(r_showshadowvolumes.integer < 2); + GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1); + GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR + GL_CullFace(GL_NONE); + r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES; +} + +void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent) +{ + R_Shadow_RenderMode_Reset(); + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthRange(0, 1); + GL_DepthTest(r_showlighting.integer < 2); + GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1); + if (!transparent) + GL_DepthFunc(GL_EQUAL); + R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255); + r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING; +} + +void R_Shadow_RenderMode_End(void) +{ + R_Shadow_RenderMode_Reset(); + R_Shadow_RenderMode_ActiveLight(NULL); + GL_DepthMask(true); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; +} + +int bboxedges[12][2] = +{ + // top + {0, 1}, // +X + {0, 2}, // +Y + {1, 3}, // Y, +X + {2, 3}, // X, +Y + // bottom + {4, 5}, // +X + {4, 6}, // +Y + {5, 7}, // Y, +X + {6, 7}, // X, +Y + // verticals + {0, 4}, // +Z + {1, 5}, // X, +Z + {2, 6}, // Y, +Z + {3, 7}, // XY, +Z +}; + +qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) +{ + if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer) + { + r_shadow_lightscissor[0] = r_refdef.view.viewport.x; + r_shadow_lightscissor[1] = r_refdef.view.viewport.y; + r_shadow_lightscissor[2] = r_refdef.view.viewport.width; + r_shadow_lightscissor[3] = r_refdef.view.viewport.height; + return false; + } + if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor)) + return true; // invisible + if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x + || r_shadow_lightscissor[1] != r_refdef.view.viewport.y + || r_shadow_lightscissor[2] != r_refdef.view.viewport.width + || r_shadow_lightscissor[3] != r_refdef.view.viewport.height) + r_refdef.stats[r_stat_lights_scissored]++; + return false; +} + +static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor) +{ + int i; + const float *vertex3f; + const float *normal3f; + float *color4f; + float dist, dot, distintensity, shadeintensity, v[3], n[3]; + switch (r_shadow_rendermode) + { + case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: + if (VectorLength2(diffusecolor) > 0) + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) + { + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f); + } + else + VectorCopy(ambientcolor, color4f); + if (r_refdef.fogenabled) + { + float f; + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f, f, color4f); + } + color4f[3] = 1; + } + } + else + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) + { + VectorCopy(ambientcolor, color4f); + if (r_refdef.fogenabled) + { + float f; + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f + 4*i, f, color4f); + } + color4f[3] = 1; + } + } + break; + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: + if (VectorLength2(diffusecolor) > 0) + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) + { + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) + { + Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; + color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; + color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + } + else + { + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + } + if (r_refdef.fogenabled) + { + float f; + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f, f, color4f); + } + } + else + VectorClear(color4f); + color4f[3] = 1; + } + } + else + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) + { + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) + { + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + if (r_refdef.fogenabled) + { + float f; + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f, f, color4f); + } + } + else + VectorClear(color4f); + color4f[3] = 1; + } + } + break; + case R_SHADOW_RENDERMODE_LIGHT_VERTEX: + if (VectorLength2(diffusecolor) > 0) + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) + { + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) + { + distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); + Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; + color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; + color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + } + else + { + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + } + if (r_refdef.fogenabled) + { + float f; + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f, f, color4f); + } + } + else + VectorClear(color4f); + color4f[3] = 1; + } + } + else + { + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) + { + Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); + if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) + { + distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + if (r_refdef.fogenabled) + { + float f; + f = RSurf_FogVertex(vertex3f); + VectorScale(color4f, f, color4f); + } + } + else + VectorClear(color4f); + color4f[3] = 1; + } + } + break; + default: + break; + } +} + +static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + // used to display how many times a surface is lit for level design purposes + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); + RSurf_DrawBatch(); +} + +static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale) +{ + // ARB2 GLSL shader path (GFFX5200, Radeon 9500) + R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false); + RSurf_DrawBatch(); +} + +static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2) +{ + int renders; + int i; + int stop; + int newfirstvertex; + int newlastvertex; + int newnumtriangles; + int *newe; + const int *e; + float *c; + int maxtriangles = 1024; + int newelements[1024*3]; + R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2); + for (renders = 0;renders < 4;renders++) + { + stop = true; + newfirstvertex = 0; + newlastvertex = 0; + newnumtriangles = 0; + newe = newelements; + // due to low fillrate on the cards this vertex lighting path is + // designed for, we manually cull all triangles that do not + // contain a lit vertex + // this builds batches of triangles from multiple surfaces and + // renders them at once + for (i = 0, e = element3i;i < numtriangles;i++, e += 3) + { + if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01) + { + if (newnumtriangles) + { + newfirstvertex = min(newfirstvertex, e[0]); + newlastvertex = max(newlastvertex, e[0]); + } + else + { + newfirstvertex = e[0]; + newlastvertex = e[0]; + } + newfirstvertex = min(newfirstvertex, e[1]); + newlastvertex = max(newlastvertex, e[1]); + newfirstvertex = min(newfirstvertex, e[2]); + newlastvertex = max(newlastvertex, e[2]); + newe[0] = e[0]; + newe[1] = e[1]; + newe[2] = e[2]; + newnumtriangles++; + newe += 3; + if (newnumtriangles >= maxtriangles) + { + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0); + newnumtriangles = 0; + newe = newelements; + stop = false; + } + } + } + if (newnumtriangles >= 1) + { + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0); + stop = false; + } + // if we couldn't find any lit triangles, exit early + if (stop) + break; + // now reduce the intensity for the next overbright pass + // we have to clamp to 0 here incase the drivers have improper + // handling of negative colors + // (some old drivers even have improper handling of >1 color) + stop = true; + for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4) + { + if (c[0] > 1 || c[1] > 1 || c[2] > 1) + { + c[0] = max(0, c[0] - 1); + c[1] = max(0, c[1] - 1); + c[2] = max(0, c[2] - 1); + stop = false; + } + else + VectorClear(c); + } + // another check... + if (stop) + break; + } +} + +static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale) +{ + // OpenGL 1.1 path (anything) + float ambientcolorbase[3], diffusecolorbase[3]; + float ambientcolorpants[3], diffusecolorpants[3]; + float ambientcolorshirt[3], diffusecolorshirt[3]; + const float *surfacecolor = rsurface.texture->dlightcolor; + const float *surfacepants = rsurface.colormap_pantscolor; + const float *surfaceshirt = rsurface.colormap_shirtcolor; + rtexture_t *basetexture = rsurface.texture->basetexture; + rtexture_t *pantstexture = rsurface.texture->pantstexture; + rtexture_t *shirttexture = rsurface.texture->shirttexture; + qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f); + qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f); + ambientscale *= 2 * r_refdef.view.colorscale; + diffusescale *= 2 * r_refdef.view.colorscale; + ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2]; + diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2]; + ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2]; + diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2]; + ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2]; + diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2]; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4])); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + R_Mesh_TexBind(0, basetexture); + R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix); + R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); + switch(r_shadow_rendermode) + { + case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: + R_Mesh_TexBind(1, r_shadow_attenuation3dtexture); + R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); + R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + break; + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: + R_Mesh_TexBind(2, r_shadow_attenuation2dtexture); + R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz); + R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + // fall through + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: + R_Mesh_TexBind(1, r_shadow_attenuation2dtexture); + R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); + R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + break; + case R_SHADOW_RENDERMODE_LIGHT_VERTEX: + break; + default: + break; + } + //R_Mesh_TexBind(0, basetexture); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase); + if (dopants) + { + R_Mesh_TexBind(0, pantstexture); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants); + } + if (doshirt) + { + R_Mesh_TexBind(0, shirttexture); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt); + } +} + +extern cvar_t gl_lightmaps; +void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + float ambientscale, diffusescale, specularscale; + qboolean negated; + float lightcolor[3]; + VectorCopy(rsurface.rtlight->currentcolor, lightcolor); + ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient; + diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient); + specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale; + if (!r_shadow_usenormalmap.integer) + { + ambientscale += 1.0f * diffusescale; + diffusescale = 0; + specularscale = 0; + } + if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f)) + return; + negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract; + if(negated) + { + VectorNegate(lightcolor, lightcolor); + GL_BlendEquationSubtract(true); + } + RSurf_SetupDepthAndCulling(); + switch (r_shadow_rendermode) + { + case R_SHADOW_RENDERMODE_VISIBLELIGHTING: + GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); + R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist); + break; + case R_SHADOW_RENDERMODE_LIGHT_GLSL: + R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale); + break; + case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: + case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: + case R_SHADOW_RENDERMODE_LIGHT_VERTEX: + R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale); + break; + default: + Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); + break; + } + if(negated) + GL_BlendEquationSubtract(false); +} + +void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags) +{ + matrix4x4_t tempmatrix = *matrix; + Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1); + + // if this light has been compiled before, free the associated data + R_RTLight_Uncompile(rtlight); + + // clear it completely to avoid any lingering data + memset(rtlight, 0, sizeof(*rtlight)); + + // copy the properties + rtlight->matrix_lighttoworld = tempmatrix; + Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix); + Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin); + rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix); + VectorCopy(color, rtlight->color); + rtlight->cubemapname[0] = 0; + if (cubemapname && cubemapname[0]) + strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname)); + rtlight->shadow = shadow; + rtlight->corona = corona; + rtlight->style = style; + rtlight->isstatic = isstatic; + rtlight->coronasizescale = coronasizescale; + rtlight->ambientscale = ambientscale; + rtlight->diffusescale = diffusescale; + rtlight->specularscale = specularscale; + rtlight->flags = flags; + + // compute derived data + //rtlight->cullradius = rtlight->radius; + //rtlight->cullradius2 = rtlight->radius * rtlight->radius; + rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius; + rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius; + rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius; + rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius; + rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius; + rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius; +} + +// compiles rtlight geometry +// (undone by R_FreeCompiledRTLight, which R_UpdateLight calls) +void R_RTLight_Compile(rtlight_t *rtlight) +{ + int i; + int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes; + int lighttris, shadowtris, shadowzpasstris, shadowzfailtris; + entity_render_t *ent = r_refdef.scene.worldentity; + dp_model_t *model = r_refdef.scene.worldmodel; + unsigned char *data; + shadowmesh_t *mesh; + + // compile the light + rtlight->compiled = true; + rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1; + rtlight->static_numleafs = 0; + rtlight->static_numleafpvsbytes = 0; + rtlight->static_leaflist = NULL; + rtlight->static_leafpvs = NULL; + rtlight->static_numsurfaces = 0; + rtlight->static_surfacelist = NULL; + rtlight->static_shadowmap_receivers = 0x3F; + rtlight->static_shadowmap_casters = 0x3F; + rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius; + rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius; + rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius; + rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius; + rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius; + rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius; + + if (model && model->GetLightInfo) + { + // this variable must be set for the CompileShadowVolume/CompileShadowMap code + r_shadow_compilingrtlight = rtlight; + R_FrameData_SetMark(); + model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL); + R_FrameData_ReturnToMark(); + numleafpvsbytes = (model->brush.num_leafs + 7) >> 3; + numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3; + numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3; + data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes); + rtlight->static_numsurfaces = numsurfaces; + rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces; + rtlight->static_numleafs = numleafs; + rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs; + rtlight->static_numleafpvsbytes = numleafpvsbytes; + rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes; + rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes; + rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes; + rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes; + rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes; + if (rtlight->static_numsurfaces) + memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist)); + if (rtlight->static_numleafs) + memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist)); + if (rtlight->static_numleafpvsbytes) + memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes); + if (rtlight->static_numshadowtrispvsbytes) + memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes); + if (rtlight->static_numlighttrispvsbytes) + memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes); + R_FrameData_SetMark(); + switch (rtlight->shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (model->CompileShadowMap && rtlight->shadow) + model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + break; + default: + if (model->CompileShadowVolume && rtlight->shadow) + model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + break; + } + R_FrameData_ReturnToMark(); + // now we're done compiling the rtlight + r_shadow_compilingrtlight = NULL; + } + + + // use smallest available cullradius - box radius or light radius + //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin); + //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius); + + shadowzpasstris = 0; + if (rtlight->static_meshchain_shadow_zpass) + for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next) + shadowzpasstris += mesh->numtriangles; + + shadowzfailtris = 0; + if (rtlight->static_meshchain_shadow_zfail) + for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next) + shadowzfailtris += mesh->numtriangles; + + lighttris = 0; + if (rtlight->static_numlighttrispvsbytes) + for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++) + if (CHECKPVSBIT(rtlight->static_lighttrispvs, i)) + lighttris++; + + shadowtris = 0; + if (rtlight->static_numlighttrispvsbytes) + for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++) + if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i)) + shadowtris++; + + if (developer_extra.integer) + Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris); +} + +void R_RTLight_Uncompile(rtlight_t *rtlight) +{ + if (rtlight->compiled) + { + if (rtlight->static_meshchain_shadow_zpass) + Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass); + rtlight->static_meshchain_shadow_zpass = NULL; + if (rtlight->static_meshchain_shadow_zfail) + Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail); + rtlight->static_meshchain_shadow_zfail = NULL; + if (rtlight->static_meshchain_shadow_shadowmap) + Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap); + rtlight->static_meshchain_shadow_shadowmap = NULL; + // these allocations are grouped + if (rtlight->static_surfacelist) + Mem_Free(rtlight->static_surfacelist); + rtlight->static_numleafs = 0; + rtlight->static_numleafpvsbytes = 0; + rtlight->static_leaflist = NULL; + rtlight->static_leafpvs = NULL; + rtlight->static_numsurfaces = 0; + rtlight->static_surfacelist = NULL; + rtlight->static_numshadowtrispvsbytes = 0; + rtlight->static_shadowtrispvs = NULL; + rtlight->static_numlighttrispvsbytes = 0; + rtlight->static_lighttrispvs = NULL; + rtlight->compiled = false; + } +} + +void R_Shadow_UncompileWorldLights(void) +{ + size_t lightindex; + dlight_t *light; + size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + R_RTLight_Uncompile(&light->rtlight); + } +} + +static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight) +{ + int i, j; + mplane_t plane; + // reset the count of frustum planes + // see rtlight->cached_frustumplanes definition for how much this array + // can hold + rtlight->cached_numfrustumplanes = 0; + + if (r_trippy.integer) + return; + + // haven't implemented a culling path for ortho rendering + if (!r_refdef.view.useperspective) + { + // check if the light is on screen and copy the 4 planes if it is + for (i = 0;i < 4;i++) + if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125) + break; + if (i == 4) + for (i = 0;i < 4;i++) + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i]; + return; + } + +#if 1 + // generate a deformed frustum that includes the light origin, this is + // used to cull shadow casting surfaces that can not possibly cast a + // shadow onto the visible light-receiving surfaces, which can be a + // performance gain + // + // if the light origin is onscreen the result will be 4 planes exactly + // if the light origin is offscreen on only one axis the result will + // be exactly 5 planes (split-side case) + // if the light origin is offscreen on two axes the result will be + // exactly 4 planes (stretched corner case) + for (i = 0;i < 4;i++) + { + // quickly reject standard frustum planes that put the light + // origin outside the frustum + if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125) + continue; + // copy the plane + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i]; + } + // if all the standard frustum planes were accepted, the light is onscreen + // otherwise we need to generate some more planes below... + if (rtlight->cached_numfrustumplanes < 4) + { + // at least one of the stock frustum planes failed, so we need to + // create one or two custom planes to enclose the light origin + for (i = 0;i < 4;i++) + { + // create a plane using the view origin and light origin, and a + // single point from the frustum corner set + TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal); + VectorNormalize(plane.normal); + plane.dist = DotProduct(r_refdef.view.origin, plane.normal); + // see if this plane is backwards and flip it if so + for (j = 0;j < 4;j++) + if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125) + break; + if (j < 4) + { + VectorNegate(plane.normal, plane.normal); + plane.dist *= -1; + // flipped plane, test again to see if it is now valid + for (j = 0;j < 4;j++) + if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125) + break; + // if the plane is still not valid, then it is dividing the + // frustum and has to be rejected + if (j < 4) + continue; + } + // we have created a valid plane, compute extra info + PlaneClassify(&plane); + // copy the plane + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane; +#if 1 + // if we've found 5 frustum planes then we have constructed a + // proper split-side case and do not need to keep searching for + // planes to enclose the light origin + if (rtlight->cached_numfrustumplanes == 5) + break; +#endif + } + } +#endif + +#if 0 + for (i = 0;i < rtlight->cached_numfrustumplanes;i++) + { + plane = rtlight->cached_frustumplanes[i]; + Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane)); + } +#endif + +#if 0 + // now add the light-space box planes if the light box is rotated, as any + // caster outside the oriented light box is irrelevant (even if it passed + // the worldspace light box, which is axial) + if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1) + { + for (i = 0;i < 6;i++) + { + vec3_t v; + VectorClear(v); + v[i >> 1] = (i & 1) ? -1 : 1; + Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal); + VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal); + plane.dist = VectorNormalizeLength(plane.normal); + plane.dist += DotProduct(plane.normal, rtlight->shadoworigin); + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane; + } + } +#endif + +#if 0 + // add the world-space reduced box planes + for (i = 0;i < 6;i++) + { + VectorClear(plane.normal); + plane.normal[i >> 1] = (i & 1) ? -1 : 1; + plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1]; + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane; + } +#endif + +#if 0 + { + int j, oldnum; + vec3_t points[8]; + vec_t bestdist; + // reduce all plane distances to tightly fit the rtlight cull box, which + // is in worldspace + VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]); + VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]); + VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]); + VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]); + VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]); + VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]); + VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]); + VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]); + oldnum = rtlight->cached_numfrustumplanes; + rtlight->cached_numfrustumplanes = 0; + for (j = 0;j < oldnum;j++) + { + // find the nearest point on the box to this plane + bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]); + for (i = 1;i < 8;i++) + { + dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]); + if (bestdist > dist) + bestdist = dist; + } + Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist); + // if the nearest point is near or behind the plane, we want this + // plane, otherwise the plane is useless as it won't cull anything + if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125) + { + PlaneClassify(&rtlight->cached_frustumplanes[j]); + rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j]; + } + } + } +#endif +} + +static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides) +{ + shadowmesh_t *mesh; + + RSurf_ActiveWorldEntity(); + + if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) + { + CHECKGLERROR + GL_CullFace(GL_NONE); + mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap; + for (;mesh;mesh = mesh->next) + { + if (!mesh->sidetotals[r_shadow_shadowmapside]) + continue; + r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside]; + R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f); + R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); + } + CHECKGLERROR + } + else if (r_refdef.scene.worldentity->model) + r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs); + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs) +{ + qboolean zpass = false; + shadowmesh_t *mesh; + int t, tend; + int surfacelistindex; + msurface_t *surface; + + // if triangle neighbors are disabled, shadowvolumes are disabled + if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i) + return; + + RSurf_ActiveWorldEntity(); + + if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) + { + CHECKGLERROR + if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES) + { + zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs); + R_Shadow_RenderMode_StencilShadowVolumes(zpass); + } + mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail; + for (;mesh;mesh = mesh->next) + { + r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles; + R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f); + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) + { + // increment stencil if frontface is infront of depthbuffer + GL_CullFace(r_refdef.view.cullface_back); + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255); + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); + // decrement stencil if backface is infront of depthbuffer + GL_CullFace(r_refdef.view.cullface_front); + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255); + } + else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL) + { + // decrement stencil if backface is behind depthbuffer + GL_CullFace(r_refdef.view.cullface_front); + R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255); + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); + // increment stencil if frontface is behind depthbuffer + GL_CullFace(r_refdef.view.cullface_back); + R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255); + } + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); + } + CHECKGLERROR + } + else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh) + { + // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light + R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex]; + for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++) + if (CHECKPVSBIT(trispvs, t)) + shadowmarklist[numshadowmark++] = t; + } + R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs); + } + else if (numsurfaces) + { + r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs); + } + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +static void R_Shadow_DrawEntityShadow(entity_render_t *ent) +{ + vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs; + vec_t relativeshadowradius; + RSurf_ActiveModelEntity(ent, false, false, false); + Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin); + // we need to re-init the shader for each entity because the matrix changed + relativeshadowradius = rsurface.rtlight->radius / ent->scale; + relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius; + relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius; + relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius; + relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius; + relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius; + relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius; + switch (r_shadow_rendermode) + { + case R_SHADOW_RENDERMODE_SHADOWMAP2D: + ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs); + break; + default: + ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); + break; + } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +void R_Shadow_SetupEntityLight(const entity_render_t *ent) +{ + // set up properties for rendering light onto this entity + RSurf_ActiveModelEntity(ent, true, true, false); + Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix); + Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight); + Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight); + Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin); +} + +static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs) +{ + if (!r_refdef.scene.worldmodel->DrawLight) + return; + + // set up properties for rendering light onto this entity + RSurf_ActiveWorldEntity(); + rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight; + Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight); + Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight); + VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin); + + r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs); + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +static void R_Shadow_DrawEntityLight(entity_render_t *ent) +{ + dp_model_t *model = ent->model; + if (!model->DrawLight) + return; + + R_Shadow_SetupEntityLight(ent); + + model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL); + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +static void R_Shadow_PrepareLight(rtlight_t *rtlight) +{ + int i; + float f; + int numleafs, numsurfaces; + int *leaflist, *surfacelist; + unsigned char *leafpvs; + unsigned char *shadowtrispvs; + unsigned char *lighttrispvs; + //unsigned char *surfacesides; + int numlightentities; + int numlightentities_noselfshadow; + int numshadowentities; + int numshadowentities_noselfshadow; + static entity_render_t *lightentities[MAX_EDICTS]; + static entity_render_t *lightentities_noselfshadow[MAX_EDICTS]; + static entity_render_t *shadowentities[MAX_EDICTS]; + static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS]; + qboolean nolight; + + rtlight->draw = false; + rtlight->cached_numlightentities = 0; + rtlight->cached_numlightentities_noselfshadow = 0; + rtlight->cached_numshadowentities = 0; + rtlight->cached_numshadowentities_noselfshadow = 0; + rtlight->cached_numsurfaces = 0; + rtlight->cached_lightentities = NULL; + rtlight->cached_lightentities_noselfshadow = NULL; + rtlight->cached_shadowentities = NULL; + rtlight->cached_shadowentities_noselfshadow = NULL; + rtlight->cached_shadowtrispvs = NULL; + rtlight->cached_lighttrispvs = NULL; + rtlight->cached_surfacelist = NULL; + + // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights) + // skip lights that are basically invisible (color 0 0 0) + nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f); + + // loading is done before visibility checks because loading should happen + // all at once at the start of a level, not when it stalls gameplay. + // (especially important to benchmarks) + // compile light + if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer) + { + if (rtlight->compiled) + R_RTLight_Uncompile(rtlight); + R_RTLight_Compile(rtlight); + } + + // load cubemap + rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube; + + // look up the light style value at this time + f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value; + VectorScale(rtlight->color, f, rtlight->currentcolor); + /* + if (rtlight->selected) + { + f = 2 + sin(realtime * M_PI * 4.0); + VectorScale(rtlight->currentcolor, f, rtlight->currentcolor); + } + */ + + // if lightstyle is currently off, don't draw the light + if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f)) + return; + + // skip processing on corona-only lights + if (nolight) + return; + + // if the light box is offscreen, skip it + if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs)) + return; + + VectorCopy(rtlight->cullmins, rtlight->cached_cullmins); + VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs); + + R_Shadow_ComputeShadowCasterCullingPlanes(rtlight); + + // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw + if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer)) + return; + + if (rtlight->compiled && r_shadow_realtime_world_compile.integer) + { + // compiled light, world available and can receive realtime lighting + // retrieve leaf information + numleafs = rtlight->static_numleafs; + leaflist = rtlight->static_leaflist; + leafpvs = rtlight->static_leafpvs; + numsurfaces = rtlight->static_numsurfaces; + surfacelist = rtlight->static_surfacelist; + //surfacesides = NULL; + shadowtrispvs = rtlight->static_shadowtrispvs; + lighttrispvs = rtlight->static_lighttrispvs; + } + else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo) + { + // dynamic light, world available and can receive realtime lighting + // calculate lit surfaces and leafs + r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes); + R_Shadow_ComputeShadowCasterCullingPlanes(rtlight); + leaflist = r_shadow_buffer_leaflist; + leafpvs = r_shadow_buffer_leafpvs; + surfacelist = r_shadow_buffer_surfacelist; + //surfacesides = r_shadow_buffer_surfacesides; + shadowtrispvs = r_shadow_buffer_shadowtrispvs; + lighttrispvs = r_shadow_buffer_lighttrispvs; + // if the reduced leaf bounds are offscreen, skip it + if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs)) + return; + } + else + { + // no world + numleafs = 0; + leaflist = NULL; + leafpvs = NULL; + numsurfaces = 0; + surfacelist = NULL; + //surfacesides = NULL; + shadowtrispvs = NULL; + lighttrispvs = NULL; + } + // check if light is illuminating any visible leafs + if (numleafs) + { + for (i = 0;i < numleafs;i++) + if (r_refdef.viewcache.world_leafvisible[leaflist[i]]) + break; + if (i == numleafs) + return; + } + + // make a list of lit entities and shadow casting entities + numlightentities = 0; + numlightentities_noselfshadow = 0; + numshadowentities = 0; + numshadowentities_noselfshadow = 0; + + // add dynamic entities that are lit by the light + for (i = 0;i < r_refdef.scene.numentities;i++) + { + dp_model_t *model; + entity_render_t *ent = r_refdef.scene.entities[i]; + vec3_t org; + if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs)) + continue; + // skip the object entirely if it is not within the valid + // shadow-casting region (which includes the lit region) + if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes)) + continue; + if (!(model = ent->model)) + continue; + if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT)) + { + // this entity wants to receive light, is visible, and is + // inside the light box + // TODO: check if the surfaces in the model can receive light + // so now check if it's in a leaf seen by the light + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs)) + continue; + if (ent->flags & RENDER_NOSELFSHADOW) + lightentities_noselfshadow[numlightentities_noselfshadow++] = ent; + else + lightentities[numlightentities++] = ent; + // since it is lit, it probably also casts a shadow... + // about the VectorDistance2 - light emitting entities should not cast their own shadow + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) + { + // note: exterior models without the RENDER_NOSELFSHADOW + // flag still create a RENDER_NOSELFSHADOW shadow but + // are lit normally, this means that they are + // self-shadowing but do not shadow other + // RENDER_NOSELFSHADOW entities such as the gun + // (very weird, but keeps the player shadow off the gun) + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } + } + else if (ent->flags & RENDER_SHADOW) + { + // this entity is not receiving light, but may still need to + // cast a shadow... + // TODO: check if the surfaces in the model can cast shadow + // now check if it is in a leaf seen by the light + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs)) + continue; + // about the VectorDistance2 - light emitting entities should not cast their own shadow + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) + { + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } + } + } + + // return if there's nothing at all to light + if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0) + return; + + // count this light in the r_speeds + r_refdef.stats[r_stat_lights]++; + + // flag it as worth drawing later + rtlight->draw = true; + + // cache all the animated entities that cast a shadow but are not visible + for (i = 0;i < numshadowentities;i++) + R_AnimCache_GetEntity(shadowentities[i], false, false); + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false); + + // allocate some temporary memory for rendering this light later in the frame + // reusable buffers need to be copied, static data can be used as-is + rtlight->cached_numlightentities = numlightentities; + rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow; + rtlight->cached_numshadowentities = numshadowentities; + rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow; + rtlight->cached_numsurfaces = numsurfaces; + rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities); + rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow); + rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities); + rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow); + if (shadowtrispvs == r_shadow_buffer_shadowtrispvs) + { + int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3); + int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3); + rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs); + rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs); + rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist); + } + else + { + // compiled light data + rtlight->cached_shadowtrispvs = shadowtrispvs; + rtlight->cached_lighttrispvs = lighttrispvs; + rtlight->cached_surfacelist = surfacelist; + } +} + +static void R_Shadow_DrawLight(rtlight_t *rtlight) +{ + int i; + int numsurfaces; + unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides; + int numlightentities; + int numlightentities_noselfshadow; + int numshadowentities; + int numshadowentities_noselfshadow; + entity_render_t **lightentities; + entity_render_t **lightentities_noselfshadow; + entity_render_t **shadowentities; + entity_render_t **shadowentities_noselfshadow; + int *surfacelist; + static unsigned char entitysides[MAX_EDICTS]; + static unsigned char entitysides_noselfshadow[MAX_EDICTS]; + vec3_t nearestpoint; + vec_t distance; + qboolean castshadows; + int lodlinear; + + // check if we cached this light this frame (meaning it is worth drawing) + if (!rtlight->draw) + return; + + numlightentities = rtlight->cached_numlightentities; + numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow; + numshadowentities = rtlight->cached_numshadowentities; + numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow; + numsurfaces = rtlight->cached_numsurfaces; + lightentities = rtlight->cached_lightentities; + lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow; + shadowentities = rtlight->cached_shadowentities; + shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow; + shadowtrispvs = rtlight->cached_shadowtrispvs; + lighttrispvs = rtlight->cached_lighttrispvs; + surfacelist = rtlight->cached_surfacelist; + + // set up a scissor rectangle for this light + if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs)) + return; + + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); + + // make this the active rtlight for rendering purposes + R_Shadow_RenderMode_ActiveLight(rtlight); + + if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows)) + { + // optionally draw visible shape of the shadow volumes + // for performance analysis by level designers + R_Shadow_RenderMode_VisibleShadowVolumes(); + if (numsurfaces) + R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + R_Shadow_RenderMode_VisibleLighting(false, false); + } + + if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow) + { + // optionally draw the illuminated areas + // for performance analysis by level designers + R_Shadow_RenderMode_VisibleLighting(false, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i]); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + } + + castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows); + + nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]); + nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]); + nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]); + distance = VectorDistance(nearestpoint, r_refdef.view.origin); + + lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius)); + //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance)); + lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize); + + if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + { + float borderbias; + int side; + int size; + int castermask = 0; + int receivermask = 0; + matrix4x4_t radiustolight = rtlight->matrix_worldtolight; + Matrix4x4_Abs(&radiustolight); + + r_shadow_shadowmaplod = 0; + for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++) + if ((r_shadow_shadowmapmaxsize >> i) > lodlinear) + r_shadow_shadowmaplod = i; + + size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize); + + borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder); + + surfacesides = NULL; + if (numsurfaces) + { + if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) + { + castermask = rtlight->static_shadowmap_casters; + receivermask = rtlight->static_shadowmap_receivers; + } + else + { + surfacesides = r_shadow_buffer_surfacesides; + for(i = 0;i < numsurfaces;i++) + { + msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i]; + surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias); + castermask |= surfacesides[i]; + receivermask |= surfacesides[i]; + } + } + } + if (receivermask < 0x3F) + { + for (i = 0;i < numlightentities;i++) + receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias); + if (receivermask < 0x3F) + for(i = 0; i < numlightentities_noselfshadow;i++) + receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias); + } + + receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder); + + if (receivermask) + { + for (i = 0;i < numshadowentities;i++) + castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); + for (i = 0;i < numshadowentities_noselfshadow;i++) + castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); + } + + //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size); + + // render shadow casters into 6 sided depth texture + for (side = 0;side < 6;side++) if (receivermask & (1 << side)) + { + R_Shadow_RenderMode_ShadowMap(side, receivermask, size); + if (! (castermask & (1 << side))) continue; + if (numsurfaces) + R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides); + for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side)) + R_Shadow_DrawEntityShadow(shadowentities[i]); + } + + if (numlightentities_noselfshadow) + { + // render lighting using the depth texture as shadowmap + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(false, false, true); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + } + + // render shadow casters into 6 sided depth texture + if (numshadowentities_noselfshadow) + { + for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side)) + { + R_Shadow_RenderMode_ShadowMap(side, 0, size); + for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side)) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + } + } + + // render lighting using the depth texture as shadowmap + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(false, false, true); + // draw lighting in the unmasked areas + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i]); + } + else if (castshadows && vid.stencil) + { + // draw stencil shadow volumes to mask off pixels that are in shadow + // so that they won't receive lighting + GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]); + R_Shadow_ClearStencil(); + + if (numsurfaces) + R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false, false); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i]); + } + else + { + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(false, false, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i]); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + } + + if (r_shadow_usingdeferredprepass) + { + // when rendering deferred lighting, we simply rasterize the box + if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + R_Shadow_RenderMode_DrawDeferredLight(false, true); + else if (castshadows && vid.stencil) + R_Shadow_RenderMode_DrawDeferredLight(true, false); + else + R_Shadow_RenderMode_DrawDeferredLight(false, false); + } +} + +static void R_Shadow_FreeDeferred(void) +{ + R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo); + r_shadow_prepassgeometryfbo = 0; + + R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo); + r_shadow_prepasslightingdiffusespecularfbo = 0; + + R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo); + r_shadow_prepasslightingdiffusefbo = 0; + + if (r_shadow_prepassgeometrydepthbuffer) + R_FreeTexture(r_shadow_prepassgeometrydepthbuffer); + r_shadow_prepassgeometrydepthbuffer = NULL; + + if (r_shadow_prepassgeometrynormalmaptexture) + R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture); + r_shadow_prepassgeometrynormalmaptexture = NULL; + + if (r_shadow_prepasslightingdiffusetexture) + R_FreeTexture(r_shadow_prepasslightingdiffusetexture); + r_shadow_prepasslightingdiffusetexture = NULL; + + if (r_shadow_prepasslightingspeculartexture) + R_FreeTexture(r_shadow_prepasslightingspeculartexture); + r_shadow_prepasslightingspeculartexture = NULL; +} + +void R_Shadow_DrawPrepass(void) +{ + int i; + int flag; + int lnum; + size_t lightindex; + dlight_t *light; + size_t range; + entity_render_t *ent; + float clearcolor[4]; + + R_Mesh_ResetTextureState(); + GL_DepthMask(true); + GL_ColorMask(1,1,1,1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(1,1,1,1); + GL_DepthTest(true); + R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL); + Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f); + GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0); + if (r_timereport_active) + R_TimeReport("prepasscleargeom"); + + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass) + r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity); + if (r_timereport_active) + R_TimeReport("prepassworld"); + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + if (ent->model && ent->model->DrawPrepass != NULL) + ent->model->DrawPrepass(ent); + } + + if (r_timereport_active) + R_TimeReport("prepassmodels"); + + GL_DepthMask(false); + GL_ColorMask(1,1,1,1); + GL_Color(1,1,1,1); + GL_DepthTest(true); + R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL); + Vector4Set(clearcolor, 0, 0, 0, 0); + GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0); + if (r_timereport_active) + R_TimeReport("prepassclearlit"); + + R_Shadow_RenderMode_Begin(); + + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + if (r_shadow_debuglight.integer >= 0) + { + lightindex = r_shadow_debuglight.integer; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light && (light->flags & flag) && light->rtlight.draw) + R_Shadow_DrawLight(&light->rtlight); + } + else + { + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light && (light->flags & flag) && light->rtlight.draw) + R_Shadow_DrawLight(&light->rtlight); + } + } + if (r_refdef.scene.rtdlight) + for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) + if (r_refdef.scene.lights[lnum]->draw) + R_Shadow_DrawLight(r_refdef.scene.lights[lnum]); + + R_Shadow_RenderMode_End(); + + if (r_timereport_active) + R_TimeReport("prepasslights"); +} + +void R_Shadow_DrawLightSprites(void); +void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + int flag; + int lnum; + size_t lightindex; + dlight_t *light; + size_t range; + float f; + + if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) || + (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) || + r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || + r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || + r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) || + r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || + r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) || + r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures) + R_Shadow_FreeShadowMaps(); + + r_shadow_fb_fbo = fbo; + r_shadow_fb_depthtexture = depthtexture; + r_shadow_fb_colortexture = colortexture; + + r_shadow_usingshadowmaportho = false; + + switch (vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: +#ifndef USE_GLES2 + if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2) + { + r_shadow_usingdeferredprepass = false; + if (r_shadow_prepass_width) + R_Shadow_FreeDeferred(); + r_shadow_prepass_width = r_shadow_prepass_height = 0; + break; + } + + if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height) + { + R_Shadow_FreeDeferred(); + + r_shadow_usingdeferredprepass = true; + r_shadow_prepass_width = vid.width; + r_shadow_prepass_height = vid.height; + r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24); + r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL); + r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL); + r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL); + + // set up the geometry pass fbo (depth + normalmap) + r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL); + R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL); + // render depth into a renderbuffer and other important properties into the normalmap texture + + // set up the lighting pass fbo (diffuse + specular) + r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL); + R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL); + // render diffuse into one texture and specular into another, + // with depth and normalmap bound as textures, + // with depth bound as attachment as well + + // set up the lighting pass fbo (diffuse) + r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL); + R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL); + // render diffuse into one texture, + // with depth and normalmap bound as textures, + // with depth bound as attachment as well + } +#endif + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + r_shadow_usingdeferredprepass = false; + break; + } + + R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles); + + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + if (r_shadow_debuglight.integer >= 0) + { + lightindex = r_shadow_debuglight.integer; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_Shadow_PrepareLight(&light->rtlight); + } + else + { + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light && (light->flags & flag)) + R_Shadow_PrepareLight(&light->rtlight); + } + } + if (r_refdef.scene.rtdlight) + { + for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) + R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]); + } + else if(gl_flashblend.integer) + { + for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) + { + rtlight_t *rtlight = r_refdef.scene.lights[lnum]; + f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value; + VectorScale(rtlight->color, f, rtlight->currentcolor); + } + } + + if (r_editlights.integer) + R_Shadow_DrawLightSprites(); +} + +void R_Shadow_DrawLights(void) +{ + int flag; + int lnum; + size_t lightindex; + dlight_t *light; + size_t range; + + R_Shadow_RenderMode_Begin(); + + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + if (r_shadow_debuglight.integer >= 0) + { + lightindex = r_shadow_debuglight.integer; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_Shadow_DrawLight(&light->rtlight); + } + else + { + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light && (light->flags & flag)) + R_Shadow_DrawLight(&light->rtlight); + } + } + if (r_refdef.scene.rtdlight) + for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) + R_Shadow_DrawLight(r_refdef.scene.lights[lnum]); + + R_Shadow_RenderMode_End(); +} + +#define MAX_MODELSHADOWS 1024 +static int r_shadow_nummodelshadows; +static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS]; + +void R_Shadow_PrepareModelShadows(void) +{ + int i; + float scale, size, radius, dot1, dot2; + prvm_vec3_t prvmshadowdir, prvmshadowfocus; + vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs; + entity_render_t *ent; + + r_shadow_nummodelshadows = 0; + if (!r_refdef.scene.numentities) + return; + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (r_shadows.integer >= 2) + break; + // fall through + case R_SHADOW_SHADOWMODE_STENCIL: + if (!vid.stencil) + return; + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW)) + { + if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS) + break; + r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent; + R_AnimCache_GetEntity(ent, false, false); + } + } + return; + default: + return; + } + + size = 2*r_shadow_shadowmapmaxsize; + scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value; + radius = 0.5f * size / scale; + + Math_atov(r_shadows_throwdirection.string, prvmshadowdir); + VectorCopy(prvmshadowdir, shadowdir); + VectorNormalize(shadowdir); + dot1 = DotProduct(r_refdef.view.forward, shadowdir); + dot2 = DotProduct(r_refdef.view.up, shadowdir); + if (fabs(dot1) <= fabs(dot2)) + VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward); + else + VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward); + VectorNormalize(shadowforward); + CrossProduct(shadowdir, shadowforward, shadowright); + Math_atov(r_shadows_focus.string, prvmshadowfocus); + VectorCopy(prvmshadowfocus, shadowfocus); + VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin); + VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin); + VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin); + VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin); + if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2]) + dot1 = 1; + VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin); + + shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0])); + shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1])); + shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2])); + shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0])); + shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1])); + shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2])); + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs)) + continue; + // cast shadows from anything of the map (submodels are optional) + if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW)) + { + if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS) + break; + r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent; + R_AnimCache_GetEntity(ent, false, false); + } + } +} + +void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + int i; + float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2; + entity_render_t *ent; + vec3_t relativelightorigin; + vec3_t relativelightdirection, relativeforward, relativeright; + vec3_t relativeshadowmins, relativeshadowmaxs; + vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus; + prvm_vec3_t prvmshadowdir, prvmshadowfocus; + float m[12]; + matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix; + r_viewport_t viewport; + GLuint shadowfbo = 0; + float clearcolor[4]; + + if (!r_shadow_nummodelshadows) + return; + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + break; + default: + return; + } + + r_shadow_fb_fbo = fbo; + r_shadow_fb_depthtexture = depthtexture; + r_shadow_fb_colortexture = colortexture; + + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight(NULL); + + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + if (!r_shadow_shadowmap2ddepthtexture) + R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize); + shadowfbo = r_shadow_fbo2d; + r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture); + r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture); + r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D; + break; + default: + break; + } + + size = 2*r_shadow_shadowmapmaxsize; + scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size; + radius = 0.5f / scale; + nearclip = -r_shadows_throwdistance.value; + farclip = r_shadows_throwdistance.value; + bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size); + + r_shadow_shadowmap_parameters[0] = size; + r_shadow_shadowmap_parameters[1] = size; + r_shadow_shadowmap_parameters[2] = 1.0; + r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f); + + Math_atov(r_shadows_throwdirection.string, prvmshadowdir); + VectorCopy(prvmshadowdir, shadowdir); + VectorNormalize(shadowdir); + Math_atov(r_shadows_focus.string, prvmshadowfocus); + VectorCopy(prvmshadowfocus, shadowfocus); + VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin); + VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin); + VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin); + VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin); + dot1 = DotProduct(r_refdef.view.forward, shadowdir); + dot2 = DotProduct(r_refdef.view.up, shadowdir); + if (fabs(dot1) <= fabs(dot2)) + VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward); + else + VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward); + VectorNormalize(shadowforward); + VectorM(scale, shadowforward, &m[0]); + if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2]) + dot1 = 1; + m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]); + CrossProduct(shadowdir, shadowforward, shadowright); + VectorM(scale, shadowright, &m[4]); + m[7] = 0.5f - DotProduct(shadoworigin, &m[4]); + VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]); + m[11] = 0.5f - DotProduct(shadoworigin, &m[8]); + Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m); + Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix); + R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); + + VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin); + + if (r_shadow_shadowmap2ddepthbuffer) + R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL); + else + R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL); + R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model? + GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value); + GL_DepthMask(true); + GL_DepthTest(true); + R_SetViewport(&viewport); + GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder); + Vector4Set(clearcolor, 1,1,1,1); + // in D3D9 we have to render to a color texture shadowmap + // in GL we render directly to a depth texture only + if (r_shadow_shadowmap2ddepthbuffer) + GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0); + else + GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0); + // render into a slightly restricted region so that the borders of the + // shadowmap area fade away, rather than streaking across everything + // outside the usable area + GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder); + + for (i = 0;i < r_shadow_nummodelshadows;i++) + { + ent = r_shadow_modelshadows[i]; + relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix); + Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward); + Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright); + relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0])); + relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1])); + relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2])); + relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0])); + relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1])); + relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2])); + RSurf_ActiveModelEntity(ent, false, false, false); + ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + } + +#if 0 + if (r_test.integer) + { + unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4); + CHECKGLERROR + qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels); + CHECKGLERROR + Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels); + Cvar_SetValueQuick(&r_test, 0); + Z_Free(rawpixels); + } +#endif + + R_Shadow_RenderMode_End(); + + Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix); + Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix); + Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); + Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias); + Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix); + Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix); + + switch (vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_SOFT: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + break; + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: +#ifdef MATRIX4x4_OPENGLORIENTATION + r_shadow_shadowmapmatrix.m[0][0] *= -1.0f; + r_shadow_shadowmapmatrix.m[0][1] *= -1.0f; + r_shadow_shadowmapmatrix.m[0][2] *= -1.0f; + r_shadow_shadowmapmatrix.m[0][3] *= -1.0f; +#else + r_shadow_shadowmapmatrix.m[0][0] *= -1.0f; + r_shadow_shadowmapmatrix.m[1][0] *= -1.0f; + r_shadow_shadowmapmatrix.m[2][0] *= -1.0f; + r_shadow_shadowmapmatrix.m[3][0] *= -1.0f; +#endif + break; + } + + r_shadow_usingshadowmaportho = true; + switch (r_shadow_shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + r_shadow_usingshadowmap2d = true; + break; + default: + break; + } +} + +void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) +{ + int i; + float relativethrowdistance; + entity_render_t *ent; + vec3_t relativelightorigin; + vec3_t relativelightdirection; + vec3_t relativeshadowmins, relativeshadowmaxs; + vec3_t tmp, shadowdir; + prvm_vec3_t prvmshadowdir; + + if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1)) + return; + + r_shadow_fb_fbo = fbo; + r_shadow_fb_depthtexture = depthtexture; + r_shadow_fb_colortexture = colortexture; + + R_ResetViewRendering3D(fbo, depthtexture, colortexture); + //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight(NULL); + r_shadow_lightscissor[0] = r_refdef.view.x; + r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height; + r_shadow_lightscissor[2] = r_refdef.view.width; + r_shadow_lightscissor[3] = r_refdef.view.height; + R_Shadow_RenderMode_StencilShadowVolumes(false); + + // get shadow dir + if (r_shadows.integer == 2) + { + Math_atov(r_shadows_throwdirection.string, prvmshadowdir); + VectorCopy(prvmshadowdir, shadowdir); + VectorNormalize(shadowdir); + } + + R_Shadow_ClearStencil(); + + for (i = 0;i < r_shadow_nummodelshadows;i++) + { + ent = r_shadow_modelshadows[i]; + + // cast shadows from anything of the map (submodels are optional) + relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix); + VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance); + VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance); + if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction + Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection); + else + { + if(ent->entitynumber != 0) + { + if(ent->entitynumber >= MAX_EDICTS) // csqc entity + { + // FIXME handle this + VectorNegate(ent->modellight_lightdir, relativelightdirection); + } + else + { + // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities) + int entnum, entnum2, recursion; + entnum = entnum2 = ent->entitynumber; + for(recursion = 32; recursion > 0; --recursion) + { + entnum2 = cl.entities[entnum].state_current.tagentity; + if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2]) + entnum = entnum2; + else + break; + } + if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain + { + VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection); + // transform into modelspace of OUR entity + Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp); + Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection); + } + else + VectorNegate(ent->modellight_lightdir, relativelightdirection); + } + } + else + VectorNegate(ent->modellight_lightdir, relativelightdirection); + } + + VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin); + RSurf_ActiveModelEntity(ent, false, false, false); + ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + } + + // not really the right mode, but this will disable any silly stencil features + R_Shadow_RenderMode_End(); + + // set up ortho view for rendering this pass + //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); + //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + //GL_ScissorTest(true); + //R_EntityMatrix(&identitymatrix); + //R_Mesh_ResetTextureState(); + R_ResetViewRendering2D(fbo, depthtexture, colortexture); + + // set up a darkening blend on shadowed areas + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //GL_DepthRange(0, 1); + //GL_DepthTest(false); + //GL_DepthMask(false); + //GL_PolygonOffset(0, 0);CHECKGLERROR + GL_Color(0, 0, 0, r_shadows_darken.value); + //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + //GL_DepthFunc(GL_ALWAYS); + R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255); + + // apply the blend to the shadowed areas + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); + R_SetupShader_Generic_NoTexture(false, true); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + + // restore the viewport + R_SetViewport(&r_refdef.view.viewport); + + // restore other state to normal + //R_Shadow_RenderMode_End(); +} + +static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery) +{ + float zdist; + vec3_t centerorigin; + float vertex3f[12]; + // if it's too close, skip it + if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f)) + return; + zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward)); + if (zdist < 32) + return; + if (usequery && r_numqueries + 2 <= r_maxqueries) + { + rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++]; + rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++]; + // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights + VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin); + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef GL_SAMPLES_PASSED_ARB + CHECKGLERROR + // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead + qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels); + GL_DepthFunc(GL_ALWAYS); + R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + qglEndQueryARB(GL_SAMPLES_PASSED_ARB); + GL_DepthFunc(GL_LEQUAL); + qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels); + R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); + qglEndQueryARB(GL_SAMPLES_PASSED_ARB); + CHECKGLERROR +#endif + break; + case RENDERPATH_D3D9: + Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + } + rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1); +} + +static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1}; + +static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) +{ + vec3_t color; + GLint allpixels = 0, visiblepixels = 0; + // now we have to check the query result + if (rtlight->corona_queryindex_visiblepixels) + { + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: +#ifdef GL_SAMPLES_PASSED_ARB + CHECKGLERROR + qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels); + qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels); + CHECKGLERROR +#endif + break; + case RENDERPATH_D3D9: + Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels); + if (visiblepixels < 1 || allpixels < 1) + return; + rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1); + cscale *= rtlight->corona_visibility; + } + else + { + // FIXME: these traces should scan all render entities instead of cl.world + if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1) + return; + } + VectorScale(rtlight->currentcolor, cscale, color); + if (VectorLength(color) > (1.0f / 256.0f)) + { + float vertex3f[12]; + qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract; + if(negated) + { + VectorNegate(color, color); + GL_BlendEquationSubtract(true); + } + R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST, 0, 4, 0, 2, false, false); + if(negated) + GL_BlendEquationSubtract(false); + } +} + +void R_Shadow_DrawCoronas(void) +{ + int i, flag; + qboolean usequery = false; + size_t lightindex; + dlight_t *light; + rtlight_t *rtlight; + size_t range; + if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer) + return; + if (r_fb.water.renderingscene) + return; + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + R_EntityMatrix(&identitymatrix); + + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + + // check occlusion of coronas + // use GL_ARB_occlusion_query if available + // otherwise use raytraces + r_numqueries = 0; + switch (vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_GLES1: + case RENDERPATH_GLES2: + usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer; +#ifdef GL_SAMPLES_PASSED_ARB + if (usequery) + { + GL_ColorMask(0,0,0,0); + if (r_maxqueries < (range + r_refdef.scene.numlights) * 2) + if (r_maxqueries < MAX_OCCLUSION_QUERIES) + { + i = r_maxqueries; + r_maxqueries = (range + r_refdef.scene.numlights) * 4; + r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES); + CHECKGLERROR + qglGenQueriesARB(r_maxqueries - i, r_queries + i); + CHECKGLERROR + } + RSurf_ActiveWorldEntity(); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_CullFace(GL_NONE); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(true); + R_Mesh_ResetTextureState(); + R_SetupShader_Generic_NoTexture(false, false); + } +#endif + break; + case RENDERPATH_D3D9: + usequery = false; + //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_SOFT: + usequery = false; + //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + } + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + rtlight = &light->rtlight; + rtlight->corona_visibility = 0; + rtlight->corona_queryindex_visiblepixels = 0; + rtlight->corona_queryindex_allpixels = 0; + if (!(rtlight->flags & flag)) + continue; + if (rtlight->corona <= 0) + continue; + if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex) + continue; + R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery); + } + for (i = 0;i < r_refdef.scene.numlights;i++) + { + rtlight = r_refdef.scene.lights[i]; + rtlight->corona_visibility = 0; + rtlight->corona_queryindex_visiblepixels = 0; + rtlight->corona_queryindex_allpixels = 0; + if (!(rtlight->flags & flag)) + continue; + if (rtlight->corona <= 0) + continue; + R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery); + } + if (usequery) + GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + + // now draw the coronas using the query data for intensity info + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + rtlight = &light->rtlight; + if (rtlight->corona_visibility <= 0) + continue; + R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale); + } + for (i = 0;i < r_refdef.scene.numlights;i++) + { + rtlight = r_refdef.scene.lights[i]; + if (rtlight->corona_visibility <= 0) + continue; + if (gl_flashblend.integer) + R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f); + else + R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale); + } +} + + + +static dlight_t *R_Shadow_NewWorldLight(void) +{ + return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray); +} + +static void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags) +{ + matrix4x4_t matrix; + // validate parameters + if (style < 0 || style >= MAX_LIGHTSTYLES) + { + Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES); + style = 0; + } + if (!cubemapname) + cubemapname = ""; + + // copy to light properties + VectorCopy(origin, light->origin); + light->angles[0] = angles[0] - 360 * floor(angles[0] / 360); + light->angles[1] = angles[1] - 360 * floor(angles[1] / 360); + light->angles[2] = angles[2] - 360 * floor(angles[2] / 360); + /* + light->color[0] = max(color[0], 0); + light->color[1] = max(color[1], 0); + light->color[2] = max(color[2], 0); + */ + light->color[0] = color[0]; + light->color[1] = color[1]; + light->color[2] = color[2]; + light->radius = max(radius, 0); + light->style = style; + light->shadow = shadowenable; + light->corona = corona; + strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname)); + light->coronasizescale = coronasizescale; + light->ambientscale = ambientscale; + light->diffusescale = diffusescale; + light->specularscale = specularscale; + light->flags = flags; + + // update renderable light data + Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius); + R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags); +} + +static void R_Shadow_FreeWorldLight(dlight_t *light) +{ + if (r_shadow_selectedlight == light) + r_shadow_selectedlight = NULL; + R_RTLight_Uncompile(&light->rtlight); + Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light); +} + +void R_Shadow_ClearWorldLights(void) +{ + size_t lightindex; + dlight_t *light; + size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_Shadow_FreeWorldLight(light); + } + r_shadow_selectedlight = NULL; +} + +static void R_Shadow_SelectLight(dlight_t *light) +{ + if (r_shadow_selectedlight) + r_shadow_selectedlight->selected = false; + r_shadow_selectedlight = light; + if (r_shadow_selectedlight) + r_shadow_selectedlight->selected = true; +} + +static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + // this is never batched (there can be only one) + float vertex3f[12]; + R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE); + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false); +} + +static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + float intensity; + float s; + vec3_t spritecolor; + skinframe_t *skinframe; + float vertex3f[12]; + + // this is never batched (due to the ent parameter changing every time) + // so numsurfaces == 1 and surfacelist[0] == lightnumber + const dlight_t *light = (dlight_t *)ent; + s = EDLIGHTSPRSIZE; + + R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s); + + intensity = 0.5f; + VectorScale(light->color, intensity, spritecolor); + if (VectorLength(spritecolor) < 0.1732f) + VectorSet(spritecolor, 0.1f, 0.1f, 0.1f); + if (VectorLength(spritecolor) > 1.0f) + VectorNormalize(spritecolor); + + // draw light sprite + if (light->cubemapname[0] && !light->shadow) + skinframe = r_editlights_sprcubemapnoshadowlight; + else if (light->cubemapname[0]) + skinframe = r_editlights_sprcubemaplight; + else if (!light->shadow) + skinframe = r_editlights_sprnoshadowlight; + else + skinframe = r_editlights_sprlight; + + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false); + + // draw selection sprite if light is selected + if (light->selected) + { + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false); + // VorteX todo: add normalmode/realtime mode light overlay sprites? + } +} + +void R_Shadow_DrawLightSprites(void) +{ + size_t lightindex; + dlight_t *light; + size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (light) + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight); + } + if (!r_editlights_lockcursor) + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL); +} + +int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color) +{ + unsigned int range; + dlight_t *light; + rtlight_t *rtlight; + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); + if (lightindex >= range) + return -1; + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + return 0; + rtlight = &light->rtlight; + //if (!(rtlight->flags & flag)) + // return 0; + VectorCopy(rtlight->shadoworigin, origin); + *radius = rtlight->radius; + VectorCopy(rtlight->color, color); + return 1; +} + +static void R_Shadow_SelectLightInView(void) +{ + float bestrating, rating, temp[3]; + dlight_t *best; + size_t lightindex; + dlight_t *light; + size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + best = NULL; + bestrating = 0; + + if (r_editlights_lockcursor) + return; + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + VectorSubtract(light->origin, r_refdef.view.origin, temp); + rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp))); + if (rating >= 0.95) + { + rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp))); + if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f) + { + bestrating = rating; + best = light; + } + } + } + R_Shadow_SelectLight(best); +} + +void R_Shadow_LoadWorldLights(void) +{ + int n, a, style, shadow, flags; + char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH]; + float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale; + if (cl.worldmodel == NULL) + { + Con_Print("No map loaded.\n"); + return; + } + dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension); + lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL); + if (lightsstring) + { + s = lightsstring; + n = 0; + while (*s) + { + /* + t = s; + shadow = true; + for (;COM_Parse(t, true) && strcmp( + if (COM_Parse(t, true)) + { + if (com_token[0] == '!') + { + shadow = false; + origin[0] = atof(com_token+1); + } + else + origin[0] = atof(com_token); + if (Com_Parse(t + } + */ + t = s; + while (*s && *s != '\n' && *s != '\r') + s++; + if (!*s) + break; + tempchar = *s; + shadow = true; + // check for modifier flags + if (*t == '!') + { + shadow = false; + t++; + } + *s = 0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + cubemapname[sizeof(cubemapname)-1] = 0; +#if MAX_QPATH != 128 +#error update this code if MAX_QPATH changes +#endif + a = sscanf(t, "%f %f %f %f %f %f %f %d %127s %f %f %f %f %f %f %f %f %i", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, cubemapname +#if _MSC_VER >= 1400 +, sizeof(cubemapname) +#endif +, &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags); + *s = tempchar; + if (a < 18) + flags = LIGHTFLAG_REALTIMEMODE; + if (a < 17) + specularscale = 1; + if (a < 16) + diffusescale = 1; + if (a < 15) + ambientscale = 0; + if (a < 14) + coronasizescale = 0.25f; + if (a < 13) + VectorClear(angles); + if (a < 10) + corona = 0; + if (a < 9 || !strcmp(cubemapname, "\"\"")) + cubemapname[0] = 0; + // remove quotes on cubemapname + if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"') + { + size_t namelen; + namelen = strlen(cubemapname) - 2; + memmove(cubemapname, cubemapname + 1, namelen); + cubemapname[namelen] = '\0'; + } + if (a < 8) + { + Con_Printf("found %d parameters on line %i, should be 8 or more parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style \"cubemapname\" corona angles[0] angles[1] angles[2] coronasizescale ambientscale diffusescale specularscale flags)\n", a, n + 1); + break; + } + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags); + if (*s == '\r') + s++; + if (*s == '\n') + s++; + n++; + } + if (*s) + Con_Printf("invalid rtlights file \"%s\"\n", name); + Mem_Free(lightsstring); + } +} + +void R_Shadow_SaveWorldLights(void) +{ + size_t lightindex; + dlight_t *light; + size_t bufchars, bufmaxchars; + char *buf, *oldbuf; + char name[MAX_QPATH]; + char line[MAX_INPUTLINE]; + size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up... + // I hate lines which are 3 times my screen size :( --blub + if (!range) + return; + if (cl.worldmodel == NULL) + { + Con_Print("No map loaded.\n"); + return; + } + dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension); + bufchars = bufmaxchars = 0; + buf = NULL; + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE) + dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f %f %f %f %f %i\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2], light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags); + else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2]) + dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]); + else + dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius, light->color[0], light->color[1], light->color[2], light->style); + if (bufchars + strlen(line) > bufmaxchars) + { + bufmaxchars = bufchars + strlen(line) + 2048; + oldbuf = buf; + buf = (char *)Mem_Alloc(tempmempool, bufmaxchars); + if (oldbuf) + { + if (bufchars) + memcpy(buf, oldbuf, bufchars); + Mem_Free(oldbuf); + } + } + if (strlen(line)) + { + memcpy(buf + bufchars, line, strlen(line)); + bufchars += strlen(line); + } + } + if (bufchars) + FS_WriteFile(name, buf, (fs_offset_t)bufchars); + if (buf) + Mem_Free(buf); +} + +void R_Shadow_LoadLightsFile(void) +{ + int n, a, style; + char tempchar, *lightsstring, *s, *t, name[MAX_QPATH]; + float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias; + if (cl.worldmodel == NULL) + { + Con_Print("No map loaded.\n"); + return; + } + dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension); + lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL); + if (lightsstring) + { + s = lightsstring; + n = 0; + while (*s) + { + t = s; + while (*s && *s != '\n' && *s != '\r') + s++; + if (!*s) + break; + tempchar = *s; + *s = 0; + a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style); + *s = tempchar; + if (a < 14) + { + Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1); + break; + } + radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f)); + radius = bound(15, radius, 4096); + VectorScale(color, (2.0f / (8388608.0f)), color); + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE); + if (*s == '\r') + s++; + if (*s == '\n') + s++; + n++; + } + if (*s) + Con_Printf("invalid lights file \"%s\"\n", name); + Mem_Free(lightsstring); + } +} + +// tyrlite/hmap2 light types in the delay field +typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t; + +void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) +{ + int entnum; + int style; + int islight; + int skin; + int pflags; + //int effects; + int type; + int n; + char *entfiledata; + const char *data; + float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4]; + char key[256], value[MAX_INPUTLINE]; + char vabuf[1024]; + + if (cl.worldmodel == NULL) + { + Con_Print("No map loaded.\n"); + return; + } + // try to load a .ent file first + dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension); + data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL); + // and if that is not found, fall back to the bsp file entity string + if (!data) + data = cl.worldmodel->brush.entities; + if (!data) + return; + for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++) + { + type = LIGHTTYPE_MINUSX; + origin[0] = origin[1] = origin[2] = 0; + originhack[0] = originhack[1] = originhack[2] = 0; + angles[0] = angles[1] = angles[2] = 0; + color[0] = color[1] = color[2] = 1; + light[0] = light[1] = light[2] = 1;light[3] = 300; + overridecolor[0] = overridecolor[1] = overridecolor[2] = 1; + fadescale = 1; + lightscale = 1; + style = 0; + skin = 0; + pflags = 0; + //effects = 0; + islight = false; + while (1) + { + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; // error + if (com_token[0] == '}') + break; // end of entity + if (com_token[0] == '_') + strlcpy(key, com_token + 1, sizeof(key)); + else + strlcpy(key, com_token, sizeof(key)); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + if (!COM_ParseToken_Simple(&data, false, false, true)) + break; // error + strlcpy(value, com_token, sizeof(value)); + + // now that we have the key pair worked out... + if (!strcmp("light", key)) + { + n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]); + if (n == 1) + { + // quake + light[0] = vec[0] * (1.0f / 256.0f); + light[1] = vec[0] * (1.0f / 256.0f); + light[2] = vec[0] * (1.0f / 256.0f); + light[3] = vec[0]; + } + else if (n == 4) + { + // halflife + light[0] = vec[0] * (1.0f / 255.0f); + light[1] = vec[1] * (1.0f / 255.0f); + light[2] = vec[2] * (1.0f / 255.0f); + light[3] = vec[3]; + } + } + else if (!strcmp("delay", key)) + type = atoi(value); + else if (!strcmp("origin", key)) + sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]); + else if (!strcmp("angle", key)) + angles[0] = 0, angles[1] = atof(value), angles[2] = 0; + else if (!strcmp("angles", key)) + sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]); + else if (!strcmp("color", key)) + sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]); + else if (!strcmp("wait", key)) + fadescale = atof(value); + else if (!strcmp("classname", key)) + { + if (!strncmp(value, "light", 5)) + { + islight = true; + if (!strcmp(value, "light_fluoro")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 1; + overridecolor[2] = 1; + } + if (!strcmp(value, "light_fluorospark")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 1; + overridecolor[2] = 1; + } + if (!strcmp(value, "light_globe")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 0.8; + overridecolor[2] = 0.4; + } + if (!strcmp(value, "light_flame_large_yellow")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 0.5; + overridecolor[2] = 0.1; + } + if (!strcmp(value, "light_flame_small_yellow")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 0.5; + overridecolor[2] = 0.1; + } + if (!strcmp(value, "light_torch_small_white")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 0.5; + overridecolor[2] = 0.1; + } + if (!strcmp(value, "light_torch_small_walltorch")) + { + originhack[0] = 0; + originhack[1] = 0; + originhack[2] = 0; + overridecolor[0] = 1; + overridecolor[1] = 0.5; + overridecolor[2] = 0.1; + } + } + } + else if (!strcmp("style", key)) + style = atoi(value); + else if (!strcmp("skin", key)) + skin = (int)atof(value); + else if (!strcmp("pflags", key)) + pflags = (int)atof(value); + //else if (!strcmp("effects", key)) + // effects = (int)atof(value); + else if (cl.worldmodel->type == mod_brushq3) + { + if (!strcmp("scale", key)) + lightscale = atof(value); + if (!strcmp("fade", key)) + fadescale = atof(value); + } + } + if (!islight) + continue; + if (lightscale <= 0) + lightscale = 1; + if (fadescale <= 0) + fadescale = 1; + if (color[0] == color[1] && color[0] == color[2]) + { + color[0] *= overridecolor[0]; + color[1] *= overridecolor[1]; + color[2] *= overridecolor[2]; + } + radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale; + color[0] = color[0] * light[0]; + color[1] = color[1] * light[1]; + color[2] = color[2] * light[2]; + switch (type) + { + case LIGHTTYPE_MINUSX: + break; + case LIGHTTYPE_RECIPX: + radius *= 2; + VectorScale(color, (1.0f / 16.0f), color); + break; + case LIGHTTYPE_RECIPXX: + radius *= 2; + VectorScale(color, (1.0f / 16.0f), color); + break; + default: + case LIGHTTYPE_NONE: + break; + case LIGHTTYPE_SUN: + break; + case LIGHTTYPE_MINUSXX: + break; + } + VectorAdd(origin, originhack, origin); + if (radius >= 1) + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE); + } + if (entfiledata) + Mem_Free(entfiledata); +} + + +static void R_Shadow_SetCursorLocationForView(void) +{ + vec_t dist, push; + vec3_t dest, endpos; + trace_t trace; + VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest); + trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true); + if (trace.fraction < 1) + { + dist = trace.fraction * r_editlights_cursordistance.value; + push = r_editlights_cursorpushback.value; + if (push > dist) + push = dist; + push = -push; + VectorMA(trace.endpos, push, r_refdef.view.forward, endpos); + VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos); + } + else + { + VectorClear( endpos ); + } + r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; + r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; + r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value; +} + +void R_Shadow_UpdateWorldLightSelection(void) +{ + if (r_editlights.integer) + { + R_Shadow_SetCursorLocationForView(); + R_Shadow_SelectLightInView(); + } + else + R_Shadow_SelectLight(NULL); +} + +static void R_Shadow_EditLights_Clear_f(void) +{ + R_Shadow_ClearWorldLights(); +} + +void R_Shadow_EditLights_Reload_f(void) +{ + if (!cl.worldmodel) + return; + strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname)); + R_Shadow_ClearWorldLights(); + R_Shadow_LoadWorldLights(); + if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)) + { + R_Shadow_LoadLightsFile(); + if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)) + R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(); + } +} + +static void R_Shadow_EditLights_Save_f(void) +{ + if (!cl.worldmodel) + return; + R_Shadow_SaveWorldLights(); +} + +static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void) +{ + R_Shadow_ClearWorldLights(); + R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(); +} + +static void R_Shadow_EditLights_ImportLightsFile_f(void) +{ + R_Shadow_ClearWorldLights(); + R_Shadow_LoadLightsFile(); +} + +static void R_Shadow_EditLights_Spawn_f(void) +{ + vec3_t color; + if (!r_editlights.integer) + { + Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (Cmd_Argc() != 1) + { + Con_Print("r_editlights_spawn does not take parameters\n"); + return; + } + color[0] = color[1] = color[2] = 1; + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE); +} + +static void R_Shadow_EditLights_Edit_f(void) +{ + vec3_t origin, angles, color; + vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale; + int style, shadows, flags, normalmode, realtimemode; + char cubemapname[MAX_INPUTLINE]; + if (!r_editlights.integer) + { + Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + VectorCopy(r_shadow_selectedlight->origin, origin); + VectorCopy(r_shadow_selectedlight->angles, angles); + VectorCopy(r_shadow_selectedlight->color, color); + radius = r_shadow_selectedlight->radius; + style = r_shadow_selectedlight->style; + if (r_shadow_selectedlight->cubemapname) + strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname)); + else + cubemapname[0] = 0; + shadows = r_shadow_selectedlight->shadow; + corona = r_shadow_selectedlight->corona; + coronasizescale = r_shadow_selectedlight->coronasizescale; + ambientscale = r_shadow_selectedlight->ambientscale; + diffusescale = r_shadow_selectedlight->diffusescale; + specularscale = r_shadow_selectedlight->specularscale; + flags = r_shadow_selectedlight->flags; + normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0; + realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0; + if (!strcmp(Cmd_Argv(1), "origin")) + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1)); + return; + } + origin[0] = atof(Cmd_Argv(2)); + origin[1] = atof(Cmd_Argv(3)); + origin[2] = atof(Cmd_Argv(4)); + } + else if (!strcmp(Cmd_Argv(1), "originscale")) + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1)); + return; + } + origin[0] *= atof(Cmd_Argv(2)); + origin[1] *= atof(Cmd_Argv(3)); + origin[2] *= atof(Cmd_Argv(4)); + } + else if (!strcmp(Cmd_Argv(1), "originx")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[0] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "originy")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[1] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "originz")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[2] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "move")) + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1)); + return; + } + origin[0] += atof(Cmd_Argv(2)); + origin[1] += atof(Cmd_Argv(3)); + origin[2] += atof(Cmd_Argv(4)); + } + else if (!strcmp(Cmd_Argv(1), "movex")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[0] += atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "movey")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[1] += atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "movez")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + origin[2] += atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "angles")) + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1)); + return; + } + angles[0] = atof(Cmd_Argv(2)); + angles[1] = atof(Cmd_Argv(3)); + angles[2] = atof(Cmd_Argv(4)); + } + else if (!strcmp(Cmd_Argv(1), "anglesx")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + angles[0] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "anglesy")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + angles[1] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "anglesz")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + angles[2] = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "color")) + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1)); + return; + } + color[0] = atof(Cmd_Argv(2)); + color[1] = atof(Cmd_Argv(3)); + color[2] = atof(Cmd_Argv(4)); + } + else if (!strcmp(Cmd_Argv(1), "radius")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + radius = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "colorscale")) + { + if (Cmd_Argc() == 3) + { + double scale = atof(Cmd_Argv(2)); + color[0] *= scale; + color[1] *= scale; + color[2] *= scale; + } + else + { + if (Cmd_Argc() != 5) + { + Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1)); + return; + } + color[0] *= atof(Cmd_Argv(2)); + color[1] *= atof(Cmd_Argv(3)); + color[2] *= atof(Cmd_Argv(4)); + } + } + else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + radius *= atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "style")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + style = atoi(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "cubemap")) + { + if (Cmd_Argc() > 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + if (Cmd_Argc() == 3) + strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname)); + else + cubemapname[0] = 0; + } + else if (!strcmp(Cmd_Argv(1), "shadows")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "corona")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + corona = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "coronasize")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + coronasizescale = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "ambient")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + ambientscale = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "diffuse")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + diffusescale = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "specular")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + specularscale = atof(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "normalmode")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2)); + } + else if (!strcmp(Cmd_Argv(1), "realtimemode")) + { + if (Cmd_Argc() != 3) + { + Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1)); + return; + } + realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2)); + } + else + { + Con_Print("usage: r_editlights_edit [property] [value]\n"); + Con_Print("Selected light's properties:\n"); + Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]); + Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]); + Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]); + Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius); + Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona); + Con_Printf("Style : %i\n", r_shadow_selectedlight->style); + Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no"); + Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname); + Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale); + Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale); + Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale); + Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale); + Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no"); + Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no"); + return; + } + flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0); + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags); +} + +static void R_Shadow_EditLights_EditAll_f(void) +{ + size_t lightindex; + dlight_t *light, *oldselected; + size_t range; + + if (!r_editlights.integer) + { + Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n"); + return; + } + + oldselected = r_shadow_selectedlight; + // EditLights doesn't seem to have a "remove" command or something so: + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + R_Shadow_SelectLight(light); + R_Shadow_EditLights_Edit_f(); + } + // return to old selected (to not mess editing once selection is locked) + R_Shadow_SelectLight(oldselected); +} + +void R_Shadow_EditLights_DrawSelectedLightProperties(void) +{ + int lightnumber, lightcount; + size_t lightindex, range; + dlight_t *light; + char temp[256]; + float x, y; + + if (!r_editlights.integer) + return; + + // update cvars so QC can query them + if (r_shadow_selectedlight) + { + dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]); + Cvar_SetQuick(&r_editlights_current_origin, temp); + dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]); + Cvar_SetQuick(&r_editlights_current_angles, temp); + dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]); + Cvar_SetQuick(&r_editlights_current_color, temp); + Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius); + Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona); + Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale); + Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style); + Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow); + Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname); + Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale); + Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale); + Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale); + Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0); + Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0); + } + + // draw properties on screen + if (!r_editlights_drawproperties.integer) + return; + x = vid_conwidth.value - 240; + y = 5; + DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0); + lightnumber = -1; + lightcount = 0; + range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked + for (lightindex = 0;lightindex < range;lightindex++) + { + light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex); + if (!light) + continue; + if (light == r_shadow_selectedlight) + lightnumber = lightindex; + lightcount++; + } + dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8; + y += 8; + if (r_shadow_selectedlight == NULL) + return; + dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; + dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8; +} + +static void R_Shadow_EditLights_ToggleShadow_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags); +} + +static void R_Shadow_EditLights_ToggleCorona_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname, r_shadow_selectedlight->coronasizescale, r_shadow_selectedlight->ambientscale, r_shadow_selectedlight->diffusescale, r_shadow_selectedlight->specularscale, r_shadow_selectedlight->flags); +} + +static void R_Shadow_EditLights_Remove_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + R_Shadow_FreeWorldLight(r_shadow_selectedlight); + r_shadow_selectedlight = NULL; +} + +static void R_Shadow_EditLights_Help_f(void) +{ + Con_Print( +"Documentation on r_editlights system:\n" +"Settings:\n" +"r_editlights : enable/disable editing mode\n" +"r_editlights_cursordistance : maximum distance of cursor from eye\n" +"r_editlights_cursorpushback : push back cursor this far from surface\n" +"r_editlights_cursorpushoff : push cursor off surface this far\n" +"r_editlights_cursorgrid : snap cursor to grid of this size\n" +"r_editlights_quakelightsizescale : imported quake light entity size scaling\n" +"Commands:\n" +"r_editlights_help : this help\n" +"r_editlights_clear : remove all lights\n" +"r_editlights_reload : reload .rtlights, .lights file, or entities\n" +"r_editlights_lock : lock selection to current light, if already locked - unlock\n" +"r_editlights_save : save to .rtlights file\n" +"r_editlights_spawn : create a light with default settings\n" +"r_editlights_edit command : edit selected light - more documentation below\n" +"r_editlights_remove : remove selected light\n" +"r_editlights_toggleshadow : toggles on/off selected light's shadow property\n" +"r_editlights_importlightentitiesfrommap : reload light entities\n" +"r_editlights_importlightsfile : reload .light file (produced by hlight)\n" +"Edit commands:\n" +"origin x y z : set light location\n" +"originx x: set x component of light location\n" +"originy y: set y component of light location\n" +"originz z: set z component of light location\n" +"move x y z : adjust light location\n" +"movex x: adjust x component of light location\n" +"movey y: adjust y component of light location\n" +"movez z: adjust z component of light location\n" +"angles x y z : set light angles\n" +"anglesx x: set x component of light angles\n" +"anglesy y: set y component of light angles\n" +"anglesz z: set z component of light angles\n" +"color r g b : set color of light (can be brighter than 1 1 1)\n" +"radius radius : set radius (size) of light\n" +"colorscale grey : multiply color of light (1 does nothing)\n" +"colorscale r g b : multiply color of light (1 1 1 does nothing)\n" +"radiusscale scale : multiply radius (size) of light (1 does nothing)\n" +"sizescale scale : multiply radius (size) of light (1 does nothing)\n" +"originscale x y z : multiply origin of light (1 1 1 does nothing)\n" +"style style : set lightstyle of light (flickering patterns, switches, etc)\n" +"cubemap basename : set filter cubemap of light\n" +"shadows 1/0 : turn on/off shadows\n" +"corona n : set corona intensity\n" +"coronasize n : set corona size (0-1)\n" +"ambient n : set ambient intensity (0-1)\n" +"diffuse n : set diffuse intensity (0-1)\n" +"specular n : set specular intensity (0-1)\n" +"normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n" +"realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n" +" : print light properties to console\n" + ); +} + +static void R_Shadow_EditLights_CopyInfo_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles); + VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color); + r_shadow_bufferlight.radius = r_shadow_selectedlight->radius; + r_shadow_bufferlight.style = r_shadow_selectedlight->style; + if (r_shadow_selectedlight->cubemapname) + strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname)); + else + r_shadow_bufferlight.cubemapname[0] = 0; + r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow; + r_shadow_bufferlight.corona = r_shadow_selectedlight->corona; + r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale; + r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale; + r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale; + r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale; + r_shadow_bufferlight.flags = r_shadow_selectedlight->flags; +} + +static void R_Shadow_EditLights_PasteInfo_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname, r_shadow_bufferlight.coronasizescale, r_shadow_bufferlight.ambientscale, r_shadow_bufferlight.diffusescale, r_shadow_bufferlight.specularscale, r_shadow_bufferlight.flags); +} + +static void R_Shadow_EditLights_Lock_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (r_editlights_lockcursor) + { + r_editlights_lockcursor = false; + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light to lock on.\n"); + return; + } + r_editlights_lockcursor = true; +} + +static void R_Shadow_EditLights_Init(void) +{ + Cvar_RegisterVariable(&r_editlights); + Cvar_RegisterVariable(&r_editlights_cursordistance); + Cvar_RegisterVariable(&r_editlights_cursorpushback); + Cvar_RegisterVariable(&r_editlights_cursorpushoff); + Cvar_RegisterVariable(&r_editlights_cursorgrid); + Cvar_RegisterVariable(&r_editlights_quakelightsizescale); + Cvar_RegisterVariable(&r_editlights_drawproperties); + Cvar_RegisterVariable(&r_editlights_current_origin); + Cvar_RegisterVariable(&r_editlights_current_angles); + Cvar_RegisterVariable(&r_editlights_current_color); + Cvar_RegisterVariable(&r_editlights_current_radius); + Cvar_RegisterVariable(&r_editlights_current_corona); + Cvar_RegisterVariable(&r_editlights_current_coronasize); + Cvar_RegisterVariable(&r_editlights_current_style); + Cvar_RegisterVariable(&r_editlights_current_shadows); + Cvar_RegisterVariable(&r_editlights_current_cubemap); + Cvar_RegisterVariable(&r_editlights_current_ambient); + Cvar_RegisterVariable(&r_editlights_current_diffuse); + Cvar_RegisterVariable(&r_editlights_current_specular); + Cvar_RegisterVariable(&r_editlights_current_normalmode); + Cvar_RegisterVariable(&r_editlights_current_realtimemode); + Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system"); + Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)"); + Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)"); + Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level"); + Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)"); + Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light"); + Cmd_AddCommand("r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)"); + Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light"); + Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light"); + Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light"); + Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)"); + Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)"); + Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light"); + Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)"); + Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock"); +} + + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +void R_LightPoint(float *color, const vec3_t p, const int flags) +{ + int i, numlights, flag; + float f, relativepoint[3], dist, dist2, lightradius2; + vec3_t diffuse, n; + rtlight_t *light; + dlight_t *dlight; + + if (r_fullbright.integer) + { + VectorSet(color, 1, 1, 1); + return; + } + + VectorClear(color); + + if (flags & LP_LIGHTMAP) + { + if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint) + { + VectorClear(diffuse); + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n); + VectorAdd(color, diffuse, color); + } + else + VectorSet(color, 1, 1, 1); + color[0] += r_refdef.scene.ambient; + color[1] += r_refdef.scene.ambient; + color[2] += r_refdef.scene.ambient; + } + + if (flags & LP_RTWORLD) + { + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); + for (i = 0; i < numlights; i++) + { + dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i); + if (!dlight) + continue; + light = &dlight->rtlight; + if (!(light->flags & flag)) + continue; + // sample + lightradius2 = light->radius * light->radius; + VectorSubtract(light->shadoworigin, p, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + dist = sqrt(dist2) / light->radius; + f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0; + if (f <= 0) + continue; + // todo: add to both ambient and diffuse + if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1) + VectorMA(color, f, light->currentcolor, color); + } + } + if (flags & LP_DYNLIGHT) + { + // sample dlights + for (i = 0;i < r_refdef.scene.numlights;i++) + { + light = r_refdef.scene.lights[i]; + // sample + lightradius2 = light->radius * light->radius; + VectorSubtract(light->shadoworigin, p, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + dist = sqrt(dist2) / light->radius; + f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0; + if (f <= 0) + continue; + // todo: add to both ambient and diffuse + if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1) + VectorMA(color, f, light->color, color); + } + } +} + +void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags) +{ + int i, numlights, flag; + rtlight_t *light; + dlight_t *dlight; + float relativepoint[3]; + float color[3]; + float dir[3]; + float dist; + float dist2; + float intensity; + float sample[5*3]; + float lightradius2; + + if (r_fullbright.integer) + { + VectorSet(ambient, 1, 1, 1); + VectorClear(diffuse); + VectorClear(lightdir); + return; + } + + if (flags == LP_LIGHTMAP) + { + VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient); + VectorClear(diffuse); + VectorClear(lightdir); + if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint) + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir); + else + VectorSet(ambient, 1, 1, 1); + return; + } + + memset(sample, 0, sizeof(sample)); + VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient); + + if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint) + { + vec3_t tempambient; + VectorClear(tempambient); + VectorClear(color); + VectorClear(relativepoint); + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint); + VectorScale(tempambient, r_refdef.lightmapintensity, tempambient); + VectorScale(color, r_refdef.lightmapintensity, color); + VectorAdd(sample, tempambient, sample); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity = VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } + + if (flags & LP_RTWORLD) + { + flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE; + numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); + for (i = 0; i < numlights; i++) + { + dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i); + if (!dlight) + continue; + light = &dlight->rtlight; + if (!(light->flags & flag)) + continue; + // sample + lightradius2 = light->radius * light->radius; + VectorSubtract(light->shadoworigin, p, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + dist = sqrt(dist2) / light->radius; + intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value; + if (intensity <= 0.0f) + continue; + if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1) + continue; + // scale down intensity to add to both ambient and diffuse + //intensity *= 0.5f; + VectorNormalize(relativepoint); + VectorScale(light->currentcolor, intensity, color); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity *= VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } + // FIXME: sample bouncegrid too! + } + + if (flags & LP_DYNLIGHT) + { + // sample dlights + for (i = 0;i < r_refdef.scene.numlights;i++) + { + light = r_refdef.scene.lights[i]; + // sample + lightradius2 = light->radius * light->radius; + VectorSubtract(light->shadoworigin, p, relativepoint); + dist2 = VectorLength2(relativepoint); + if (dist2 >= lightradius2) + continue; + dist = sqrt(dist2) / light->radius; + intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value; + if (intensity <= 0.0f) + continue; + if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1) + continue; + // scale down intensity to add to both ambient and diffuse + //intensity *= 0.5f; + VectorNormalize(relativepoint); + VectorScale(light->currentcolor, intensity, color); + VectorMA(sample , 0.5f , color, sample ); + VectorMA(sample + 3, relativepoint[0], color, sample + 3); + VectorMA(sample + 6, relativepoint[1], color, sample + 6); + VectorMA(sample + 9, relativepoint[2], color, sample + 9); + // calculate a weighted average light direction as well + intensity *= VectorLength(color); + VectorMA(sample + 12, intensity, relativepoint, sample + 12); + } + } + + // calculate the direction we'll use to reduce the sample to a directional light source + VectorCopy(sample + 12, dir); + //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]); + VectorNormalize(dir); + // extract the diffuse color along the chosen direction and scale it + diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]); + diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]); + diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]); + // subtract some of diffuse from ambient + VectorMA(sample, -0.333f, diffuse, ambient); + // store the normalized lightdir + VectorCopy(dir, lightdir); +} diff --git a/app/jni/r_shadow.h b/app/jni/r_shadow.h new file mode 100644 index 0000000..907173d --- /dev/null +++ b/app/jni/r_shadow.h @@ -0,0 +1,110 @@ + +#ifndef R_SHADOW_H +#define R_SHADOW_H + +#define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8 + +extern cvar_t r_shadow_bumpscale_basetexture; +extern cvar_t r_shadow_bumpscale_bumpmap; +extern cvar_t r_shadow_debuglight; +extern cvar_t r_shadow_gloss; +extern cvar_t r_shadow_gloss2intensity; +extern cvar_t r_shadow_glossintensity; +extern cvar_t r_shadow_glossexponent; +extern cvar_t r_shadow_gloss2exponent; +extern cvar_t r_shadow_glossexact; +extern cvar_t r_shadow_lightattenuationpower; +extern cvar_t r_shadow_lightattenuationscale; +extern cvar_t r_shadow_lightintensityscale; +extern cvar_t r_shadow_lightradiusscale; +extern cvar_t r_shadow_projectdistance; +extern cvar_t r_shadow_frontsidecasting; +extern cvar_t r_shadow_realtime_dlight; +extern cvar_t r_shadow_realtime_dlight_shadows; +extern cvar_t r_shadow_realtime_dlight_svbspculling; +extern cvar_t r_shadow_realtime_dlight_portalculling; +extern cvar_t r_shadow_realtime_world; +extern cvar_t r_shadow_realtime_world_lightmaps; +extern cvar_t r_shadow_realtime_world_shadows; +extern cvar_t r_shadow_realtime_world_compile; +extern cvar_t r_shadow_realtime_world_compileshadow; +extern cvar_t r_shadow_realtime_world_compilesvbsp; +extern cvar_t r_shadow_realtime_world_compileportalculling; +extern cvar_t r_shadow_scissor; +extern cvar_t r_shadow_polygonfactor; +extern cvar_t r_shadow_polygonoffset; +extern cvar_t r_shadow_texture3d; +extern cvar_t gl_ext_separatestencil; +extern cvar_t gl_ext_stenciltwoside; + +// used by shader for bouncegrid feature +extern rtexture_t *r_shadow_bouncegridtexture; +extern matrix4x4_t r_shadow_bouncegridmatrix; +extern vec_t r_shadow_bouncegridintensity; +extern qboolean r_shadow_bouncegriddirectional; + +void R_Shadow_Init(void); +qboolean R_Shadow_ShadowMappingEnabled(void); +void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs); +void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris); +void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs); +int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias); +int R_Shadow_CalcSphereSideMask(const vec3_t p1, float radius, float bias); +int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals); +void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist); +void R_Shadow_RenderMode_Begin(void); +void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight); +void R_Shadow_RenderMode_Reset(void); +void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass); +void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping); +void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping); +void R_Shadow_RenderMode_VisibleShadowVolumes(void); +void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent); +void R_Shadow_RenderMode_End(void); +void R_Shadow_ClearStencil(void); +void R_Shadow_SetupEntityLight(const entity_render_t *ent); + +qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs); + +// these never change, they are used to create attenuation matrices +extern matrix4x4_t matrix_attenuationxyz; +extern matrix4x4_t matrix_attenuationz; + +void R_Shadow_UpdateWorldLightSelection(void); + +extern rtlight_t *r_shadow_compilingrtlight; + +void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags); +void R_RTLight_Compile(rtlight_t *rtlight); +void R_RTLight_Uncompile(rtlight_t *rtlight); + +void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_Shadow_DrawPrepass(void); +void R_Shadow_DrawLights(void); +void R_Shadow_DrawCoronas(void); + +extern int maxshadowmark; +extern int numshadowmark; +extern int *shadowmark; +extern int *shadowmarklist; +extern int shadowmarkcount; +void R_Shadow_PrepareShadowMark(int numtris); + +extern int maxshadowsides; +extern int numshadowsides; +extern unsigned char *shadowsides; +extern int *shadowsideslist; +void R_Shadow_PrepareShadowSides(int numtris); + +void R_Shadow_PrepareModelShadows(void); + +#define LP_LIGHTMAP 1 +#define LP_RTWORLD 2 +#define LP_DYNLIGHT 4 +void R_LightPoint(float *color, const vec3_t p, const int flags); +void R_CompleteLightPoint(float *ambientcolor, float *diffusecolor, float *diffusenormal, const vec3_t p, const int flags); + +void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); + +#endif diff --git a/app/jni/r_sky.c b/app/jni/r_sky.c new file mode 100644 index 0000000..97b2daf --- /dev/null +++ b/app/jni/r_sky.c @@ -0,0 +1,461 @@ + +#include "quakedef.h" +#include "image.h" + +// FIXME: fix skybox after vid_restart +cvar_t r_sky = {CVAR_SAVE, "r_sky", "1", "enables sky rendering (black otherwise)"}; +cvar_t r_skyscroll1 = {CVAR_SAVE, "r_skyscroll1", "1", "speed at which upper clouds layer scrolls in quake sky"}; +cvar_t r_skyscroll2 = {CVAR_SAVE, "r_skyscroll2", "2", "speed at which lower clouds layer scrolls in quake sky"}; +int skyrenderlater; +int skyrendermasked; + +static int skyrendersphere; +static int skyrenderbox; +static rtexturepool_t *skytexturepool; +static char skyname[MAX_QPATH]; +static matrix4x4_t skymatrix; +static matrix4x4_t skyinversematrix; + +typedef struct suffixinfo_s +{ + const char *suffix; + qboolean flipx, flipy, flipdiagonal; +} +suffixinfo_t; +static const suffixinfo_t suffix[3][6] = +{ + { + {"px", false, false, false}, + {"nx", false, false, false}, + {"py", false, false, false}, + {"ny", false, false, false}, + {"pz", false, false, false}, + {"nz", false, false, false} + }, + { + {"posx", false, false, false}, + {"negx", false, false, false}, + {"posy", false, false, false}, + {"negy", false, false, false}, + {"posz", false, false, false}, + {"negz", false, false, false} + }, + { + {"rt", false, false, true}, + {"lf", true, true, true}, + {"bk", false, true, false}, + {"ft", true, false, false}, + {"up", false, false, true}, + {"dn", false, false, true} + } +}; + +static skinframe_t *skyboxskinframe[6]; + +void R_SkyStartFrame(void) +{ + skyrendersphere = false; + skyrenderbox = false; + skyrendermasked = false; + // for depth-masked sky, we need to know whether any sky was rendered + skyrenderlater = false; + if (r_sky.integer) + { + if (skyboxskinframe[0] || skyboxskinframe[1] || skyboxskinframe[2] || skyboxskinframe[3] || skyboxskinframe[4] || skyboxskinframe[5]) + skyrenderbox = true; + else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.solidskyskinframe) + skyrendersphere = true; + skyrendermasked = true; + } +} + +/* +================== +R_SetSkyBox +================== +*/ +static void R_UnloadSkyBox(void) +{ + int i; + int c = 0; + for (i = 0;i < 6;i++) + { + if (skyboxskinframe[i]) + { + // TODO: make a R_SkinFrame_Purge for single skins... + c++; + } + skyboxskinframe[i] = NULL; + } + if (c && developer_loading.integer) + Con_Printf("unloading skybox\n"); +} + +static int R_LoadSkyBox(void) +{ + int i, j, success; + int indices[4] = {0,1,2,3}; + char name[MAX_INPUTLINE]; + unsigned char *image_buffer; + unsigned char *temp; + char vabuf[1024]; + + R_UnloadSkyBox(); + + if (!skyname[0]) + return true; + + for (j=0; j<3; j++) + { + success = 0; + for (i=0; i<6; i++) + { + if (dpsnprintf(name, sizeof(name), "%s_%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) + { + if (dpsnprintf(name, sizeof(name), "%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) + { + if (dpsnprintf(name, sizeof(name), "env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) + { + if (dpsnprintf(name, sizeof(name), "gfx/env/%s%s", skyname, suffix[j][i].suffix) < 0 || !(image_buffer = loadimagepixelsbgra(name, false, false, false, NULL))) + continue; + } + } + } + temp = (unsigned char *)Mem_Alloc(tempmempool, image_width*image_height*4); + Image_CopyMux (temp, image_buffer, image_width, image_height, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, indices); + skyboxskinframe[i] = R_SkinFrame_LoadInternalBGRA(va(vabuf, sizeof(vabuf), "skyboxside%d", i), TEXF_CLAMP | (gl_texturecompression_sky.integer ? TEXF_COMPRESS : 0), temp, image_width, image_height, vid.sRGB3D); + Mem_Free(image_buffer); + Mem_Free(temp); + success++; + } + + if (success) + break; + } + + if (j == 3) + return false; + + if (developer_loading.integer) + Con_Printf("loading skybox \"%s\"\n", name); + + return true; +} + +int R_SetSkyBox(const char *sky) +{ + if (strcmp(sky, skyname) == 0) // no change + return true; + + if (strlen(sky) > 1000) + { + Con_Printf("sky name too long (%i, max is 1000)\n", (int)strlen(sky)); + return false; + } + + strlcpy(skyname, sky, sizeof(skyname)); + + return R_LoadSkyBox(); +} + +// LordHavoc: added LoadSky console command +static void LoadSky_f (void) +{ + switch (Cmd_Argc()) + { + case 1: + if (skyname[0]) + Con_Printf("current sky: %s\n", skyname); + else + Con_Print("no skybox has been set\n"); + break; + case 2: + if (R_SetSkyBox(Cmd_Argv(1))) + { + if (skyname[0]) + Con_Printf("skybox set to %s\n", skyname); + else + Con_Print("skybox disabled\n"); + } + else + Con_Printf("failed to load skybox %s\n", Cmd_Argv(1)); + break; + default: + Con_Print("usage: loadsky skyname\n"); + break; + } +} + +static const float skyboxvertex3f[6*4*3] = +{ + // skyside[0] + 16, -16, 16, + 16, -16, -16, + 16, 16, -16, + 16, 16, 16, + // skyside[1] + -16, 16, 16, + -16, 16, -16, + -16, -16, -16, + -16, -16, 16, + // skyside[2] + 16, 16, 16, + 16, 16, -16, + -16, 16, -16, + -16, 16, 16, + // skyside[3] + -16, -16, 16, + -16, -16, -16, + 16, -16, -16, + 16, -16, 16, + // skyside[4] + -16, -16, 16, + 16, -16, 16, + 16, 16, 16, + -16, 16, 16, + // skyside[5] + 16, -16, -16, + -16, -16, -16, + -16, 16, -16, + 16, 16, -16 +}; + +static const float skyboxtexcoord2f[6*4*2] = +{ + // skyside[0] + 0, 1, + 1, 1, + 1, 0, + 0, 0, + // skyside[1] + 1, 0, + 0, 0, + 0, 1, + 1, 1, + // skyside[2] + 1, 1, + 1, 0, + 0, 0, + 0, 1, + // skyside[3] + 0, 0, + 0, 1, + 1, 1, + 1, 0, + // skyside[4] + 0, 1, + 1, 1, + 1, 0, + 0, 0, + // skyside[5] + 0, 1, + 1, 1, + 1, 0, + 0, 0 +}; + +static const int skyboxelement3i[6*2*3] = +{ + // skyside[3] + 0, 1, 2, + 0, 2, 3, + // skyside[1] + 4, 5, 6, + 4, 6, 7, + // skyside[0] + 8, 9, 10, + 8, 10, 11, + // skyside[2] + 12, 13, 14, + 12, 14, 15, + // skyside[4] + 16, 17, 18, + 16, 18, 19, + // skyside[5] + 20, 21, 22, + 20, 22, 23 +}; + +static const unsigned short skyboxelement3s[6*2*3] = +{ + // skyside[3] + 0, 1, 2, + 0, 2, 3, + // skyside[1] + 4, 5, 6, + 4, 6, 7, + // skyside[0] + 8, 9, 10, + 8, 10, 11, + // skyside[2] + 12, 13, 14, + 12, 14, 15, + // skyside[4] + 16, 17, 18, + 16, 18, 19, + // skyside[5] + 20, 21, 22, + 20, 22, 23 +}; + +static void R_SkyBox(void) +{ + int i; + RSurf_ActiveCustomEntity(&skymatrix, &skyinversematrix, 0, 0, 1, 1, 1, 1, 6*4, skyboxvertex3f, skyboxtexcoord2f, NULL, NULL, NULL, NULL, 6*2, skyboxelement3i, skyboxelement3s, false, false); + for (i = 0;i < 6;i++) + if(skyboxskinframe[i]) + R_DrawCustomSurface(skyboxskinframe[i], &identitymatrix, MATERIALFLAG_SKY | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST, i*4, 4, i*2, 2, false, false); +} + +#define skygridx 32 +#define skygridx1 (skygridx + 1) +#define skygridxrecip (1.0f / (skygridx)) +#define skygridy 32 +#define skygridy1 (skygridy + 1) +#define skygridyrecip (1.0f / (skygridy)) +#define skysphere_numverts (skygridx1 * skygridy1) +#define skysphere_numtriangles (skygridx * skygridy * 2) +static float skysphere_vertex3f[skysphere_numverts * 3]; +static float skysphere_texcoord2f[skysphere_numverts * 2]; +static int skysphere_element3i[skysphere_numtriangles * 3]; +static unsigned short skysphere_element3s[skysphere_numtriangles * 3]; + +static void skyspherecalc(void) +{ + int i, j; + unsigned short *e; + float a, b, x, ax, ay, v[3], length, *vertex3f, *texcoord2f; + float dx, dy, dz; + dx = 16.0f; + dy = 16.0f; + dz = 16.0f / 3.0f; + vertex3f = skysphere_vertex3f; + texcoord2f = skysphere_texcoord2f; + for (j = 0;j <= skygridy;j++) + { + a = j * skygridyrecip; + ax = cos(a * M_PI * 2); + ay = -sin(a * M_PI * 2); + for (i = 0;i <= skygridx;i++) + { + b = i * skygridxrecip; + x = cos((b + 0.5) * M_PI); + v[0] = ax*x * dx; + v[1] = ay*x * dy; + v[2] = -sin((b + 0.5) * M_PI) * dz; + length = 3.0f / sqrt(v[0]*v[0]+v[1]*v[1]+(v[2]*v[2]*9)); + *texcoord2f++ = v[0] * length; + *texcoord2f++ = v[1] * length; + *vertex3f++ = v[0]; + *vertex3f++ = v[1]; + *vertex3f++ = v[2]; + } + } + e = skysphere_element3s; + for (j = 0;j < skygridy;j++) + { + for (i = 0;i < skygridx;i++) + { + *e++ = j * skygridx1 + i; + *e++ = j * skygridx1 + i + 1; + *e++ = (j + 1) * skygridx1 + i; + + *e++ = j * skygridx1 + i + 1; + *e++ = (j + 1) * skygridx1 + i + 1; + *e++ = (j + 1) * skygridx1 + i; + } + } + for (i = 0;i < skysphere_numtriangles*3;i++) + skysphere_element3i[i] = skysphere_element3s[i]; +} + +static void R_SkySphere(void) +{ + double speedscale; + static qboolean skysphereinitialized = false; + matrix4x4_t scroll1matrix, scroll2matrix; + if (!skysphereinitialized) + { + skysphereinitialized = true; + skyspherecalc(); + } + + // wrap the scroll values just to be extra kind to float accuracy + + // scroll speed for upper layer + speedscale = r_refdef.scene.time*r_skyscroll1.value*8.0/128.0; + speedscale -= floor(speedscale); + Matrix4x4_CreateTranslate(&scroll1matrix, speedscale, speedscale, 0); + // scroll speed for lower layer (transparent layer) + speedscale = r_refdef.scene.time*r_skyscroll2.value*8.0/128.0; + speedscale -= floor(speedscale); + Matrix4x4_CreateTranslate(&scroll2matrix, speedscale, speedscale, 0); + + RSurf_ActiveCustomEntity(&skymatrix, &skyinversematrix, 0, 0, 1, 1, 1, 1, skysphere_numverts, skysphere_vertex3f, skysphere_texcoord2f, NULL, NULL, NULL, NULL, skysphere_numtriangles, skysphere_element3i, skysphere_element3s, false, false); + R_DrawCustomSurface(r_refdef.scene.worldmodel->brush.solidskyskinframe, &scroll1matrix, MATERIALFLAG_SKY | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST , 0, skysphere_numverts, 0, skysphere_numtriangles, false, false); + R_DrawCustomSurface(r_refdef.scene.worldmodel->brush.alphaskyskinframe, &scroll2matrix, MATERIALFLAG_SKY | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED, 0, skysphere_numverts, 0, skysphere_numtriangles, false, false); +} + +void R_Sky(void) +{ + Matrix4x4_CreateFromQuakeEntity(&skymatrix, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], 0, 0, 0, r_refdef.farclip * (0.5f / 16.0f)); + Matrix4x4_Invert_Simple(&skyinversematrix, &skymatrix); + + if (skyrendersphere) + { + // this does not modify depth buffer + R_SkySphere(); + } + else if (skyrenderbox) + { + // this does not modify depth buffer + R_SkyBox(); + } + /* this will be skyroom someday + else + { + // this modifies the depth buffer so we have to clear it afterward + //R_SkyRoom(); + // clear the depthbuffer that was used while rendering the skyroom + //GL_Clear(GL_DEPTH_BUFFER_BIT); + } + */ +} + +//=============================================================== + +void R_ResetSkyBox(void) +{ + R_UnloadSkyBox(); + skyname[0] = 0; + R_LoadSkyBox(); +} + +static void r_sky_start(void) +{ + skytexturepool = R_AllocTexturePool(); + R_LoadSkyBox(); +} + +static void r_sky_shutdown(void) +{ + R_UnloadSkyBox(); + R_FreeTexturePool(&skytexturepool); +} + +static void r_sky_newmap(void) +{ +} + + +void R_Sky_Init(void) +{ + Cmd_AddCommand ("loadsky", &LoadSky_f, "load a skybox by basename (for example loadsky mtnsun_ loads mtnsun_ft.tga and so on)"); + Cvar_RegisterVariable (&r_sky); + Cvar_RegisterVariable (&r_skyscroll1); + Cvar_RegisterVariable (&r_skyscroll2); + memset(&skyboxskinframe, 0, sizeof(skyboxskinframe)); + skyname[0] = 0; + R_RegisterModule("R_Sky", r_sky_start, r_sky_shutdown, r_sky_newmap, NULL, NULL); +} + diff --git a/app/jni/r_sprites.c b/app/jni/r_sprites.c new file mode 100644 index 0000000..a45a3e7 --- /dev/null +++ b/app/jni/r_sprites.c @@ -0,0 +1,429 @@ + +#include "quakedef.h" +#include "r_shadow.h" + +extern cvar_t r_labelsprites_scale; +extern cvar_t r_labelsprites_roundtopixels; +extern cvar_t r_track_sprites; +extern cvar_t r_track_sprites_flags; +extern cvar_t r_track_sprites_scalew; +extern cvar_t r_track_sprites_scaleh; +extern cvar_t r_overheadsprites_perspective; +extern cvar_t r_overheadsprites_pushback; +extern cvar_t r_overheadsprites_scalex; +extern cvar_t r_overheadsprites_scaley; + +#define TSF_ROTATE 1 +#define TSF_ROTATE_CONTINOUSLY 2 + +// use same epsilon as in sv_phys.c, it's not in any header, that's why i redefine it +// MIN_EPSILON is for accurateness' sake :) +#ifndef EPSILON +# define EPSILON (1.0f / 32.0f) +# define MIN_EPSILON 0.0001f +#endif + +/* R_Track_Sprite + If the sprite is out of view, track it. + `origin`, `left` and `up` are changed by this function to achive a rotation around + the hotspot. + + --blub + */ +#define SIDE_TOP 1 +#define SIDE_LEFT 2 +#define SIDE_BOTTOM 3 +#define SIDE_RIGHT 4 + +static void R_TrackSprite(const entity_render_t *ent, vec3_t origin, vec3_t left, vec3_t up, int *edge, float *dir_angle) +{ + float distance; + vec3_t bCoord; // body coordinates of object + unsigned int i; + + // temporarily abuse bCoord as the vector player->sprite-origin + VectorSubtract(origin, r_refdef.view.origin, bCoord); + distance = VectorLength(bCoord); + + // Now get the bCoords :) + Matrix4x4_Transform(&r_refdef.view.inverse_matrix, origin, bCoord); + + *edge = 0; // FIXME::should assume edge == 0, which is correct currently + for(i = 0; i < 4; ++i) + { + if(PlaneDiff(origin, &r_refdef.view.frustum[i]) < -EPSILON) + break; + } + + // If it wasn't outside a plane, no tracking needed + if(i < 4) + { + float x, y; // screen X and Y coordinates + float ax, ay; // absolute coords, used for division + // I divide x and y by the greater absolute value to get ranges -1.0 to +1.0 + + bCoord[2] *= r_refdef.view.frustum_x; + bCoord[1] *= r_refdef.view.frustum_y; + + //Con_Printf("%f %f %f\n", bCoord[0], bCoord[1], bCoord[2]); + + ax = fabs(bCoord[1]); + ay = fabs(bCoord[2]); + // get the greater value and determine the screen edge it's on + if(ax < ay) + { + ax = ay; + // 180 or 0 degrees + if(bCoord[2] < 0.0f) + *edge = SIDE_BOTTOM; + else + *edge = SIDE_TOP; + } else { + if(bCoord[1] < 0.0f) + *edge = SIDE_RIGHT; + else + *edge = SIDE_LEFT; + } + + // umm... + if(ax < MIN_EPSILON) // this was == 0.0f before --blub + ax = MIN_EPSILON; + // get the -1 to +1 range + x = bCoord[1] / ax; + y = bCoord[2] / ax; + + ax = (1.0f / VectorLength(left)); + ay = (1.0f / VectorLength(up)); + // Using the placement below the distance of a sprite is + // real dist = sqrt(d*d + dfxa*dfxa + dgyb*dgyb) + // d is the distance we use + // f is frustum X + // x is x + // a is ax + // g is frustum Y + // y is y + // b is ay + + // real dist (r) shall be d, so + // r*r = d*d + dfxa*dfxa + dgyb*dgyb + // r*r = d*d * (1 + fxa*fxa + gyb*gyb) + // d*d = r*r / (1 + fxa*fxa + gyb*gyb) + // d = sqrt(r*r / (1 + fxa*fxa + gyb*gyb)) + // thus: + distance = sqrt((distance*distance) / (1.0 + + r_refdef.view.frustum_x*r_refdef.view.frustum_x * x*x * ax*ax + + r_refdef.view.frustum_y*r_refdef.view.frustum_y * y*y * ay*ay)); + // ^ the one we want ^ the one we have ^ our factors + + // Place the sprite a few units ahead of the player + VectorCopy(r_refdef.view.origin, origin); + VectorMA(origin, distance, r_refdef.view.forward, origin); + // Move the sprite left / up the screeen height + VectorMA(origin, distance * r_refdef.view.frustum_x * x * ax, left, origin); + VectorMA(origin, distance * r_refdef.view.frustum_y * y * ay, up, origin); + + if(r_track_sprites_flags.integer & TSF_ROTATE_CONTINOUSLY) + { + // compute the rotation, negate y axis, we're pointing outwards + *dir_angle = atan(-y / x) * 180.0f/M_PI; + // we need the real, full angle + if(x < 0.0f) + *dir_angle += 180.0f; + } + + left[0] *= r_track_sprites_scalew.value; + left[1] *= r_track_sprites_scalew.value; + left[2] *= r_track_sprites_scalew.value; + + up[0] *= r_track_sprites_scaleh.value; + up[1] *= r_track_sprites_scaleh.value; + up[2] *= r_track_sprites_scaleh.value; + } +} + +static void R_RotateSprite(const mspriteframe_t *frame, vec3_t origin, vec3_t left, vec3_t up, int edge, float dir_angle) +{ + if(!(r_track_sprites_flags.integer & TSF_ROTATE)) + { + // move down by its size if on top, otherwise it's invisible + if(edge == SIDE_TOP) + VectorMA(origin, -(fabs(frame->up)+fabs(frame->down)), up, origin); + } else { + static float rotation_angles[5] = + { + 0, // no edge + -90.0f, //top + 0.0f, // left + 90.0f, // bottom + 180.0f, // right + }; + + // rotate around the hotspot according to which edge it's on + // since the hotspot == the origin, only rotate the vectors + matrix4x4_t rotm; + vec3_t axis; + vec3_t temp; + vec2_t dir; + float angle; + + if(edge < 1 || edge > 4) + return; // this usually means something went wrong somewhere, there's no way to get a wrong edge value currently + + dir[0] = frame->right + frame->left; + dir[1] = frame->down + frame->up; + + // only rotate when the hotspot isn't the center though. + if(dir[0] < MIN_EPSILON && dir[1] < MIN_EPSILON) + { + return; + } + + // Now that we've kicked center-hotspotted sprites, rotate using the appropriate matrix :) + + // determine the angle of a sprite, we could only do that once though and + // add a `qboolean initialized' to the mspriteframe_t struct... let's get the direction vector of it :) + + angle = atan(dir[1] / dir[0]) * 180.0f/M_PI; + + // we need the real, full angle + if(dir[0] < 0.0f) + angle += 180.0f; + + // Rotate around rotation_angle - frame_angle + // The axis SHOULD equal r_refdef.view.forward, but let's generalize this: + CrossProduct(up, left, axis); + if(r_track_sprites_flags.integer & TSF_ROTATE_CONTINOUSLY) + Matrix4x4_CreateRotate(&rotm, dir_angle - angle, axis[0], axis[1], axis[2]); + else + Matrix4x4_CreateRotate(&rotm, rotation_angles[edge] - angle, axis[0], axis[1], axis[2]); + Matrix4x4_Transform(&rotm, up, temp); + VectorCopy(temp, up); + Matrix4x4_Transform(&rotm, left, temp); + VectorCopy(temp, left); + } +} + +static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1}; + +static void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) +{ + int i; + dp_model_t *model = ent->model; + vec3_t left, up, org, mforward, mleft, mup, middle; + float scale, dx, dy, hud_vs_screen; + int edge = 0; + float dir_angle = 0.0f; + float vertex3f[12]; + + // nudge it toward the view to make sure it isn't in a wall + Matrix4x4_ToVectors(&ent->matrix, mforward, mleft, mup, org); + VectorSubtract(org, r_refdef.view.forward, org); + switch(model->sprite.sprnum_type) + { + case SPR_VP_PARALLEL_UPRIGHT: + // flames and such + // vertical beam sprite, faces view plane + scale = ent->scale / sqrt(r_refdef.view.forward[0]*r_refdef.view.forward[0]+r_refdef.view.forward[1]*r_refdef.view.forward[1]); + left[0] = -r_refdef.view.forward[1] * scale; + left[1] = r_refdef.view.forward[0] * scale; + left[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = ent->scale; + break; + case SPR_FACING_UPRIGHT: + // flames and such + // vertical beam sprite, faces viewer's origin (not the view plane) + scale = ent->scale / sqrt((org[0] - r_refdef.view.origin[0])*(org[0] - r_refdef.view.origin[0])+(org[1] - r_refdef.view.origin[1])*(org[1] - r_refdef.view.origin[1])); + left[0] = (org[1] - r_refdef.view.origin[1]) * scale; + left[1] = -(org[0] - r_refdef.view.origin[0]) * scale; + left[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = ent->scale; + break; + default: + Con_Printf("R_SpriteSetup: unknown sprite type %i\n", model->sprite.sprnum_type); + // fall through to normal sprite + case SPR_VP_PARALLEL: + // normal sprite + // faces view plane + VectorScale(r_refdef.view.left, ent->scale, left); + VectorScale(r_refdef.view.up, ent->scale, up); + break; + case SPR_LABEL_SCALE: + // normal sprite + // faces view plane + // fixed HUD pixel size specified in sprite + // honors scale + // honors a global label scaling cvar + + if(r_fb.water.renderingscene) // labels are considered HUD items, and don't appear in reflections + return; + + // See the R_TrackSprite definition for a reason for this copying + VectorCopy(r_refdef.view.left, left); + VectorCopy(r_refdef.view.up, up); + // It has to be done before the calculations, because it moves the origin. + if(r_track_sprites.integer) + R_TrackSprite(ent, org, left, up, &edge, &dir_angle); + + scale = 2 * ent->scale * (DotProduct(r_refdef.view.forward, org) - DotProduct(r_refdef.view.forward, r_refdef.view.origin)) * r_labelsprites_scale.value; + VectorScale(left, scale * r_refdef.view.frustum_x / vid_conwidth.integer, left); // 1px + VectorScale(up, scale * r_refdef.view.frustum_y / vid_conheight.integer, up); // 1px + break; + case SPR_LABEL: + // normal sprite + // faces view plane + // fixed pixel size specified in sprite + // tries to get the right size in HUD units, if possible + // ignores scale + // honors a global label scaling cvar before the rounding + // FIXME assumes that 1qu is 1 pixel in the sprite like in SPR32 format. Should not do that, but instead query the source image! This bug only applies to the roundtopixels case, though. + + if(r_fb.water.renderingscene) // labels are considered HUD items, and don't appear in reflections + return; + + // See the R_TrackSprite definition for a reason for this copying + VectorCopy(r_refdef.view.left, left); + VectorCopy(r_refdef.view.up, up); + // It has to be done before the calculations, because it moves the origin. + if(r_track_sprites.integer) + R_TrackSprite(ent, org, left, up, &edge, &dir_angle); + + scale = 2 * (DotProduct(r_refdef.view.forward, org) - DotProduct(r_refdef.view.forward, r_refdef.view.origin)); + + if(r_labelsprites_roundtopixels.integer) + { + hud_vs_screen = max( + vid_conwidth.integer / (float) r_refdef.view.width, + vid_conheight.integer / (float) r_refdef.view.height + ) / max(0.125, r_labelsprites_scale.value); + + // snap to "good sizes" + // 1 for (0.6, 1.41] + // 2 for (1.8, 3.33] + if(hud_vs_screen <= 0.6) + hud_vs_screen = 0; // don't, use real HUD pixels + else if(hud_vs_screen <= 1.41) + hud_vs_screen = 1; + else if(hud_vs_screen <= 3.33) + hud_vs_screen = 2; + else + hud_vs_screen = 0; // don't, use real HUD pixels + + if(hud_vs_screen) + { + // use screen pixels + VectorScale(left, scale * r_refdef.view.frustum_x / (r_refdef.view.width * hud_vs_screen), left); // 1px + VectorScale(up, scale * r_refdef.view.frustum_y / (r_refdef.view.height * hud_vs_screen), up); // 1px + } + else + { + // use HUD pixels + VectorScale(left, scale * r_refdef.view.frustum_x / vid_conwidth.integer * r_labelsprites_scale.value, left); // 1px + VectorScale(up, scale * r_refdef.view.frustum_y / vid_conheight.integer * r_labelsprites_scale.value, up); // 1px + } + + if(hud_vs_screen == 1) + { + VectorMA(r_refdef.view.origin, scale, r_refdef.view.forward, middle); // center of screen in distance scale + dx = 0.5 - fmod(r_refdef.view.width * 0.5 + (DotProduct(org, left) - DotProduct(middle, left)) / DotProduct(left, left) + 0.5, 1.0); + dy = 0.5 - fmod(r_refdef.view.height * 0.5 + (DotProduct(org, up) - DotProduct(middle, up)) / DotProduct(up, up) + 0.5, 1.0); + VectorMAMAM(1, org, dx, left, dy, up, org); + } + } + else + { + // use HUD pixels + VectorScale(left, scale * r_refdef.view.frustum_x / vid_conwidth.integer * r_labelsprites_scale.value, left); // 1px + VectorScale(up, scale * r_refdef.view.frustum_y / vid_conheight.integer * r_labelsprites_scale.value, up); // 1px + } + break; + case SPR_ORIENTED: + // bullet marks on walls + // ignores viewer entirely + VectorCopy(mleft, left); + VectorCopy(mup, up); + break; + case SPR_VP_PARALLEL_ORIENTED: + // I have no idea what people would use this for... + // oriented relative to view space + // FIXME: test this and make sure it mimicks software + left[0] = mleft[0] * r_refdef.view.forward[0] + mleft[1] * r_refdef.view.left[0] + mleft[2] * r_refdef.view.up[0]; + left[1] = mleft[0] * r_refdef.view.forward[1] + mleft[1] * r_refdef.view.left[1] + mleft[2] * r_refdef.view.up[1]; + left[2] = mleft[0] * r_refdef.view.forward[2] + mleft[1] * r_refdef.view.left[2] + mleft[2] * r_refdef.view.up[2]; + up[0] = mup[0] * r_refdef.view.forward[0] + mup[1] * r_refdef.view.left[0] + mup[2] * r_refdef.view.up[0]; + up[1] = mup[0] * r_refdef.view.forward[1] + mup[1] * r_refdef.view.left[1] + mup[2] * r_refdef.view.up[1]; + up[2] = mup[0] * r_refdef.view.forward[2] + mup[1] * r_refdef.view.left[2] + mup[2] * r_refdef.view.up[2]; + break; + case SPR_OVERHEAD: + // Overhead games sprites, have some special hacks to look good + VectorScale(r_refdef.view.left, ent->scale * r_overheadsprites_scalex.value, left); + VectorScale(r_refdef.view.up, ent->scale * r_overheadsprites_scaley.value, up); + VectorSubtract(org, r_refdef.view.origin, middle); + VectorNormalize(middle); + // offset and rotate + dir_angle = r_overheadsprites_perspective.value * (1 - fabs(DotProduct(middle, r_refdef.view.forward))); + up[2] = up[2] + dir_angle; + VectorNormalize(up); + VectorScale(up, ent->scale * r_overheadsprites_scaley.value, up); + // offset (move nearer to player, yz is camera plane) + org[0] = org[0] - middle[0]*r_overheadsprites_pushback.value; + org[1] = org[1] - middle[1]*r_overheadsprites_pushback.value; + org[2] = org[2] - middle[2]*r_overheadsprites_pushback.value; + // little perspective effect + up[2] = up[2] + dir_angle * 0.3; + // a bit of counter-camera rotation + up[0] = up[0] + r_refdef.view.forward[0] * 0.07; + up[1] = up[1] + r_refdef.view.forward[1] * 0.07; + up[2] = up[2] + r_refdef.view.forward[2] * 0.07; + break; + } + + // LordHavoc: interpolated sprite rendering + for (i = 0;i < MAX_FRAMEBLENDS;i++) + { + if (ent->frameblend[i].lerp >= 0.01f) + { + mspriteframe_t *frame; + texture_t *texture; + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, ent->flags, 0, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha * ent->frameblend[i].lerp, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + frame = model->sprite.sprdata_frames + ent->frameblend[i].subframe; + texture = R_GetCurrentTexture(model->data_textures + ent->frameblend[i].subframe); + + // lit sprite by lightgrid if it is not fullbright, lit only ambient + if (!(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + VectorAdd(ent->modellight_ambient, ent->modellight_diffuse, rsurface.modellight_ambient); // sprites dont use lightdirection + + // SPR_LABEL should not use depth test AT ALL + if(model->sprite.sprnum_type == SPR_LABEL || model->sprite.sprnum_type == SPR_LABEL_SCALE) + if(texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) + texture->currentmaterialflags = (texture->currentmaterialflags & ~MATERIALFLAG_SHORTDEPTHRANGE) | MATERIALFLAG_NODEPTHTEST; + + if(edge) + { + // FIXME:: save vectors/origin and re-rotate? necessary if the hotspot can change per frame + R_RotateSprite(frame, org, left, up, edge, dir_angle); + edge = 0; + } + + R_CalcSprite_Vertex3f(vertex3f, org, left, up, frame->left, frame->right, frame->down, frame->up); + + R_DrawCustomSurface_Texture(texture, &identitymatrix, texture->currentmaterialflags, 0, 4, 0, 2, false, false); + } + } + + rsurface.entity = NULL; +} + +void R_Model_Sprite_Draw(entity_render_t *ent) +{ + vec3_t org; + if (ent->frameblend[0].subframe < 0) + return; + + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + R_MeshQueue_AddTransparent((ent->flags & RENDER_WORLDOBJECT) ? TRANSPARENTSORT_SKY : (ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_Model_Sprite_Draw_TransparentCallback, ent, 0, rsurface.rtlight); +} + diff --git a/app/jni/r_textures.h b/app/jni/r_textures.h new file mode 100644 index 0000000..e9c9aab --- /dev/null +++ b/app/jni/r_textures.h @@ -0,0 +1,222 @@ + +#ifndef R_TEXTURES_H +#define R_TEXTURES_H + +// transparent +#define TEXF_ALPHA 0x00000001 +// mipmapped +#define TEXF_MIPMAP 0x00000002 +// multiply RGB by A channel before uploading +#define TEXF_RGBMULTIPLYBYALPHA 0x00000004 +// indicates texture coordinates should be clamped rather than wrapping +#define TEXF_CLAMP 0x00000020 +// indicates texture should be uploaded using GL_NEAREST or GL_NEAREST_MIPMAP_NEAREST mode +#define TEXF_FORCENEAREST 0x00000040 +// indicates texture should be uploaded using GL_LINEAR or GL_LINEAR_MIPMAP_NEAREST or GL_LINEAR_MIPMAP_LINEAR mode +#define TEXF_FORCELINEAR 0x00000080 +// indicates texture should be affected by gl_picmip and gl_max_size cvar +#define TEXF_PICMIP 0x00000100 +// indicates texture should be compressed if possible +#define TEXF_COMPRESS 0x00000200 +// use this flag to block R_PurgeTexture from freeing a texture (only used by r_texture_white and similar which may be used in skinframe_t) +#define TEXF_PERSISTENT 0x00000400 +// indicates texture should use GL_COMPARE_R_TO_TEXTURE mode +#define TEXF_COMPARE 0x00000800 +// indicates texture should use lower precision where supported +#define TEXF_LOWPRECISION 0x00001000 +// indicates texture should support R_UpdateTexture on small regions, actual uploads may be delayed until R_Mesh_TexBind if gl_nopartialtextureupdates is on +#define TEXF_ALLOWUPDATES 0x00002000 +// indicates texture should be affected by gl_picmip_world and r_picmipworld (maybe others in the future) instead of gl_picmip_other +#define TEXF_ISWORLD 0x00004000 +// indicates texture should be affected by gl_picmip_sprites and r_picmipsprites (maybe others in the future) instead of gl_picmip_other +#define TEXF_ISSPRITE 0x00008000 +// indicates the texture will be used as a render target (D3D hint) +#define TEXF_RENDERTARGET 0x0010000 +// used for checking if textures mismatch +#define TEXF_IMPORTANTBITS (TEXF_ALPHA | TEXF_MIPMAP | TEXF_RGBMULTIPLYBYALPHA | TEXF_CLAMP | TEXF_FORCENEAREST | TEXF_FORCELINEAR | TEXF_PICMIP | TEXF_COMPRESS | TEXF_COMPARE | TEXF_LOWPRECISION | TEXF_RENDERTARGET) +// set as a flag to force the texture to be reloaded +#define TEXF_FORCE_RELOAD 0x80000000 + +typedef enum textype_e +{ + // 8bit paletted + TEXTYPE_PALETTE, + // 32bit RGBA + TEXTYPE_RGBA, + // 32bit BGRA (preferred format due to faster uploads on most hardware) + TEXTYPE_BGRA, + // 8bit ALPHA (used for freetype fonts) + TEXTYPE_ALPHA, + // 4x4 block compressed 15bit color (4 bits per pixel) + TEXTYPE_DXT1, + // 4x4 block compressed 15bit color plus 1bit alpha (4 bits per pixel) + TEXTYPE_DXT1A, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) + TEXTYPE_DXT3, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) + TEXTYPE_DXT5, + + // 8bit paletted in sRGB colorspace + TEXTYPE_SRGB_PALETTE, + // 32bit RGBA in sRGB colorspace + TEXTYPE_SRGB_RGBA, + // 32bit BGRA (preferred format due to faster uploads on most hardware) in sRGB colorspace + TEXTYPE_SRGB_BGRA, + // 4x4 block compressed 15bit color (4 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT1, + // 4x4 block compressed 15bit color plus 1bit alpha (4 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT1A, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT3, + // 4x4 block compressed 15bit color plus 8bit alpha (8 bits per pixel) in sRGB colorspace + TEXTYPE_SRGB_DXT5, + + // this represents the same format as the framebuffer, for fast copies + TEXTYPE_COLORBUFFER, + // this represents an RGBA half_float texture (4 16bit floats) + TEXTYPE_COLORBUFFER16F, + // this represents an RGBA float texture (4 32bit floats) + TEXTYPE_COLORBUFFER32F, + // depth-stencil buffer (or texture) + TEXTYPE_DEPTHBUFFER16, + // depth-stencil buffer (or texture) + TEXTYPE_DEPTHBUFFER24, + // 32bit D24S8 buffer (24bit depth, 8bit stencil), not supported on OpenGL ES + TEXTYPE_DEPTHBUFFER24STENCIL8, + // shadowmap-friendly format with depth comparison (not supported on some hardware) + TEXTYPE_SHADOWMAP16_COMP, + // shadowmap-friendly format with raw reading (not supported on some hardware) + TEXTYPE_SHADOWMAP16_RAW, + // shadowmap-friendly format with depth comparison (not supported on some hardware) + TEXTYPE_SHADOWMAP24_COMP, + // shadowmap-friendly format with raw reading (not supported on some hardware) + TEXTYPE_SHADOWMAP24_RAW, +} +textype_t; + +/* +#ifdef WIN32 +#define SUPPORTD3D +#define SUPPORTDIRECTX +#ifdef SUPPORTD3D +#include +#endif +#endif +*/ + +// contents of this structure are mostly private to gl_textures.c +typedef struct rtexture_s +{ + // this is exposed (rather than private) for speed reasons only + int texnum; // GL texture slot number + int renderbuffernum; // GL renderbuffer slot number + qboolean dirty; // indicates that R_RealGetTexture should be called + qboolean glisdepthstencil; // indicates that FBO attachment has to be GL_DEPTH_STENCIL_ATTACHMENT + int gltexturetypeenum; // used by R_Mesh_TexBind + // d3d stuff the backend needs + void *d3dtexture; + void *d3dsurface; +#ifdef SUPPORTD3D + qboolean d3disrendertargetsurface; + qboolean d3disdepthstencilsurface; + int d3dformat; + int d3dusage; + int d3dpool; + int d3daddressu; + int d3daddressv; + int d3daddressw; + int d3dmagfilter; + int d3dminfilter; + int d3dmipfilter; + int d3dmaxmiplevelfilter; + int d3dmipmaplodbias; + int d3dmaxmiplevel; +#endif +} +rtexture_t; + +// contents of this structure are private to gl_textures.c +typedef struct rtexturepool_s +{ + int useless; +} +rtexturepool_t; + +typedef void (*updatecallback_t)(rtexture_t *rt, void *data); + +// allocate a texture pool, to be used with R_LoadTexture +rtexturepool_t *R_AllocTexturePool(void); +// free a texture pool (textures can not be freed individually) +void R_FreeTexturePool(rtexturepool_t **rtexturepool); + +// the color/normal/etc cvars should be checked by callers of R_LoadTexture* functions to decide whether to add TEXF_COMPRESS to the flags +extern cvar_t gl_texturecompression; +extern cvar_t gl_texturecompression_color; +extern cvar_t gl_texturecompression_normal; +extern cvar_t gl_texturecompression_gloss; +extern cvar_t gl_texturecompression_glow; +extern cvar_t gl_texturecompression_2d; +extern cvar_t gl_texturecompression_q3bsplightmaps; +extern cvar_t gl_texturecompression_q3bspdeluxemaps; +extern cvar_t gl_texturecompression_sky; +extern cvar_t gl_texturecompression_lightcubemaps; +extern cvar_t gl_texturecompression_reflectmask; +extern cvar_t r_texture_dds_load; +extern cvar_t r_texture_dds_save; + +// add a texture to a pool and optionally precache (upload) it +// (note: data == NULL is perfectly acceptable) +// (note: palette must not be NULL if using TEXTYPE_PALETTE) +rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette); +rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette); +rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette); +rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype, qboolean filter); +rtexture_t *R_LoadTextureRenderBuffer(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, textype_t textype); +rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, qboolean srgb, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel, qboolean optionaltexture); + +// saves a texture to a DDS file +int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha); + +// free a texture +void R_FreeTexture(rtexture_t *rt); + +// update a portion of the image data of a texture, used by lightmap updates +// and procedural textures such as video playback, actual uploads may be +// delayed by gl_nopartialtextureupdates cvar until R_Mesh_TexBind uses it +void R_UpdateTexture(rtexture_t *rt, const unsigned char *data, int x, int y, int z, int width, int height, int depth); + +// returns the renderer dependent texture slot number (call this before each +// use, as a texture might not have been precached) +#define R_GetTexture(rt) ((rt) ? ((rt)->dirty ? R_RealGetTexture(rt) : (rt)->texnum) : r_texture_white->texnum) +int R_RealGetTexture (rtexture_t *rt); + +// returns width of texture, as was specified when it was uploaded +int R_TextureWidth(rtexture_t *rt); + +// returns height of texture, as was specified when it was uploaded +int R_TextureHeight(rtexture_t *rt); + +// returns flags of texture, as was specified when it was uploaded +int R_TextureFlags(rtexture_t *rt); + +// only frees the texture if TEXF_PERSISTENT is not set +// also resets the variable +void R_PurgeTexture(rtexture_t *prt); + +// frees processing buffers each frame, and may someday animate procedural textures +void R_Textures_Frame(void); + +// maybe rename this - sounds awful? [11/21/2007 Black] +void R_MarkDirtyTexture(rtexture_t *rt); +void R_MakeTextureDynamic(rtexture_t *rt, updatecallback_t updatecallback, void *data); + +// Clear the texture's contents +void R_ClearTexture (rtexture_t *rt); + +// returns the desired picmip level for given TEXF_ flags +int R_PicmipForFlags(int flags); + +void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal); + +#endif + diff --git a/app/jni/render.h b/app/jni/render.h new file mode 100644 index 0000000..b0ccf79 --- /dev/null +++ b/app/jni/render.h @@ -0,0 +1,646 @@ +/* +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 RENDER_H +#define RENDER_H + +#include "svbsp.h" + +// 1.0f / N table +extern float ixtable[4096]; + +// fog stuff +void FOG_clear(void); + +// sky stuff +extern cvar_t r_sky; +extern cvar_t r_skyscroll1; +extern cvar_t r_skyscroll2; +extern int skyrenderlater, skyrendermasked; +int R_SetSkyBox(const char *sky); +void R_SkyStartFrame(void); +void R_Sky(void); +void R_ResetSkyBox(void); + +// SHOWLMP stuff (Nehahra) +void SHOWLMP_decodehide(void); +void SHOWLMP_decodeshow(void); +void SHOWLMP_drawall(void); + +// render profiling stuff +extern int r_timereport_active; + +// lighting stuff +extern cvar_t r_ambient; +extern cvar_t gl_flashblend; + +// vis stuff +extern cvar_t r_novis; + +extern cvar_t r_trippy; + +extern cvar_t r_lerpsprites; +extern cvar_t r_lerpmodels; +extern cvar_t r_lerplightstyles; +extern cvar_t r_waterscroll; + +extern cvar_t developer_texturelogging; + +// shadow volume bsp struct with automatically growing nodes buffer +extern svbsp_t r_svbsp; + +typedef struct rmesh_s +{ + // vertices of this mesh + int maxvertices; + int numvertices; + float *vertex3f; + float *svector3f; + float *tvector3f; + float *normal3f; + float *texcoord2f; + float *texcoordlightmap2f; + float *color4f; + // triangles of this mesh + int maxtriangles; + int numtriangles; + int *element3i; + int *neighbor3i; + // snapping epsilon + float epsilon2; +} +rmesh_t; + +// useful functions for rendering +void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b); +void R_FillColors(float *out, int verts, float r, float g, float b, float a); +int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v); +void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f); +void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes); + +#define TOP_RANGE 16 // soldier uniform colors +#define BOTTOM_RANGE 96 + +//============================================================================= + +extern cvar_t r_nearclip; + +// forces all rendering to draw triangle outlines +extern cvar_t r_showoverdraw; +extern cvar_t r_showtris; +extern cvar_t r_shownormals; +extern cvar_t r_showlighting; +extern cvar_t r_showshadowvolumes; +extern cvar_t r_showcollisionbrushes; +extern cvar_t r_showcollisionbrushes_polygonfactor; +extern cvar_t r_showcollisionbrushes_polygonoffset; +extern cvar_t r_showdisabledepthtest; + +extern cvar_t r_drawentities; +extern cvar_t r_draw2d; +extern qboolean r_draw2d_force; +extern cvar_t r_drawviewmodel; +extern cvar_t r_drawworld; +extern cvar_t r_speeds; +extern cvar_t r_fullbright; +extern cvar_t r_wateralpha; +extern cvar_t r_dynamic; + +void R_Init(void); +void R_UpdateVariables(void); // must call after setting up most of r_refdef, but before calling R_RenderView +void R_RenderView(); // must set r_refdef and call R_UpdateVariables first +void R_RenderView_UpdateViewVectors(void); // just updates r_refdef.view.{forward,left,up,origin,right,inverse_matrix} + +typedef enum r_refdef_scene_type_s { + RST_CLIENT, + RST_MENU, + RST_COUNT +} r_refdef_scene_type_t; + +void R_SelectScene( r_refdef_scene_type_t scenetype ); +r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype ); + +void R_SkinFrame_PrepareForPurge(void); +void R_SkinFrame_MarkUsed(skinframe_t *skinframe); +void R_SkinFrame_Purge(void); +// set last to NULL to start from the beginning +skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ); +skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add); +skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain); +skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB); +skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height); +skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette); +skinframe_t *R_SkinFrame_LoadMissing(void); + +rtexture_t *R_GetCubemap(const char *basename); + +void R_View_WorldVisibility(qboolean forcenovis); +void R_DrawDecals(void); +void R_DrawParticles(void); +void R_DrawExplosions(void); + +#define gl_solid_format 3 +#define gl_alpha_format 4 + +int R_CullBox(const vec3_t mins, const vec3_t maxs); +int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes); + +#include "r_modules.h" + +#include "meshqueue.h" + +/// free all R_FrameData memory +void R_FrameData_Reset(void); +/// prepare for a new frame, recycles old buffers if a resize occurred previously +void R_FrameData_NewFrame(void); +/// allocate some temporary memory for your purposes +void *R_FrameData_Alloc(size_t size); +/// allocate some temporary memory and copy this data into it +void *R_FrameData_Store(size_t size, void *data); +/// set a marker that allows you to discard the following temporary memory allocations +void R_FrameData_SetMark(void); +/// discard recent memory allocations (rewind to marker) +void R_FrameData_ReturnToMark(void); + +/// enum of the various types of hardware buffer object used in rendering +/// note that the r_buffermegs[] array must be maintained to match this +typedef enum r_bufferdata_type_e +{ + R_BUFFERDATA_VERTEX, /// vertex buffer + R_BUFFERDATA_INDEX16, /// index buffer - 16bit (because D3D cares) + R_BUFFERDATA_INDEX32, /// index buffer - 32bit (because D3D cares) + R_BUFFERDATA_UNIFORM, /// uniform buffer + R_BUFFERDATA_COUNT /// how many kinds of buffer we have +} +r_bufferdata_type_t; + +/// free all dynamic vertex/index/uniform buffers +void R_BufferData_Reset(void); +/// begin a new frame (recycle old buffers) +void R_BufferData_NewFrame(void); +/// request space in a vertex/index/uniform buffer for the chosen data, returns the buffer pointer and offset, always successful +r_meshbuffer_t *R_BufferData_Store(size_t size, const void *data, r_bufferdata_type_t type, int *returnbufferoffset); + +/// free all R_AnimCache memory +void R_AnimCache_Free(void); +/// clear the animcache pointers on all known render entities +void R_AnimCache_ClearCache(void); +/// get the skeletal data or cached animated mesh data for an entity (optionally with normals and tangents) +qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents); +/// generate animcache data for all entities marked visible +void R_AnimCache_CacheVisibleEntities(void); + +#include "r_lerpanim.h" + +extern cvar_t r_render; +extern cvar_t r_renderview; +extern cvar_t r_waterwarp; + +extern cvar_t r_textureunits; + +extern cvar_t r_glsl_offsetmapping; +extern cvar_t r_glsl_offsetmapping_reliefmapping; +extern cvar_t r_glsl_offsetmapping_scale; +extern cvar_t r_glsl_offsetmapping_lod; +extern cvar_t r_glsl_offsetmapping_lod_distance; +extern cvar_t r_glsl_deluxemapping; + +extern cvar_t gl_polyblend; +extern cvar_t gl_dither; + +extern cvar_t cl_deathfade; + +extern cvar_t r_smoothnormals_areaweighting; + +extern cvar_t r_test; + +#include "gl_backend.h" + +extern rtexture_t *r_texture_blanknormalmap; +extern rtexture_t *r_texture_white; +extern rtexture_t *r_texture_grey128; +extern rtexture_t *r_texture_black; +extern rtexture_t *r_texture_notexture; +extern rtexture_t *r_texture_whitecube; +extern rtexture_t *r_texture_normalizationcube; +extern rtexture_t *r_texture_fogattenuation; +extern rtexture_t *r_texture_fogheighttexture; + +extern unsigned int r_queries[MAX_OCCLUSION_QUERIES]; +extern unsigned int r_numqueries; +extern unsigned int r_maxqueries; + +void R_TimeReport(const char *name); + +// r_stain +void R_Stain(const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2); + +void R_CalcBeam_Vertex3f(float *vert, const float *org1, const float *org2, float width); +void R_CalcSprite_Vertex3f(float *vertex3f, const float *origin, const float *left, const float *up, float scalex1, float scalex2, float scaley1, float scaley2); + +extern mempool_t *r_main_mempool; + +typedef struct rsurfacestate_s +{ + // current model array pointers + // these may point to processing buffers if model is animated, + // otherwise they point to static data. + // these are not directly used for rendering, they are just another level + // of processing + // + // these either point at array_model* buffers (if the model is animated) + // or the model->surfmesh.data_* buffers (if the model is not animated) + // + // these are only set when an entity render begins, they do not change on + // a per surface basis. + // + // this indicates the model* arrays are pointed at array_model* buffers + // (in other words, the model has been animated in software) + qboolean forcecurrenttextureupdate; // set for RSurf_ActiveCustomEntity to force R_GetCurrentTexture to recalculate the texture parameters (such as entity alpha) + qboolean modelgeneratedvertex; + // skeletal animation can be done by entity (animcache) or per batch, + // batch may be non-skeletal even if entity is skeletal, indicating that + // the dynamicvertex code path had to apply skeletal manually for a case + // where gpu-skinning is not possible, for this reason batch has its own + // variables + int entityskeletalnumtransforms; // how many transforms are used for this mesh + float *entityskeletaltransform3x4; // use gpu-skinning shader on this mesh + const r_meshbuffer_t *entityskeletaltransform3x4buffer; // uniform buffer + int entityskeletaltransform3x4offset; + int entityskeletaltransform3x4size; + float *modelvertex3f; + const r_meshbuffer_t *modelvertex3f_vertexbuffer; + int modelvertex3f_bufferoffset; + float *modelsvector3f; + const r_meshbuffer_t *modelsvector3f_vertexbuffer; + int modelsvector3f_bufferoffset; + float *modeltvector3f; + const r_meshbuffer_t *modeltvector3f_vertexbuffer; + int modeltvector3f_bufferoffset; + float *modelnormal3f; + const r_meshbuffer_t *modelnormal3f_vertexbuffer; + int modelnormal3f_bufferoffset; + float *modellightmapcolor4f; + const r_meshbuffer_t *modellightmapcolor4f_vertexbuffer; + int modellightmapcolor4f_bufferoffset; + float *modeltexcoordtexture2f; + const r_meshbuffer_t *modeltexcoordtexture2f_vertexbuffer; + int modeltexcoordtexture2f_bufferoffset; + float *modeltexcoordlightmap2f; + const r_meshbuffer_t *modeltexcoordlightmap2f_vertexbuffer; + int modeltexcoordlightmap2f_bufferoffset; + unsigned char *modelskeletalindex4ub; + const r_meshbuffer_t *modelskeletalindex4ub_vertexbuffer; + int modelskeletalindex4ub_bufferoffset; + unsigned char *modelskeletalweight4ub; + const r_meshbuffer_t *modelskeletalweight4ub_vertexbuffer; + int modelskeletalweight4ub_bufferoffset; + r_vertexmesh_t *modelvertexmesh; + const r_meshbuffer_t *modelvertexmesh_vertexbuffer; + int modelvertexmesh_bufferoffset; + int *modelelement3i; + const r_meshbuffer_t *modelelement3i_indexbuffer; + int modelelement3i_bufferoffset; + unsigned short *modelelement3s; + const r_meshbuffer_t *modelelement3s_indexbuffer; + int modelelement3s_bufferoffset; + int *modellightmapoffsets; + int modelnumvertices; + int modelnumtriangles; + const msurface_t *modelsurfaces; + // current rendering array pointers + // these may point to any of several different buffers depending on how + // much processing was needed to prepare this model for rendering + // these usually equal the model* pointers, they only differ if + // deformvertexes is used in a q3 shader, and consequently these can + // change on a per-surface basis (according to rsurface.texture) + qboolean batchgeneratedvertex; + qboolean batchmultidraw; + int batchmultidrawnumsurfaces; + const msurface_t **batchmultidrawsurfacelist; + int batchfirstvertex; + int batchnumvertices; + int batchfirsttriangle; + int batchnumtriangles; + r_vertexmesh_t *batchvertexmesh; + const r_meshbuffer_t *batchvertexmesh_vertexbuffer; + int batchvertexmesh_bufferoffset; + float *batchvertex3f; + const r_meshbuffer_t *batchvertex3f_vertexbuffer; + int batchvertex3f_bufferoffset; + float *batchsvector3f; + const r_meshbuffer_t *batchsvector3f_vertexbuffer; + int batchsvector3f_bufferoffset; + float *batchtvector3f; + const r_meshbuffer_t *batchtvector3f_vertexbuffer; + int batchtvector3f_bufferoffset; + float *batchnormal3f; + const r_meshbuffer_t *batchnormal3f_vertexbuffer; + int batchnormal3f_bufferoffset; + float *batchlightmapcolor4f; + const r_meshbuffer_t *batchlightmapcolor4f_vertexbuffer; + int batchlightmapcolor4f_bufferoffset; + float *batchtexcoordtexture2f; + const r_meshbuffer_t *batchtexcoordtexture2f_vertexbuffer; + int batchtexcoordtexture2f_bufferoffset; + float *batchtexcoordlightmap2f; + const r_meshbuffer_t *batchtexcoordlightmap2f_vertexbuffer; + int batchtexcoordlightmap2f_bufferoffset; + unsigned char *batchskeletalindex4ub; + const r_meshbuffer_t *batchskeletalindex4ub_vertexbuffer; + int batchskeletalindex4ub_bufferoffset; + unsigned char *batchskeletalweight4ub; + const r_meshbuffer_t *batchskeletalweight4ub_vertexbuffer; + int batchskeletalweight4ub_bufferoffset; + int *batchelement3i; + const r_meshbuffer_t *batchelement3i_indexbuffer; + int batchelement3i_bufferoffset; + unsigned short *batchelement3s; + const r_meshbuffer_t *batchelement3s_indexbuffer; + int batchelement3s_bufferoffset; + int batchskeletalnumtransforms; + float *batchskeletaltransform3x4; + const r_meshbuffer_t *batchskeletaltransform3x4buffer; // uniform buffer + int batchskeletaltransform3x4offset; + int batchskeletaltransform3x4size; + // rendering pass processing arrays in GL11 and GL13 paths + float *passcolor4f; + const r_meshbuffer_t *passcolor4f_vertexbuffer; + int passcolor4f_bufferoffset; + + // some important fields from the entity + int ent_skinnum; + int ent_qwskin; + int ent_flags; + int ent_alttextures; // used by q1bsp animated textures (pressed buttons) + double shadertime; // r_refdef.scene.time - ent->shadertime + // transform matrices to render this entity and effects on this entity + matrix4x4_t matrix; + matrix4x4_t inversematrix; + // scale factors for transforming lengths into/out of entity space + float matrixscale; + float inversematrixscale; + // animation blending state from entity + frameblend_t frameblend[MAX_FRAMEBLENDS]; + skeleton_t *skeleton; + // directional model shading state from entity + vec3_t modellight_ambient; + vec3_t modellight_diffuse; + vec3_t modellight_lightdir; + // colormapping state from entity (these are black if colormapping is off) + vec3_t colormap_pantscolor; + vec3_t colormap_shirtcolor; + // special coloring of ambient/diffuse textures (gloss not affected) + // colormod[3] is the alpha of the entity + float colormod[4]; + // special coloring of glow textures + float glowmod[3]; + // view location in model space + vec3_t localvieworigin; + // polygon offset data for submodels + float basepolygonfactor; + float basepolygonoffset; + // current textures in batching code + texture_t *texture; + rtexture_t *lightmaptexture; + rtexture_t *deluxemaptexture; + // whether lightmapping is active on this batch + // (otherwise vertex colored) + qboolean uselightmaptexture; + // fog plane in model space for direct application to vertices + float fograngerecip; + float fogmasktabledistmultiplier; + float fogplane[4]; + float fogheightfade; + float fogplaneviewdist; + + // rtlight rendering + // light currently being rendered + const rtlight_t *rtlight; + + // this is the location of the light in entity space + vec3_t entitylightorigin; + // this transforms entity coordinates to light filter cubemap coordinates + // (also often used for other purposes) + matrix4x4_t entitytolight; + // based on entitytolight this transforms -1 to +1 to 0 to 1 for purposes + // of attenuation texturing in full 3D (Z result often ignored) + matrix4x4_t entitytoattenuationxyz; + // this transforms only the Z to S, and T is always 0.5 + matrix4x4_t entitytoattenuationz; + + // user wavefunc parameters (from csqc) + float userwavefunc_param[Q3WAVEFUNC_USER_COUNT]; + + // pointer to an entity_render_t used only by R_GetCurrentTexture and + // RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity as a unique id within + // each frame (see r_frame also) + entity_render_t *entity; +} +rsurfacestate_t; + +extern rsurfacestate_t rsurface; + +void R_HDR_UpdateIrisAdaptation(const vec3_t point); + +void RSurf_ActiveWorldEntity(void); +void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass); +void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents); +void RSurf_SetupDepthAndCulling(void); + +void R_Mesh_ResizeArrays(int newvertices); + +texture_t *R_GetCurrentTexture(texture_t *t); +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass); +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass); +void R_AddWaterPlanes(entity_render_t *ent); +void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass); +void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass); + +#define BATCHNEED_VERTEXMESH_VERTEX (1<< 1) // set up rsurface.batchvertexmesh +#define BATCHNEED_VERTEXMESH_NORMAL (1<< 2) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_VECTOR (1<< 3) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_VERTEXCOLOR (1<< 4) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_TEXCOORD (1<< 5) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_LIGHTMAP (1<< 6) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_SKELETAL (1<< 7) // set up skeletal index and weight data for vertex shader +#define BATCHNEED_ARRAY_VERTEX (1<< 8) // set up rsurface.batchvertex3f and optionally others +#define BATCHNEED_ARRAY_NORMAL (1<< 9) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_VECTOR (1<<10) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_VERTEXCOLOR (1<<11) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_TEXCOORD (1<<12) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_LIGHTMAP (1<<13) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_SKELETAL (1<<14) // set up skeletal index and weight data for vertex shader +#define BATCHNEED_NOGAPS (1<<15) // force vertex copying if firstvertex is not zero or there are gaps +#define BATCHNEED_ALLOWMULTIDRAW (1<<16) // allow multiple draws +void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist); +void RSurf_DrawBatch(void); + +void R_DecalSystem_SplatEntities(const vec3_t org, const vec3_t normal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float size); + +typedef enum rsurfacepass_e +{ + RSURFPASS_BASE, + RSURFPASS_BACKGROUND, + RSURFPASS_RTLIGHT, + RSURFPASS_DEFERREDGEOMETRY +} +rsurfacepass_t; + +void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha); +void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy); +void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal); +void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *waterplane, qboolean notrippy); +void R_SetupShader_DeferredLight(const rtlight_t *rtlight); + +typedef struct r_waterstate_waterplane_s +{ + rtexture_t *texture_refraction; // MATERIALFLAG_WATERSHADER or MATERIALFLAG_REFRACTION + rtexture_t *texture_reflection; // MATERIALFLAG_WATERSHADER or MATERIALFLAG_REFLECTION + rtexture_t *texture_camera; // MATERIALFLAG_CAMERA + int fbo_refraction; + int fbo_reflection; + int fbo_camera; + mplane_t plane; + int materialflags; // combined flags of all water surfaces on this plane + unsigned char pvsbits[(MAX_MAP_LEAFS+7)>>3]; // FIXME: buffer overflow on huge maps + qboolean pvsvalid; + int camera_entity; + vec3_t mins, maxs; +} +r_waterstate_waterplane_t; + +typedef struct r_waterstate_s +{ + int waterwidth, waterheight; + int texturewidth, textureheight; + int camerawidth, cameraheight; + rtexture_t *depthtexture; + + int maxwaterplanes; // same as MAX_WATERPLANES + int numwaterplanes; + r_waterstate_waterplane_t waterplanes[MAX_WATERPLANES]; + + float screenscale[2]; + float screencenter[2]; + + qboolean enabled; + + qboolean renderingscene; // true while rendering a refraction or reflection texture, disables water surfaces + qboolean hideplayer; +} +r_waterstate_t; + +typedef struct r_framebufferstate_s +{ + textype_t textype; // type of color buffer we're using (dependent on r_viewfbo cvar) + int fbo; // non-zero if r_viewfbo is enabled and working + int screentexturewidth, screentextureheight; // dimensions of texture + + rtexture_t *colortexture; // non-NULL if fbo is non-zero + rtexture_t *depthtexture; // non-NULL if fbo is non-zero + rtexture_t *ghosttexture; // for r_motionblur (not recommended on multi-GPU hardware!) + rtexture_t *bloomtexture[2]; // for r_bloom, multi-stage processing + int bloomfbo[2]; // fbos for rendering into bloomtexture[] + int bloomindex; // which bloomtexture[] contains the final image + + int bloomwidth, bloomheight; + int bloomtexturewidth, bloomtextureheight; + + // arrays for rendering the screen passes + float screentexcoord2f[8]; // texcoords for colortexture or ghosttexture + float bloomtexcoord2f[8]; // texcoords for bloomtexture[] + float offsettexcoord2f[8]; // temporary use while updating bloomtexture[] + + r_viewport_t bloomviewport; + + r_waterstate_t water; + + qboolean ghosttexture_valid; // don't draw garbage on first frame with motionblur + qboolean usedepthtextures; // use depth texture instead of depth renderbuffer (faster if you need to read it later anyway) +} +r_framebufferstate_t; + +extern r_framebufferstate_t r_fb; + +extern cvar_t r_viewfbo; + +void R_ResetViewRendering2D_Common(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, float x2, float y2); // this is called by R_ResetViewRendering2D and _DrawQ_Setup and internal +void R_ResetViewRendering2D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_ResetViewRendering3D(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_SetupView(qboolean allowwaterclippingplane, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +extern const float r_screenvertex3f[12]; +extern cvar_t r_shadows; +extern cvar_t r_shadows_darken; +extern cvar_t r_shadows_drawafterrtlighting; +extern cvar_t r_shadows_castfrombmodels; +extern cvar_t r_shadows_throwdistance; +extern cvar_t r_shadows_throwdirection; +extern cvar_t r_shadows_focus; +extern cvar_t r_shadows_shadowmapscale; +extern cvar_t r_shadows_shadowmapbias; +extern cvar_t r_transparent_alphatocoverage; +extern cvar_t r_transparent_sortsurfacesbynearest; +extern cvar_t r_transparent_useplanardistance; +extern cvar_t r_transparent_sortarraysize; +extern cvar_t r_transparent_sortmindist; +extern cvar_t r_transparent_sortmaxdist; + +void R_Model_Sprite_Draw(entity_render_t *ent); + +struct prvm_prog_s; +void R_UpdateFog(void); +qboolean CL_VM_UpdateView(double frametime); +void SCR_DrawConsole(void); +void R_Shadow_EditLights_DrawSelectedLightProperties(void); +void R_DecalSystem_Reset(decalsystem_t *decalsystem); +void R_Shadow_UpdateBounceGridTexture(void); +void R_DrawLightningBeams(void); +void VM_CL_AddPolygonsToMeshQueue(struct prvm_prog_s *prog); +void R_DrawPortals(void); +void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture); +void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); +void R_Water_AddWaterPlane(msurface_t *surface, int entno); +int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color); +dp_font_t *FindFont(const char *title, qboolean allocate_new); +void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, float voffset); + +void Render_Init(void); + +// these are called by Render_Init +void R_Textures_Init(void); +void GL_Draw_Init(void); +void GL_Main_Init(void); +void R_Shadow_Init(void); +void R_Sky_Init(void); +void GL_Surf_Init(void); +void R_Particles_Init(void); +void R_Explosion_Init(void); +void gl_backend_init(void); +void Sbar_Init(void); +void R_LightningBeams_Init(void); +void Mod_RenderInit(void); +void Font_Init(void); + +qboolean R_CompileShader_CheckStaticParms(void); +void R_GLSL_Restart_f(void); + +#endif diff --git a/app/jni/resource.h b/app/jni/resource.h new file mode 100644 index 0000000..27fc918 --- /dev/null +++ b/app/jni/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by darkplaces.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/app/jni/sbar.c b/app/jni/sbar.c new file mode 100644 index 0000000..a43a5d3 --- /dev/null +++ b/app/jni/sbar.c @@ -0,0 +1,2238 @@ +/* +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" +#include +#include "cl_collision.h" +#include "csprogs.h" + +cachepic_t *sb_disc; + +#define STAT_MINUS 10 // num frame for '-' stats digit +cachepic_t *sb_nums[2][11]; +cachepic_t *sb_colon, *sb_slash; +cachepic_t *sb_ibar; +cachepic_t *sb_sbar; +cachepic_t *sb_scorebar; +// AK only used by NEX +cachepic_t *sb_sbar_minimal; +cachepic_t *sb_sbar_overlay; + +// AK changed the bound to 9 +cachepic_t *sb_weapons[7][9]; // 0 is active, 1 is owned, 2-5 are flashes +cachepic_t *sb_ammo[4]; +cachepic_t *sb_sigil[4]; +cachepic_t *sb_armor[3]; +cachepic_t *sb_items[32]; + +// 0-4 are based on health (in 20 increments) +// 0 is static, 1 is temporary animation +cachepic_t *sb_faces[5][2]; +cachepic_t *sb_health; // GAME_NEXUIZ + +cachepic_t *sb_face_invis; +cachepic_t *sb_face_quad; +cachepic_t *sb_face_invuln; +cachepic_t *sb_face_invis_invuln; + +qboolean sb_showscores; + +int sb_lines; // scan lines to draw + +cachepic_t *rsb_invbar[2]; +cachepic_t *rsb_weapons[5]; +cachepic_t *rsb_items[2]; +cachepic_t *rsb_ammo[3]; +cachepic_t *rsb_teambord; // PGM 01/19/97 - team color border + +//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher +cachepic_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 +cachepic_t *hsb_items[2]; + +cachepic_t *zymsb_crosshair_center; +cachepic_t *zymsb_crosshair_line; +cachepic_t *zymsb_crosshair_health; +cachepic_t *zymsb_crosshair_ammo; +cachepic_t *zymsb_crosshair_clip; +cachepic_t *zymsb_crosshair_background; +cachepic_t *zymsb_crosshair_left1; +cachepic_t *zymsb_crosshair_left2; +cachepic_t *zymsb_crosshair_right; + +cachepic_t *sb_ranking; +cachepic_t *sb_complete; +cachepic_t *sb_inter; +cachepic_t *sb_finale; + +cvar_t showfps = {CVAR_SAVE, "showfps", "0", "shows your rendered fps (frames per second)"}; +cvar_t showsound = {CVAR_SAVE, "showsound", "0", "shows number of active sound sources, sound latency, and other statistics"}; +cvar_t showblur = {CVAR_SAVE, "showblur", "0", "shows the current alpha level of motionblur"}; +cvar_t showspeed = {CVAR_SAVE, "showspeed", "0", "shows your current speed (qu per second); number selects unit: 1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots"}; +cvar_t showtopspeed = {CVAR_SAVE, "showtopspeed", "0", "shows your top speed (kept on screen for max 3 seconds); value -1 takes over the unit from showspeed, otherwise it's an unit number just like in showspeed"}; +cvar_t showtime = {CVAR_SAVE, "showtime", "0", "shows current time of day (useful on screenshots)"}; +cvar_t showtime_format = {CVAR_SAVE, "showtime_format", "%H:%M:%S", "format string for time of day"}; +cvar_t showdate = {CVAR_SAVE, "showdate", "0", "shows current date (useful on screenshots)"}; +cvar_t showdate_format = {CVAR_SAVE, "showdate_format", "%Y-%m-%d", "format string for date"}; +cvar_t showtex = {0, "showtex", "0", "shows the name of the texture on the crosshair (for map debugging)"}; +cvar_t sbar_alpha_bg = {CVAR_SAVE, "sbar_alpha_bg", "0.4", "opacity value of the statusbar background image"}; +cvar_t sbar_alpha_fg = {CVAR_SAVE, "sbar_alpha_fg", "1", "opacity value of the statusbar weapon/item icons and numbers"}; +cvar_t sbar_hudselector = {CVAR_SAVE, "sbar_hudselector", "0", "selects which of the builtin hud layouts to use (meaning is somewhat dependent on gamemode, so nexuiz has a very different set of hud layouts than quake for example)"}; +cvar_t sbar_scorerank = {CVAR_SAVE, "sbar_scorerank", "1", "shows an overlay for your score (or team score) and rank in the scoreboard"}; +cvar_t sbar_gametime = {CVAR_SAVE, "sbar_gametime", "1", "shows an overlay for the time left in the current match/level (or current game time if there is no timelimit set)"}; +cvar_t sbar_miniscoreboard_size = {CVAR_SAVE, "sbar_miniscoreboard_size", "-1", "sets the size of the mini deathmatch overlay in items, or disables it when set to 0, or sets it to a sane default when set to -1"}; +cvar_t sbar_flagstatus_right = {CVAR_SAVE, "sbar_flagstatus_right", "0", "moves Nexuiz flag status icons to the right"}; +cvar_t sbar_flagstatus_pos = {CVAR_SAVE, "sbar_flagstatus_pos", "115", "pixel position of the Nexuiz flag status icons, from the bottom"}; +cvar_t sbar_info_pos = {CVAR_SAVE, "sbar_info_pos", "180", "pixel position of the info strings (such as showfps), from the bottom"}; + +cvar_t cl_deathscoreboard = {0, "cl_deathscoreboard", "1", "shows scoreboard (+showscores) while dead"}; + +cvar_t crosshair_color_red = {CVAR_SAVE, "crosshair_color_red", "1", "customizable crosshair color"}; +cvar_t crosshair_color_green = {CVAR_SAVE, "crosshair_color_green", "0", "customizable crosshair color"}; +cvar_t crosshair_color_blue = {CVAR_SAVE, "crosshair_color_blue", "0", "customizable crosshair color"}; +cvar_t crosshair_color_alpha = {CVAR_SAVE, "crosshair_color_alpha", "1", "how opaque the crosshair should be"}; +cvar_t crosshair_size = {CVAR_SAVE, "crosshair_size", "1", "adjusts size of the crosshair on the screen"}; + +static void Sbar_MiniDeathmatchOverlay (int x, int y); +static void Sbar_DeathmatchOverlay (void); +static void Sbar_IntermissionOverlay (void); +static void Sbar_FinaleOverlay (void); + + +extern qboolean vrMode; +extern vec3_t hmdorientation; +extern cvar_t r_worldscale; + +//Calculate the y-offset of the status bar dependent on where the user is looking +int Sbar_GetYOffset() +{ + if (hmdorientation[PITCH] <= 15.0f || !vrMode) + return 0; + + int offset = (vid_conheight.value * ((hmdorientation[PITCH] - 15.0f) / 90.0f)); + if (offset < 0) offset = 0; + return offset; +} + +int Sbar_GetXOffset() +{ + if (!vrMode) + return 0; + + //This will give the status bar depth in the 3D space + return (r_stereo_side ? -20 : 20); +} + +/* +=============== +Sbar_ShowScores + +Tab key down +=============== +*/ +static void Sbar_ShowScores (void) +{ + if (sb_showscores) + return; + sb_showscores = true; + CL_VM_UpdateShowingScoresState(sb_showscores); +} + +/* +=============== +Sbar_DontShowScores + +Tab key up +=============== +*/ +static void Sbar_DontShowScores (void) +{ + sb_showscores = false; + CL_VM_UpdateShowingScoresState(sb_showscores); +} + +static void sbar_start(void) +{ + char vabuf[1024]; + int i; + + if (gamemode == GAME_DELUXEQUAKE || gamemode == GAME_BLOODOMNICIDE) + { + } + else if (gamemode == GAME_NEXUIZ) + { + for (i = 0;i < 10;i++) + sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET); + sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET); + sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET); + + sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET); + sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_bullets", CACHEPICFLAG_QUIET); + sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET); + sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET); + + sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor", CACHEPICFLAG_QUIET); + sb_armor[1] = NULL; + sb_armor[2] = NULL; + + sb_health = Draw_CachePic_Flags ("gfx/sb_health", CACHEPICFLAG_QUIET); + + sb_items[2] = Draw_CachePic_Flags ("gfx/sb_slowmo", CACHEPICFLAG_QUIET); + sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invinc", CACHEPICFLAG_QUIET); + sb_items[4] = Draw_CachePic_Flags ("gfx/sb_energy", CACHEPICFLAG_QUIET); + sb_items[5] = Draw_CachePic_Flags ("gfx/sb_str", CACHEPICFLAG_QUIET); + + sb_items[11] = Draw_CachePic_Flags ("gfx/sb_flag_red_taken", CACHEPICFLAG_QUIET); + sb_items[12] = Draw_CachePic_Flags ("gfx/sb_flag_red_lost", CACHEPICFLAG_QUIET); + sb_items[13] = Draw_CachePic_Flags ("gfx/sb_flag_red_carrying", CACHEPICFLAG_QUIET); + sb_items[14] = Draw_CachePic_Flags ("gfx/sb_key_carrying", CACHEPICFLAG_QUIET); + sb_items[15] = Draw_CachePic_Flags ("gfx/sb_flag_blue_taken", CACHEPICFLAG_QUIET); + sb_items[16] = Draw_CachePic_Flags ("gfx/sb_flag_blue_lost", CACHEPICFLAG_QUIET); + sb_items[17] = Draw_CachePic_Flags ("gfx/sb_flag_blue_carrying", CACHEPICFLAG_QUIET); + + sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET); + sb_sbar_minimal = Draw_CachePic_Flags ("gfx/sbar_minimal", CACHEPICFLAG_QUIET); + sb_sbar_overlay = Draw_CachePic_Flags ("gfx/sbar_overlay", CACHEPICFLAG_QUIET); + + for(i = 0; i < 9;i++) + sb_weapons[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inv_weapon%i",i), CACHEPICFLAG_QUIET); + } + else if (gamemode == GAME_ZYMOTIC) + { + zymsb_crosshair_center = Draw_CachePic_Flags ("gfx/hud/crosshair_center", CACHEPICFLAG_QUIET); + zymsb_crosshair_line = Draw_CachePic_Flags ("gfx/hud/crosshair_line", CACHEPICFLAG_QUIET); + zymsb_crosshair_health = Draw_CachePic_Flags ("gfx/hud/crosshair_health", CACHEPICFLAG_QUIET); + zymsb_crosshair_clip = Draw_CachePic_Flags ("gfx/hud/crosshair_clip", CACHEPICFLAG_QUIET); + zymsb_crosshair_ammo = Draw_CachePic_Flags ("gfx/hud/crosshair_ammo", CACHEPICFLAG_QUIET); + zymsb_crosshair_background = Draw_CachePic_Flags ("gfx/hud/crosshair_background", CACHEPICFLAG_QUIET); + zymsb_crosshair_left1 = Draw_CachePic_Flags ("gfx/hud/crosshair_left1", CACHEPICFLAG_QUIET); + zymsb_crosshair_left2 = Draw_CachePic_Flags ("gfx/hud/crosshair_left2", CACHEPICFLAG_QUIET); + zymsb_crosshair_right = Draw_CachePic_Flags ("gfx/hud/crosshair_right", CACHEPICFLAG_QUIET); + } + else + { + sb_disc = Draw_CachePic_Flags ("gfx/disc", CACHEPICFLAG_QUIET); + + for (i = 0;i < 10;i++) + { + sb_nums[0][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/num_%i",i), CACHEPICFLAG_QUIET); + sb_nums[1][i] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/anum_%i",i), CACHEPICFLAG_QUIET); + } + + sb_nums[0][10] = Draw_CachePic_Flags ("gfx/num_minus", CACHEPICFLAG_QUIET); + sb_nums[1][10] = Draw_CachePic_Flags ("gfx/anum_minus", CACHEPICFLAG_QUIET); + + sb_colon = Draw_CachePic_Flags ("gfx/num_colon", CACHEPICFLAG_QUIET); + sb_slash = Draw_CachePic_Flags ("gfx/num_slash", CACHEPICFLAG_QUIET); + + sb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_shotgun", CACHEPICFLAG_QUIET); + sb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_sshotgun", CACHEPICFLAG_QUIET); + sb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_nailgun", CACHEPICFLAG_QUIET); + sb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_snailgun", CACHEPICFLAG_QUIET); + sb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_rlaunch", CACHEPICFLAG_QUIET); + sb_weapons[0][5] = Draw_CachePic_Flags ("gfx/inv_srlaunch", CACHEPICFLAG_QUIET); + sb_weapons[0][6] = Draw_CachePic_Flags ("gfx/inv_lightng", CACHEPICFLAG_QUIET); + + sb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_shotgun", CACHEPICFLAG_QUIET); + sb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_sshotgun", CACHEPICFLAG_QUIET); + sb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_nailgun", CACHEPICFLAG_QUIET); + sb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_snailgun", CACHEPICFLAG_QUIET); + sb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_rlaunch", CACHEPICFLAG_QUIET); + sb_weapons[1][5] = Draw_CachePic_Flags ("gfx/inv2_srlaunch", CACHEPICFLAG_QUIET); + sb_weapons[1][6] = Draw_CachePic_Flags ("gfx/inv2_lightng", CACHEPICFLAG_QUIET); + + for (i = 0;i < 5;i++) + { + sb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_shotgun",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_sshotgun",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_nailgun",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_snailgun",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_rlaunch",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][5] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_srlaunch",i+1), CACHEPICFLAG_QUIET); + sb_weapons[2+i][6] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_lightng",i+1), CACHEPICFLAG_QUIET); + } + + sb_ammo[0] = Draw_CachePic_Flags ("gfx/sb_shells", CACHEPICFLAG_QUIET); + sb_ammo[1] = Draw_CachePic_Flags ("gfx/sb_nails", CACHEPICFLAG_QUIET); + sb_ammo[2] = Draw_CachePic_Flags ("gfx/sb_rocket", CACHEPICFLAG_QUIET); + sb_ammo[3] = Draw_CachePic_Flags ("gfx/sb_cells", CACHEPICFLAG_QUIET); + + sb_armor[0] = Draw_CachePic_Flags ("gfx/sb_armor1", CACHEPICFLAG_QUIET); + sb_armor[1] = Draw_CachePic_Flags ("gfx/sb_armor2", CACHEPICFLAG_QUIET); + sb_armor[2] = Draw_CachePic_Flags ("gfx/sb_armor3", CACHEPICFLAG_QUIET); + + sb_items[0] = Draw_CachePic_Flags ("gfx/sb_key1", CACHEPICFLAG_QUIET); + sb_items[1] = Draw_CachePic_Flags ("gfx/sb_key2", CACHEPICFLAG_QUIET); + sb_items[2] = Draw_CachePic_Flags ("gfx/sb_invis", CACHEPICFLAG_QUIET); + sb_items[3] = Draw_CachePic_Flags ("gfx/sb_invuln", CACHEPICFLAG_QUIET); + sb_items[4] = Draw_CachePic_Flags ("gfx/sb_suit", CACHEPICFLAG_QUIET); + sb_items[5] = Draw_CachePic_Flags ("gfx/sb_quad", CACHEPICFLAG_QUIET); + + sb_sigil[0] = Draw_CachePic_Flags ("gfx/sb_sigil1", CACHEPICFLAG_QUIET); + sb_sigil[1] = Draw_CachePic_Flags ("gfx/sb_sigil2", CACHEPICFLAG_QUIET); + sb_sigil[2] = Draw_CachePic_Flags ("gfx/sb_sigil3", CACHEPICFLAG_QUIET); + sb_sigil[3] = Draw_CachePic_Flags ("gfx/sb_sigil4", CACHEPICFLAG_QUIET); + + sb_faces[4][0] = Draw_CachePic_Flags ("gfx/face1", CACHEPICFLAG_QUIET); + sb_faces[4][1] = Draw_CachePic_Flags ("gfx/face_p1", CACHEPICFLAG_QUIET); + sb_faces[3][0] = Draw_CachePic_Flags ("gfx/face2", CACHEPICFLAG_QUIET); + sb_faces[3][1] = Draw_CachePic_Flags ("gfx/face_p2", CACHEPICFLAG_QUIET); + sb_faces[2][0] = Draw_CachePic_Flags ("gfx/face3", CACHEPICFLAG_QUIET); + sb_faces[2][1] = Draw_CachePic_Flags ("gfx/face_p3", CACHEPICFLAG_QUIET); + sb_faces[1][0] = Draw_CachePic_Flags ("gfx/face4", CACHEPICFLAG_QUIET); + sb_faces[1][1] = Draw_CachePic_Flags ("gfx/face_p4", CACHEPICFLAG_QUIET); + sb_faces[0][0] = Draw_CachePic_Flags ("gfx/face5", CACHEPICFLAG_QUIET); + sb_faces[0][1] = Draw_CachePic_Flags ("gfx/face_p5", CACHEPICFLAG_QUIET); + + sb_face_invis = Draw_CachePic_Flags ("gfx/face_invis", CACHEPICFLAG_QUIET); + sb_face_invuln = Draw_CachePic_Flags ("gfx/face_invul2", CACHEPICFLAG_QUIET); + sb_face_invis_invuln = Draw_CachePic_Flags ("gfx/face_inv2", CACHEPICFLAG_QUIET); + sb_face_quad = Draw_CachePic_Flags ("gfx/face_quad", CACHEPICFLAG_QUIET); + + sb_sbar = Draw_CachePic_Flags ("gfx/sbar", CACHEPICFLAG_QUIET); + sb_ibar = Draw_CachePic_Flags ("gfx/ibar", CACHEPICFLAG_QUIET); + sb_scorebar = Draw_CachePic_Flags ("gfx/scorebar", CACHEPICFLAG_QUIET); + + //MED 01/04/97 added new hipnotic weapons + if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) + { + hsb_weapons[0][0] = Draw_CachePic_Flags ("gfx/inv_laser", CACHEPICFLAG_QUIET); + hsb_weapons[0][1] = Draw_CachePic_Flags ("gfx/inv_mjolnir", CACHEPICFLAG_QUIET); + hsb_weapons[0][2] = Draw_CachePic_Flags ("gfx/inv_gren_prox", CACHEPICFLAG_QUIET); + hsb_weapons[0][3] = Draw_CachePic_Flags ("gfx/inv_prox_gren", CACHEPICFLAG_QUIET); + hsb_weapons[0][4] = Draw_CachePic_Flags ("gfx/inv_prox", CACHEPICFLAG_QUIET); + + hsb_weapons[1][0] = Draw_CachePic_Flags ("gfx/inv2_laser", CACHEPICFLAG_QUIET); + hsb_weapons[1][1] = Draw_CachePic_Flags ("gfx/inv2_mjolnir", CACHEPICFLAG_QUIET); + hsb_weapons[1][2] = Draw_CachePic_Flags ("gfx/inv2_gren_prox", CACHEPICFLAG_QUIET); + hsb_weapons[1][3] = Draw_CachePic_Flags ("gfx/inv2_prox_gren", CACHEPICFLAG_QUIET); + hsb_weapons[1][4] = Draw_CachePic_Flags ("gfx/inv2_prox", CACHEPICFLAG_QUIET); + + for (i = 0;i < 5;i++) + { + hsb_weapons[2+i][0] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_laser",i+1), CACHEPICFLAG_QUIET); + hsb_weapons[2+i][1] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_mjolnir",i+1), CACHEPICFLAG_QUIET); + hsb_weapons[2+i][2] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_gren_prox",i+1), CACHEPICFLAG_QUIET); + hsb_weapons[2+i][3] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox_gren",i+1), CACHEPICFLAG_QUIET); + hsb_weapons[2+i][4] = Draw_CachePic_Flags (va(vabuf, sizeof(vabuf), "gfx/inva%i_prox",i+1), CACHEPICFLAG_QUIET); + } + + hsb_items[0] = Draw_CachePic_Flags ("gfx/sb_wsuit", CACHEPICFLAG_QUIET); + hsb_items[1] = Draw_CachePic_Flags ("gfx/sb_eshld", CACHEPICFLAG_QUIET); + } + else if (gamemode == GAME_ROGUE) + { + rsb_invbar[0] = Draw_CachePic_Flags ("gfx/r_invbar1", CACHEPICFLAG_QUIET); + rsb_invbar[1] = Draw_CachePic_Flags ("gfx/r_invbar2", CACHEPICFLAG_QUIET); + + rsb_weapons[0] = Draw_CachePic_Flags ("gfx/r_lava", CACHEPICFLAG_QUIET); + rsb_weapons[1] = Draw_CachePic_Flags ("gfx/r_superlava", CACHEPICFLAG_QUIET); + rsb_weapons[2] = Draw_CachePic_Flags ("gfx/r_gren", CACHEPICFLAG_QUIET); + rsb_weapons[3] = Draw_CachePic_Flags ("gfx/r_multirock", CACHEPICFLAG_QUIET); + rsb_weapons[4] = Draw_CachePic_Flags ("gfx/r_plasma", CACHEPICFLAG_QUIET); + + rsb_items[0] = Draw_CachePic_Flags ("gfx/r_shield1", CACHEPICFLAG_QUIET); + rsb_items[1] = Draw_CachePic_Flags ("gfx/r_agrav1", CACHEPICFLAG_QUIET); + + // PGM 01/19/97 - team color border + rsb_teambord = Draw_CachePic_Flags ("gfx/r_teambord", CACHEPICFLAG_QUIET); + // PGM 01/19/97 - team color border + + rsb_ammo[0] = Draw_CachePic_Flags ("gfx/r_ammolava", CACHEPICFLAG_QUIET); + rsb_ammo[1] = Draw_CachePic_Flags ("gfx/r_ammomulti", CACHEPICFLAG_QUIET); + rsb_ammo[2] = Draw_CachePic_Flags ("gfx/r_ammoplasma", CACHEPICFLAG_QUIET); + } + } + + sb_ranking = Draw_CachePic_Flags ("gfx/ranking", CACHEPICFLAG_QUIET); + sb_complete = Draw_CachePic_Flags ("gfx/complete", CACHEPICFLAG_QUIET); + sb_inter = Draw_CachePic_Flags ("gfx/inter", CACHEPICFLAG_QUIET); + sb_finale = Draw_CachePic_Flags ("gfx/finale", CACHEPICFLAG_QUIET); +} + +static void sbar_shutdown(void) +{ +} + +static void sbar_newmap(void) +{ +} + +void Sbar_Init (void) +{ + Cmd_AddCommand("+showscores", Sbar_ShowScores, "show scoreboard"); + Cmd_AddCommand("-showscores", Sbar_DontShowScores, "hide scoreboard"); + Cvar_RegisterVariable(&showfps); + Cvar_RegisterVariable(&showsound); + Cvar_RegisterVariable(&showblur); + Cvar_RegisterVariable(&showspeed); + Cvar_RegisterVariable(&showtopspeed); + Cvar_RegisterVariable(&showtime); + Cvar_RegisterVariable(&showtime_format); + Cvar_RegisterVariable(&showdate); + Cvar_RegisterVariable(&showdate_format); + Cvar_RegisterVariable(&showtex); + Cvar_RegisterVariable(&sbar_alpha_bg); + Cvar_RegisterVariable(&sbar_alpha_fg); + Cvar_RegisterVariable(&sbar_hudselector); + Cvar_RegisterVariable(&sbar_scorerank); + Cvar_RegisterVariable(&sbar_gametime); + Cvar_RegisterVariable(&sbar_miniscoreboard_size); + Cvar_RegisterVariable(&sbar_info_pos); + Cvar_RegisterVariable(&cl_deathscoreboard); + + Cvar_RegisterVariable(&crosshair_color_red); + Cvar_RegisterVariable(&crosshair_color_green); + Cvar_RegisterVariable(&crosshair_color_blue); + Cvar_RegisterVariable(&crosshair_color_alpha); + Cvar_RegisterVariable(&crosshair_size); + + Cvar_RegisterVariable(&sbar_flagstatus_right); // (GAME_NEXUZI ONLY) + Cvar_RegisterVariable(&sbar_flagstatus_pos); // (GAME_NEXUIZ ONLY) + + R_RegisterModule("sbar", sbar_start, sbar_shutdown, sbar_newmap, NULL, NULL); +} + + +//============================================================================= + +// drawing routines are relative to the status bar location + +int sbar_x, sbar_y; + +/* +============= +Sbar_DrawPic +============= +*/ +static void Sbar_DrawStretchPic (int x, int y, cachepic_t *pic, float alpha, float overridewidth, float overrideheight) +{ + DrawQ_Pic (sbar_x + x, sbar_y + y, pic, overridewidth, overrideheight, 1, 1, 1, alpha, 0); +} + +static void Sbar_DrawPic (int x, int y, cachepic_t *pic) +{ + DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, sbar_alpha_fg.value, 0); +} + +static void Sbar_DrawAlphaPic (int x, int y, cachepic_t *pic, float alpha) +{ + DrawQ_Pic (sbar_x + x, sbar_y + y, pic, 0, 0, 1, 1, 1, alpha, 0); +} + +/* +================ +Sbar_DrawCharacter + +Draws one solid graphics character +================ +*/ +static void Sbar_DrawCharacter (int x, int y, int num) +{ + char vabuf[1024]; + DrawQ_String (sbar_x + x + 4 , sbar_y + y, va(vabuf, sizeof(vabuf), "%c", num), 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, true, FONT_SBAR); +} + +/* +================ +Sbar_DrawString +================ +*/ +static void Sbar_DrawString (int x, int y, char *str) +{ + DrawQ_String (sbar_x + x, sbar_y + y, str, 0, 8, 8, 1, 1, 1, sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR); +} + +/* +============= +Sbar_DrawNum +============= +*/ +static void Sbar_DrawNum (int x, int y, int num, int digits, int color) +{ + char str[32], *ptr; + int l, frame; + + l = dpsnprintf(str, sizeof(str), "%i", num); + 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_DrawPic (x, y, sb_nums[color][frame]); + x += 24; + + ptr++; + } +} + +/* +============= +Sbar_DrawXNum +============= +*/ + +static void Sbar_DrawXNum (int x, int y, int num, int digits, int lettersize, float r, float g, float b, float a, int flags) +{ + char str[32], *ptr; + int l, frame; + + if (digits < 0) + { + digits = -digits; + l = dpsnprintf(str, sizeof(str), "%0*i", digits, num); + } + else + l = dpsnprintf(str, sizeof(str), "%i", num); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l) * lettersize; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + DrawQ_Pic (sbar_x + x, sbar_y + y, sb_nums[0][frame],lettersize,lettersize,r,g,b,a * sbar_alpha_fg.value,flags); + x += lettersize; + + ptr++; + } +} + +//============================================================================= + + +static int Sbar_IsTeammatch(void) +{ + // currently only nexuiz uses the team score board + return ((gamemode == GAME_NEXUIZ) + && (teamplay.integer > 0)); +} + +/* +=============== +Sbar_SortFrags +=============== +*/ +static int fragsort[MAX_SCOREBOARD]; +static int scoreboardlines; + +int Sbar_GetSortedPlayerIndex (int index) +{ + return index >= 0 && index < scoreboardlines ? fragsort[index] : -1; +} + +static scoreboard_t teams[MAX_SCOREBOARD]; +static int teamsort[MAX_SCOREBOARD]; +static int teamlines; +void Sbar_SortFrags (void) +{ + int i, j, k, color; + + // sort by frags + scoreboardlines = 0; + for (i=0 ; i max) + str[max] = 0; + + // print the filename and message + Sbar_DrawString(8, 12, str); + + // print the time + Sbar_DrawString(8 + max*8, 12, timestr); + +#else + char str[80]; + int minutes, seconds, tens, units; + int l; + + if (gamemode != GAME_NEXUIZ) { + dpsnprintf (str, sizeof(str), "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); + Sbar_DrawString (8, 4, str); + + dpsnprintf (str, sizeof(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; + dpsnprintf (str, sizeof(str), "Time :%3i:%i%i", minutes, tens, units); + Sbar_DrawString (184, 4, str); + +// draw level name + if (gamemode == GAME_NEXUIZ) { + l = (int) strlen (cl.worldname); + Sbar_DrawString (232 - l*4, 12, cl.worldname); + } else { + l = (int) strlen (cl.worldmessage); + Sbar_DrawString (232 - l*4, 12, cl.worldmessage); + } +#endif +} + +/* +=============== +Sbar_DrawScoreboard +=============== +*/ +static void Sbar_DrawScoreboard (void) +{ + Sbar_SoloScoreboard (); + // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode + //if (cl.gametype == GAME_DEATHMATCH) + if (!cl.islocalgame) + Sbar_DeathmatchOverlay (); +} + +//============================================================================= + +// AK to make DrawInventory smaller +static void Sbar_DrawWeapon(int nr, float fade, int active) +{ + char vabuf[1024]; + if (sbar_hudselector.integer == 1) + { + // width = 300, height = 100 + const int w_width = 32, w_height = 12, w_space = 2, font_size = 8; + + DrawQ_Pic((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr, vid_conheight.integer - w_height, sb_weapons[0][nr], w_width, w_height, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 0.6, (active ? 1 : 0.6) * fade * sbar_alpha_fg.value, DRAWFLAG_NORMAL); + // FIXME ?? + DrawQ_String((vid_conwidth.integer - w_width * 9) * 0.5 + w_width * nr + w_space, vid_conheight.integer - w_height + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 1, 0, sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT); + } + else + { + // width = 300, height = 100 + const int w_width = 300, w_height = 100, w_space = 10; + const float w_scale = 0.4; + + DrawQ_Pic(vid_conwidth.integer - (w_width + w_space) * w_scale, (w_height + w_space) * w_scale * nr + w_space, sb_weapons[0][nr], w_width * w_scale, w_height * w_scale, (active) ? 1 : 0.6, active ? 1 : 0.6, active ? 1 : 1, fade * sbar_alpha_fg.value, DRAWFLAG_NORMAL); + //DrawQ_String(vid_conwidth.integer - (w_space + font_size ), (w_height + w_space) * w_scale * nr + w_space, va(vabuf, sizeof(vabuf), "%i",nr+1), 0, font_size, font_size, 1, 0, 0, fade, 0, NULL, true, FONT_DEFAULT); + } +} + +/* +=============== +Sbar_DrawInventory +=============== +*/ +static void Sbar_DrawInventory (void) +{ + int i; + char num[6]; + float time; + int flashon; + + if (gamemode == GAME_ROGUE) + { + if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + Sbar_DrawAlphaPic (0, -24, rsb_invbar[0], sbar_alpha_bg.value); + else + Sbar_DrawAlphaPic (0, -24, rsb_invbar[1], sbar_alpha_bg.value); + } + else + Sbar_DrawAlphaPic (0, -24, sb_ibar, sbar_alpha_bg.value); + + // weapons + for (i=0 ; i<7 ; i++) + { + if (cl.stats[STAT_ITEMS] & (IT_SHOTGUN<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (1<= 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++) + { + dpsnprintf (num, sizeof(num), "%4i",cl.stats[STAT_SHELLS+i] ); + if (num[0] != ' ') + Sbar_DrawCharacter ( (6*i+0)*8 - 2, -24, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[2] - '0'); + if (num[3] != ' ') + Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[3] - '0'); + } + + // items + for (i=0 ; i<6 ; i++) + if (cl.stats[STAT_ITEMS] & (1<<(17+i))) + { + //MED 01/04/97 changed keys + if (!(gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) || (i>1)) + Sbar_DrawPic (192 + i*16, -16, sb_items[i]); + } + + //MED 01/04/97 added hipnotic items + // hipnotic items + if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) + { + for (i=0 ; i<2 ; i++) + if (cl.stats[STAT_ITEMS] & (1<<(24+i))) + Sbar_DrawPic (288 + i*16, -16, hsb_items[i]); + } + + if (gamemode == GAME_ROGUE) + { + // new rogue items + for (i=0 ; i<2 ; i++) + if (cl.stats[STAT_ITEMS] & (1<<(29+i))) + Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); + } + else + { + // sigils + for (i=0 ; i<4 ; i++) + if (cl.stats[STAT_ITEMS] & (1<<(28+i))) + Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); + } +} + +//============================================================================= + +/* +=============== +Sbar_DrawFrags +=============== +*/ +static void Sbar_DrawFrags (void) +{ + int i, k, l, x, f; + char num[12]; + scoreboard_t *s; + unsigned char *c; + + Sbar_SortFrags (); + + // draw the text + l = min(scoreboardlines, 4); + + x = 23 * 8; + + for (i = 0;i < l;i++) + { + k = fragsort[i]; + s = &cl.scores[k]; + + // draw background + c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4]; + DrawQ_Fill (sbar_x + x + 10, sbar_y - 23, 28, 4, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + c = palette_rgb_shirtscoreboard[s->colors & 0xf]; + DrawQ_Fill (sbar_x + x + 10, sbar_y + 4 - 23, 28, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + + // draw number + f = s->frags; + dpsnprintf (num, sizeof(num), "%3i",f); + + if (k == cl.viewentity - 1) + { + Sbar_DrawCharacter ( x + 2, -24, 16); + Sbar_DrawCharacter ( x + 32 - 4, -24, 17); + } + Sbar_DrawCharacter (x + 8, -24, num[0]); + Sbar_DrawCharacter (x + 16, -24, num[1]); + Sbar_DrawCharacter (x + 24, -24, num[2]); + x += 32; + } +} + +//============================================================================= + + +/* +=============== +Sbar_DrawFace +=============== +*/ +static void Sbar_DrawFace (void) +{ + int f; + +// PGM 01/19/97 - team color drawing +// PGM 03/02/97 - fixed so color swatch only appears in CTF modes + if (gamemode == GAME_ROGUE && !cl.islocalgame && (teamplay.integer > 3) && (teamplay.integer < 7)) + { + char num[12]; + scoreboard_t *s; + unsigned char *c; + + s = &cl.scores[cl.viewentity - 1]; + // draw background + Sbar_DrawPic (112, 0, rsb_teambord); + c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4]; + DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+3, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + c = palette_rgb_shirtscoreboard[s->colors & 0xf]; + DrawQ_Fill (sbar_x + 113, vid_conheight.integer-SBAR_HEIGHT+12, 22, 9, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + + // draw number + f = s->frags; + dpsnprintf (num, sizeof(num), "%3i",f); + + if ((s->colors & 0xf0)==0) + { + 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.stats[STAT_ITEMS] & (IT_INVISIBILITY | IT_INVULNERABILITY) ) == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + Sbar_DrawPic (112, 0, sb_face_invis_invuln); + else if (cl.stats[STAT_ITEMS] & IT_QUAD) + Sbar_DrawPic (112, 0, sb_face_quad ); + else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) + Sbar_DrawPic (112, 0, sb_face_invis ); + else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) + Sbar_DrawPic (112, 0, sb_face_invuln); + else + { + f = cl.stats[STAT_HEALTH] / 20; + f = bound(0, f, 4); + Sbar_DrawPic (112, 0, sb_faces[f][cl.time <= cl.faceanimtime]); + } +} +double topspeed = 0; +double topspeedxy = 0; +time_t current_time = 3; +time_t top_time = 0; +time_t topxy_time = 0; + +static void get_showspeed_unit(int unitnumber, double *conversion_factor, const char **unit) +{ + if(unitnumber < 0) + unitnumber = showspeed.integer; + switch(unitnumber) + { + default: + case 1: + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + *unit = "in/s"; + else + *unit = "qu/s"; + *conversion_factor = 1.0; + break; + case 2: + *unit = "m/s"; + *conversion_factor = 0.0254; + if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5; + // 1qu=1.5in is for non-Nexuiz/Xonotic only - Nexuiz/Xonotic players are overly large, but 1qu=1in fixes that + break; + case 3: + *unit = "km/h"; + *conversion_factor = 0.0254 * 3.6; + if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5; + break; + case 4: + *unit = "mph"; + *conversion_factor = 0.0254 * 3.6 * 0.6213711922; + if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5; + break; + case 5: + *unit = "knots"; + *conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h + if(gamemode != GAME_NEXUIZ && gamemode != GAME_XONOTIC) *conversion_factor *= 1.5; + break; + } +} + +static double showfps_nexttime = 0, showfps_lasttime = -1; +static double showfps_framerate = 0; +static int showfps_framecount = 0; + +void Sbar_ShowFPS_Update(void) +{ + double interval = 1; + double newtime; + newtime = realtime; + if (newtime >= showfps_nexttime) + { + showfps_framerate = showfps_framecount / (newtime - showfps_lasttime); + if (showfps_nexttime < newtime - interval * 1.5) + showfps_nexttime = newtime; + showfps_lasttime = newtime; + showfps_nexttime += interval; + showfps_framecount = 0; + } + showfps_framecount++; +} + +void Sbar_ShowFPS(void) +{ + float fps_x, fps_y, fps_scalex, fps_scaley, fps_strings = 0; + char soundstring[32]; + char fpsstring[32]; + char timestring[32]; + char datestring[32]; + char timedemostring1[32]; + char timedemostring2[32]; + char speedstring[32]; + char blurstring[32]; + char topspeedstring[48]; + char texstring[MAX_QPATH]; + qboolean red = false; + soundstring[0] = 0; + fpsstring[0] = 0; + timedemostring1[0] = 0; + timedemostring2[0] = 0; + timestring[0] = 0; + datestring[0] = 0; + speedstring[0] = 0; + blurstring[0] = 0; + texstring[0] = 0; + topspeedstring[0] = 0; + if (showfps.integer) + { + red = (showfps_framerate < 1.0f); + if(showfps.integer == 2) + dpsnprintf(fpsstring, sizeof(fpsstring), "%7.3f mspf", (1000.0 / showfps_framerate)); + else if (red) + dpsnprintf(fpsstring, sizeof(fpsstring), "%4i spf", (int)(1.0 / showfps_framerate + 0.5)); + else + dpsnprintf(fpsstring, sizeof(fpsstring), "%4i fps", (int)(showfps_framerate + 0.5)); + fps_strings++; + if (cls.timedemo) + { + dpsnprintf(timedemostring1, sizeof(timedemostring1), "frame%4i %f", cls.td_frames, realtime - cls.td_starttime); + dpsnprintf(timedemostring2, sizeof(timedemostring2), "%i seconds %3.0f/%3.0f/%3.0f fps", cls.td_onesecondavgcount, cls.td_onesecondminfps, cls.td_onesecondavgfps / max(1, cls.td_onesecondavgcount), cls.td_onesecondmaxfps); + fps_strings++; + fps_strings++; + } + } + if (showtime.integer) + { + strlcpy(timestring, Sys_TimeString(showtime_format.string), sizeof(timestring)); + fps_strings++; + } + if (showdate.integer) + { + strlcpy(datestring, Sys_TimeString(showdate_format.string), sizeof(datestring)); + fps_strings++; + } + if (showblur.integer) + { + dpsnprintf(blurstring, sizeof(blurstring), "%3i%% blur", (int)(cl.motionbluralpha * 100)); + fps_strings++; + } + if (showsound.integer) + { + dpsnprintf(soundstring, sizeof(soundstring), "%4i/4%i at %3ims", cls.soundstats.mixedsounds, cls.soundstats.totalsounds, cls.soundstats.latency_milliseconds); + fps_strings++; + } + if (showspeed.integer || showtopspeed.integer) + { + double speed, speedxy, f; + const char *unit; + speed = VectorLength(cl.movement_velocity); + speedxy = sqrt(cl.movement_velocity[0] * cl.movement_velocity[0] + cl.movement_velocity[1] * cl.movement_velocity[1]); + if (showspeed.integer) + { + get_showspeed_unit(showspeed.integer, &f, &unit); + dpsnprintf(speedstring, sizeof(speedstring), "%.0f (%.0f) %s", f*speed, f*speedxy, unit); + fps_strings++; + } + if (showtopspeed.integer) + { + qboolean topspeed_latched = false, topspeedxy_latched = false; + get_showspeed_unit(showtopspeed.integer, &f, &unit); + if (speed >= topspeed || current_time - top_time > 3) + { + topspeed = speed; + time(&top_time); + } + else + topspeed_latched = true; + if (speedxy >= topspeedxy || current_time - topxy_time > 3) + { + topspeedxy = speedxy; + time(&topxy_time); + } + else + topspeedxy_latched = true; + dpsnprintf(topspeedstring, sizeof(topspeedstring), "%s%.0f%s (%s%.0f%s) %s", + topspeed_latched ? "^1" : "^xf88", f*topspeed, "^xf88", + topspeedxy_latched ? "^1" : "^xf88", f*topspeedxy, "^xf88", + unit); + time(¤t_time); + fps_strings++; + } + } + if (showtex.integer) + { + vec3_t org; + vec3_t dest; + vec3_t temp; + trace_t trace; + + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, org); + VectorSet(temp, 65536, 0, 0); + Matrix4x4_Transform(&r_refdef.view.matrix, temp, dest); + trace.hittexture = NULL; // to make sure + // TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip + // probably needs adding a new SUPERCONTENTS type + trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true); + if(trace.hittexture) + strlcpy(texstring, trace.hittexture->name, sizeof(texstring)); + else + strlcpy(texstring, "(no texture hit)", sizeof(texstring)); + fps_strings++; + } + if (fps_strings) + { + fps_scalex = 12; + fps_scaley = 12; + //fps_y = vid_conheight.integer - sb_lines; // yes this may draw over the sbar + //fps_y = bound(0, fps_y, vid_conheight.integer - fps_strings*fps_scaley); + fps_y = vid_conheight.integer - sbar_info_pos.integer - fps_strings*fps_scaley; + if (soundstring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(soundstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, soundstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (fpsstring[0]) + { + r_draw2d_force = true; + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(fpsstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + if (red) + DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 0, 0, 1, 0, NULL, true, FONT_INFOBAR); + else + DrawQ_String(fps_x, fps_y, fpsstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + r_draw2d_force = false; + } + if (timedemostring1[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(timedemostring1, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, timedemostring1, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (timedemostring2[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(timedemostring2, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, timedemostring2, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (timestring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(timestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, timestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (datestring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(datestring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, datestring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (speedstring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(speedstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, speedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (topspeedstring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(topspeedstring, 0, fps_scalex, fps_scaley, false, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, topspeedstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, false, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (blurstring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(blurstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, blurstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + if (texstring[0]) + { + fps_x = (vid_conwidth.integer / 2) - (DrawQ_TextWidth(texstring, 0, fps_scalex, fps_scaley, true, FONT_INFOBAR) / 2) + Sbar_GetXOffset(); + DrawQ_String(fps_x, fps_y, texstring, 0, fps_scalex, fps_scaley, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + fps_y += fps_scaley; + } + } +} + +static void Sbar_DrawGauge(float x, float y, cachepic_t *pic, float width, float height, float rangey, float rangeheight, float c1, float c2, float c1r, float c1g, float c1b, float c1a, float c2r, float c2g, float c2b, float c2a, float c3r, float c3g, float c3b, float c3a, int drawflags) +{ + float r[5]; + c2 = bound(0, c2, 1); + c1 = bound(0, c1, 1 - c2); + r[0] = 0; + r[1] = rangey + rangeheight * (c2 + c1); + r[2] = rangey + rangeheight * (c2); + r[3] = rangey; + r[4] = height; + if (r[1] > r[0]) + DrawQ_SuperPic(x, y + r[0], pic, width, (r[1] - r[0]), 0,(r[0] / height), c3r,c3g,c3b,c3a, 1,(r[0] / height), c3r,c3g,c3b,c3a, 0,(r[1] / height), c3r,c3g,c3b,c3a, 1,(r[1] / height), c3r,c3g,c3b,c3a, drawflags); + if (r[2] > r[1]) + DrawQ_SuperPic(x, y + r[1], pic, width, (r[2] - r[1]), 0,(r[1] / height), c1r,c1g,c1b,c1a, 1,(r[1] / height), c1r,c1g,c1b,c1a, 0,(r[2] / height), c1r,c1g,c1b,c1a, 1,(r[2] / height), c1r,c1g,c1b,c1a, drawflags); + if (r[3] > r[2]) + DrawQ_SuperPic(x, y + r[2], pic, width, (r[3] - r[2]), 0,(r[2] / height), c2r,c2g,c2b,c2a, 1,(r[2] / height), c2r,c2g,c2b,c2a, 0,(r[3] / height), c2r,c2g,c2b,c2a, 1,(r[3] / height), c2r,c2g,c2b,c2a, drawflags); + if (r[4] > r[3]) + DrawQ_SuperPic(x, y + r[3], pic, width, (r[4] - r[3]), 0,(r[3] / height), c3r,c3g,c3b,c3a, 1,(r[3] / height), c3r,c3g,c3b,c3a, 0,(r[4] / height), c3r,c3g,c3b,c3a, 1,(r[4] / height), c3r,c3g,c3b,c3a, drawflags); +} + +/* +=============== +Sbar_Draw +=============== +*/ +extern float v_dmg_time, v_dmg_roll, v_dmg_pitch; +extern cvar_t v_kicktime; +void Sbar_Score (int margin); +void Sbar_Draw (void) +{ + cachepic_t *pic; + char vabuf[1024]; + + if(cl.csqc_vidvars.drawenginesbar) //[515]: csqc drawsbar + { + if (sb_showscores) + Sbar_DrawScoreboard (); + else if (cl.intermission == 1) + { + if(gamemode == GAME_NEXUIZ) // display full scoreboard (that is, show scores + map name) + { + Sbar_DrawScoreboard(); + return; + } + Sbar_IntermissionOverlay(); + } + else if (cl.intermission == 2) + Sbar_FinaleOverlay(); + else if (gamemode == GAME_DELUXEQUAKE) + { + } + else if (gamemode == GAME_NEXUIZ) + { + if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer)) + { + sbar_x = (vid_conwidth.integer - 640)/2 + Sbar_GetXOffset(); + sbar_y = vid_conheight.integer - (Sbar_GetYOffset() + 40); + Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value); + Sbar_DrawScoreboard (); + } + else if (sb_lines && sbar_hudselector.integer == 1) + { + int i; + float fade; + int redflag, blueflag; + float x; + + sbar_x = (vid_conwidth.integer - 320)/2 + Sbar_GetXOffset(); + sbar_y = vid_conheight.integer - (Sbar_GetYOffset() + 40); + + // calculate intensity to draw weapons bar at + fade = 3.2 - 2 * (cl.time - cl.weapontime); + fade = bound(0.7, fade, 1); + for (i = 0; i < 8;i++) + if (cl.stats[STAT_ITEMS] & (1 << i)) + Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON])); + if((cl.stats[STAT_ITEMS] & (1<<12))) + Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1)); + + // flag icons + redflag = ((cl.stats[STAT_ITEMS]>>15) & 3); + blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3); + x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x; + if (redflag == 3 && blueflag == 3) + { + // The Impossible Combination[tm] + // Can only happen in Key Hunt mode... + Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[14]); + } + else + { + if (redflag) + Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 64)), sb_items[redflag+10]); + if (blueflag) + Sbar_DrawPic ((int) x, (int) ((vid_conheight.integer - sbar_y) - (sbar_flagstatus_pos.value + 128)), sb_items[blueflag+14]); + } + + // armor + if (cl.stats[STAT_ARMOR] > 0) + { + Sbar_DrawStretchPic (72, 0, sb_armor[0], sbar_alpha_fg.value, 24, 24); + if(cl.stats[STAT_ARMOR] > 200) + Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0,1,0,1,0); + else if(cl.stats[STAT_ARMOR] > 100) + Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.2,1,0.2,1,0); + else if(cl.stats[STAT_ARMOR] > 50) + Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.6,0.7,0.8,1,0); + else if(cl.stats[STAT_ARMOR] > 25) + Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,1,1,0.2,1,0); + else + Sbar_DrawXNum(0,0,cl.stats[STAT_ARMOR],3,24,0.7,0,0,1,0); + } + + // health + if (cl.stats[STAT_HEALTH] != 0) + { + Sbar_DrawStretchPic (184, 0, sb_health, sbar_alpha_fg.value, 24, 24); + if(cl.stats[STAT_HEALTH] > 200) + Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0,1,0,1,0); + else if(cl.stats[STAT_HEALTH] > 100) + Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.2,1,0.2,1,0); + else if(cl.stats[STAT_HEALTH] > 50) + Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0); + else if(cl.stats[STAT_HEALTH] > 25) + Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,1,1,0.2,1,0); + else + Sbar_DrawXNum(112,0,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0); + } + + // ammo + if ((cl.stats[STAT_ITEMS] & (NEX_IT_SHELLS | NEX_IT_BULLETS | NEX_IT_ROCKETS | NEX_IT_CELLS)) || cl.stats[STAT_AMMO] != 0) + { + if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS) + Sbar_DrawStretchPic (296, 0, sb_ammo[0], sbar_alpha_fg.value, 24, 24); + else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS) + Sbar_DrawStretchPic (296, 0, sb_ammo[1], sbar_alpha_fg.value, 24, 24); + else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS) + Sbar_DrawStretchPic (296, 0, sb_ammo[2], sbar_alpha_fg.value, 24, 24); + else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS) + Sbar_DrawStretchPic (296, 0, sb_ammo[3], sbar_alpha_fg.value, 24, 24); + if(cl.stats[STAT_AMMO] > 10) + Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.6,0.7,0.8,1,0); + else + Sbar_DrawXNum(224, 0, cl.stats[STAT_AMMO], 3, 24, 0.7,0,0,1,0); + } + + if (sbar_x + 320 + 160 <= vid_conwidth.integer) + Sbar_MiniDeathmatchOverlay (sbar_x + 320, sbar_y); + if (sbar_x > 0) + Sbar_Score(16); + // The margin can be at most 8 to support 640x480 console size: + // 320 + 2 * (144 + 16) = 640 + } + else if (sb_lines) + { + int i; + float fade; + int redflag, blueflag; + float x; + + sbar_x = (vid_conwidth.integer - 640)/2 + Sbar_GetXOffset(); + sbar_y = vid_conheight.integer - (Sbar_GetYOffset() + 40); + + // calculate intensity to draw weapons bar at + fade = 3 - 2 * (cl.time - cl.weapontime); + if (fade > 0) + { + fade = min(fade, 1); + for (i = 0; i < 8;i++) + if (cl.stats[STAT_ITEMS] & (1 << i)) + Sbar_DrawWeapon(i + 1, fade, (i + 2 == cl.stats[STAT_ACTIVEWEAPON])); + + if((cl.stats[STAT_ITEMS] & (1<<12))) + Sbar_DrawWeapon(0, fade, (cl.stats[STAT_ACTIVEWEAPON] == 1)); + } + + //if (!cl.islocalgame) + // Sbar_DrawFrags (); + + if (sb_lines > 24) + Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_fg.value); + else + Sbar_DrawAlphaPic (0, 0, sb_sbar_minimal, sbar_alpha_fg.value); + + // flag icons + redflag = ((cl.stats[STAT_ITEMS]>>15) & 3); + blueflag = ((cl.stats[STAT_ITEMS]>>17) & 3); + x = sbar_flagstatus_right.integer ? vid_conwidth.integer - 10 - sbar_x - 64 : 10 - sbar_x; + if (redflag == 3 && blueflag == 3) + { + // The Impossible Combination[tm] + // Can only happen in Key Hunt mode... + Sbar_DrawPic ((int) x, -179, sb_items[14]); + } + else + { + if (redflag) + Sbar_DrawPic ((int) x, -117, sb_items[redflag+10]); + if (blueflag) + Sbar_DrawPic ((int) x, -177, sb_items[blueflag+14]); + } + + // armor + Sbar_DrawXNum ((340-3*24), 12, cl.stats[STAT_ARMOR], 3, 24, 0.6,0.7,0.8,1,0); + + // health + if(cl.stats[STAT_HEALTH] > 100) + Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,1,1,1,1,0); + else if(cl.stats[STAT_HEALTH] <= 25 && cl.time - (int)cl.time > 0.5) + Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.7,0,0,1,0); + else + Sbar_DrawXNum((154-3*24),12,cl.stats[STAT_HEALTH],3,24,0.6,0.7,0.8,1,0); + + // AK dont draw ammo for the laser + if(cl.stats[STAT_ACTIVEWEAPON] != 12) + { + if (cl.stats[STAT_ITEMS] & NEX_IT_SHELLS) + Sbar_DrawPic (519, 0, sb_ammo[0]); + else if (cl.stats[STAT_ITEMS] & NEX_IT_BULLETS) + Sbar_DrawPic (519, 0, sb_ammo[1]); + else if (cl.stats[STAT_ITEMS] & NEX_IT_ROCKETS) + Sbar_DrawPic (519, 0, sb_ammo[2]); + else if (cl.stats[STAT_ITEMS] & NEX_IT_CELLS) + Sbar_DrawPic (519, 0, sb_ammo[3]); + + if(cl.stats[STAT_AMMO] <= 10) + Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.7, 0,0,1,0); + else + Sbar_DrawXNum ((519-3*24), 12, cl.stats[STAT_AMMO], 3, 24, 0.6, 0.7,0.8,1,0); + + } + + if (sb_lines > 24) + DrawQ_Pic(sbar_x,sbar_y,sb_sbar_overlay,0,0,1,1,1,1,DRAWFLAG_MODULATE); + + if (sbar_x + 600 + 160 <= vid_conwidth.integer) + Sbar_MiniDeathmatchOverlay (sbar_x + 600, sbar_y); + + if (sbar_x > 0) + Sbar_Score(-16); + // Because: + // Mini scoreboard uses 12*4 per other team, that is, 144 + // pixels when there are four teams... + // Nexuiz by default sets vid_conwidth to 800... makes + // sbar_x == 80... + // so we need to shift it by 64 pixels to the right to fit + // BUT: then it overlaps with the image that gets drawn + // for viewsize 100! Therefore, just account for 3 teams, + // that is, 96 pixels mini scoreboard size, needing 16 pixels + // to the right! + } + } + else if (gamemode == GAME_ZYMOTIC) + { +#if 1 + float scale = 64.0f / 256.0f; + float kickoffset[3]; + VectorClear(kickoffset); + if (v_dmg_time > 0) + { + kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale; + kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale; + } + sbar_x = (int)((vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]); + sbar_y = (int)((vid_conheight.integer - 256 * scale)/2 + kickoffset[1]); + // left1 16, 48 : 126 -66 + // left2 16, 128 : 196 -66 + // right 176, 48 : 196 -136 + Sbar_DrawGauge(sbar_x + 16 * scale, sbar_y + 48 * scale, zymsb_crosshair_left1, 64*scale, 80*scale, 78*scale, -66*scale, cl.stats[STAT_AMMO] * (1.0 / 200.0), cl.stats[STAT_SHELLS] * (1.0 / 200.0), 0.8f,0.8f,0.0f,1.0f, 0.8f,0.5f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL); + Sbar_DrawGauge(sbar_x + 16 * scale, sbar_y + 128 * scale, zymsb_crosshair_left2, 64*scale, 80*scale, 68*scale, -66*scale, cl.stats[STAT_NAILS] * (1.0 / 200.0), cl.stats[STAT_ROCKETS] * (1.0 / 200.0), 0.8f,0.8f,0.0f,1.0f, 0.8f,0.5f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL); + Sbar_DrawGauge(sbar_x + 176 * scale, sbar_y + 48 * scale, zymsb_crosshair_right, 64*scale, 160*scale, 148*scale, -136*scale, cl.stats[STAT_ARMOR] * (1.0 / 300.0), cl.stats[STAT_HEALTH] * (1.0 / 300.0), 0.0f,0.5f,1.0f,1.0f, 1.0f,0.0f,0.0f,1.0f, 0.3f,0.3f,0.3f,1.0f, DRAWFLAG_NORMAL); + DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL); +#else + float scale = 128.0f / 256.0f; + float healthstart, healthheight, healthstarttc, healthendtc; + float shieldstart, shieldheight, shieldstarttc, shieldendtc; + float ammostart, ammoheight, ammostarttc, ammoendtc; + float clipstart, clipheight, clipstarttc, clipendtc; + float kickoffset[3], offset; + VectorClear(kickoffset); + if (v_dmg_time > 0) + { + kickoffset[0] = (v_dmg_time/v_kicktime.value*v_dmg_roll) * 10 * scale; + kickoffset[1] = (v_dmg_time/v_kicktime.value*v_dmg_pitch) * 10 * scale; + } + sbar_x = (vid_conwidth.integer - 256 * scale)/2 + kickoffset[0]; + sbar_y = (vid_conheight.integer - 256 * scale)/2 + kickoffset[1]; + offset = 0; // TODO: offset should be controlled by recoil (question: how to detect firing?) + DrawQ_SuperPic(sbar_x + 120 * scale, sbar_y + ( 88 - offset) * scale, zymsb_crosshair_line, 16 * scale, 36 * scale, 0,0, 1,1,1,1, 1,0, 1,1,1,1, 0,1, 1,1,1,1, 1,1, 1,1,1,1, 0); + DrawQ_SuperPic(sbar_x + (132 + offset) * scale, sbar_y + 120 * scale, zymsb_crosshair_line, 36 * scale, 16 * scale, 0,1, 1,1,1,1, 0,0, 1,1,1,1, 1,1, 1,1,1,1, 1,0, 1,1,1,1, 0); + DrawQ_SuperPic(sbar_x + 120 * scale, sbar_y + (132 + offset) * scale, zymsb_crosshair_line, 16 * scale, 36 * scale, 1,1, 1,1,1,1, 0,1, 1,1,1,1, 1,0, 1,1,1,1, 0,0, 1,1,1,1, 0); + DrawQ_SuperPic(sbar_x + ( 88 - offset) * scale, sbar_y + 120 * scale, zymsb_crosshair_line, 36 * scale, 16 * scale, 1,0, 1,1,1,1, 1,1, 1,1,1,1, 0,0, 1,1,1,1, 0,1, 1,1,1,1, 0); + healthheight = cl.stats[STAT_HEALTH] * (152.0f / 300.0f); + shieldheight = cl.stats[STAT_ARMOR] * (152.0f / 300.0f); + healthstart = 204 - healthheight; + shieldstart = healthstart - shieldheight; + healthstarttc = healthstart * (1.0f / 256.0f); + healthendtc = (healthstart + healthheight) * (1.0f / 256.0f); + shieldstarttc = shieldstart * (1.0f / 256.0f); + shieldendtc = (shieldstart + shieldheight) * (1.0f / 256.0f); + ammoheight = cl.stats[STAT_SHELLS] * (62.0f / 200.0f); + ammostart = 114 - ammoheight; + ammostarttc = ammostart * (1.0f / 256.0f); + ammoendtc = (ammostart + ammoheight) * (1.0f / 256.0f); + clipheight = cl.stats[STAT_AMMO] * (122.0f / 200.0f); + clipstart = 190 - clipheight; + clipstarttc = clipstart * (1.0f / 256.0f); + clipendtc = (clipstart + clipheight) * (1.0f / 256.0f); + if (healthheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + healthstart * scale, zymsb_crosshair_health, 256 * scale, healthheight * scale, 0,healthstarttc, 1.0f,0.0f,0.0f,1.0f, 1,healthstarttc, 1.0f,0.0f,0.0f,1.0f, 0,healthendtc, 1.0f,0.0f,0.0f,1.0f, 1,healthendtc, 1.0f,0.0f,0.0f,1.0f, DRAWFLAG_NORMAL); + if (shieldheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + shieldstart * scale, zymsb_crosshair_health, 256 * scale, shieldheight * scale, 0,shieldstarttc, 0.0f,0.5f,1.0f,1.0f, 1,shieldstarttc, 0.0f,0.5f,1.0f,1.0f, 0,shieldendtc, 0.0f,0.5f,1.0f,1.0f, 1,shieldendtc, 0.0f,0.5f,1.0f,1.0f, DRAWFLAG_NORMAL); + if (ammoheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + ammostart * scale, zymsb_crosshair_ammo, 256 * scale, ammoheight * scale, 0,ammostarttc, 0.8f,0.8f,0.0f,1.0f, 1,ammostarttc, 0.8f,0.8f,0.0f,1.0f, 0,ammoendtc, 0.8f,0.8f,0.0f,1.0f, 1,ammoendtc, 0.8f,0.8f,0.0f,1.0f, DRAWFLAG_NORMAL); + if (clipheight > 0) DrawQ_SuperPic(sbar_x + 0 * scale, sbar_y + clipstart * scale, zymsb_crosshair_clip, 256 * scale, clipheight * scale, 0,clipstarttc, 1.0f,1.0f,0.0f,1.0f, 1,clipstarttc, 1.0f,1.0f,0.0f,1.0f, 0,clipendtc, 1.0f,1.0f,0.0f,1.0f, 1,clipendtc, 1.0f,1.0f,0.0f,1.0f, DRAWFLAG_NORMAL); + DrawQ_Pic(sbar_x + 0 * scale, sbar_y + 0 * scale, zymsb_crosshair_background, 256 * scale, 256 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL); + DrawQ_Pic(sbar_x + 120 * scale, sbar_y + 120 * scale, zymsb_crosshair_center, 16 * scale, 16 * scale, 1, 1, 1, 1, DRAWFLAG_NORMAL); +#endif + } + else // Quake and others + { + //Include stereo offset in x + sbar_x = (vid_conwidth.integer - 320)/2 + Sbar_GetXOffset(); + sbar_y = vid_conheight.integer - (Sbar_GetYOffset() + 40) - SBAR_HEIGHT; + // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode + //if (cl.gametype == GAME_DEATHMATCH && gamemode != GAME_TRANSFUSION) + + if (sb_lines > 24) + { + if (gamemode != GAME_GOODVSBAD2) + Sbar_DrawInventory (); + if (!cl.islocalgame && gamemode != GAME_TRANSFUSION) + Sbar_DrawFrags (); + } + + if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0 && cl_deathscoreboard.integer)) + { + if (gamemode != GAME_GOODVSBAD2) + Sbar_DrawAlphaPic (0, 0, sb_scorebar, sbar_alpha_bg.value); + Sbar_DrawScoreboard (); + } + else if (sb_lines) + { + Sbar_DrawAlphaPic (0, 0, sb_sbar, sbar_alpha_bg.value); + + // keys (hipnotic only) + //MED 01/04/97 moved keys here so they would not be overwritten + if (gamemode == GAME_HIPNOTIC || gamemode == GAME_QUOTH) + { + if (cl.stats[STAT_ITEMS] & IT_KEY1) + Sbar_DrawPic (209, 3, sb_items[0]); + if (cl.stats[STAT_ITEMS] & IT_KEY2) + Sbar_DrawPic (209, 12, sb_items[1]); + } + // armor + if (gamemode != GAME_GOODVSBAD2) + { + if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + Sbar_DrawNum (24, 0, 666, 3, 1); + Sbar_DrawPic (0, 0, sb_disc); + } + else + { + if (gamemode == GAME_ROGUE) + { + Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25); + if (cl.stats[STAT_ITEMS] & RIT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.stats[STAT_ITEMS] & RIT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.stats[STAT_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.stats[STAT_ITEMS] & IT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.stats[STAT_ITEMS] & IT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.stats[STAT_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 (gamemode == GAME_ROGUE) + { + if (cl.stats[STAT_ITEMS] & RIT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.stats[STAT_ITEMS] & RIT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.stats[STAT_ITEMS] & RIT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.stats[STAT_ITEMS] & RIT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + else if (cl.stats[STAT_ITEMS] & RIT_LAVA_NAILS) + Sbar_DrawPic (224, 0, rsb_ammo[0]); + else if (cl.stats[STAT_ITEMS] & RIT_PLASMA_AMMO) + Sbar_DrawPic (224, 0, rsb_ammo[1]); + else if (cl.stats[STAT_ITEMS] & RIT_MULTI_ROCKETS) + Sbar_DrawPic (224, 0, rsb_ammo[2]); + } + else + { + if (cl.stats[STAT_ITEMS] & IT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.stats[STAT_ITEMS] & IT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.stats[STAT_ITEMS] & IT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.stats[STAT_ITEMS] & IT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + } + + Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10); + + // LordHavoc: changed to draw the deathmatch overlays in any multiplayer mode + if ((!cl.islocalgame || cl.gametype != GAME_COOP)) + { + if (gamemode == GAME_TRANSFUSION) + Sbar_MiniDeathmatchOverlay (0, 0); + else + Sbar_MiniDeathmatchOverlay (sbar_x + 324, vid_conheight.integer - 8*8); + Sbar_Score(24); + } + } + } + } + + if (cl.csqc_vidvars.drawcrosshair && crosshair.integer >= 1 && !cl.intermission && !r_letterbox.value) + { + pic = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/crosshair%i", crosshair.integer)); + int stereoOffset = r_worldscale.value > 200.0f ? 12 : 5; + int yOffset = (r_worldscale.value > 200.0f ? 20 : 5); + DrawQ_Pic((vid_conwidth.integer - pic->width * crosshair_size.value) * 0.5f + (r_stereo_side ? -stereoOffset : stereoOffset), + (vid_conheight.integer - pic->height * crosshair_size.value) * 0.5f + yOffset, + pic, pic->width * crosshair_size.value, pic->height * crosshair_size.value, + crosshair_color_red.value, crosshair_color_green.value, crosshair_color_blue.value, crosshair_color_alpha.value, 0); + } + + if (cl_prydoncursor.integer > 0) + DrawQ_Pic((cl.cmd.cursor_screen[0] + 1) * 0.5 * vid_conwidth.integer, (cl.cmd.cursor_screen[1] + 1) * 0.5 * vid_conheight.integer, Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/prydoncursor%03i", cl_prydoncursor.integer)), 0, 0, 1, 1, 1, 1, 0); +} + +//============================================================================= + +/* +================== +Sbar_DeathmatchOverlay + +================== +*/ +static float Sbar_PrintScoreboardItem(scoreboard_t *s, float x, float y) +{ + int minutes; + qboolean myself = false; + unsigned char *c; + char vabuf[1024]; + minutes = (int)((cl.intermission ? cl.completed_time - s->qw_entertime : cl.time - s->qw_entertime) / 60.0); + + if((s - cl.scores) == cl.playerentity - 1) + myself = true; + if((s - teams) >= 0 && (s - teams) < MAX_SCOREBOARD) + if((s->colors & 15) == (cl.scores[cl.playerentity - 1].colors & 15)) + myself = true; + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + if (s->qw_spectator) + { + if (s->qw_ping || s->qw_packetloss) + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i spectator %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + else + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %4i spectator %c%s", minutes, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + else + { + // draw colors behind score + // + // + // + // + // + c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4]; + DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + c = palette_rgb_shirtscoreboard[s->colors & 0xf]; + DrawQ_Fill(x + 14*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + // print the text + //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT); + if (s->qw_ping || s->qw_packetloss) + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %4i %5i %-4s %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + else + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %4i %5i %-4s %c%s", minutes,(int) s->frags, cl.qw_teamplay ? s->qw_team : "", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + } + else + { + if (s->qw_spectator) + { + if (s->qw_ping || s->qw_packetloss) + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i spect %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + else + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " spect %c%s", myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + else + { + // draw colors behind score + c = palette_rgb_pantsscoreboard[(s->colors & 0xf0) >> 4]; + DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+1, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + c = palette_rgb_shirtscoreboard[s->colors & 0xf]; + DrawQ_Fill(x + 9*8*FONT_SBAR->maxwidth, y+4, 40*FONT_SBAR->maxwidth, 3, c[0] * (1.0f / 255.0f), c[1] * (1.0f / 255.0f), c[2] * (1.0f / 255.0f), sbar_alpha_fg.value, 0); + // print the text + //DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%c%4i %s", myself ? 13 : ' ', (int) s->frags, s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, true, FONT_DEFAULT); + if (s->qw_ping || s->qw_packetloss) + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), "%4i %3i %5i %c%s", bound(0, s->qw_ping, 9999), bound(0, s->qw_packetloss, 99), (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + else + DrawQ_String(x, y, va(vabuf, sizeof(vabuf), " %5i %c%s", (int) s->frags, myself ? 13 : ' ', s->name), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + } + return 8; +} + +void Sbar_DeathmatchOverlay (void) +{ + int i, y, xmin, xmax, ymin, ymax; + char vabuf[1024]; + + // request new ping times every two second + if (cl.last_ping_request < realtime - 2 && cls.netcon) + { + cl.last_ping_request = realtime; + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "pings"); + } + else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE || cls.protocol == PROTOCOL_NEHAHRABJP || cls.protocol == PROTOCOL_NEHAHRABJP2 || cls.protocol == PROTOCOL_NEHAHRABJP3 || cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5 || cls.protocol == PROTOCOL_DARKPLACES6/* || cls.protocol == PROTOCOL_DARKPLACES7*/) + { + // these servers usually lack the pings command and so a less efficient "ping" command must be sent, which on modern DP servers will also reply with a pingplreport command after the ping listing + static int ping_anyway_counter = 0; + if(cl.parsingtextexpectingpingforscores == 1) + { + Con_DPrintf("want to send ping, but still waiting for other reply\n"); + if(++ping_anyway_counter >= 5) + cl.parsingtextexpectingpingforscores = 0; + } + if(cl.parsingtextexpectingpingforscores != 1) + { + ping_anyway_counter = 0; + cl.parsingtextexpectingpingforscores = 1; // hide the output of the next ping report + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "ping"); + } + } + else + { + // newer server definitely has pings command, so use it for more efficiency, avoids ping reports spamming the console if they are misparsed, and saves a little bandwidth + MSG_WriteByte(&cls.netcon->message, clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "pings"); + } + } + + // scores + Sbar_SortFrags (); + + ymin = 8; + ymax = 40 + 8 + (Sbar_IsTeammatch() ? (teamlines * 8 + 5): 0) + scoreboardlines * 8 - 1; + + if (cls.protocol == PROTOCOL_QUAKEWORLD) + xmin = (int) (vid_conwidth.integer - (26 + 15) * 8 * FONT_SBAR->maxwidth) / 2; // 26 characters until name, then we assume 15 character names (they can be longer but usually aren't) + else + xmin = (int) (vid_conwidth.integer - (16 + 25) * 8 * FONT_SBAR->maxwidth) / 2; // 16 characters until name, then we assume 25 character names (they can be longer but usually aren't) + xmax = vid_conwidth.integer - xmin; + + if(gamemode == GAME_NEXUIZ) + DrawQ_Pic (xmin - 8, ymin - 8, 0, xmax-xmin+1 + 2*8, ymax-ymin+1 + 2*8, 0, 0, 0, sbar_alpha_bg.value, 0); + + DrawQ_Pic ((vid_conwidth.integer - sb_ranking->width)/2, 8, sb_ranking, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); + + // draw the text + y = 40; + if (cls.protocol == PROTOCOL_QUAKEWORLD) + { + DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% time frags team name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + else + { + DrawQ_String(xmin, y, va(vabuf, sizeof(vabuf), "ping pl%% frags name"), 0, 8, 8, 1, 1, 1, 1 * sbar_alpha_fg.value, 0, NULL, false, FONT_SBAR ); + } + y += 8; + + if (Sbar_IsTeammatch ()) + { + // show team scores first + for (i = 0;i < teamlines && y < vid_conheight.integer;i++) + y += (int)Sbar_PrintScoreboardItem((teams + teamsort[i]), xmin, y); + y += 5; + } + + for (i = 0;i < scoreboardlines && y < vid_conheight.integer;i++) + y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], xmin, y); +} + +/* +================== +Sbar_MiniDeathmatchOverlay + +================== +*/ +void Sbar_MiniDeathmatchOverlay (int x, int y) +{ + int i, j, numlines, range_begin, range_end, myteam, teamsep; + + // do not draw this if sbar_miniscoreboard_size is zero + if(sbar_miniscoreboard_size.value == 0) + return; + // adjust the given y if sbar_miniscoreboard_size doesn't indicate default (< 0) + if(sbar_miniscoreboard_size.value > 0) + y = (int) (vid_conheight.integer - sbar_miniscoreboard_size.value * 8); + + // scores + Sbar_SortFrags (); + + // decide where to print + if (gamemode == GAME_TRANSFUSION) + numlines = (vid_conwidth.integer - x + 127) / 128; + else + numlines = (vid_conheight.integer - y + 7) / 8; + + // give up if there isn't room + if (x >= vid_conwidth.integer || y >= vid_conheight.integer || numlines < 1) + return; + + //find us + for (i = 0; i < scoreboardlines; i++) + if (fragsort[i] == cl.playerentity - 1) + break; + + range_begin = 0; + range_end = scoreboardlines; + teamsep = 0; + + if (gamemode != GAME_TRANSFUSION) + if (Sbar_IsTeammatch ()) + { + // reserve space for the team scores + numlines -= teamlines; + + // find first and last player of my team (only draw the team totals and my own team) + range_begin = range_end = i; + myteam = cl.scores[fragsort[i]].colors & 15; + while(range_begin > 0 && (cl.scores[fragsort[range_begin-1]].colors & 15) == myteam) + --range_begin; + while(range_end < scoreboardlines && (cl.scores[fragsort[range_end]].colors & 15) == myteam) + ++range_end; + + // looks better than two players + if(numlines == 2) + { + teamsep = 8; + numlines = 1; + } + } + + // figure out start + i -= numlines/2; + i = min(i, range_end - numlines); + i = max(i, range_begin); + + if (gamemode == GAME_TRANSFUSION) + { + for (;i < range_end && x < vid_conwidth.integer;i++) + x += 128 + (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y); + } + else + { + if(range_end - i < numlines) // won't draw to bottom? + y += 8 * (numlines - (range_end - i)); // bottom align + // show team scores first + for (j = 0;j < teamlines && y < vid_conheight.integer;j++) + y += (int)Sbar_PrintScoreboardItem((teams + teamsort[j]), x, y); + y += teamsep; + for (;i < range_end && y < vid_conheight.integer;i++) + y += (int)Sbar_PrintScoreboardItem(cl.scores + fragsort[i], x, y); + } +} + +static int Sbar_TeamColorCompare(const void *t1_, const void *t2_) +{ + static int const sortorder[16] = + { + 1001, + 1002, + 1003, + 1004, + 1, // red + 1005, + 1006, + 1007, + 1008, + 4, // pink + 1009, + 1010, + 3, // yellow + 2, // blue + 1011, + 1012 + }; + const scoreboard_t *t1 = *(scoreboard_t **) t1_; + const scoreboard_t *t2 = *(scoreboard_t **) t2_; + int tc1 = sortorder[t1->colors & 15]; + int tc2 = sortorder[t2->colors & 15]; + return tc1 - tc2; +} + +void Sbar_Score (int margin) +{ + int i, me, score, otherleader, place, distribution, minutes, seconds; + double timeleft; + int sbar_x_save = sbar_x; + int sbar_y_save = sbar_y; + + + sbar_y = (int) (vid_conheight.value - (Sbar_GetYOffset() + 44)); + sbar_x -= margin; + + me = cl.playerentity - 1; + if (sbar_scorerank.integer && me >= 0 && me < cl.maxclients) + { + if(Sbar_IsTeammatch()) + { + // Layout: + // + // team1 team3 team4 + // + // TEAM2 + + scoreboard_t *teamcolorsort[16]; + + Sbar_SortFrags(); + for(i = 0; i < teamlines; ++i) + teamcolorsort[i] = &(teams[i]); + + // Now sort them by color + qsort(teamcolorsort, teamlines, sizeof(*teamcolorsort), Sbar_TeamColorCompare); + + // : margin + // -12*4: four digits space + place = (teamlines - 1) * (-12 * 4); + + for(i = 0; i < teamlines; ++i) + { + int cindex = teamcolorsort[i]->colors & 15; + unsigned char *c = palette_rgb_shirtscoreboard[cindex]; + float cm = max(max(c[0], c[1]), c[2]); + float cr = c[0] / cm; + float cg = c[1] / cm; + float cb = c[2] / cm; + if(cindex == (cl.scores[cl.playerentity - 1].colors & 15)) // my team + { + Sbar_DrawXNum(-32*4, 0, teamcolorsort[i]->frags, 4, 32, cr, cg, cb, 1, 0); + } + else // other team + { + Sbar_DrawXNum(place, -12, teamcolorsort[i]->frags, 4, 12, cr, cg, cb, 1, 0); + place += 4 * 12; + } + } + } + else + { + // Layout: + // + // leading place + // + // FRAGS + // + // find leading score other than ourselves, to calculate distribution + // find our place in the scoreboard + score = cl.scores[me].frags; + for (i = 0, otherleader = -1, place = 1;i < cl.maxclients;i++) + { + if (cl.scores[i].name[0] && i != me) + { + if (otherleader == -1 || cl.scores[i].frags > cl.scores[otherleader].frags) + otherleader = i; + if (score < cl.scores[i].frags || (score == cl.scores[i].frags && i < me)) + place++; + } + } + distribution = otherleader >= 0 ? score - cl.scores[otherleader].frags : 0; + if (place == 1) + Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 1, 1, 0); + else if (place == 2) + Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 1, 0, 1, 0); + else + Sbar_DrawXNum(-3*12, -12, place, 3, 12, 1, 0, 0, 1, 0); + if (otherleader < 0) + Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0); + if (distribution >= 0) + { + Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 1, 1, 0); + Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 1, 1, 0); + } + else if (distribution >= -5) + { + Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 1, 0, 1, 0); + Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 1, 0, 1, 0); + } + else + { + Sbar_DrawXNum(-7*12, -12, distribution, 4, 12, 1, 0, 0, 1, 0); + Sbar_DrawXNum(-32*4, 0, score, 4, 32, 1, 0, 0, 1, 0); + } + } + } + + if (sbar_gametime.integer && cl.statsf[STAT_TIMELIMIT]) + { + timeleft = max(0, cl.statsf[STAT_TIMELIMIT] * 60 - cl.time); + minutes = (int)floor(timeleft / 60); + seconds = (int)(floor(timeleft) - minutes * 60); + if (minutes >= 5) + { + Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0); + if(sb_colon && sb_colon->tex != r_texture_notexture) + DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0); + Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0); + } + else if (minutes >= 1) + { + Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 0, 1, 0); + if(sb_colon && sb_colon->tex != r_texture_notexture) + DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 0, sbar_alpha_fg.value, 0); + Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 0, 1, 0); + } + else if ((int)(timeleft * 4) & 1) + Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0); + else + Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 0, 0, 1, 0); + } + else if (sbar_gametime.integer) + { + minutes = (int)floor(cl.time / 60); + seconds = (int)(floor(cl.time) - minutes * 60); + Sbar_DrawXNum(-12*6, 32, minutes, 3, 12, 1, 1, 1, 1, 0); + if(sb_colon && sb_colon->tex != r_texture_notexture) + DrawQ_Pic(sbar_x + -12*3, sbar_y + 32, sb_colon, 12, 12, 1, 1, 1, sbar_alpha_fg.value, 0); + Sbar_DrawXNum(-12*2, 32, seconds, -2, 12, 1, 1, 1, 1, 0); + } + + sbar_x = sbar_x_save; + sbar_y = sbar_y_save; +} + +/* +================== +Sbar_IntermissionOverlay + +================== +*/ +void Sbar_IntermissionOverlay (void) +{ + int dig; + int num; + + if (cl.gametype == GAME_DEATHMATCH) + { + Sbar_DeathmatchOverlay (); + return; + } + + sbar_x = ((vid_conwidth.integer - 320) >> 1) + Sbar_GetXOffset(); + sbar_y = (vid_conheight.integer - 200) >> 1; + + DrawQ_Pic (sbar_x + 64, sbar_y + 24, sb_complete, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); + DrawQ_Pic (sbar_x + 0, sbar_y + 56, sb_inter, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); + +// time + dig = (int)cl.completed_time / 60; + Sbar_DrawNum (160, 64, dig, 3, 0); + num = (int)cl.completed_time - dig*60; + Sbar_DrawPic (234,64,sb_colon); + Sbar_DrawPic (246,64,sb_nums[0][num/10]); + Sbar_DrawPic (266,64,sb_nums[0][num%10]); + +// LA: Display as "a" instead of "a/b" if b is 0 + if(cl.stats[STAT_TOTALSECRETS]) + { + Sbar_DrawNum (160, 104, cl.stats[STAT_SECRETS], 3, 0); + if (gamemode != GAME_NEXUIZ) + Sbar_DrawPic (232, 104, sb_slash); + Sbar_DrawNum (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); + } + else + { + Sbar_DrawNum (240, 104, cl.stats[STAT_SECRETS], 3, 0); + } + + if(cl.stats[STAT_TOTALMONSTERS]) + { + Sbar_DrawNum (160, 144, cl.stats[STAT_MONSTERS], 3, 0); + if (gamemode != GAME_NEXUIZ) + Sbar_DrawPic (232, 144, sb_slash); + Sbar_DrawNum (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0); + } + else + { + Sbar_DrawNum (240, 144, cl.stats[STAT_MONSTERS], 3, 0); + } +} + + +/* +================== +Sbar_FinaleOverlay + +================== +*/ +void Sbar_FinaleOverlay (void) +{ + DrawQ_Pic((vid_conwidth.integer - sb_finale->width)/2, 16, sb_finale, 0, 0, 1, 1, 1, 1 * sbar_alpha_fg.value, 0); +} + diff --git a/app/jni/sbar.h b/app/jni/sbar.h new file mode 100644 index 0000000..0739756 --- /dev/null +++ b/app/jni/sbar.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. + +*/ + +#ifndef SBAR_H +#define SBAR_H + +#define SBAR_HEIGHT 24 + +extern int sb_lines; ///< scan lines to draw +extern cvar_t sbar_alpha_bg; +extern cvar_t sbar_alpha_fg; + +void Sbar_Init (void); + +/// called every frame by screen +void Sbar_Draw (void); + +int Sbar_GetSortedPlayerIndex (int index); +void Sbar_SortFrags (void); + +#endif + diff --git a/app/jni/screen.h b/app/jni/screen.h new file mode 100644 index 0000000..cd9305d --- /dev/null +++ b/app/jni/screen.h @@ -0,0 +1,87 @@ +/* +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 + +#ifndef SCREEN_H +#define SCREEN_H + +void CL_Screen_Init (void); +void CL_BeginUpdateScreen (); +void CL_EndUpdateScreen (); +void SCR_CenterPrint(const char *str); + +void SCR_BeginLoadingPlaque (qboolean startup); + +// invoke refresh of loading plaque (nothing else seen) +void SCR_UpdateLoadingScreen(qboolean clear, qboolean startup); +void SCR_UpdateLoadingScreenIfShown(void); + +// pushes an item on the loading screen +void SCR_PushLoadingScreen (qboolean redraw, const char *msg, float len_in_parent); +void SCR_PopLoadingScreen (qboolean redraw); +void SCR_ClearLoadingScreen (qboolean redraw); + +extern float scr_con_current; // current height of displayed console + +extern int sb_lines; + +extern cvar_t scr_viewsize; +extern cvar_t scr_fov; +extern cvar_t showfps; +extern cvar_t showtime; +extern cvar_t showdate; + +extern cvar_t crosshair; +extern cvar_t crosshair_size; + +extern cvar_t scr_conalpha; +extern cvar_t scr_conalphafactor; +extern cvar_t scr_conalpha2factor; +extern cvar_t scr_conalpha3factor; +extern cvar_t scr_conscroll_x; +extern cvar_t scr_conscroll_y; +extern cvar_t scr_conscroll2_x; +extern cvar_t scr_conscroll2_y; +extern cvar_t scr_conscroll3_x; +extern cvar_t scr_conscroll3_y; +extern cvar_t scr_conbrightness; +extern cvar_t r_letterbox; + +extern cvar_t scr_refresh; +extern cvar_t scr_stipple; + +extern cvar_t r_stereo_separation; +extern cvar_t r_stereo_angle; +qboolean R_Stereo_Active(void); +extern int r_stereo_side; + +typedef struct scr_touchscreenarea_s +{ + const char *pic; + float rect[4]; + float active; +} +scr_touchscreenarea_t; + +extern int scr_numtouchscreenareas; +extern scr_touchscreenarea_t scr_touchscreenareas[16]; + +#endif + diff --git a/app/jni/server.h b/app/jni/server.h new file mode 100644 index 0000000..669174b --- /dev/null +++ b/app/jni/server.h @@ -0,0 +1,615 @@ +/* +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 + +#ifndef SERVER_H +#define SERVER_H + +typedef struct server_static_s +{ + /// number of svs.clients slots (updated by maxplayers command) + int maxclients, maxclients_next; + /// client slots + struct client_s *clients; + /// episode completion information + int serverflags; + /// cleared when at SV_SpawnServer + qboolean changelevel_issued; + /// server infostring + char serverinfo[MAX_SERVERINFO_STRING]; + // performance data + float perf_cpuload; + float perf_lost; + float perf_offset_avg; + float perf_offset_max; + float perf_offset_sdev; + // temporary performance data accumulators + float perf_acc_realtime; + float perf_acc_sleeptime; + float perf_acc_lost; + float perf_acc_offset; + float perf_acc_offset_squared; + float perf_acc_offset_max; + int perf_acc_offset_samples; + + // csqc stuff + unsigned char *csqc_progdata; + size_t csqc_progsize_deflated; + unsigned char *csqc_progdata_deflated; + + // independent server thread (when running client) + qboolean threaded; // true if server is running on separate thread + qboolean volatile threadstop; + void *threadmutex; + void *thread; +} server_static_t; + +//============================================================================= + +typedef enum server_state_e {ss_loading, ss_active} server_state_t; + +#define MAX_CONNECTFLOODADDRESSES 16 +#define MAX_GETSTATUSFLOODADDRESSES 128 +typedef struct server_floodaddress_s +{ + double lasttime; + lhnetaddress_t address; +} +server_floodaddress_t; + +typedef struct server_s +{ + /// false if only a net client + qboolean active; + + qboolean paused; + double pausedstart; + /// handle connections specially + qboolean loadgame; + + /// one of the PROTOCOL_ values + protocolversion_t protocol; + + double time; + + double frametime; + + // used by PF_checkclient + int lastcheck; + double lastchecktime; + + // crc of clientside progs at time of level start + int csqc_progcrc; // -1 = no progs + int csqc_progsize; // -1 = no progs + char csqc_progname[MAX_QPATH]; // copied from csqc_progname at level start + + /// collision culling data + world_t world; + + /// map name + char name[64]; // %s followed by entrance name + // variants of map name + char worldmessage[40]; // map title (not related to filename) + char worldbasename[MAX_QPATH]; // %s + char worldname[MAX_QPATH]; // maps/%s.bsp + char worldnamenoextension[MAX_QPATH]; // maps/%s + struct model_s *worldmodel; + // NULL terminated + // LordHavoc: precaches are now MAX_QPATH rather than a pointer + // updated by SV_ModelIndex + char model_precache[MAX_MODELS][MAX_QPATH]; + struct model_s *models[MAX_MODELS]; + // NULL terminated + // LordHavoc: precaches are now MAX_QPATH rather than a pointer + // updated by SV_SoundIndex + char sound_precache[MAX_SOUNDS][MAX_QPATH]; + char lightstyles[MAX_LIGHTSTYLES][64]; + /// some actions are only valid during load + server_state_t state; + + sizebuf_t datagram; + unsigned char datagram_buf[NET_MAXMESSAGE]; + + // copied to all clients at end of frame + sizebuf_t reliable_datagram; + unsigned char reliable_datagram_buf[NET_MAXMESSAGE]; + + sizebuf_t signon; + /// LordHavoc: increased signon message buffer from 8192 + unsigned char signon_buf[NET_MAXMESSAGE]; + + /// connection flood blocking + /// note this is in server_t rather than server_static_t so that it is + /// reset on each map command (such as New Game in singleplayer) + server_floodaddress_t connectfloodaddresses[MAX_CONNECTFLOODADDRESSES]; + server_floodaddress_t getstatusfloodaddresses[MAX_GETSTATUSFLOODADDRESSES]; + +#define SV_MAX_PARTICLEEFFECTNAME 256 + qboolean particleeffectnamesloaded; + char particleeffectname[SV_MAX_PARTICLEEFFECTNAME][MAX_QPATH]; + + int writeentitiestoclient_stats_culled_pvs; + int writeentitiestoclient_stats_culled_trace; + int writeentitiestoclient_stats_visibleentities; + int writeentitiestoclient_stats_totalentities; + int writeentitiestoclient_cliententitynumber; + int writeentitiestoclient_clientnumber; + sizebuf_t *writeentitiestoclient_msg; + vec3_t writeentitiestoclient_eyes[MAX_CLIENTNETWORKEYES]; + int writeentitiestoclient_numeyes; + int writeentitiestoclient_pvsbytes; + unsigned char writeentitiestoclient_pvs[MAX_MAP_LEAFS/8]; + const entity_state_t *writeentitiestoclient_sendstates[MAX_EDICTS]; + unsigned short writeentitiestoclient_csqcsendstates[MAX_EDICTS]; + + int numsendentities; + entity_state_t sendentities[MAX_EDICTS]; + entity_state_t *sendentitiesindex[MAX_EDICTS]; + + int sententitiesmark; + int sententities[MAX_EDICTS]; + int sententitiesconsideration[MAX_EDICTS]; + + /// legacy support for self.Version based csqc entity networking + unsigned char csqcentityversion[MAX_EDICTS]; // legacy +} server_t; + +#define NUM_CSQCENTITIES_PER_FRAME 256 +typedef struct csqcentityframedb_s +{ + int framenum; + int num; + unsigned short entno[NUM_CSQCENTITIES_PER_FRAME]; + int sendflags[NUM_CSQCENTITIES_PER_FRAME]; +} csqcentityframedb_t; + +// if defined this does ping smoothing, otherwise it does not +//#define NUM_PING_TIMES 16 + +#define NUM_SPAWN_PARMS 16 + +typedef struct client_s +{ + /// false = empty client slot + qboolean active; + /// false = don't do ClientDisconnect on drop + qboolean clientconnectcalled; + /// false = don't allow spawn + qboolean prespawned; + /// false = don't allow begin + qboolean spawned; + /// false = don't send datagrams + qboolean begun; + /// 1 = send svc_serverinfo and advance to 2, 2 doesn't send, then advances to 0 (allowing unlimited sending) when prespawn is received + int sendsignon; + + /// requested rate in bytes per second + int rate; + + /// realtime this client connected + double connecttime; + + /// keepalive messages must be sent periodically during signon + double keepalivetime; + + /// communications handle + netconn_t *netconnection; + + int movesequence; + signed char movement_count[NETGRAPH_PACKETS]; + int movement_highestsequence_seen; // not the same as movesequence if prediction is off + /// movement + usercmd_t cmd; + /// intended motion calced from cmd + vec3_t wishdir; + + /// PRVM_EDICT_NUM(clientnum+1) + prvm_edict_t *edict; + +#ifdef NUM_PING_TIMES + float ping_times[NUM_PING_TIMES]; + /// ping_times[num_pings%NUM_PING_TIMES] + int num_pings; +#endif + /// LordHavoc: can be used for prediction or whatever... + float ping; + + /// this is used by sv_clmovement_minping code + double clmovement_disabletimeout; + /// this is used by sv_clmovement_inputtimeout code + float clmovement_inputtimeout; + +/// spawn parms are carried from level to level + prvm_vec_t spawn_parms[NUM_SPAWN_PARMS]; + + // properties that are sent across the network only when changed + char name[MAX_SCOREBOARDNAME], old_name[MAX_SCOREBOARDNAME]; + int colors, old_colors; + int frags, old_frags; + char playermodel[MAX_QPATH], old_model[MAX_QPATH]; + char playerskin[MAX_QPATH], old_skin[MAX_QPATH]; + + /// netaddress support + char netaddress[MAX_QPATH]; + + /// visibility state + float visibletime[MAX_EDICTS]; + + // scope is whether an entity is currently being networked to this client + // sendflags is what properties have changed on the entity since the last + // update that was sent + int csqcnumedicts; + unsigned char csqcentityscope[MAX_EDICTS]; + unsigned int csqcentitysendflags[MAX_EDICTS]; + +#define NUM_CSQCENTITYDB_FRAMES 256 + unsigned char csqcentityglobalhistory[MAX_EDICTS]; // set to 1 if the entity was ever csqc networked to the client, and never reset back to 0 + csqcentityframedb_t csqcentityframehistory[NUM_CSQCENTITYDB_FRAMES]; + int csqcentityframehistory_next; + int csqcentityframe_lastreset; + + /// prevent animated names + float nametime; + + /// latest received clc_ackframe (used to detect packet loss) + int latestframenum; + + /// cache weaponmodel name lookups + char weaponmodel[MAX_QPATH]; + int weaponmodelindex; + + /// clientcamera (entity to use as camera) + int clientcamera; + + entityframe_database_t *entitydatabase; + entityframe4_database_t *entitydatabase4; + entityframe5_database_t *entitydatabase5; + + // delta compression of stats + unsigned char statsdeltabits[(MAX_CL_STATS+7)/8]; + int stats[MAX_CL_STATS]; + + unsigned char unreliablemsg_data[NET_MAXMESSAGE]; + sizebuf_t unreliablemsg; + int unreliablemsg_splitpoints; + int unreliablemsg_splitpoint[NET_MAXMESSAGE/16]; + + // information on an active download if any + qfile_t *download_file; + int download_expectedposition; ///< next position the client should ack + qboolean download_started; + char download_name[MAX_QPATH]; + qboolean download_deflate; + + // fixangle data + qboolean fixangle_angles_set; + vec3_t fixangle_angles; + + /// demo recording + qfile_t *sv_demo_file; + + // number of skipped entity frames + // if it exceeds a limit, an empty entity frame is sent + int num_skippedentityframes; + + // last sent move sequence + // if the move sequence changed, an empty entity frame is sent + int lastmovesequence; +} client_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 +#define MOVETYPE_BOUNCEMISSILE 11 ///< bounce w/o gravity +#define MOVETYPE_FOLLOW 12 ///< track movement of aiment +#define MOVETYPE_FAKEPUSH 13 ///< tenebrae's push that doesn't push +#define MOVETYPE_PHYSICS 32 ///< indicates this object is physics controlled +#define MOVETYPE_FLY_WORLDONLY 33 ///< like MOVETYPE_FLY, but uses MOVE_WORLDONLY for all its traces; objects of this movetype better be SOLID_NOT or SOLID_TRIGGER please, or else... + +// 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 +// LordHavoc: corpse code +#define SOLID_CORPSE 5 ///< same as SOLID_BBOX, except it behaves as SOLID_NOT against SOLID_SLIDEBOX objects (players/monsters) +// LordHavoc: physics +// VorteX: now these fields are deprecated, as geomtype is more flexible +#define SOLID_PHYSICS_BOX 32 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_SPHERE 33 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_CAPSULE 34 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_TRIMESH 35 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_CYLINDER 36 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) + +// 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_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 + +#define SPAWNFLAG_NOT_EASY 256 +#define SPAWNFLAG_NOT_MEDIUM 512 +#define SPAWNFLAG_NOT_HARD 1024 +#define SPAWNFLAG_NOT_DEATHMATCH 2048 + +//============================================================================ + +extern cvar_t coop; +extern cvar_t deathmatch; +extern cvar_t fraglimit; +extern cvar_t gamecfg; +extern cvar_t noexit; +extern cvar_t nomonsters; +extern cvar_t pausable; +extern cvar_t pr_checkextension; +extern cvar_t samelevel; +extern cvar_t saved1; +extern cvar_t saved2; +extern cvar_t saved3; +extern cvar_t saved4; +extern cvar_t savedgamecfg; +extern cvar_t scratch1; +extern cvar_t scratch2; +extern cvar_t scratch3; +extern cvar_t scratch4; +extern cvar_t skill; +extern cvar_t slowmo; +extern cvar_t sv_accelerate; +extern cvar_t sv_aim; +extern cvar_t sv_airaccel_qw; +extern cvar_t sv_airaccel_sideways_friction; +extern cvar_t sv_airaccelerate; +extern cvar_t sv_airstopaccelerate; +extern cvar_t sv_airstrafeaccelerate; +extern cvar_t sv_maxairstrafespeed; +extern cvar_t sv_airstrafeaccel_qw; +extern cvar_t sv_aircontrol; +extern cvar_t sv_aircontrol_power; +extern cvar_t sv_aircontrol_penalty; +extern cvar_t sv_airspeedlimit_nonqw; +extern cvar_t sv_allowdownloads; +extern cvar_t sv_allowdownloads_archive; +extern cvar_t sv_allowdownloads_config; +extern cvar_t sv_allowdownloads_dlcache; +extern cvar_t sv_allowdownloads_inarchive; +extern cvar_t sv_areagrid_mingridsize; +extern cvar_t sv_checkforpacketsduringsleep; +extern cvar_t sv_clmovement_enable; +extern cvar_t sv_clmovement_minping; +extern cvar_t sv_clmovement_minping_disabletime; +extern cvar_t sv_clmovement_inputtimeout; +extern cvar_t sv_clmovement_maxnetfps; +extern cvar_t sv_cullentities_nevercullbmodels; +extern cvar_t sv_cullentities_pvs; +extern cvar_t sv_cullentities_stats; +extern cvar_t sv_cullentities_trace; +extern cvar_t sv_cullentities_trace_delay; +extern cvar_t sv_cullentities_trace_enlarge; +extern cvar_t sv_cullentities_trace_prediction; +extern cvar_t sv_cullentities_trace_samples; +extern cvar_t sv_cullentities_trace_samples_extra; +extern cvar_t sv_debugmove; +extern cvar_t sv_echobprint; +extern cvar_t sv_edgefriction; +extern cvar_t sv_entpatch; +extern cvar_t sv_fixedframeratesingleplayer; +extern cvar_t sv_freezenonclients; +extern cvar_t sv_friction; +extern cvar_t sv_gameplayfix_blowupfallenzombies; +extern cvar_t sv_gameplayfix_consistentplayerprethink; +extern cvar_t sv_gameplayfix_delayprojectiles; +extern cvar_t sv_gameplayfix_droptofloorstartsolid; +extern cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect; +extern cvar_t sv_gameplayfix_easierwaterjump; +extern cvar_t sv_gameplayfix_findradiusdistancetobox; +extern cvar_t sv_gameplayfix_gravityunaffectedbyticrate; +extern cvar_t sv_gameplayfix_grenadebouncedownslopes; +extern cvar_t sv_gameplayfix_multiplethinksperframe; +extern cvar_t sv_gameplayfix_noairborncorpse; +extern cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems; +extern cvar_t sv_gameplayfix_nudgeoutofsolid; +extern cvar_t sv_gameplayfix_nudgeoutofsolid_separation; +extern cvar_t sv_gameplayfix_q2airaccelerate; +extern cvar_t sv_gameplayfix_nogravityonground; +extern cvar_t sv_gameplayfix_setmodelrealbox; +extern cvar_t sv_gameplayfix_slidemoveprojectiles; +extern cvar_t sv_gameplayfix_stepdown; +extern cvar_t sv_gameplayfix_stepmultipletimes; +extern cvar_t sv_gameplayfix_nostepmoveonsteepslopes; +extern cvar_t sv_gameplayfix_swiminbmodels; +extern cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag; +extern cvar_t sv_gameplayfix_downtracesupportsongroundflag; +extern cvar_t sv_gameplayfix_q1bsptracelinereportstexture; +extern cvar_t sv_gameplayfix_unstickplayers; +extern cvar_t sv_gameplayfix_unstickentities; +extern cvar_t sv_gameplayfix_fixedcheckwatertransition; +extern cvar_t sv_gravity; +extern cvar_t sv_idealpitchscale; +extern cvar_t sv_jumpstep; +extern cvar_t sv_jumpvelocity; +extern cvar_t sv_maxairspeed; +extern cvar_t sv_maxrate; +extern cvar_t sv_maxspeed; +extern cvar_t sv_maxvelocity; +extern cvar_t sv_nostep; +extern cvar_t sv_playerphysicsqc; +extern cvar_t sv_progs; +extern cvar_t sv_protocolname; +extern cvar_t sv_random_seed; +extern cvar_t sv_ratelimitlocalplayer; +extern cvar_t sv_sound_land; +extern cvar_t sv_sound_watersplash; +extern cvar_t sv_stepheight; +extern cvar_t sv_stopspeed; +extern cvar_t sv_wallfriction; +extern cvar_t sv_wateraccelerate; +extern cvar_t sv_waterfriction; +extern cvar_t sv_areadebug; +extern cvar_t sys_ticrate; +extern cvar_t teamplay; +extern cvar_t temp1; +extern cvar_t timelimit; + +extern mempool_t *sv_mempool; + +/// persistant server info +extern server_static_t svs; +/// local server +extern server_t sv; + +extern client_t *host_client; + +//=========================================================== + +void SV_Init (void); + +void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); +void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate); +void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation, qboolean reliable, float speed); +void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation, float speed); + +void SV_ConnectClient (int clientnum, netconn_t *netconnection); +void SV_DropClient (qboolean crash); + +void SV_SendClientMessages(void); + +void SV_ReadClientMessage(void); + +// precachemode values: +// 0 = fail if not precached, +// 1 = warn if not found and precache if possible +// 2 = precache +int SV_ModelIndex(const char *s, int precachemode); +int SV_SoundIndex(const char *s, int precachemode); + +int SV_ParticleEffectIndex(const char *name); + +dp_model_t *SV_GetModelByIndex(int modelindex); +dp_model_t *SV_GetModelFromEdict(prvm_edict_t *ed); + +void SV_SetIdealPitch (void); + +void SV_AddUpdates (void); + +void SV_ClientThink (void); + +void SV_ClientPrint(const char *msg); +void SV_ClientPrintf(const char *fmt, ...) DP_FUNC_PRINTF(1); +void SV_BroadcastPrint(const char *msg); +void SV_BroadcastPrintf(const char *fmt, ...) DP_FUNC_PRINTF(1); + +void SV_Physics (void); +void SV_Physics_ClientMove (void); +//void SV_Physics_ClientEntity (prvm_edict_t *ent); + +qboolean SV_PlayerCheckGround (prvm_edict_t *ent); +qboolean SV_CheckBottom (prvm_edict_t *ent); +qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace); + +/*! Needs to be called any time an entity changes origin, mins, maxs, or solid + * sets ent->v.absmin and ent->v.absmax + * call TouchAreaGrid as well to fire triggers that overlap the box + */ +void SV_LinkEdict(prvm_edict_t *ent); +void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent); +void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent); // if we detected a touch from another source + +/*! move an entity that is stuck by small amounts in various directions to try to nudge it back into the collision hull + * returns true if it found a better place + */ +qboolean SV_UnstickEntity (prvm_edict_t *ent); +/*! move an entity that is stuck out of the surface it is stuck in (can move large amounts) + * returns true if it found a better place + */ +qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent); + +/// calculates hitsupercontentsmask for a generic qc entity +int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict); +/// traces a box move against worldmodel and all entities in the specified area +trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask); +trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask); +trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask); +int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts); + +qboolean SV_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs); + +int SV_PointSuperContents(const vec3_t point); + +void SV_FlushBroadcastMessages(void); +void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats); + +void VM_SV_MoveToGoal(prvm_prog_t *prog); + +void SV_ApplyClientMove (void); +void SV_SaveSpawnparms (void); +void SV_SpawnServer (const char *server); + +void SV_CheckVelocity (prvm_edict_t *ent); + +void SV_SetupVM(void); + +const char *Host_TimingReport(char *buf, size_t buflen); ///< for output in Host_Status_f + +int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent); +void SV_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix); + +void SV_StartThread(void); +void SV_StopThread(void); +#define SV_LockThreadMutex() (void)(svs.threaded ? Thread_LockMutex(svs.threadmutex) : 0) +#define SV_UnlockThreadMutex() (void)(svs.threaded ? Thread_UnlockMutex(svs.threadmutex) : 0) + +void VM_CustomStats_Clear(void); +void VM_SV_UpdateCustomStats(client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats); +void Host_Savegame_to(prvm_prog_t *prog, const char *name); +void SV_SendServerinfo(client_t *client); + +#endif + diff --git a/app/jni/shader_glsl.h b/app/jni/shader_glsl.h new file mode 100644 index 0000000..487bd64 --- /dev/null +++ b/app/jni/shader_glsl.h @@ -0,0 +1,1699 @@ +"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n", +"// written by Forest 'LordHavoc' Hale\n", +"// shadowmapping enhancements by Lee 'eihrul' Salzman\n", +"\n", +"#ifdef USESKELETAL\n", +"# ifdef GL_ARB_uniform_buffer_object\n", +"# extension GL_ARB_uniform_buffer_object : enable\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAP2D\n", +"# ifdef GL_EXT_gpu_shader4\n", +"# extension GL_EXT_gpu_shader4 : enable\n", +"# endif\n", +"# ifdef GL_ARB_texture_gather\n", +"# extension GL_ARB_texture_gather : enable\n", +"# else\n", +"# ifdef GL_AMD_texture_texture4\n", +"# extension GL_AMD_texture_texture4 : enable\n", +"# endif\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USECELSHADING\n", +"# define SHADEDIFFUSE myhalf diffuse = cast_myhalf(min(max(float(dot(surfacenormal, lightnormal)) * 2.0, 0.0), 1.0));\n", +"# ifdef USEEXACTSPECULARMATH\n", +"# define SHADESPECULAR(specpow) myhalf specular = pow(cast_myhalf(max(float(dot(reflect(lightnormal, surfacenormal), eyenormal))*-1.0, 0.0)), 1.0 + specpow);specular = max(0.0, specular * 10.0 - 9.0);\n", +"# else\n", +"# define SHADESPECULAR(specpow) myhalf3 specularnormal = normalize(lightnormal + eyenormal);myhalf specular = pow(cast_myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + specpow);specular = max(0.0, specular * 10.0 - 9.0);\n", +"# endif\n", +"#else\n", +"# define SHADEDIFFUSE myhalf diffuse = cast_myhalf(max(float(dot(surfacenormal, lightnormal)), 0.0));\n", +"# ifdef USEEXACTSPECULARMATH\n", +"# define SHADESPECULAR(specpow) myhalf specular = pow(cast_myhalf(max(float(dot(reflect(lightnormal, surfacenormal), eyenormal))*-1.0, 0.0)), 1.0 + specpow);\n", +"# else\n", +"# define SHADESPECULAR(specpow) myhalf3 specularnormal = normalize(lightnormal + eyenormal);myhalf specular = pow(cast_myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + specpow);\n", +"# endif\n", +"#endif\n", +"\n", +"#if defined(GLSL130) || defined(GLSL140)\n", +"precision highp float;\n", +"# ifdef VERTEX_SHADER\n", +"# define dp_varying out\n", +"# define dp_attribute in\n", +"# endif\n", +"# ifdef FRAGMENT_SHADER\n", +"out vec4 dp_FragColor;\n", +"# define dp_varying in\n", +"# define dp_attribute in\n", +"# endif\n", +"# define dp_offsetmapping_dFdx dFdx\n", +"# define dp_offsetmapping_dFdy dFdy\n", +"# define dp_textureGrad textureGrad\n", +"# define dp_textureOffset(a,b,c,d) textureOffset(a,b,ivec2(c,d))\n", +"# define dp_texture2D texture\n", +"# define dp_texture3D texture\n", +"# define dp_textureCube texture\n", +"# define dp_shadow2D(a,b) float(texture(a,b))\n", +"#else\n", +"# ifdef FRAGMENT_SHADER\n", +"# define dp_FragColor gl_FragColor\n", +"# endif\n", +"# define dp_varying varying\n", +"# define dp_attribute attribute\n", +"# define dp_offsetmapping_dFdx(a) vec2(0.0, 0.0)\n", +"# define dp_offsetmapping_dFdy(a) vec2(0.0, 0.0)\n", +"# define dp_textureGrad(a,b,c,d) texture2D(a,b)\n", +"# define dp_textureOffset(a,b,c,d) texture2DOffset(a,b,ivec2(c,d))\n", +"# define dp_texture2D texture2D\n", +"# define dp_texture3D texture3D\n", +"# define dp_textureCube textureCube\n", +"# define dp_shadow2D(a,b) float(shadow2D(a,b))\n", +"#endif\n", +"\n", +"// GL ES and GLSL130 shaders use precision modifiers, standard GL does not\n", +"// in GLSL130 we don't use them though because of syntax differences (can't use precision with inout)\n", +"#ifndef GL_ES\n", +"#define lowp\n", +"#define mediump\n", +"#define highp\n", +"#endif\n", +"\n", +"#ifdef USEDEPTHRGB\n", +" // for 565 RGB we'd need to use different multipliers\n", +"#define decodedepthmacro(d) dot((d).rgb, vec3(1.0, 255.0 / 65536.0, 255.0 / 16777215.0))\n", +"#define encodedepthmacro(d) (vec4(d, d*256.0, d*65536.0, 0.0) - floor(vec4(d, d*256.0, d*65536.0, 0.0)))\n", +"#endif\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"dp_attribute vec4 Attrib_Position; // vertex\n", +"dp_attribute vec4 Attrib_Color; // color\n", +"dp_attribute vec4 Attrib_TexCoord0; // material texcoords\n", +"dp_attribute vec3 Attrib_TexCoord1; // svector\n", +"dp_attribute vec3 Attrib_TexCoord2; // tvector\n", +"dp_attribute vec3 Attrib_TexCoord3; // normal\n", +"dp_attribute vec4 Attrib_TexCoord4; // lightmap texcoords\n", +"#ifdef USESKELETAL\n", +"//uniform mat4 Skeletal_Transform[128];\n", +"// this is used with glBindBufferRange to bind a uniform block to the name\n", +"// Skeletal_Transform12_UniformBlock, the Skeletal_Transform12 variable is\n", +"// directly accessible without a namespace.\n", +"// explanation: http://www.opengl.org/wiki/Interface_Block_%28GLSL%29#Syntax\n", +"uniform Skeletal_Transform12_UniformBlock\n", +"{\n", +" vec4 Skeletal_Transform12[768];\n", +"};\n", +"dp_attribute vec4 Attrib_SkeletalIndex;\n", +"dp_attribute vec4 Attrib_SkeletalWeight;\n", +"#endif\n", +"#endif\n", +"dp_varying mediump vec4 VertexColor;\n", +"\n", +"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE) || defined(USEFOGHEIGHTTEXTURE)\n", +"# define USEFOG\n", +"#endif\n", +"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP)\n", +"# define USELIGHTMAP\n", +"#endif\n", +"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE) || defined(MODE_FAKELIGHT) || defined(USEFOG)\n", +"# define USEEYEVECTOR\n", +"#endif\n", +"\n", +"//#ifdef __GLSL_CG_DATA_TYPES\n", +"//# define myhalf half\n", +"//# define myhalf2 half2\n", +"//# define myhalf3 half3\n", +"//# define myhalf4 half4\n", +"//# define cast_myhalf half\n", +"//# define cast_myhalf2 half2\n", +"//# define cast_myhalf3 half3\n", +"//# define cast_myhalf4 half4\n", +"//#else\n", +"# define myhalf mediump float\n", +"# define myhalf2 mediump vec2\n", +"# define myhalf3 mediump vec3\n", +"# define myhalf4 mediump vec4\n", +"# define cast_myhalf float\n", +"# define cast_myhalf2 vec2\n", +"# define cast_myhalf3 vec3\n", +"# define cast_myhalf4 vec4\n", +"//#endif\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"uniform highp mat4 ModelViewProjectionMatrix;\n", +"#endif\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"#ifdef USETRIPPY\n", +"// LordHavoc: based on shader code linked at: http://www.youtube.com/watch?v=JpksyojwqzE\n", +"// tweaked scale\n", +"uniform highp float ClientTime;\n", +"vec4 TrippyVertex(vec4 position)\n", +"{\n", +" float worldTime = ClientTime;\n", +" // tweaked for Quake\n", +" worldTime *= 10.0;\n", +" position *= 0.125;\n", +" //~tweaked for Quake\n", +" float distanceSquared = (position.x * position.x + position.z * position.z);\n", +" position.y += 5.0*sin(distanceSquared*sin(worldTime/143.0)/1000.0);\n", +" float y = position.y;\n", +" float x = position.x;\n", +" float om = sin(distanceSquared*sin(worldTime/256.0)/5000.0) * sin(worldTime/200.0);\n", +" position.y = x*sin(om)+y*cos(om);\n", +" position.x = x*cos(om)-y*sin(om);\n", +" return position;\n", +"}\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef MODE_DEPTH_OR_SHADOW\n", +"dp_varying highp float Depth;\n", +"#ifdef VERTEX_SHADER\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +"#define Attrib_Position SkeletalVertex\n", +"#endif\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +" Depth = gl_Position.z;\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main(void)\n", +"{\n", +"#ifdef USEDEPTHRGB\n", +" dp_FragColor = encodedepthmacro(Depth);\n", +"#else\n", +" dp_FragColor = vec4(1.0,1.0,1.0,1.0);\n", +"#endif\n", +"}\n", +"#endif\n", +"#else // !MODE_DEPTH_ORSHADOW\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_POSTPROCESS\n", +"dp_varying mediump vec2 TexCoord1;\n", +"dp_varying mediump vec2 TexCoord2;\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"void main(void)\n", +"{\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +" TexCoord1 = Attrib_TexCoord0.xy;\n", +"#ifdef USEBLOOM\n", +" TexCoord2 = Attrib_TexCoord4.xy;\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"uniform sampler2D Texture_First;\n", +"#ifdef USEBLOOM\n", +"uniform sampler2D Texture_Second;\n", +"uniform mediump vec4 BloomColorSubtract;\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +"uniform sampler2D Texture_GammaRamps;\n", +"#endif\n", +"#ifdef USESATURATION\n", +"uniform mediump float Saturation;\n", +"#endif\n", +"#ifdef USEVIEWTINT\n", +"uniform mediump vec4 ViewTintColor;\n", +"#endif\n", +"//uncomment these if you want to use them:\n", +"uniform mediump vec4 UserVec1;\n", +"uniform mediump vec4 UserVec2;\n", +"// uniform mediump vec4 UserVec3;\n", +"// uniform mediump vec4 UserVec4;\n", +"// uniform highp float ClientTime;\n", +"uniform mediump vec2 PixelSize;\n", +"void main(void)\n", +"{\n", +" dp_FragColor = dp_texture2D(Texture_First, TexCoord1);\n", +"\n", +"#ifdef USEPOSTPROCESSING\n", +"// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n", +"// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n", +" float sobel = 1.0;\n", +" // vec2 ts = textureSize(Texture_First, 0);\n", +" // vec2 px = vec2(1/ts.x, 1/ts.y);\n", +" vec2 px = PixelSize;\n", +" vec3 x1 = dp_texture2D(Texture_First, TexCoord1 + vec2(-px.x, px.y)).rgb;\n", +" vec3 x2 = dp_texture2D(Texture_First, TexCoord1 + vec2(-px.x, 0.0)).rgb;\n", +" vec3 x3 = dp_texture2D(Texture_First, TexCoord1 + vec2(-px.x,-px.y)).rgb;\n", +" vec3 x4 = dp_texture2D(Texture_First, TexCoord1 + vec2( px.x, px.y)).rgb;\n", +" vec3 x5 = dp_texture2D(Texture_First, TexCoord1 + vec2( px.x, 0.0)).rgb;\n", +" vec3 x6 = dp_texture2D(Texture_First, TexCoord1 + vec2( px.x,-px.y)).rgb;\n", +" vec3 y1 = dp_texture2D(Texture_First, TexCoord1 + vec2( px.x,-px.y)).rgb;\n", +" vec3 y2 = dp_texture2D(Texture_First, TexCoord1 + vec2( 0.0,-px.y)).rgb;\n", +" vec3 y3 = dp_texture2D(Texture_First, TexCoord1 + vec2(-px.x,-px.y)).rgb;\n", +" vec3 y4 = dp_texture2D(Texture_First, TexCoord1 + vec2( px.x, px.y)).rgb;\n", +" vec3 y5 = dp_texture2D(Texture_First, TexCoord1 + vec2( 0.0, px.y)).rgb;\n", +" vec3 y6 = dp_texture2D(Texture_First, TexCoord1 + vec2(-px.x, px.y)).rgb;\n", +" float px1 = -1.0 * dot(vec3(0.3, 0.59, 0.11), x1);\n", +" float px2 = -2.0 * dot(vec3(0.3, 0.59, 0.11), x2);\n", +" float px3 = -1.0 * dot(vec3(0.3, 0.59, 0.11), x3);\n", +" float px4 = 1.0 * dot(vec3(0.3, 0.59, 0.11), x4);\n", +" float px5 = 2.0 * dot(vec3(0.3, 0.59, 0.11), x5);\n", +" float px6 = 1.0 * dot(vec3(0.3, 0.59, 0.11), x6);\n", +" float py1 = -1.0 * dot(vec3(0.3, 0.59, 0.11), y1);\n", +" float py2 = -2.0 * dot(vec3(0.3, 0.59, 0.11), y2);\n", +" float py3 = -1.0 * dot(vec3(0.3, 0.59, 0.11), y3);\n", +" float py4 = 1.0 * dot(vec3(0.3, 0.59, 0.11), y4);\n", +" float py5 = 2.0 * dot(vec3(0.3, 0.59, 0.11), y5);\n", +" float py6 = 1.0 * dot(vec3(0.3, 0.59, 0.11), y6);\n", +" sobel = 0.25 * abs(px1 + px2 + px3 + px4 + px5 + px6) + 0.25 * abs(py1 + py2 + py3 + py4 + py5 + py6);\n", +" dp_FragColor += dp_texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n", +" dp_FragColor += dp_texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n", +" dp_FragColor += dp_texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n", +" dp_FragColor += dp_texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2( 0.707107, 0.707107)) * UserVec1.y;\n", +" dp_FragColor += dp_texture2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*vec2(-0.453990, 0.891007)) * UserVec1.y;\n", +" dp_FragColor /= (1.0 + 5.0 * UserVec1.y);\n", +" dp_FragColor.rgb = dp_FragColor.rgb * (1.0 + UserVec2.x) + vec3(max(0.0, sobel - UserVec2.z))*UserVec2.y;\n", +"#endif\n", +"\n", +"#ifdef USEBLOOM\n", +" dp_FragColor += max(vec4(0,0,0,0), dp_texture2D(Texture_Second, TexCoord2) - BloomColorSubtract);\n", +"#endif\n", +"\n", +"#ifdef USEVIEWTINT\n", +" dp_FragColor = mix(dp_FragColor, ViewTintColor, ViewTintColor.a);\n", +"#endif\n", +"\n", +"#ifdef USESATURATION\n", +" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n", +" float y = dot(dp_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n", +" // 'vampire sight' effect, wheres red is compensated\n", +" #ifdef SATURATION_REDCOMPENSATE\n", +" float rboost = max(0.0, (dp_FragColor.r - max(dp_FragColor.g, dp_FragColor.b))*(1.0 - Saturation));\n", +" dp_FragColor.rgb = mix(vec3(y), dp_FragColor.rgb, Saturation);\n", +" dp_FragColor.r += rboost;\n", +" #else\n", +" // normal desaturation\n", +" //dp_FragColor = vec3(y) + (dp_FragColor.rgb - vec3(y)) * Saturation;\n", +" dp_FragColor.rgb = mix(vec3(y), dp_FragColor.rgb, Saturation);\n", +" #endif\n", +"#endif\n", +"\n", +"#ifdef USEGAMMARAMPS\n", +" dp_FragColor.r = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.r, 0)).r;\n", +" dp_FragColor.g = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.g, 0)).g;\n", +" dp_FragColor.b = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.b, 0)).b;\n", +"#endif\n", +"}\n", +"#endif\n", +"#else // !MODE_POSTPROCESS\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_GENERIC\n", +"#ifdef USEDIFFUSE\n", +"dp_varying mediump vec2 TexCoord1;\n", +"#endif\n", +"#ifdef USESPECULAR\n", +"dp_varying mediump vec2 TexCoord2;\n", +"#endif\n", +"uniform myhalf Alpha;\n", +"#ifdef VERTEX_SHADER\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +"#define Attrib_Position SkeletalVertex\n", +"#endif\n", +" VertexColor = Attrib_Color;\n", +"#ifdef USEDIFFUSE\n", +" TexCoord1 = Attrib_TexCoord0.xy;\n", +"#endif\n", +"#ifdef USESPECULAR\n", +" TexCoord2 = Attrib_TexCoord1.xy;\n", +"#endif\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"#ifdef USEDIFFUSE\n", +"uniform sampler2D Texture_First;\n", +"#endif\n", +"#ifdef USESPECULAR\n", +"uniform sampler2D Texture_Second;\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +"uniform sampler2D Texture_GammaRamps;\n", +"#endif\n", +"\n", +"void main(void)\n", +"{\n", +"#ifdef USEVIEWTINT\n", +" dp_FragColor = VertexColor;\n", +"#else\n", +" dp_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n", +"#endif\n", +"#ifdef USEDIFFUSE\n", +"# ifdef USEREFLECTCUBE\n", +" // suppress texture alpha\n", +" dp_FragColor.rgb *= dp_texture2D(Texture_First, TexCoord1).rgb;\n", +"# else\n", +" dp_FragColor *= dp_texture2D(Texture_First, TexCoord1);\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESPECULAR\n", +" vec4 tex2 = dp_texture2D(Texture_Second, TexCoord2);\n", +"# ifdef USECOLORMAPPING\n", +" dp_FragColor *= tex2;\n", +"# endif\n", +"# ifdef USEGLOW\n", +" dp_FragColor += tex2;\n", +"# endif\n", +"# ifdef USEVERTEXTEXTUREBLEND\n", +" dp_FragColor = mix(dp_FragColor, tex2, tex2.a);\n", +"# endif\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +" dp_FragColor.r = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.r, 0)).r;\n", +" dp_FragColor.g = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.g, 0)).g;\n", +" dp_FragColor.b = dp_texture2D(Texture_GammaRamps, vec2(dp_FragColor.b, 0)).b;\n", +"#endif\n", +"#ifdef USEALPHAKILL\n", +" dp_FragColor.a *= Alpha;\n", +"#endif\n", +"}\n", +"#endif\n", +"#else // !MODE_GENERIC\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_BLOOMBLUR\n", +"dp_varying mediump vec2 TexCoord;\n", +"#ifdef VERTEX_SHADER\n", +"void main(void)\n", +"{\n", +" VertexColor = Attrib_Color;\n", +" TexCoord = Attrib_TexCoord0.xy;\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"uniform sampler2D Texture_First;\n", +"uniform mediump vec4 BloomBlur_Parameters;\n", +"\n", +"void main(void)\n", +"{\n", +" int i;\n", +" vec2 tc = TexCoord;\n", +" vec3 color = dp_texture2D(Texture_First, tc).rgb;\n", +" tc += BloomBlur_Parameters.xy;\n", +" for (i = 1;i < SAMPLES;i++)\n", +" {\n", +" color += dp_texture2D(Texture_First, tc).rgb;\n", +" tc += BloomBlur_Parameters.xy;\n", +" }\n", +" dp_FragColor = vec4(color * BloomBlur_Parameters.z + vec3(BloomBlur_Parameters.w), 1);\n", +"}\n", +"#endif\n", +"#else // !MODE_BLOOMBLUR\n", +"#ifdef MODE_REFRACTION\n", +"dp_varying mediump vec2 TexCoord;\n", +"dp_varying highp vec4 ModelViewProjectionPosition;\n", +"uniform highp mat4 TexMatrix;\n", +"#ifdef VERTEX_SHADER\n", +"\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +"#define Attrib_Position SkeletalVertex\n", +"#endif\n", +"#ifdef USEALPHAGENVERTEX\n", +" VertexColor = Attrib_Color;\n", +"#endif\n", +" TexCoord = vec2(TexMatrix * Attrib_TexCoord0);\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"uniform sampler2D Texture_Normal;\n", +"uniform sampler2D Texture_Refraction;\n", +"\n", +"uniform mediump vec4 DistortScaleRefractReflect;\n", +"uniform mediump vec4 ScreenScaleRefractReflect;\n", +"uniform mediump vec4 ScreenCenterRefractReflect;\n", +"uniform mediump vec4 RefractColor;\n", +"uniform mediump vec4 ReflectColor;\n", +"uniform highp float ClientTime;\n", +"#ifdef USENORMALMAPSCROLLBLEND\n", +"uniform highp vec2 NormalmapScrollBlend;\n", +"#endif\n", +"\n", +"void main(void)\n", +"{\n", +" vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n", +" //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n", +" vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n", +"#ifdef USEALPHAGENVERTEX\n", +" vec2 distort = DistortScaleRefractReflect.xy * VertexColor.a;\n", +" vec4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), VertexColor.a);\n", +"#else\n", +" vec2 distort = DistortScaleRefractReflect.xy;\n", +" vec4 refractcolor = RefractColor;\n", +"#endif\n", +" #ifdef USENORMALMAPSCROLLBLEND\n", +" vec3 normal = dp_texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n", +" normal += dp_texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n", +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * distort;\n", +" #else\n", +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(dp_texture2D(Texture_Normal, TexCoord)) - cast_myhalf3(0.5))).xy * distort;\n", +" #endif\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n", +" dp_FragColor = vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord).rgb, 1.0) * refractcolor;\n", +"}\n", +"#endif\n", +"#else // !MODE_REFRACTION\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_WATER\n", +"dp_varying mediump vec2 TexCoord;\n", +"dp_varying highp vec3 EyeVector;\n", +"dp_varying highp vec4 ModelViewProjectionPosition;\n", +"#ifdef VERTEX_SHADER\n", +"uniform highp vec3 EyePosition;\n", +"uniform highp mat4 TexMatrix;\n", +"\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +" mat3 SkeletalNormalMatrix = mat3(cross(SkeletalMatrix[1].xyz, SkeletalMatrix[2].xyz), cross(SkeletalMatrix[2].xyz, SkeletalMatrix[0].xyz), cross(SkeletalMatrix[0].xyz, SkeletalMatrix[1].xyz)); // is actually transpose(inverse(mat3(SkeletalMatrix))) * det(mat3(SkeletalMatrix))\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +" vec3 SkeletalSVector = normalize(Attrib_TexCoord1.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalTVector = normalize(Attrib_TexCoord2.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalNormal = normalize(Attrib_TexCoord3.xyz * SkeletalNormalMatrix);\n", +"#define Attrib_Position SkeletalVertex\n", +"#define Attrib_TexCoord1 SkeletalSVector\n", +"#define Attrib_TexCoord2 SkeletalTVector\n", +"#define Attrib_TexCoord3 SkeletalNormal\n", +"#endif\n", +"#ifdef USEALPHAGENVERTEX\n", +" VertexColor = Attrib_Color;\n", +"#endif\n", +" TexCoord = vec2(TexMatrix * Attrib_TexCoord0);\n", +" vec3 EyeRelative = EyePosition - Attrib_Position.xyz;\n", +" EyeVector.x = dot(EyeRelative, Attrib_TexCoord1.xyz);\n", +" EyeVector.y = dot(EyeRelative, Attrib_TexCoord2.xyz);\n", +" EyeVector.z = dot(EyeRelative, Attrib_TexCoord3.xyz);\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"uniform sampler2D Texture_Normal;\n", +"uniform sampler2D Texture_Refraction;\n", +"uniform sampler2D Texture_Reflection;\n", +"\n", +"uniform mediump vec4 DistortScaleRefractReflect;\n", +"uniform mediump vec4 ScreenScaleRefractReflect;\n", +"uniform mediump vec4 ScreenCenterRefractReflect;\n", +"uniform mediump vec4 RefractColor;\n", +"uniform mediump vec4 ReflectColor;\n", +"uniform mediump float ReflectFactor;\n", +"uniform mediump float ReflectOffset;\n", +"uniform highp float ClientTime;\n", +"#ifdef USENORMALMAPSCROLLBLEND\n", +"uniform highp vec2 NormalmapScrollBlend;\n", +"#endif\n", +"\n", +"void main(void)\n", +"{\n", +" vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n", +" //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" //SafeScreenTexCoord = gl_FragCoord.xyxy * vec4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n", +" // slight water animation via 2 layer scrolling (todo: tweak)\n", +"#ifdef USEALPHAGENVERTEX\n", +" vec4 distort = DistortScaleRefractReflect * VertexColor.a;\n", +" float reflectoffset = ReflectOffset * VertexColor.a;\n", +" float reflectfactor = ReflectFactor * VertexColor.a;\n", +" vec4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), VertexColor.a);\n", +"#else\n", +" vec4 distort = DistortScaleRefractReflect;\n", +" float reflectoffset = ReflectOffset;\n", +" float reflectfactor = ReflectFactor;\n", +" vec4 refractcolor = RefractColor;\n", +"#endif\n", +" #ifdef USENORMALMAPSCROLLBLEND\n", +" vec3 normal = dp_texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n", +" normal += dp_texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n", +" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(normal) + vec3(0.15)).xyxy * distort;\n", +" #else\n", +" vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(vec3(dp_texture2D(Texture_Normal, TexCoord)) - vec3(0.5))).xyxy * distort;\n", +" #endif\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.005, 0.01)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.005, -0.01)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.005, 0.01)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.005, -0.01)).rgb) / 0.002);\n", +" ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n", +" f = min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.005, 0.005)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.005, -0.005)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, 0.005)).rgb) / 0.002);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.005, -0.005)).rgb) / 0.002);\n", +" ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n", +" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * reflectfactor + reflectoffset;\n", +" dp_FragColor = mix(vec4(dp_texture2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * refractcolor, vec4(dp_texture2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n", +"}\n", +"#endif\n", +"#else // !MODE_WATER\n", +"\n", +"\n", +"\n", +"\n", +"// common definitions between vertex shader and fragment shader:\n", +"\n", +"dp_varying mediump vec4 TexCoordSurfaceLightmap;\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"dp_varying mediump vec2 TexCoord2;\n", +"#endif\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +"dp_varying mediump vec3 CubeVector;\n", +"#endif\n", +"\n", +"#if (defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)) && defined(USEDIFFUSE)\n", +"dp_varying mediump vec3 LightVector;\n", +"#endif\n", +"\n", +"#ifdef USEEYEVECTOR\n", +"dp_varying highp vec4 EyeVectorFogDepth;\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE) || defined(USEBOUNCEGRIDDIRECTIONAL)\n", +"dp_varying highp vec4 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n", +"dp_varying highp vec4 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n", +"dp_varying highp vec4 VectorR; // direction of R texcoord (surface normal)\n", +"#else\n", +"# ifdef USEFOG\n", +"dp_varying highp vec3 EyeVectorModelSpace;\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USEREFLECTION\n", +"dp_varying highp vec4 ModelViewProjectionPosition;\n", +"#endif\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"uniform highp vec3 LightPosition;\n", +"dp_varying highp vec4 ModelViewPosition;\n", +"#endif\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform highp vec3 LightPosition;\n", +"#endif\n", +"uniform highp vec3 EyePosition;\n", +"#ifdef MODE_LIGHTDIRECTION\n", +"uniform highp vec3 LightDir;\n", +"#endif\n", +"uniform highp vec4 FogPlane;\n", +"\n", +"#ifdef USESHADOWMAPORTHO\n", +"dp_varying highp vec3 ShadowMapTC;\n", +"#endif\n", +"\n", +"#ifdef USEBOUNCEGRID\n", +"dp_varying highp vec3 BounceGridTexCoord;\n", +"#endif\n", +"\n", +"#ifdef MODE_DEFERREDGEOMETRY\n", +"dp_varying highp float Depth;\n", +"#endif\n", +"\n", +"\n", +"\n", +"\n", +"\n", +"\n", +"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n", +"\n", +"// fragment shader specific:\n", +"#ifdef FRAGMENT_SHADER\n", +"\n", +"uniform sampler2D Texture_Normal;\n", +"uniform sampler2D Texture_Color;\n", +"uniform sampler2D Texture_Gloss;\n", +"#ifdef USEGLOW\n", +"uniform sampler2D Texture_Glow;\n", +"#endif\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform sampler2D Texture_SecondaryNormal;\n", +"uniform sampler2D Texture_SecondaryColor;\n", +"uniform sampler2D Texture_SecondaryGloss;\n", +"#ifdef USEGLOW\n", +"uniform sampler2D Texture_SecondaryGlow;\n", +"#endif\n", +"#endif\n", +"#ifdef USECOLORMAPPING\n", +"uniform sampler2D Texture_Pants;\n", +"uniform sampler2D Texture_Shirt;\n", +"#endif\n", +"#ifdef USEFOG\n", +"#ifdef USEFOGHEIGHTTEXTURE\n", +"uniform sampler2D Texture_FogHeightTexture;\n", +"#endif\n", +"uniform sampler2D Texture_FogMask;\n", +"#endif\n", +"#ifdef USELIGHTMAP\n", +"uniform sampler2D Texture_Lightmap;\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n", +"uniform sampler2D Texture_Deluxemap;\n", +"#endif\n", +"#ifdef USEREFLECTION\n", +"uniform sampler2D Texture_Reflection;\n", +"#endif\n", +"\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"uniform sampler2D Texture_ScreenNormalMap;\n", +"#endif\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +"#ifdef USECELOUTLINES\n", +"uniform sampler2D Texture_ScreenNormalMap;\n", +"#endif\n", +"uniform sampler2D Texture_ScreenDiffuse;\n", +"uniform sampler2D Texture_ScreenSpecular;\n", +"#endif\n", +"\n", +"uniform mediump vec3 Color_Pants;\n", +"uniform mediump vec3 Color_Shirt;\n", +"uniform mediump vec3 FogColor;\n", +"\n", +"#ifdef USEFOG\n", +"uniform highp float FogRangeRecip;\n", +"uniform highp float FogPlaneViewDist;\n", +"uniform highp float FogHeightFade;\n", +"vec3 FogVertex(vec4 surfacecolor)\n", +"{\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE) || defined(USEBOUNCEGRIDDIRECTIONAL)\n", +" vec3 EyeVectorModelSpace = vec3(VectorS.w, VectorT.w, VectorR.w);\n", +"#endif\n", +" float FogPlaneVertexDist = EyeVectorFogDepth.w;\n", +" float fogfrac;\n", +" vec3 fc = FogColor;\n", +"#ifdef USEFOGALPHAHACK\n", +" fc *= surfacecolor.a;\n", +"#endif\n", +"#ifdef USEFOGHEIGHTTEXTURE\n", +" vec4 fogheightpixel = dp_texture2D(Texture_FogHeightTexture, vec2(1,1) + vec2(FogPlaneVertexDist, FogPlaneViewDist) * (-2.0 * FogHeightFade));\n", +" fogfrac = fogheightpixel.a;\n", +" return mix(fogheightpixel.rgb * fc, surfacecolor.rgb, dp_texture2D(Texture_FogMask, cast_myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n", +"#else\n", +"# ifdef USEFOGOUTSIDE\n", +" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n", +"# else\n", +" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n", +"# endif\n", +" return mix(fc, surfacecolor.rgb, dp_texture2D(Texture_FogMask, cast_myhalf2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef USEOFFSETMAPPING\n", +"uniform mediump vec4 OffsetMapping_ScaleSteps;\n", +"uniform mediump float OffsetMapping_Bias;\n", +"#ifdef USEOFFSETMAPPING_LOD\n", +"uniform mediump float OffsetMapping_LodDistance;\n", +"#endif\n", +"vec2 OffsetMapping(vec2 TexCoord, vec2 dPdx, vec2 dPdy)\n", +"{\n", +" float i;\n", +" // distance-based LOD\n", +"#ifdef USEOFFSETMAPPING_LOD\n", +" //mediump float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n", +" //mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n", +" mediump float GuessLODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n", +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n", +" // stupid workaround because 1-step and 2-step reliefmapping is void\n", +" mediump float LODSteps = max(3.0, ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y));\n", +"#else\n", +" mediump float LODSteps = ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y);\n", +"#endif\n", +" mediump float LODFactor = LODSteps / OffsetMapping_ScaleSteps.y;\n", +" mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, LODSteps, 1.0 / LODSteps, OffsetMapping_ScaleSteps.w * LODFactor);\n", +"#else\n", +" #define ScaleSteps OffsetMapping_ScaleSteps\n", +"#endif\n", +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n", +" float f;\n", +" // 14 sample relief mapping: linear search and then binary search\n", +" // this basically steps forward a small amount repeatedly until it finds\n", +" // itself inside solid, then jitters forward and back using decreasing\n", +" // amounts to find the impact\n", +" //vec3 OffsetVector = vec3(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * ScaleSteps.x) * vec2(-1, 1), -1);\n", +" //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * ScaleSteps.x * vec2(-1, 1), -1);\n", +" vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * ScaleSteps.x * vec2(-1, 1), -1);\n", +" vec3 RT = vec3(vec2(TexCoord.xy - OffsetVector.xy*OffsetMapping_Bias), 1);\n", +" OffsetVector *= ScaleSteps.z;\n", +" for(i = 1.0; i < ScaleSteps.y; ++i)\n", +" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n", +" for(i = 0.0, f = 1.0; i < ScaleSteps.w; ++i, f *= 0.5)\n", +" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n", +" return RT.xy;\n", +"#else\n", +" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n", +" //vec2 OffsetVector = vec2(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * ScaleSteps.x) * vec2(-1, 1));\n", +" //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * ScaleSteps.x * vec2(-1, 1));\n", +" vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * ScaleSteps.x * vec2(-1, 1));\n", +" OffsetVector *= ScaleSteps.z;\n", +" for(i = 0.0; i < ScaleSteps.y; ++i)\n", +" TexCoord += OffsetVector * ((1.0 - OffsetMapping_Bias) - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n", +" return TexCoord;\n", +"#endif\n", +"}\n", +"#endif // USEOFFSETMAPPING\n", +"\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n", +"uniform sampler2D Texture_Attenuation;\n", +"uniform samplerCube Texture_Cube;\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n", +"\n", +"#ifdef USESHADOWMAP2D\n", +"# ifdef USESHADOWSAMPLER\n", +"uniform sampler2DShadow Texture_ShadowMap2D;\n", +"# else\n", +"uniform sampler2D Texture_ShadowMap2D;\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAPVSDCT\n", +"uniform samplerCube Texture_CubeProjection;\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +"uniform mediump vec2 ShadowMap_TextureScale;\n", +"uniform mediump vec4 ShadowMap_Parameters;\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +"# ifdef USESHADOWMAPORTHO\n", +"# define GetShadowMapTC2D(dir) (min(dir, ShadowMap_Parameters.xyz))\n", +"# else\n", +"# ifdef USESHADOWMAPVSDCT\n", +"vec3 GetShadowMapTC2D(vec3 dir)\n", +"{\n", +" vec3 adir = abs(dir);\n", +" float m = max(max(adir.x, adir.y), adir.z);\n", +" vec4 proj = dp_textureCube(Texture_CubeProjection, dir);\n", +"#ifdef USEDEPTHRGB\n", +" return vec3(mix(dir.xy, dir.zz, proj.xy) * (ShadowMap_Parameters.x / m) + proj.zw * ShadowMap_Parameters.z, m + 64.0 * ShadowMap_Parameters.w);\n", +"#else\n", +" vec2 mparams = ShadowMap_Parameters.xy / m;\n", +" return vec3(mix(dir.xy, dir.zz, proj.xy) * mparams.x + proj.zw * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n", +"#endif\n", +"}\n", +"# else\n", +"vec3 GetShadowMapTC2D(vec3 dir)\n", +"{\n", +" vec3 adir = abs(dir);\n", +" float m; vec4 proj;\n", +" if (adir.x > adir.y) { m = adir.x; proj = vec4(dir.zyx, 0.5); } else { m = adir.y; proj = vec4(dir.xzy, 1.5); }\n", +" if (adir.z > m) { m = adir.z; proj = vec4(dir, 2.5); }\n", +"#ifdef USEDEPTHRGB\n", +" return vec3(proj.xy * (ShadowMap_Parameters.x / m) + vec2(0.5,0.5) + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, m + 64.0 * ShadowMap_Parameters.w);\n", +"#else\n", +" vec2 mparams = ShadowMap_Parameters.xy / m;\n", +" return vec3(proj.xy * mparams.x + vec2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n", +"#endif\n", +"}\n", +"# endif\n", +"# endif\n", +"#endif // defined(USESHADOWMAP2D)\n", +"\n", +"# ifdef USESHADOWMAP2D\n", +"float ShadowMapCompare(vec3 dir)\n", +"{\n", +" vec3 shadowmaptc = GetShadowMapTC2D(dir);\n", +" float f;\n", +"\n", +"# ifdef USEDEPTHRGB\n", +"# ifdef USESHADOWMAPPCF\n", +"# define texval(x, y) decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale))\n", +"# if USESHADOWMAPPCF > 1\n", +" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n", +" center *= ShadowMap_TextureScale;\n", +" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n", +" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n", +" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n", +" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n", +" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n", +" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n", +"# else\n", +" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n", +" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n", +" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n", +" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n", +" vec3 cols = row2 + mix(row1, row3, offset.y);\n", +" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n", +"# endif\n", +"# else\n", +" f = step(shadowmaptc.z, decodedepthmacro(dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale)));\n", +"# endif\n", +"# else\n", +"# ifdef USESHADOWSAMPLER\n", +"# ifdef USESHADOWMAPPCF\n", +"# define texval(off) dp_shadow2D(Texture_ShadowMap2D, vec3(off, shadowmaptc.z)) \n", +" vec2 offset = fract(shadowmaptc.xy - 0.5);\n", +" vec4 size = vec4(offset + 1.0, 2.0 - offset);\n", +"# if USESHADOWMAPPCF > 1\n", +" vec2 center = (shadowmaptc.xy - offset + 0.5)*ShadowMap_TextureScale;\n", +" vec4 weight = (vec4(-1.5, -1.5, 2.0, 2.0) + (shadowmaptc.xy - 0.5*offset).xyxy)*ShadowMap_TextureScale.xyxy;\n", +" f = (1.0/25.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.xy), texval(weight.zy), texval(weight.xw), texval(weight.zw))) +\n", +" (2.0/25.0)*dot(size, vec4(texval(vec2(weight.z, center.y)), texval(vec2(center.x, weight.w)), texval(vec2(weight.x, center.y)), texval(vec2(center.x, weight.y)))) +\n", +" (4.0/25.0)*texval(center);\n", +"# else\n", +" vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (shadowmaptc.xy - 0.5*offset).xyxy)*ShadowMap_TextureScale.xyxy;\n", +" f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));\n", +"# endif \n", +"# else\n", +" f = dp_shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));\n", +"# endif\n", +"# else\n", +"# ifdef USESHADOWMAPPCF\n", +"# if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n", +"# ifdef GL_ARB_texture_gather\n", +"# define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec2(x, y))\n", +"# else\n", +"# define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale)\n", +"# endif\n", +" vec2 offset = fract(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n", +"# if USESHADOWMAPPCF > 1\n", +" vec4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n", +" vec4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n", +" vec4 group3 = step(shadowmaptc.z, texval( 2.0, -2.0));\n", +" vec4 group4 = step(shadowmaptc.z, texval(-2.0, 0.0));\n", +" vec4 group5 = step(shadowmaptc.z, texval( 0.0, 0.0));\n", +" vec4 group6 = step(shadowmaptc.z, texval( 2.0, 0.0));\n", +" vec4 group7 = step(shadowmaptc.z, texval(-2.0, 2.0));\n", +" vec4 group8 = step(shadowmaptc.z, texval( 0.0, 2.0));\n", +" vec4 group9 = step(shadowmaptc.z, texval( 2.0, 2.0));\n", +" vec4 locols = vec4(group1.ab, group3.ab);\n", +" vec4 hicols = vec4(group7.rg, group9.rg);\n", +" locols.yz += group2.ab;\n", +" hicols.yz += group8.rg;\n", +" vec4 midcols = vec4(group1.rg, group3.rg) + vec4(group7.ab, group9.ab) +\n", +" vec4(group4.rg, group6.rg) + vec4(group4.ab, group6.ab) +\n", +" mix(locols, hicols, offset.y);\n", +" vec4 cols = group5 + vec4(group2.rg, group8.ab);\n", +" cols.xyz += mix(midcols.xyz, midcols.yzw, offset.x);\n", +" f = dot(cols, vec4(1.0/25.0));\n", +"# else\n", +" vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n", +" vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n", +" vec4 group3 = step(shadowmaptc.z, texval(-1.0, 1.0));\n", +" vec4 group4 = step(shadowmaptc.z, texval( 1.0, 1.0));\n", +" vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n", +" mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n", +" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n", +"# endif\n", +"# else\n", +"# ifdef GL_EXT_gpu_shader4\n", +"# define texval(x, y) dp_textureOffset(Texture_ShadowMap2D, center, x, y).r\n", +"# else\n", +"# define texval(x, y) dp_texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r \n", +"# endif\n", +"# if USESHADOWMAPPCF > 1\n", +" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n", +" center *= ShadowMap_TextureScale;\n", +" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n", +" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n", +" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n", +" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n", +" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n", +" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n", +"# else\n", +" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n", +" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n", +" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n", +" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n", +" vec3 cols = row2 + mix(row1, row3, offset.y);\n", +" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n", +"# endif\n", +"# endif\n", +"# else\n", +" f = step(shadowmaptc.z, dp_texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n", +"# endif\n", +"# endif\n", +"# endif\n", +"# ifdef USESHADOWMAPORTHO\n", +" return mix(ShadowMap_Parameters.w, 1.0, f);\n", +"# else\n", +" return f;\n", +"# endif\n", +"}\n", +"# endif\n", +"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n", +"#endif // FRAGMENT_SHADER\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_DEFERREDGEOMETRY\n", +"#ifdef VERTEX_SHADER\n", +"uniform highp mat4 TexMatrix;\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform highp mat4 BackgroundTexMatrix;\n", +"#endif\n", +"uniform highp mat4 ModelViewMatrix;\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +" mat3 SkeletalNormalMatrix = mat3(cross(SkeletalMatrix[1].xyz, SkeletalMatrix[2].xyz), cross(SkeletalMatrix[2].xyz, SkeletalMatrix[0].xyz), cross(SkeletalMatrix[0].xyz, SkeletalMatrix[1].xyz)); // is actually transpose(inverse(mat3(SkeletalMatrix))) * det(mat3(SkeletalMatrix))\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +" vec3 SkeletalSVector = normalize(Attrib_TexCoord1.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalTVector = normalize(Attrib_TexCoord2.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalNormal = normalize(Attrib_TexCoord3.xyz * SkeletalNormalMatrix);\n", +"#define Attrib_Position SkeletalVertex\n", +"#define Attrib_TexCoord1 SkeletalSVector\n", +"#define Attrib_TexCoord2 SkeletalTVector\n", +"#define Attrib_TexCoord3 SkeletalNormal\n", +"#endif\n", +" TexCoordSurfaceLightmap = vec4((TexMatrix * Attrib_TexCoord0).xy, 0.0, 0.0);\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" VertexColor = Attrib_Color;\n", +" TexCoord2 = vec2(BackgroundTexMatrix * Attrib_TexCoord0);\n", +"#endif\n", +"\n", +" // transform unnormalized eye direction into tangent space\n", +"#ifdef USEOFFSETMAPPING\n", +" vec3 EyeRelative = EyePosition - Attrib_Position.xyz;\n", +" EyeVectorFogDepth.x = dot(EyeRelative, Attrib_TexCoord1.xyz);\n", +" EyeVectorFogDepth.y = dot(EyeRelative, Attrib_TexCoord2.xyz);\n", +" EyeVectorFogDepth.z = dot(EyeRelative, Attrib_TexCoord3.xyz);\n", +" EyeVectorFogDepth.w = 0.0;\n", +"#endif\n", +"\n", +" VectorS = (ModelViewMatrix * vec4(Attrib_TexCoord1.xyz, 0));\n", +" VectorT = (ModelViewMatrix * vec4(Attrib_TexCoord2.xyz, 0));\n", +" VectorR = (ModelViewMatrix * vec4(Attrib_TexCoord3.xyz, 0));\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +" Depth = (ModelViewMatrix * Attrib_Position).z;\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main(void)\n", +"{\n", +"#ifdef USEOFFSETMAPPING\n", +" // apply offsetmapping\n", +" vec2 dPdx = dp_offsetmapping_dFdx(TexCoordSurfaceLightmap.xy);\n", +" vec2 dPdy = dp_offsetmapping_dFdy(TexCoordSurfaceLightmap.xy);\n", +" vec2 TexCoordOffset = OffsetMapping(TexCoordSurfaceLightmap.xy, dPdx, dPdy);\n", +"# define offsetMappedTexture2D(t) dp_textureGrad(t, TexCoordOffset, dPdx, dPdy)\n", +"#else\n", +"# define offsetMappedTexture2D(t) dp_texture2D(t, TexCoordSurfaceLightmap.xy)\n", +"#endif\n", +"\n", +"#ifdef USEALPHAKILL\n", +" if (offsetMappedTexture2D(Texture_Color).a < 0.5)\n", +" discard;\n", +"#endif\n", +"\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" float alpha = offsetMappedTexture2D(Texture_Color).a;\n", +" float terrainblend = clamp(float(VertexColor.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n", +" //float terrainblend = min(float(VertexColor.a) * alpha * 2.0, float(1.0));\n", +" //float terrainblend = float(VertexColor.a) * alpha > 0.5;\n", +"#endif\n", +"\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" vec3 surfacenormal = mix(vec3(dp_texture2D(Texture_SecondaryNormal, TexCoord2)), vec3(offsetMappedTexture2D(Texture_Normal)), terrainblend) - vec3(0.5, 0.5, 0.5);\n", +" float a = mix(dp_texture2D(Texture_SecondaryGloss, TexCoord2).a, offsetMappedTexture2D(Texture_Gloss).a, terrainblend);\n", +"#else\n", +" vec3 surfacenormal = vec3(offsetMappedTexture2D(Texture_Normal)) - vec3(0.5, 0.5, 0.5);\n", +" float a = offsetMappedTexture2D(Texture_Gloss).a;\n", +"#endif\n", +"\n", +" vec3 pixelnormal = normalize(surfacenormal.x * VectorS.xyz + surfacenormal.y * VectorT.xyz + surfacenormal.z * VectorR.xyz);\n", +" dp_FragColor = vec4(pixelnormal.x, pixelnormal.y, Depth, a);\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"#else // !MODE_DEFERREDGEOMETRY\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"#ifdef VERTEX_SHADER\n", +"uniform highp mat4 ModelViewMatrix;\n", +"void main(void)\n", +"{\n", +" ModelViewPosition = ModelViewMatrix * Attrib_Position;\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"uniform highp mat4 ViewToLight;\n", +"// ScreenToDepth = vec2(Far / (Far - Near), Far * Near / (Near - Far));\n", +"uniform highp vec2 ScreenToDepth;\n", +"uniform myhalf3 DeferredColor_Ambient;\n", +"uniform myhalf3 DeferredColor_Diffuse;\n", +"#ifdef USESPECULAR\n", +"uniform myhalf3 DeferredColor_Specular;\n", +"uniform myhalf SpecularPower;\n", +"#endif\n", +"uniform myhalf2 PixelToScreenTexCoord;\n", +"void main(void)\n", +"{\n", +" // calculate viewspace pixel position\n", +" vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n", +" vec3 position;\n", +" // get the geometry information (depth, normal, specular exponent)\n", +" myhalf4 normalmap = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord);\n", +" // decode viewspace pixel normal\n", +"// myhalf3 surfacenormal = normalize(normalmap.rgb - cast_myhalf3(0.5,0.5,0.5));\n", +" myhalf3 surfacenormal = myhalf3(normalmap.rg, sqrt(1.0-dot(normalmap.rg, normalmap.rg)));\n", +" // decode viewspace pixel position\n", +"// position.z = decodedepthmacro(dp_texture2D(Texture_ScreenDepth, ScreenTexCoord));\n", +" position.z = normalmap.b;\n", +"// position.z = ScreenToDepth.y / (dp_texture2D(Texture_ScreenDepth, ScreenTexCoord).r + ScreenToDepth.x);\n", +" position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n", +"\n", +" // now do the actual shading\n", +" // surfacenormal = pixel normal in viewspace\n", +" // LightVector = pixel to light in viewspace\n", +" // CubeVector = pixel in lightspace\n", +" // eyenormal = pixel to view direction in viewspace\n", +" vec3 CubeVector = vec3(ViewToLight * vec4(position,1));\n", +" myhalf fade = cast_myhalf(dp_texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n", +"#ifdef USEDIFFUSE\n", +" // calculate diffuse shading\n", +" myhalf3 lightnormal = cast_myhalf3(normalize(LightPosition - position));\n", +"SHADEDIFFUSE\n", +"#endif\n", +"#ifdef USESPECULAR\n", +" // calculate directional shading\n", +" myhalf3 eyenormal = -normalize(cast_myhalf3(position));\n", +"SHADESPECULAR(SpecularPower * normalmap.a)\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +" fade *= ShadowMapCompare(CubeVector);\n", +"#endif\n", +"\n", +"#ifdef USESPECULAR\n", +" gl_FragData[0] = vec4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n", +" gl_FragData[1] = vec4(DeferredColor_Specular * (specular * fade), 1.0);\n", +"# ifdef USECUBEFILTER\n", +" vec3 cubecolor = dp_textureCube(Texture_Cube, CubeVector).rgb;\n", +" gl_FragData[0].rgb *= cubecolor;\n", +" gl_FragData[1].rgb *= cubecolor;\n", +"# endif\n", +"#else\n", +"# ifdef USEDIFFUSE\n", +" gl_FragColor = vec4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n", +"# else\n", +" gl_FragColor = vec4(DeferredColor_Ambient * fade, 1.0);\n", +"# endif\n", +"# ifdef USECUBEFILTER\n", +" vec3 cubecolor = dp_textureCube(Texture_Cube, CubeVector).rgb;\n", +" gl_FragColor.rgb *= cubecolor;\n", +"# endif\n", +"#endif\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"#else // !MODE_DEFERREDLIGHTSOURCE\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"uniform highp mat4 TexMatrix;\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform highp mat4 BackgroundTexMatrix;\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform highp mat4 ModelToLight;\n", +"#endif\n", +"#ifdef USESHADOWMAPORTHO\n", +"uniform highp mat4 ShadowMapMatrix;\n", +"#endif\n", +"#ifdef USEBOUNCEGRID\n", +"uniform highp mat4 BounceGridMatrix;\n", +"#endif\n", +"void main(void)\n", +"{\n", +"#ifdef USESKELETAL\n", +" ivec4 si0 = ivec4(Attrib_SkeletalIndex * 3.0);\n", +" ivec4 si1 = si0 + ivec4(1, 1, 1, 1);\n", +" ivec4 si2 = si0 + ivec4(2, 2, 2, 2);\n", +" vec4 sw = Attrib_SkeletalWeight;\n", +" vec4 SkeletalMatrix1 = Skeletal_Transform12[si0.x] * sw.x + Skeletal_Transform12[si0.y] * sw.y + Skeletal_Transform12[si0.z] * sw.z + Skeletal_Transform12[si0.w] * sw.w;\n", +" vec4 SkeletalMatrix2 = Skeletal_Transform12[si1.x] * sw.x + Skeletal_Transform12[si1.y] * sw.y + Skeletal_Transform12[si1.z] * sw.z + Skeletal_Transform12[si1.w] * sw.w;\n", +" vec4 SkeletalMatrix3 = Skeletal_Transform12[si2.x] * sw.x + Skeletal_Transform12[si2.y] * sw.y + Skeletal_Transform12[si2.z] * sw.z + Skeletal_Transform12[si2.w] * sw.w;\n", +" mat4 SkeletalMatrix = mat4(SkeletalMatrix1, SkeletalMatrix2, SkeletalMatrix3, vec4(0.0, 0.0, 0.0, 1.0));\n", +"// ivec4 si = ivec4(Attrib_SkeletalIndex);\n", +"// mat4 SkeletalMatrix = Skeletal_Transform[si.x] * Attrib_SkeletalWeight.x + Skeletal_Transform[si.y] * Attrib_SkeletalWeight.y + Skeletal_Transform[si.z] * Attrib_SkeletalWeight.z + Skeletal_Transform[si.w] * Attrib_SkeletalWeight.w;\n", +" mat3 SkeletalNormalMatrix = mat3(cross(SkeletalMatrix[1].xyz, SkeletalMatrix[2].xyz), cross(SkeletalMatrix[2].xyz, SkeletalMatrix[0].xyz), cross(SkeletalMatrix[0].xyz, SkeletalMatrix[1].xyz)); // is actually transpose(inverse(mat3(SkeletalMatrix))) * det(mat3(SkeletalMatrix))\n", +" vec4 SkeletalVertex = Attrib_Position * SkeletalMatrix;\n", +" SkeletalVertex.w = 1.0;\n", +" vec3 SkeletalSVector = normalize(Attrib_TexCoord1.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalTVector = normalize(Attrib_TexCoord2.xyz * SkeletalNormalMatrix);\n", +" vec3 SkeletalNormal = normalize(Attrib_TexCoord3.xyz * SkeletalNormalMatrix);\n", +"#define Attrib_Position SkeletalVertex\n", +"#define Attrib_TexCoord1 SkeletalSVector\n", +"#define Attrib_TexCoord2 SkeletalTVector\n", +"#define Attrib_TexCoord3 SkeletalNormal\n", +"#endif\n", +"\n", +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n", +" VertexColor = Attrib_Color;\n", +"#endif\n", +" // copy the surface texcoord\n", +"#ifdef USELIGHTMAP\n", +" TexCoordSurfaceLightmap = vec4((TexMatrix * Attrib_TexCoord0).xy, Attrib_TexCoord4.xy);\n", +"#else\n", +" TexCoordSurfaceLightmap = vec4((TexMatrix * Attrib_TexCoord0).xy, 0.0, 0.0);\n", +"#endif\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" TexCoord2 = vec2(BackgroundTexMatrix * Attrib_TexCoord0);\n", +"#endif\n", +"\n", +"#ifdef USEBOUNCEGRID\n", +" BounceGridTexCoord = vec3(BounceGridMatrix * Attrib_Position);\n", +"#ifdef USEBOUNCEGRIDDIRECTIONAL\n", +" BounceGridTexCoord.z *= 0.125;\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +" // transform vertex position into light attenuation/cubemap space\n", +" // (-1 to +1 across the light box)\n", +" CubeVector = vec3(ModelToLight * Attrib_Position);\n", +"\n", +"# ifdef USEDIFFUSE\n", +" // transform unnormalized light direction into tangent space\n", +" // (we use unnormalized to ensure that it interpolates correctly and then\n", +" // normalize it per pixel)\n", +" vec3 lightminusvertex = LightPosition - Attrib_Position.xyz;\n", +" LightVector.x = dot(lightminusvertex, Attrib_TexCoord1.xyz);\n", +" LightVector.y = dot(lightminusvertex, Attrib_TexCoord2.xyz);\n", +" LightVector.z = dot(lightminusvertex, Attrib_TexCoord3.xyz);\n", +"# endif\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n", +" LightVector.x = dot(LightDir, Attrib_TexCoord1.xyz);\n", +" LightVector.y = dot(LightDir, Attrib_TexCoord2.xyz);\n", +" LightVector.z = dot(LightDir, Attrib_TexCoord3.xyz);\n", +"#endif\n", +"\n", +" // transform unnormalized eye direction into tangent space\n", +"#ifdef USEEYEVECTOR\n", +" vec3 EyeRelative = EyePosition - Attrib_Position.xyz;\n", +" EyeVectorFogDepth.x = dot(EyeRelative, Attrib_TexCoord1.xyz);\n", +" EyeVectorFogDepth.y = dot(EyeRelative, Attrib_TexCoord2.xyz);\n", +" EyeVectorFogDepth.z = dot(EyeRelative, Attrib_TexCoord3.xyz);\n", +"#ifdef USEFOG\n", +" EyeVectorFogDepth.w = dot(FogPlane, Attrib_Position);\n", +"#else\n", +" EyeVectorFogDepth.w = 0.0;\n", +"#endif\n", +"#endif\n", +"\n", +"\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(USEREFLECTCUBE) || defined(USEBOUNCEGRIDDIRECTIONAL)\n", +"# ifdef USEFOG\n", +" VectorS = vec4(Attrib_TexCoord1.xyz, EyePosition.x - Attrib_Position.x);\n", +" VectorT = vec4(Attrib_TexCoord2.xyz, EyePosition.y - Attrib_Position.y);\n", +" VectorR = vec4(Attrib_TexCoord3.xyz, EyePosition.z - Attrib_Position.z);\n", +"# else\n", +" VectorS = vec4(Attrib_TexCoord1, 0);\n", +" VectorT = vec4(Attrib_TexCoord2, 0);\n", +" VectorR = vec4(Attrib_TexCoord3, 0);\n", +"# endif\n", +"#else\n", +"# ifdef USEFOG\n", +" EyeVectorModelSpace = EyePosition - Attrib_Position.xyz;\n", +"# endif\n", +"#endif\n", +"\n", +" // transform vertex to clipspace (post-projection, but before perspective divide by W occurs)\n", +" gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n", +"\n", +"#ifdef USESHADOWMAPORTHO\n", +" ShadowMapTC = vec3(ShadowMapMatrix * gl_Position);\n", +"#endif\n", +"\n", +"#ifdef USEREFLECTION\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#endif\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +"uniform myhalf2 PixelToScreenTexCoord;\n", +"uniform myhalf3 DeferredMod_Diffuse;\n", +"uniform myhalf3 DeferredMod_Specular;\n", +"#endif\n", +"uniform myhalf3 Color_Ambient;\n", +"uniform myhalf3 Color_Diffuse;\n", +"uniform myhalf3 Color_Specular;\n", +"uniform myhalf SpecularPower;\n", +"#ifdef USEGLOW\n", +"uniform myhalf3 Color_Glow;\n", +"#endif\n", +"uniform myhalf Alpha;\n", +"#ifdef USEREFLECTION\n", +"uniform mediump vec4 DistortScaleRefractReflect;\n", +"uniform mediump vec4 ScreenScaleRefractReflect;\n", +"uniform mediump vec4 ScreenCenterRefractReflect;\n", +"uniform mediump vec4 ReflectColor;\n", +"#endif\n", +"#ifdef USEREFLECTCUBE\n", +"uniform highp mat4 ModelToReflectCube;\n", +"uniform sampler2D Texture_ReflectMask;\n", +"uniform samplerCube Texture_ReflectCube;\n", +"#endif\n", +"#ifdef MODE_LIGHTDIRECTION\n", +"uniform myhalf3 LightColor;\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform myhalf3 LightColor;\n", +"#endif\n", +"#ifdef USEBOUNCEGRID\n", +"uniform sampler3D Texture_BounceGrid;\n", +"uniform float BounceGridIntensity;\n", +"uniform highp mat4 BounceGridMatrix;\n", +"#endif\n", +"uniform highp float ClientTime;\n", +"#ifdef USENORMALMAPSCROLLBLEND\n", +"uniform highp vec2 NormalmapScrollBlend;\n", +"#endif\n", +"void main(void)\n", +"{\n", +"#ifdef USEOFFSETMAPPING\n", +" // apply offsetmapping\n", +" vec2 dPdx = dp_offsetmapping_dFdx(TexCoordSurfaceLightmap.xy);\n", +" vec2 dPdy = dp_offsetmapping_dFdy(TexCoordSurfaceLightmap.xy);\n", +" vec2 TexCoordOffset = OffsetMapping(TexCoordSurfaceLightmap.xy, dPdx, dPdy);\n", +"# define offsetMappedTexture2D(t) dp_textureGrad(t, TexCoordOffset, dPdx, dPdy)\n", +"# define TexCoord TexCoordOffset\n", +"#else\n", +"# define offsetMappedTexture2D(t) dp_texture2D(t, TexCoordSurfaceLightmap.xy)\n", +"# define TexCoord TexCoordSurfaceLightmap.xy\n", +"#endif\n", +"\n", +" // combine the diffuse textures (base, pants, shirt)\n", +" myhalf4 color = cast_myhalf4(offsetMappedTexture2D(Texture_Color));\n", +"#ifdef USEALPHAKILL\n", +" if (color.a < 0.5)\n", +" discard;\n", +"#endif\n", +" color.a *= Alpha;\n", +"#ifdef USECOLORMAPPING\n", +" color.rgb += cast_myhalf3(offsetMappedTexture2D(Texture_Pants)) * Color_Pants + cast_myhalf3(offsetMappedTexture2D(Texture_Shirt)) * Color_Shirt;\n", +"#endif\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"#ifdef USEBOTHALPHAS\n", +" myhalf4 color2 = cast_myhalf4(dp_texture2D(Texture_SecondaryColor, TexCoord2));\n", +" myhalf terrainblend = clamp(cast_myhalf(VertexColor.a) * color.a, cast_myhalf(1.0 - color2.a), cast_myhalf(1.0));\n", +" color.rgb = mix(color2.rgb, color.rgb, terrainblend);\n", +"#else\n", +" myhalf terrainblend = clamp(cast_myhalf(VertexColor.a) * color.a * 2.0 - 0.5, cast_myhalf(0.0), cast_myhalf(1.0));\n", +" //myhalf terrainblend = min(cast_myhalf(VertexColor.a) * color.a * 2.0, cast_myhalf(1.0));\n", +" //myhalf terrainblend = cast_myhalf(VertexColor.a) * color.a > 0.5;\n", +" color.rgb = mix(cast_myhalf3(dp_texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n", +"#endif\n", +" color.a = 1.0;\n", +" //color = mix(cast_myhalf4(1, 0, 0, 1), color, terrainblend);\n", +"#endif\n", +"#ifdef USEALPHAGENVERTEX\n", +" color.a *= VertexColor.a;\n", +"#endif\n", +"\n", +" // get the surface normal\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" myhalf3 surfacenormal = normalize(mix(cast_myhalf3(dp_texture2D(Texture_SecondaryNormal, TexCoord2)), cast_myhalf3(offsetMappedTexture2D(Texture_Normal)), terrainblend) - cast_myhalf3(0.5, 0.5, 0.5));\n", +"#else\n", +" myhalf3 surfacenormal = normalize(cast_myhalf3(offsetMappedTexture2D(Texture_Normal)) - cast_myhalf3(0.5, 0.5, 0.5));\n", +"#endif\n", +"\n", +" // get the material colors\n", +" myhalf3 diffusetex = color.rgb;\n", +"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n", +"# ifdef USEVERTEXTEXTUREBLEND\n", +" myhalf4 glosstex = mix(cast_myhalf4(dp_texture2D(Texture_SecondaryGloss, TexCoord2)), cast_myhalf4(offsetMappedTexture2D(Texture_Gloss)), terrainblend);\n", +"# else\n", +" myhalf4 glosstex = cast_myhalf4(offsetMappedTexture2D(Texture_Gloss));\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USEREFLECTCUBE\n", +" myhalf3 TangentReflectVector = reflect(-EyeVectorFogDepth.xyz, surfacenormal);\n", +" myhalf3 ModelReflectVector = TangentReflectVector.x * VectorS.xyz + TangentReflectVector.y * VectorT.xyz + TangentReflectVector.z * VectorR.xyz;\n", +" myhalf3 ReflectCubeTexCoord = cast_myhalf3(ModelToReflectCube * vec4(ModelReflectVector, 0));\n", +" diffusetex += cast_myhalf3(offsetMappedTexture2D(Texture_ReflectMask)) * cast_myhalf3(dp_textureCube(Texture_ReflectCube, ReflectCubeTexCoord));\n", +"#endif\n", +"\n", +"#ifdef USESPECULAR\n", +" myhalf3 eyenormal = normalize(cast_myhalf3(EyeVectorFogDepth.xyz));\n", +"#endif\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +" // light source\n", +"#ifdef USEDIFFUSE\n", +" myhalf3 lightnormal = cast_myhalf3(normalize(LightVector));\n", +"SHADEDIFFUSE\n", +" color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n", +"#ifdef USESPECULAR\n", +"SHADESPECULAR(SpecularPower * glosstex.a)\n", +" color.rgb += glosstex.rgb * (specular * Color_Specular);\n", +"#endif\n", +"#else\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"#endif\n", +" color.rgb *= LightColor;\n", +" color.rgb *= cast_myhalf(dp_texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n", +"#if defined(USESHADOWMAP2D)\n", +" color.rgb *= ShadowMapCompare(CubeVector);\n", +"#endif\n", +"# ifdef USECUBEFILTER\n", +" color.rgb *= cast_myhalf3(dp_textureCube(Texture_Cube, CubeVector));\n", +"# endif\n", +"#endif // MODE_LIGHTSOURCE\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTDIRECTION\n", +" #define SHADING\n", +" #ifdef USEDIFFUSE\n", +" myhalf3 lightnormal = cast_myhalf3(normalize(LightVector));\n", +" #endif\n", +" #define lightcolor LightColor\n", +"#endif // MODE_LIGHTDIRECTION\n", +"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", +" #define SHADING\n", +" // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n", +" myhalf3 lightnormal_modelspace = cast_myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + cast_myhalf3(-1.0, -1.0, -1.0);\n", +" myhalf3 lightcolor = cast_myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\n", +" // convert modelspace light vector to tangentspace\n", +" myhalf3 lightnormal;\n", +" lightnormal.x = dot(lightnormal_modelspace, cast_myhalf3(VectorS));\n", +" lightnormal.y = dot(lightnormal_modelspace, cast_myhalf3(VectorT));\n", +" lightnormal.z = dot(lightnormal_modelspace, cast_myhalf3(VectorR));\n", +" lightnormal = normalize(lightnormal); // VectorS/T/R are not always perfectly normalized, and EXACTSPECULARMATH is very picky about this\n", +" // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n", +" // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n", +" // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n", +" // on that luxel, and NOT to its center, because recursive triangle subdivision is used\n", +" // to map the luxels to coordinates on the draw surfaces), which also causes\n", +" // deluxemaps to be wrong because light contributions from the wrong side of the surface\n", +" // are added up. To prevent divisions by zero or strong exaggerations, a max()\n", +" // nudge is done here at expense of some additional fps. This is ONLY needed for\n", +" // deluxemaps, tangentspace deluxemap avoid this problem by design.\n", +" lightcolor *= 1.0 / max(0.25, lightnormal.z);\n", +"#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", +"#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", +" #define SHADING\n", +" // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n", +" myhalf3 lightnormal = cast_myhalf3(dp_texture2D(Texture_Deluxemap, TexCoordSurfaceLightmap.zw)) * 2.0 + cast_myhalf3(-1.0, -1.0, -1.0);\n", +" myhalf3 lightcolor = cast_myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR)\n", +" #define SHADING\n", +" // forced deluxemap on lightmapped/vertexlit surfaces\n", +" myhalf3 lightnormal = cast_myhalf3(0.0, 0.0, 1.0);\n", +" #ifdef USELIGHTMAP\n", +" myhalf3 lightcolor = cast_myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw));\n", +" #else\n", +" myhalf3 lightcolor = cast_myhalf3(VertexColor.rgb);\n", +" #endif\n", +"#endif\n", +"#ifdef MODE_FAKELIGHT\n", +" #define SHADING\n", +" myhalf3 lightnormal = cast_myhalf3(normalize(EyeVectorFogDepth.xyz));\n", +" myhalf3 lightcolor = cast_myhalf3(1.0);\n", +"#endif // MODE_FAKELIGHT\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTMAP\n", +" color.rgb = diffusetex * (Color_Ambient + cast_myhalf3(dp_texture2D(Texture_Lightmap, TexCoordSurfaceLightmap.zw)) * Color_Diffuse);\n", +"#endif // MODE_LIGHTMAP\n", +"#ifdef MODE_VERTEXCOLOR\n", +" color.rgb = diffusetex * (Color_Ambient + cast_myhalf3(VertexColor.rgb) * Color_Diffuse);\n", +"#endif // MODE_VERTEXCOLOR\n", +"#ifdef MODE_FLATCOLOR\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"#endif // MODE_FLATCOLOR\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef SHADING\n", +"# ifdef USEDIFFUSE\n", +"SHADEDIFFUSE\n", +"# ifdef USESPECULAR\n", +"SHADESPECULAR(SpecularPower * glosstex.a)\n", +" color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n", +"# else\n", +" color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n", +"# endif\n", +"# else\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAPORTHO\n", +" color.rgb *= ShadowMapCompare(ShadowMapTC);\n", +"#endif\n", +"\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +" vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n", +" color.rgb += diffusetex * cast_myhalf3(dp_texture2D(Texture_ScreenDiffuse, ScreenTexCoord)) * DeferredMod_Diffuse;\n", +" color.rgb += glosstex.rgb * cast_myhalf3(dp_texture2D(Texture_ScreenSpecular, ScreenTexCoord)) * DeferredMod_Specular;\n", +"// color.rgb = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord).rgb * vec3(1.0, 1.0, 0.001);\n", +"#endif\n", +"\n", +"#ifdef USEBOUNCEGRID\n", +"#ifdef USEBOUNCEGRIDDIRECTIONAL\n", +"// myhalf4 bouncegrid_coeff1 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord ));\n", +"// myhalf4 bouncegrid_coeff2 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.125))) * 2.0 + cast_myhalf4(-1.0, -1.0, -1.0, -1.0);\n", +" myhalf4 bouncegrid_coeff3 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.250)));\n", +" myhalf4 bouncegrid_coeff4 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.375)));\n", +" myhalf4 bouncegrid_coeff5 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.500)));\n", +" myhalf4 bouncegrid_coeff6 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.625)));\n", +" myhalf4 bouncegrid_coeff7 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.750)));\n", +" myhalf4 bouncegrid_coeff8 = cast_myhalf4(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord + vec3(0.0, 0.0, 0.875)));\n", +" myhalf3 bouncegrid_dir = normalize(mat3(BounceGridMatrix) * (surfacenormal.x * VectorS.xyz + surfacenormal.y * VectorT.xyz + surfacenormal.z * VectorR.xyz));\n", +" myhalf3 bouncegrid_dirp = max(cast_myhalf3(0.0, 0.0, 0.0), bouncegrid_dir);\n", +" myhalf3 bouncegrid_dirn = max(cast_myhalf3(0.0, 0.0, 0.0), -bouncegrid_dir);\n", +"// bouncegrid_dirp = bouncegrid_dirn = cast_myhalf3(1.0,1.0,1.0);\n", +" myhalf3 bouncegrid_light = cast_myhalf3(\n", +" dot(bouncegrid_coeff3.xyz, bouncegrid_dirp) + dot(bouncegrid_coeff6.xyz, bouncegrid_dirn),\n", +" dot(bouncegrid_coeff4.xyz, bouncegrid_dirp) + dot(bouncegrid_coeff7.xyz, bouncegrid_dirn),\n", +" dot(bouncegrid_coeff5.xyz, bouncegrid_dirp) + dot(bouncegrid_coeff8.xyz, bouncegrid_dirn));\n", +" color.rgb += diffusetex * bouncegrid_light * BounceGridIntensity;\n", +"// color.rgb = bouncegrid_dir.rgb * 0.5 + vec3(0.5, 0.5, 0.5);\n", +"#else\n", +" color.rgb += diffusetex * cast_myhalf3(dp_texture3D(Texture_BounceGrid, BounceGridTexCoord)) * BounceGridIntensity;\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef USEGLOW\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" color.rgb += mix(cast_myhalf3(dp_texture2D(Texture_SecondaryGlow, TexCoord2)), cast_myhalf3(offsetMappedTexture2D(Texture_Glow)), terrainblend) * Color_Glow;\n", +"#else\n", +" color.rgb += cast_myhalf3(offsetMappedTexture2D(Texture_Glow)) * Color_Glow;\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef USECELOUTLINES\n", +"# ifdef USEDEFERREDLIGHTMAP\n", +"// vec2 ScreenTexCoord = gl_FragCoord.xy * PixelToScreenTexCoord;\n", +" vec4 ScreenTexCoordStep = vec4(PixelToScreenTexCoord.x, 0.0, 0.0, PixelToScreenTexCoord.y);\n", +" vec4 DepthNeighbors;\n", +"\n", +" // enable to test ink on white geometry\n", +"// color.rgb = vec3(1.0, 1.0, 1.0);\n", +"\n", +" // note: this seems to be negative\n", +" float DepthCenter = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord).b;\n", +"\n", +" // edge detect method\n", +"// DepthNeighbors.x = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord - ScreenTexCoordStep.xy).b;\n", +"// DepthNeighbors.y = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + ScreenTexCoordStep.xy).b;\n", +"// DepthNeighbors.z = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + ScreenTexCoordStep.zw).b;\n", +"// DepthNeighbors.w = dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord - ScreenTexCoordStep.zw).b;\n", +"// float DepthAverage = dot(DepthNeighbors, vec4(0.25, 0.25, 0.25, 0.25));\n", +"// float DepthDelta = abs(dot(DepthNeighbors.xy, vec2(-1.0, 1.0))) + abs(dot(DepthNeighbors.zw, vec2(-1.0, 1.0)));\n", +"// color.rgb *= max(0.5, 1.0 - max(0.0, abs(DepthCenter - DepthAverage) - 0.2 * DepthDelta) / (0.01 + 0.2 * DepthDelta));\n", +"// color.rgb *= step(abs(DepthCenter - DepthAverage), 0.2 * DepthDelta); \n", +"\n", +" // shadow method\n", +" float DepthScale1 = 4.0 / DepthCenter; // inner ink (shadow on object)\n", +"// float DepthScale1 = -4.0 / DepthCenter; // outer ink (shadow around object)\n", +"// float DepthScale1 = 0.003;\n", +" float DepthScale2 = DepthScale1 / 2.0;\n", +"// float DepthScale3 = DepthScale1 / 4.0;\n", +" float DepthBias1 = -DepthCenter * DepthScale1;\n", +" float DepthBias2 = -DepthCenter * DepthScale2;\n", +"// float DepthBias3 = -DepthCenter * DepthScale3;\n", +" float DepthShadow = max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2(-1.0, 0.0)).b * DepthScale1 + DepthBias1)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 1.0, 0.0)).b * DepthScale1 + DepthBias1)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, -1.0)).b * DepthScale1 + DepthBias1)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, 1.0)).b * DepthScale1 + DepthBias1)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2(-2.0, 0.0)).b * DepthScale2 + DepthBias2)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 2.0, 0.0)).b * DepthScale2 + DepthBias2)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, -2.0)).b * DepthScale2 + DepthBias2)\n", +" + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, 2.0)).b * DepthScale2 + DepthBias2)\n", +"// + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2(-3.0, 0.0)).b * DepthScale3 + DepthBias3)\n", +"// + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 3.0, 0.0)).b * DepthScale3 + DepthBias3)\n", +"// + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, -3.0)).b * DepthScale3 + DepthBias3)\n", +"// + max(0.0, dp_texture2D(Texture_ScreenNormalMap, ScreenTexCoord + PixelToScreenTexCoord * vec2( 0.0, 3.0)).b * DepthScale3 + DepthBias3)\n", +" - 0.0;\n", +" color.rgb *= 1.0 - max(0.0, min(DepthShadow, 1.0));\n", +"// color.r = DepthCenter / -1024.0;\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USEFOG\n", +" color.rgb = FogVertex(color);\n", +"#endif\n", +"\n", +" // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n", +"#ifdef USEREFLECTION\n", +" vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n", +" //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(cast_myhalf3(offsetMappedTexture2D(Texture_Normal)) - cast_myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" vec2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW.zw + ScreenCenterRefractReflect.zw;\n", +" #ifdef USENORMALMAPSCROLLBLEND\n", +"# ifdef USEOFFSETMAPPING\n", +" vec3 normal = dp_textureGrad(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y, dPdx*NormalmapScrollBlend.y, dPdy*NormalmapScrollBlend.y).rgb - vec3(1.0);\n", +"# else\n", +" vec3 normal = dp_texture2D(Texture_Normal, (TexCoord + vec2(0.08, 0.08)*ClientTime*NormalmapScrollBlend.x*0.5)*NormalmapScrollBlend.y).rgb - vec3(1.0);\n", +"# endif\n", +" normal += dp_texture2D(Texture_Normal, (TexCoord + vec2(-0.06, -0.09)*ClientTime*NormalmapScrollBlend.x)*NormalmapScrollBlend.y*0.75).rgb;\n", +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(normal))).xy * DistortScaleRefractReflect.zw;\n", +" #else\n", +" vec2 ScreenTexCoord = SafeScreenTexCoord + vec3(normalize(cast_myhalf3(offsetMappedTexture2D(Texture_Normal)) - cast_myhalf3(0.5))).xy * DistortScaleRefractReflect.zw;\n", +" #endif\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord + vec2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(dp_texture2D(Texture_Reflection, ScreenTexCoord + vec2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord = mix(SafeScreenTexCoord, ScreenTexCoord, f);\n", +" color.rgb = mix(color.rgb, cast_myhalf3(dp_texture2D(Texture_Reflection, ScreenTexCoord)) * ReflectColor.rgb, ReflectColor.a);\n", +"#endif\n", +"\n", +" dp_FragColor = vec4(color);\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"\n", +"#endif // !MODE_DEFERREDLIGHTSOURCE\n", +"#endif // !MODE_DEFERREDGEOMETRY\n", +"#endif // !MODE_WATER\n", +"#endif // !MODE_REFRACTION\n", +"#endif // !MODE_BLOOMBLUR\n", +"#endif // !MODE_GENERIC\n", +"#endif // !MODE_POSTPROCESS\n", +"#endif // !MODE_DEPTH_OR_SHADOW\n", diff --git a/app/jni/shader_hlsl.h b/app/jni/shader_hlsl.h new file mode 100644 index 0000000..7881aa6 --- /dev/null +++ b/app/jni/shader_hlsl.h @@ -0,0 +1,1561 @@ +"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n", +"// written by Forest 'LordHavoc' Hale\n", +"// shadowmapping enhancements by Lee 'eihrul' Salzman\n", +"\n", +"// FIXME: we need to get rid of ModelViewProjectionPosition to make room for the texcoord for this\n", +"#if defined(USEREFLECTION)\n", +"#undef USESHADOWMAPORTHO\n", +"#endif\n", +"\n", +"#if defined(USEFOGINSIDE) || defined(USEFOGOUTSIDE) || defined(USEFOGHEIGHTTEXTURE)\n", +"# define USEFOG\n", +"#endif\n", +"#if defined(MODE_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP)\n", +"#define USELIGHTMAP\n", +"#endif\n", +"#if defined(USESPECULAR) || defined(USEOFFSETMAPPING) || defined(USEREFLECTCUBE) || defined(MODE_FAKELIGHT)\n", +"#define USEEYEVECTOR\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"#ifdef HLSL\n", +"//#undef USESHADOWMAPPCF\n", +"//#define texDepth2D(tex,texcoord) tex2D(tex,texcoord).r\n", +"#define texDepth2D(tex,texcoord) dot(tex2D(tex,texcoord).rgb, float3(1.0, 255.0/65536.0, 255.0/16777216.0))\n", +"#else\n", +"#define texDepth2D(tex,texcoord) tex2D(tex,texcoord).r\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"#ifdef USETRIPPY\n", +"// LordHavoc: based on shader code linked at: http://www.youtube.com/watch?v=JpksyojwqzE\n", +"// tweaked scale\n", +"float4 TrippyVertex(float4 position)\n", +"(\n", +"uniform float ClientTime : register(c2)\n", +")\n", +"{\n", +" float worldTime = ClientTime;\n", +" // tweaked for Quake\n", +" worldTime *= 10.0;\n", +" position *= 0.125;\n", +" //~tweaked for Quake\n", +" float distanceSquared = (position.x * position.x + position.z * position.z);\n", +" position.y += 5.0*sin(distanceSquared*sin(worldTime/143.0)/1000.0);\n", +" float y = position.y;\n", +" float x = position.x;\n", +" float om = sin(distanceSquared*sin(worldTime/256.0)/5000.0) * sin(worldTime/200.0);\n", +" position.y = x*sin(om)+y*cos(om);\n", +" position.x = x*cos(om)-y*sin(om);\n", +" return position;\n", +"}\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef MODE_DEPTH_OR_SHADOW\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"out float4 gl_Position : POSITION,\n", +"out float Depth : TEXCOORD0\n", +")\n", +"{\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +" Depth = gl_Position.z;\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"float Depth : TEXCOORD0,\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +"// float4 temp = float4(Depth,Depth*(65536.0/255.0),Depth*(16777216.0/255.0),0.0);\n", +" float4 temp = float4(Depth,Depth*256.0,Depth*65536.0,0.0);\n", +" temp.yz -= floor(temp.yz);\n", +" dp_FragColor = temp;\n", +"// dp_FragColor = float4(Depth,0,0,0);\n", +"}\n", +"#endif\n", +"#else // !MODE_DEPTH_OR_SHADOW\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_POSTPROCESS\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"float4 gl_MultiTexCoord4 : TEXCOORD4,\n", +"out float4 gl_Position : POSITION,\n", +"out float2 TexCoord1 : TEXCOORD0,\n", +"out float2 TexCoord2 : TEXCOORD1\n", +")\n", +"{\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +" TexCoord1 = gl_MultiTexCoord0.xy;\n", +"#ifdef USEBLOOM\n", +" TexCoord2 = gl_MultiTexCoord4.xy;\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"float2 TexCoord1 : TEXCOORD0,\n", +"float2 TexCoord2 : TEXCOORD1,\n", +"uniform sampler Texture_First : register(s0),\n", +"#ifdef USEBLOOM\n", +"uniform sampler Texture_Second : register(s1),\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +"uniform sampler Texture_GammaRamps : register(s2),\n", +"#endif\n", +"#ifdef USESATURATION\n", +"uniform float Saturation : register(c30),\n", +"#endif\n", +"#ifdef USEVIEWTINT\n", +"uniform float4 ViewTintColor : register(c41),\n", +"#endif\n", +"uniform float4 UserVec1 : register(c37),\n", +"uniform float4 UserVec2 : register(c38),\n", +"uniform float4 UserVec3 : register(c39),\n", +"uniform float4 UserVec4 : register(c40),\n", +"uniform float ClientTime : register(c2),\n", +"uniform float2 PixelSize : register(c25),\n", +"uniform float4 BloomColorSubtract : register(c43),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" dp_FragColor = tex2D(Texture_First, TexCoord1);\n", +"\n", +"#ifdef USEPOSTPROCESSING\n", +"// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n", +"// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n", +" float sobel = 1.0;\n", +" // float2 ts = textureSize(Texture_First, 0);\n", +" // float2 px = float2(1/ts.x, 1/ts.y);\n", +" float2 px = PixelSize;\n", +" float3 x1 = tex2D(Texture_First, TexCoord1 + float2(-px.x, px.y)).rgb;\n", +" float3 x2 = tex2D(Texture_First, TexCoord1 + float2(-px.x, 0.0)).rgb;\n", +" float3 x3 = tex2D(Texture_First, TexCoord1 + float2(-px.x,-px.y)).rgb;\n", +" float3 x4 = tex2D(Texture_First, TexCoord1 + float2( px.x, px.y)).rgb;\n", +" float3 x5 = tex2D(Texture_First, TexCoord1 + float2( px.x, 0.0)).rgb;\n", +" float3 x6 = tex2D(Texture_First, TexCoord1 + float2( px.x,-px.y)).rgb;\n", +" float3 y1 = tex2D(Texture_First, TexCoord1 + float2( px.x,-px.y)).rgb;\n", +" float3 y2 = tex2D(Texture_First, TexCoord1 + float2( 0.0,-px.y)).rgb;\n", +" float3 y3 = tex2D(Texture_First, TexCoord1 + float2(-px.x,-px.y)).rgb;\n", +" float3 y4 = tex2D(Texture_First, TexCoord1 + float2( px.x, px.y)).rgb;\n", +" float3 y5 = tex2D(Texture_First, TexCoord1 + float2( 0.0, px.y)).rgb;\n", +" float3 y6 = tex2D(Texture_First, TexCoord1 + float2(-px.x, px.y)).rgb;\n", +" float px1 = -1.0 * dot(float3(0.3, 0.59, 0.11), x1);\n", +" float px2 = -2.0 * dot(float3(0.3, 0.59, 0.11), x2);\n", +" float px3 = -1.0 * dot(float3(0.3, 0.59, 0.11), x3);\n", +" float px4 = 1.0 * dot(float3(0.3, 0.59, 0.11), x4);\n", +" float px5 = 2.0 * dot(float3(0.3, 0.59, 0.11), x5);\n", +" float px6 = 1.0 * dot(float3(0.3, 0.59, 0.11), x6);\n", +" float py1 = -1.0 * dot(float3(0.3, 0.59, 0.11), y1);\n", +" float py2 = -2.0 * dot(float3(0.3, 0.59, 0.11), y2);\n", +" float py3 = -1.0 * dot(float3(0.3, 0.59, 0.11), y3);\n", +" float py4 = 1.0 * dot(float3(0.3, 0.59, 0.11), y4);\n", +" float py5 = 2.0 * dot(float3(0.3, 0.59, 0.11), y5);\n", +" float py6 = 1.0 * dot(float3(0.3, 0.59, 0.11), y6);\n", +" sobel = 0.25 * abs(px1 + px2 + px3 + px4 + px5 + px6) + 0.25 * abs(py1 + py2 + py3 + py4 + py5 + py6);\n", +" dp_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.987688, -0.156434)) * UserVec1.y;\n", +" dp_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.156434, -0.891007)) * UserVec1.y;\n", +" dp_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.891007, -0.453990)) * UserVec1.y;\n", +" dp_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2( 0.707107, 0.707107)) * UserVec1.y;\n", +" dp_FragColor += tex2D(Texture_First, TexCoord1 + PixelSize*UserVec1.x*float2(-0.453990, 0.891007)) * UserVec1.y;\n", +" dp_FragColor /= (1.0 + 5.0 * UserVec1.y);\n", +" dp_FragColor.rgb = dp_FragColor.rgb * (1.0 + UserVec2.x) + float3(1,1,1)*max(0.0, sobel - UserVec2.z)*UserVec2.y;\n", +"#endif\n", +"\n", +"#ifdef USEBLOOM\n", +" dp_FragColor += max(float4(0,0,0,0), tex2D(Texture_Second, TexCoord2) - BloomColorSubtract);\n", +"#endif\n", +"\n", +"#ifdef USEVIEWTINT\n", +" dp_FragColor = lerp(dp_FragColor, ViewTintColor, ViewTintColor.a);\n", +"#endif\n", +"\n", +"#ifdef USESATURATION\n", +" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n", +" float y = dot(dp_FragColor.rgb, float3(0.299, 0.587, 0.114));\n", +" // 'vampire sight' effect, wheres red is compensated\n", +" #ifdef SATURATION_REDCOMPENSATE\n", +" float rboost = max(0.0, (dp_FragColor.r - max(dp_FragColor.g, dp_FragColor.b))*(1.0 - Saturation));\n", +" dp_FragColor.rgb = lerp(float3(y,y,y), dp_FragColor.rgb, Saturation);\n", +" dp_FragColor.r += r;\n", +" #else\n", +" // normal desaturation\n", +" //dp_FragColor = float3(y,y,y) + (dp_FragColor.rgb - float3(y)) * Saturation;\n", +" dp_FragColor.rgb = lerp(float3(y,y,y), dp_FragColor.rgb, Saturation);\n", +" #endif\n", +"#endif\n", +"\n", +"#ifdef USEGAMMARAMPS\n", +" dp_FragColor.r = tex2D(Texture_GammaRamps, float2(dp_FragColor.r, 0)).r;\n", +" dp_FragColor.g = tex2D(Texture_GammaRamps, float2(dp_FragColor.g, 0)).g;\n", +" dp_FragColor.b = tex2D(Texture_GammaRamps, float2(dp_FragColor.b, 0)).b;\n", +"#endif\n", +"}\n", +"#endif\n", +"#else // !MODE_POSTPROCESS\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_GENERIC\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"float4 gl_Color : COLOR0,\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"float4 gl_MultiTexCoord1 : TEXCOORD1,\n", +"out float4 gl_Position : POSITION,\n", +"#ifdef USEDIFFUSE\n", +"out float2 TexCoord1 : TEXCOORD0,\n", +"#endif\n", +"#ifdef USESPECULAR\n", +"out float2 TexCoord2 : TEXCOORD1,\n", +"#endif\n", +"out float4 gl_FrontColor : COLOR\n", +")\n", +"{\n", +" gl_FrontColor = gl_Color;\n", +"#ifdef USEDIFFUSE\n", +" TexCoord1 = gl_MultiTexCoord0.xy;\n", +"#endif\n", +"#ifdef USESPECULAR\n", +" TexCoord2 = gl_MultiTexCoord1.xy;\n", +"#endif\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"\n", +"void main\n", +"(\n", +"float4 gl_FrontColor : COLOR0,\n", +"float2 TexCoord1 : TEXCOORD0,\n", +"float2 TexCoord2 : TEXCOORD1,\n", +"#ifdef USEDIFFUSE\n", +"uniform sampler Texture_First : register(s0),\n", +"#endif\n", +"#ifdef USESPECULAR\n", +"uniform sampler Texture_Second : register(s1),\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +"uniform sampler Texture_GammaRamps : register(s2),\n", +"#endif\n", +"uniform half Alpha : register(c0),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +"#ifdef USEVIEWTINT\n", +" dp_FragColor = gl_FrontColor;\n", +"#else\n", +" dp_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n", +"#endif\n", +"#ifdef USEDIFFUSE\n", +"# ifdef USEREFLECTCUBE\n", +" // suppress texture alpha\n", +" dp_FragColor.rgb *= tex2D(Texture_First, TexCoord1).rgb;\n", +"# else\n", +" dp_FragColor *= tex2D(Texture_First, TexCoord1);\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESPECULAR\n", +" float4 tex2 = tex2D(Texture_Second, TexCoord2);\n", +"# ifdef USECOLORMAPPING\n", +" dp_FragColor *= tex2;\n", +"# endif\n", +"# ifdef USEGLOW\n", +" dp_FragColor += tex2;\n", +"# endif\n", +"# ifdef USEVERTEXTEXTUREBLEND\n", +" dp_FragColor = lerp(dp_FragColor, tex2, tex2.a);\n", +"# endif\n", +"#endif\n", +"#ifdef USEGAMMARAMPS\n", +" dp_FragColor.r = tex2D(Texture_GammaRamps, vec2(dp_FragColor.r, 0)).r;\n", +" dp_FragColor.g = tex2D(Texture_GammaRamps, vec2(dp_FragColor.g, 0)).g;\n", +" dp_FragColor.b = tex2D(Texture_GammaRamps, vec2(dp_FragColor.b, 0)).b;\n", +"#endif\n", +"#ifdef USEALPHAKILL\n", +" dp_FragColor.a *= Alpha;\n", +"#endif\n", +"}\n", +"#endif\n", +"#else // !MODE_GENERIC\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_BLOOMBLUR\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"out float4 gl_Position : POSITION,\n", +"out float2 TexCoord : TEXCOORD0\n", +")\n", +"{\n", +" TexCoord = gl_MultiTexCoord0.xy;\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"\n", +"void main\n", +"(\n", +"float2 TexCoord : TEXCOORD0,\n", +"uniform sampler Texture_First : register(s0),\n", +"uniform float4 BloomBlur_Parameters : register(c1),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" int i;\n", +" float2 tc = TexCoord;\n", +" float3 color = tex2D(Texture_First, tc).rgb;\n", +" tc += BloomBlur_Parameters.xy;\n", +" for (i = 1;i < SAMPLES;i++)\n", +" {\n", +" color += tex2D(Texture_First, tc).rgb;\n", +" tc += BloomBlur_Parameters.xy;\n", +" }\n", +" dp_FragColor = float4(color * BloomBlur_Parameters.z + float3(BloomBlur_Parameters.w), 1);\n", +"}\n", +"#endif\n", +"#else // !MODE_BLOOMBLUR\n", +"#ifdef MODE_REFRACTION\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"#ifdef USEALPHAGENVERTEX\n", +"float4 gl_Color : COLOR0,\n", +"#endif\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"uniform float4x4 TexMatrix : register(c0),\n", +"uniform float3 EyePosition : register(c24),\n", +"#ifdef USEALPHAGENVERTEX\n", +"out float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"out float4 gl_Position : POSITION,\n", +"out float2 TexCoord : TEXCOORD0,\n", +"out float3 EyeVector : TEXCOORD1,\n", +"out float4 ModelViewProjectionPosition : TEXCOORD2\n", +")\n", +"{\n", +"#ifdef USEALPHAGENVERTEX\n", +" gl_FrontColor = gl_Color;\n", +"#endif\n", +" TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"#ifdef USEALPHAGENVERTEX\n", +"float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"float2 TexCoord : TEXCOORD0,\n", +"float3 EyeVector : TEXCOORD1,\n", +"float4 ModelViewProjectionPosition : TEXCOORD2,\n", +"uniform sampler Texture_Normal : register(s0),\n", +"uniform sampler Texture_Refraction : register(s3),\n", +"uniform sampler Texture_Reflection : register(s7),\n", +"uniform float4 DistortScaleRefractReflect : register(c14),\n", +"uniform float4 ScreenScaleRefractReflect : register(c32),\n", +"uniform float4 ScreenCenterRefractReflect : register(c31),\n", +"uniform float4 RefractColor : register(c29),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" float2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n", +" //float2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n", +" float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n", +"#ifdef USEALPHAGENVERTEX\n", +" float2 distort = DistortScaleRefractReflect.xy * gl_FrontColor.a;\n", +" float4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), gl_FrontColor.a);\n", +"#else\n", +" float2 distort = DistortScaleRefractReflect.xy;\n", +" float4 refractcolor = RefractColor;\n", +"#endif\n", +" float2 ScreenTexCoord = SafeScreenTexCoord + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy * distort;\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord + float2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord = lerp(SafeScreenTexCoord, ScreenTexCoord, f);\n", +" dp_FragColor = float4(tex2D(Texture_Refraction, ScreenTexCoord).rgb, 1) * refractcolor;\n", +"}\n", +"#endif\n", +"#else // !MODE_REFRACTION\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_WATER\n", +"#ifdef VERTEX_SHADER\n", +"\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"#ifdef USEALPHAGENVERTEX\n", +"float4 gl_Color : COLOR0,\n", +"#endif\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"float4 gl_MultiTexCoord1 : TEXCOORD1,\n", +"float4 gl_MultiTexCoord2 : TEXCOORD2,\n", +"float4 gl_MultiTexCoord3 : TEXCOORD3,\n", +"uniform float4x4 TexMatrix : register(c0),\n", +"uniform float3 EyePosition : register(c24),\n", +"#ifdef USEALPHAGENVERTEX\n", +"out float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"out float4 gl_Position : POSITION,\n", +"out float2 TexCoord : TEXCOORD0,\n", +"out float3 EyeVector : TEXCOORD1,\n", +"out float4 ModelViewProjectionPosition : TEXCOORD2\n", +")\n", +"{\n", +"#ifdef USEALPHAGENVERTEX\n", +" gl_FrontColor = gl_Color;\n", +"#endif\n", +" TexCoord = mul(TexMatrix, gl_MultiTexCoord0).xy;\n", +" float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n", +" EyeVector = float3(dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz));\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"#ifdef USEALPHAGENVERTEX\n", +"float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"float2 TexCoord : TEXCOORD0,\n", +"float3 EyeVector : TEXCOORD1,\n", +"float4 ModelViewProjectionPosition : TEXCOORD2,\n", +"uniform sampler Texture_Normal : register(s0),\n", +"uniform sampler Texture_Refraction : register(s3),\n", +"uniform sampler Texture_Reflection : register(s7),\n", +"uniform float4 DistortScaleRefractReflect : register(c14),\n", +"uniform float4 ScreenScaleRefractReflect : register(c32),\n", +"uniform float4 ScreenCenterRefractReflect : register(c31),\n", +"uniform float4 RefractColor : register(c29),\n", +"uniform float4 ReflectColor : register(c26),\n", +"uniform float ReflectFactor : register(c27),\n", +"uniform float ReflectOffset : register(c28),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n", +" //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" float4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" //SafeScreenTexCoord = gl_FragCoord.xyxy * float4(1.0 / 1920.0, 1.0 / 1200.0, 1.0 / 1920.0, 1.0 / 1200.0);\n", +"#ifdef USEALPHAGENVERTEX\n", +" float4 distort = DistortScaleRefractReflect * gl_FrontColor.a;\n", +" float reflectoffset = ReflectOffset * gl_FrontColor.a;\n", +" float reflectfactor = ReflectFactor * gl_FrontColor.a;\n", +" float4 refractcolor = mix(RefractColor, vec4(1.0, 1.0, 1.0, 1.0), gl_FrontColor.a);\n", +"#else\n", +" float4 distort = DistortScaleRefractReflect;\n", +" float reflectoffset = ReflectOffset;\n", +" float reflectfactor = ReflectFactor;\n", +" float4 refractcolor = RefractColor;\n", +"#endif\n", +" float4 ScreenTexCoord = SafeScreenTexCoord + float2(normalize(tex2D(Texture_Normal, TexCoord).rgb - float3(0.5,0.5,0.5)).xy).xyxy * distort;\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Refraction, ScreenTexCoord.xy + float2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord.xy = lerp(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n", +" f = min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord.zw + float2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord.zw = lerp(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n", +" float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * reflectfactor + reflectoffset;\n", +" dp_FragColor = lerp(float4(tex2D(Texture_Refraction, ScreenTexCoord.xy).rgb, 1) * refractcolor, float4(tex2D(Texture_Reflection, ScreenTexCoord.zw).rgb, 1) * ReflectColor, Fresnel);\n", +"}\n", +"#endif\n", +"#else // !MODE_WATER\n", +"\n", +"\n", +"\n", +"\n", +"// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n", +"\n", +"// fragment shader specific:\n", +"#ifdef FRAGMENT_SHADER\n", +"\n", +"#ifdef USEFOG\n", +"float3 FogVertex(float4 surfacecolor, float3 FogColor, float3 EyeVectorModelSpace, float FogPlaneVertexDist, float FogRangeRecip, float FogPlaneViewDist, float FogHeightFade, sampler Texture_FogMask, sampler Texture_FogHeightTexture)\n", +"{\n", +" float fogfrac;\n", +" float3 fc = FogColor;\n", +"#ifdef USEFOGALPHAHACK\n", +" fc *= surfacecolor.a;\n", +"#endif\n", +"#ifdef USEFOGHEIGHTTEXTURE\n", +" float4 fogheightpixel = tex2D(Texture_FogHeightTexture, float2(1,1) + float2(FogPlaneVertexDist, FogPlaneViewDist) * (-2.0 * FogHeightFade));\n", +" fogfrac = fogheightpixel.a;\n", +" return lerp(fogheightpixel.rgb * fc, surfacecolor.rgb, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n", +"#else\n", +"# ifdef USEFOGOUTSIDE\n", +" fogfrac = min(0.0, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0, min(0.0, FogPlaneVertexDist) * FogHeightFade);\n", +"# else\n", +" fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0, FogPlaneVertexDist)) * min(1.0, (min(0.0, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);\n", +"# endif\n", +" return lerp(fc, surfacecolor.rgb, tex2D(Texture_FogMask, float2(length(EyeVectorModelSpace)*fogfrac*FogRangeRecip, 0.0)).r);\n", +"#endif\n", +"}\n", +"#endif\n", +"\n", +"#ifdef USEOFFSETMAPPING\n", +"float2 OffsetMapping(float2 TexCoord, float4 OffsetMapping_ScaleSteps, float OffsetMapping_Bias, float OffsetMapping_LodDistance, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\n", +"{\n", +" float i;\n", +" // distance-based LOD\n", +"#ifdef USEOFFSETMAPPING_LOD\n", +" //float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n", +" //float4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n", +" float GuessLODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n", +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n", +" // stupid workaround because 1-step and 2-step reliefmapping is void\n", +" float LODSteps = max(3.0, ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y));\n", +"#else\n", +" float LODSteps = ceil(GuessLODFactor * OffsetMapping_ScaleSteps.y);\n", +"#endif\n", +" float LODFactor = LODSteps / OffsetMapping_ScaleSteps.y;\n", +" float4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, LODSteps, 1.0 / LODSteps, OffsetMapping_ScaleSteps.w * LODFactor);\n", +"#else\n", +" #define ScaleSteps OffsetMapping_ScaleSteps\n", +"#endif\n", +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n", +" // 14 sample relief mapping: linear search and then binary search\n", +" // this basically steps forward a small amount repeatedly until it finds\n", +" // itself inside solid, then jitters forward and back using decreasing\n", +" // amounts to find the impact\n", +" //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * ScaleSteps.x) * float2(-1, 1), -1);\n", +" //float3 OffsetVector = float3(normalize(EyeVector.xy) * ScaleSteps.x * float2(-1, 1), -1);\n", +" float3 OffsetVector = float3(normalize(EyeVector).xy * ScaleSteps.x * float2(-1, 1), -1);\n", +" float3 RT = float3(float2(TexCoord.xy - OffsetVector.xy*OffsetMapping_Bias), 1);\n", +" OffsetVector *= ScaleSteps.z;\n", +" for(i = 1.0; i < ScaleSteps.y; ++i)\n", +" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n", +" for(i = 0.0, f = 1.0; i < ScaleSteps.w; ++i, f *= 0.5)\n", +" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n", +" return RT.xy;\n", +"#else\n", +" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n", +" //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * ScaleSteps.x) * float2(-1, 1));\n", +" //float2 OffsetVector = float2(normalize(EyeVector.xy) * ScaleSteps.x * float2(-1, 1));\n", +" float2 OffsetVector = float2(normalize(EyeVector).xy * ScaleSteps.x * float2(-1, 1));\n", +" OffsetVector *= ScaleSteps.z;\n", +" for(i = 0.0; i < ScaleSteps.y; ++i)\n", +" TexCoord += OffsetVector * ((1.0 - OffsetMapping_Bias) - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n", +" return TexCoord;\n", +"#endif\n", +"}\n", +"#endif // USEOFFSETMAPPING\n", +"\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n", +"#if defined(USESHADOWMAP2D)\n", +"# ifdef USESHADOWMAPORTHO\n", +"# define GetShadowMapTC2D(dir, ShadowMap_Parameters) (min(dir, ShadowMap_Parameters.xyz))\n", +"# else\n", +"# ifdef USESHADOWMAPVSDCT\n", +"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters, samplerCUBE Texture_CubeProjection)\n", +"{\n", +" float3 adir = abs(dir);\n", +" float2 mparams = ShadowMap_Parameters.xy / max(max(adir.x, adir.y), adir.z);\n", +" float4 proj = texCUBE(Texture_CubeProjection, dir);\n", +" return float3(lerp(dir.xy, dir.zz, proj.xy) * mparams.x + proj.zw * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n", +"}\n", +"# else\n", +"float3 GetShadowMapTC2D(float3 dir, float4 ShadowMap_Parameters)\n", +"{\n", +" float3 adir = abs(dir);\n", +" float m; float4 proj;\n", +" if (adir.x > adir.y) { m = adir.x; proj = float4(dir.zyx, 0.5); } else { m = adir.y; proj = float4(dir.xzy, 1.5); }\n", +" if (adir.z > m) { m = adir.z; proj = float4(dir, 2.5); }\n", +"#ifdef HLSL\n", +" return float3(proj.xy * ShadowMap_Parameters.x / m + float2(0.5,0.5) + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, m + 64 * ShadowMap_Parameters.w);\n", +"#else\n", +" float2 mparams = ShadowMap_Parameters.xy / m;\n", +" return float3(proj.xy * mparams.x + float2(proj.z < 0.0 ? 1.5 : 0.5, proj.w) * ShadowMap_Parameters.z, mparams.y + ShadowMap_Parameters.w);\n", +"#endif\n", +"}\n", +"# endif\n", +"# endif\n", +"#endif // defined(USESHADOWMAP2D)\n", +"\n", +"# ifdef USESHADOWMAP2D\n", +"#ifdef USESHADOWMAPVSDCT\n", +"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale, samplerCUBE Texture_CubeProjection)\n", +"#else\n", +"float ShadowMapCompare(float3 dir, sampler Texture_ShadowMap2D, float4 ShadowMap_Parameters, float2 ShadowMap_TextureScale)\n", +"#endif\n", +"{\n", +"#ifdef USESHADOWMAPVSDCT\n", +" float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters, Texture_CubeProjection);\n", +"#else\n", +" float3 shadowmaptc = GetShadowMapTC2D(dir, ShadowMap_Parameters);\n", +"#endif\n", +" float f;\n", +"\n", +"# ifdef USESHADOWSAMPLER\n", +"# ifdef USESHADOWMAPPCF\n", +"# define texval(x, y) tex2Dproj(Texture_ShadowMap2D, float4(center + float2(x, y)*ShadowMap_TextureScale, shadowmaptc.z, 1.0)).r \n", +" float2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n", +" f = dot(float4(0.25,0.25,0.25,0.25), float4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n", +"# else\n", +" f = tex2Dproj(Texture_ShadowMap2D, float4(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z, 1.0)).r;\n", +"# endif\n", +"# else\n", +"# ifdef USESHADOWMAPPCF\n", +"# if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n", +"# ifdef GL_ARB_texture_gather\n", +"# define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, int2(x, y))\n", +"# else\n", +"# define texval(x, y) texture4(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale)\n", +"# endif\n", +" float2 offset = frac(shadowmaptc.xy - 0.5), center = (shadowmaptc.xy - offset)*ShadowMap_TextureScale;\n", +"# if USESHADOWMAPPCF > 1\n", +" float4 group1 = step(shadowmaptc.z, texval(-2.0, -2.0));\n", +" float4 group2 = step(shadowmaptc.z, texval( 0.0, -2.0));\n", +" float4 group3 = step(shadowmaptc.z, texval( 2.0, -2.0));\n", +" float4 group4 = step(shadowmaptc.z, texval(-2.0, 0.0));\n", +" float4 group5 = step(shadowmaptc.z, texval( 0.0, 0.0));\n", +" float4 group6 = step(shadowmaptc.z, texval( 2.0, 0.0));\n", +" float4 group7 = step(shadowmaptc.z, texval(-2.0, 2.0));\n", +" float4 group8 = step(shadowmaptc.z, texval( 0.0, 2.0));\n", +" float4 group9 = step(shadowmaptc.z, texval( 2.0, 2.0));\n", +" float4 locols = float4(group1.ab, group3.ab);\n", +" float4 hicols = float4(group7.rg, group9.rg);\n", +" locols.yz += group2.ab;\n", +" hicols.yz += group8.rg;\n", +" float4 midcols = float4(group1.rg, group3.rg) + float4(group7.ab, group9.ab) +\n", +" float4(group4.rg, group6.rg) + float4(group4.ab, group6.ab) +\n", +" lerp(locols, hicols, offset.y);\n", +" float4 cols = group5 + float4(group2.rg, group8.ab);\n", +" cols.xyz += lerp(midcols.xyz, midcols.yzw, offset.x);\n", +" f = dot(cols, float4(1.0/25.0));\n", +"# else\n", +" float4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n", +" float4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n", +" float4 group3 = step(shadowmaptc.z, texval(-1.0, 1.0));\n", +" float4 group4 = step(shadowmaptc.z, texval( 1.0, 1.0));\n", +" float4 cols = float4(group1.rg, group2.rg) + float4(group3.ab, group4.ab) +\n", +" lerp(float4(group1.ab, group2.ab), float4(group3.rg, group4.rg), offset.y);\n", +" f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n", +"# endif\n", +"# else\n", +"# ifdef GL_EXT_gpu_shader4\n", +"# define texval(x, y) tex2DOffset(Texture_ShadowMap2D, center, int2(x, y)).r\n", +"# else\n", +"# define texval(x, y) texDepth2D(Texture_ShadowMap2D, center + float2(x, y)*ShadowMap_TextureScale).r \n", +"# endif\n", +"# if USESHADOWMAPPCF > 1\n", +" float2 center = shadowmaptc.xy - 0.5, offset = frac(center);\n", +" center *= ShadowMap_TextureScale;\n", +" float4 row1 = step(shadowmaptc.z, float4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n", +" float4 row2 = step(shadowmaptc.z, float4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n", +" float4 row3 = step(shadowmaptc.z, float4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n", +" float4 row4 = step(shadowmaptc.z, float4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n", +" float4 cols = row2 + row3 + lerp(row1, row4, offset.y);\n", +" f = dot(lerp(cols.xyz, cols.yzw, offset.x), float3(1.0/9.0));\n", +"# else\n", +" float2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = frac(shadowmaptc.xy);\n", +" float3 row1 = step(shadowmaptc.z, float3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n", +" float3 row2 = step(shadowmaptc.z, float3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n", +" float3 row3 = step(shadowmaptc.z, float3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n", +" float3 cols = row2 + lerp(row1, row3, offset.y);\n", +" f = dot(lerp(cols.xy, cols.yz, offset.x), float2(0.25,0.25));\n", +"# endif\n", +"# endif\n", +"# else\n", +" f = step(shadowmaptc.z, tex2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n", +"# endif\n", +"# endif\n", +"# ifdef USESHADOWMAPORTHO\n", +" return lerp(ShadowMap_Parameters.w, 1.0, f);\n", +"# else\n", +" return f;\n", +"# endif\n", +"}\n", +"# endif\n", +"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n", +"#endif // FRAGMENT_SHADER\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_DEFERREDGEOMETRY\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"float4 gl_Color : COLOR0,\n", +"#endif\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"float4 gl_MultiTexCoord1 : TEXCOORD1,\n", +"float4 gl_MultiTexCoord2 : TEXCOORD2,\n", +"float4 gl_MultiTexCoord3 : TEXCOORD3,\n", +"uniform float4x4 TexMatrix : register(c0),\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform float4x4 BackgroundTexMatrix : register(c4),\n", +"#endif\n", +"uniform float4x4 ModelViewMatrix : register(c12),\n", +"#ifdef USEOFFSETMAPPING\n", +"uniform float3 EyePosition : register(c24),\n", +"#endif\n", +"out float4 gl_Position : POSITION,\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"out float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"out float4 TexCoordBoth : TEXCOORD0,\n", +"#ifdef USEOFFSETMAPPING\n", +"out float3 EyeVector : TEXCOORD2,\n", +"#endif\n", +"out float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n", +"out float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n", +"out float4 VectorR : TEXCOORD7 // direction of R texcoord (surface normal), Depth value\n", +")\n", +"{\n", +" TexCoordBoth = mul(TexMatrix, gl_MultiTexCoord0);\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" gl_FrontColor = gl_Color;\n", +" TexCoordBoth.zw = float2(Backgroundmul(TexMatrix, gl_MultiTexCoord0));\n", +"#endif\n", +"\n", +" // transform unnormalized eye direction into tangent space\n", +"#ifdef USEOFFSETMAPPING\n", +" float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n", +" EyeVector = float3(dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz));\n", +"#endif\n", +"\n", +" VectorS = mul(ModelViewMatrix, float4(gl_MultiTexCoord1.xyz, 0)).xyz;\n", +" VectorT = mul(ModelViewMatrix, float4(gl_MultiTexCoord2.xyz, 0)).xyz;\n", +" VectorR.xyz = mul(ModelViewMatrix, float4(gl_MultiTexCoord3.xyz, 0)).xyz;\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +" VectorR.w = mul(ModelViewMatrix, gl_Vertex).z;\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"float4 TexCoordBoth : TEXCOORD0,\n", +"float3 EyeVector : TEXCOORD2,\n", +"float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n", +"float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n", +"float4 VectorR : TEXCOORD7, // direction of R texcoord (surface normal), Depth value\n", +"uniform sampler Texture_Normal : register(s0),\n", +"#ifdef USEALPHAKILL\n", +"uniform sampler Texture_Color : register(s1),\n", +"#endif\n", +"uniform sampler Texture_Gloss : register(s2),\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform sampler Texture_SecondaryNormal : register(s4),\n", +"uniform sampler Texture_SecondaryGloss : register(s6),\n", +"#endif\n", +"#ifdef USEOFFSETMAPPING\n", +"uniform float4 OffsetMapping_ScaleSteps : register(c24),\n", +"uniform float4 OffsetMapping_LodDistance : register(c53),\n", +"uniform float OffsetMapping_Bias : register(c54),\n", +"#endif\n", +"uniform half SpecularPower : register(c36),\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" float2 TexCoord = TexCoordBoth.xy;\n", +"#ifdef USEOFFSETMAPPING\n", +" // apply offsetmapping\n", +" float2 dPdx = ddx(TexCoord);\n", +" float2 dPdy = ddy(TexCoord);\n", +" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, OffsetMapping_Bias, OffsetMapping_LodDistance, EyeVector, Texture_Normal, dPdx, dPdy);\n", +"# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n", +"#else\n", +"# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n", +"#endif\n", +"\n", +"#ifdef USEALPHAKILL\n", +" if (offsetMappedTexture2D(Texture_Color).a < 0.5)\n", +" discard;\n", +"#endif\n", +"\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" float alpha = offsetMappedTexture2D(Texture_Color).a;\n", +" float terrainblend = clamp(float(gl_FrontColor.a) * alpha * 2.0 - 0.5, float(0.0), float(1.0));\n", +" //float terrainblend = min(float(gl_FrontColor.a) * alpha * 2.0, float(1.0));\n", +" //float terrainblend = float(gl_FrontColor.a) * alpha > 0.5;\n", +"#endif\n", +"\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" float3 surfacenormal = lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, offsetMappedTexture2D(Texture_Normal).rgb, terrainblend) - float3(0.5, 0.5, 0.5);\n", +" float a = lerp(tex2D(Texture_SecondaryGloss, TexCoord2).a, offsetMappedTexture2D(Texture_Gloss).a, terrainblend);\n", +"#else\n", +" float3 surfacenormal = offsetMappedTexture2D(Texture_Normal).rgb - float3(0.5, 0.5, 0.5);\n", +" float a = offsetMappedTexture2D(Texture_Gloss).a;\n", +"#endif\n", +"\n", +" float3 pixelnormal = normalize(surfacenormal.x * VectorS.xyz + surfacenormal.y * VectorT.xyz + surfacenormal.z * VectorR.xyz);\n", +" dp_FragColor = float4(pixelnormal.x, pixelnormal.y, VectorR.w, a);\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"#else // !MODE_DEFERREDGEOMETRY\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"uniform float4x4 ModelViewMatrix : register(c12),\n", +"out float4 gl_Position : POSITION,\n", +"out float4 ModelViewPosition : TEXCOORD0\n", +")\n", +"{\n", +" ModelViewPosition = mul(ModelViewMatrix, gl_Vertex);\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"#ifdef HLSL\n", +"float2 Pixel : VPOS,\n", +"#else\n", +"float2 Pixel : WPOS,\n", +"#endif\n", +"float4 ModelViewPosition : TEXCOORD0,\n", +"uniform float4x4 ViewToLight : register(c44),\n", +"uniform float2 ScreenToDepth : register(c33), // ScreenToDepth = float2(Far / (Far - Near), Far * Near / (Near - Far));\n", +"uniform float3 LightPosition : register(c23),\n", +"uniform half2 PixelToScreenTexCoord : register(c42),\n", +"uniform half3 DeferredColor_Ambient : register(c9),\n", +"uniform half3 DeferredColor_Diffuse : register(c10),\n", +"#ifdef USESPECULAR\n", +"uniform half3 DeferredColor_Specular : register(c11),\n", +"uniform half SpecularPower : register(c36),\n", +"#endif\n", +"uniform sampler Texture_Attenuation : register(s9),\n", +"uniform sampler Texture_ScreenDepth : register(s13),\n", +"uniform sampler Texture_ScreenNormalMap : register(s14),\n", +"\n", +"#ifdef USECUBEFILTER\n", +"uniform samplerCUBE Texture_Cube : register(s10),\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAP2D\n", +"# ifdef USESHADOWSAMPLER\n", +"uniform sampler Texture_ShadowMap2D : register(s15),\n", +"# else\n", +"uniform sampler Texture_ShadowMap2D : register(s15),\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAPVSDCT\n", +"uniform samplerCUBE Texture_CubeProjection : register(s12),\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +"uniform float2 ShadowMap_TextureScale : register(c35),\n", +"uniform float4 ShadowMap_Parameters : register(c34),\n", +"#endif\n", +"\n", +"out float4 gl_FragData0 : COLOR0,\n", +"out float4 gl_FragData1 : COLOR1\n", +")\n", +"{\n", +" // calculate viewspace pixel position\n", +" float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n", +" float3 position;\n", +" // get the geometry information (depth, normal, specular exponent)\n", +" half4 normalmap = half4(tex2D(Texture_ScreenNormalMap, ScreenTexCoord));\n", +" // decode viewspace pixel normal\n", +"// float3 surfacenormal = normalize(normalmap.rgb - cast_myhalf3(0.5,0.5,0.5));\n", +" float3 surfacenormal = half3(normalmap.rg, sqrt(1.0-dot(normalmap.rg, normalmap.rg)));\n", +" // decode viewspace pixel position\n", +"// position.z = decodedepthmacro(dp_texture2D(Texture_ScreenDepth, ScreenTexCoord));\n", +" position.z = normalmap.b;\n", +"// position.z = ScreenToDepth.y / (dp_texture2D(Texture_ScreenDepth, ScreenTexCoord).r + ScreenToDepth.x);\n", +" position.xy = ModelViewPosition.xy * (position.z / ModelViewPosition.z);\n", +"\n", +" // now do the actual shading\n", +" // surfacenormal = pixel normal in viewspace\n", +" // LightVector = pixel to light in viewspace\n", +" // CubeVector = position in lightspace\n", +" // eyevector = pixel to view in viewspace\n", +" float3 CubeVector = mul(ViewToLight, float4(position,1)).xyz;\n", +" half fade = half(tex2D(Texture_Attenuation, float2(length(CubeVector), 0.0)).r);\n", +"#ifdef USEDIFFUSE\n", +" // calculate diffuse shading\n", +" half3 lightnormal = half3(normalize(LightPosition - position));\n", +" half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n", +"#endif\n", +"#ifdef USESPECULAR\n", +" // calculate directional shading\n", +" float3 eyevector = position * -1.0;\n", +"# ifdef USEEXACTSPECULARMATH\n", +" half specular = half(pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(eyevector)))*-1.0, 0.0)), 1.0 + SpecularPower * normalmap.a));\n", +"# else\n", +" half3 specularnormal = half3(normalize(lightnormal + half3(normalize(eyevector))));\n", +" half specular = half(pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + SpecularPower * normalmap.a));\n", +"# endif\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +" fade *= half(ShadowMapCompare(CubeVector, Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n", +"#ifdef USESHADOWMAPVSDCT\n", +", Texture_CubeProjection\n", +"#endif\n", +" ));\n", +"#endif\n", +"\n", +"#ifdef USEDIFFUSE\n", +" gl_FragData0 = float4((DeferredColor_Ambient + DeferredColor_Diffuse * diffuse) * fade, 1.0);\n", +"#else\n", +" gl_FragData0 = float4(DeferredColor_Ambient * fade, 1.0);\n", +"#endif\n", +"#ifdef USESPECULAR\n", +" gl_FragData1 = float4(DeferredColor_Specular * (specular * fade), 1.0);\n", +"#else\n", +" gl_FragData1 = float4(0.0, 0.0, 0.0, 1.0);\n", +"#endif\n", +"\n", +"# ifdef USECUBEFILTER\n", +" float3 cubecolor = texCUBE(Texture_Cube, CubeVector).rgb;\n", +" gl_FragData0.rgb *= cubecolor;\n", +" gl_FragData1.rgb *= cubecolor;\n", +"# endif\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"#else // !MODE_DEFERREDLIGHTSOURCE\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef VERTEX_SHADER\n", +"void main\n", +"(\n", +"float4 gl_Vertex : POSITION,\n", +"uniform float4x4 ModelViewProjectionMatrix : register(c8),\n", +"#if defined(USEVERTEXTEXTUREBLEND) || defined(MODE_VERTEXCOLOR) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR)\n", +"float4 gl_Color : COLOR0,\n", +"#endif\n", +"float4 gl_MultiTexCoord0 : TEXCOORD0,\n", +"float4 gl_MultiTexCoord1 : TEXCOORD1,\n", +"float4 gl_MultiTexCoord2 : TEXCOORD2,\n", +"float4 gl_MultiTexCoord3 : TEXCOORD3,\n", +"float4 gl_MultiTexCoord4 : TEXCOORD4,\n", +"\n", +"uniform float3 EyePosition : register(c24),\n", +"uniform float4x4 TexMatrix : register(c0),\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform float4x4 BackgroundTexMatrix : register(c4),\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform float4x4 ModelToLight : register(c20),\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform float3 LightPosition : register(c27),\n", +"#endif\n", +"#ifdef MODE_LIGHTDIRECTION\n", +"uniform float3 LightDir : register(c26),\n", +"#endif\n", +"uniform float4 FogPlane : register(c25),\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"uniform float3 LightPosition : register(c27),\n", +"#endif\n", +"#ifdef USESHADOWMAPORTHO\n", +"uniform float4x4 ShadowMapMatrix : register(c16),\n", +"#endif\n", +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n", +"out float4 gl_FrontColor : COLOR,\n", +"#endif\n", +"out float4 TexCoordBoth : TEXCOORD0,\n", +"#ifdef USELIGHTMAP\n", +"out float2 TexCoordLightmap : TEXCOORD1,\n", +"#endif\n", +"#ifdef USEEYEVECTOR\n", +"out float3 EyeVector : TEXCOORD2,\n", +"#endif\n", +"#ifdef USEREFLECTION\n", +"out float4 ModelViewProjectionPosition : TEXCOORD3,\n", +"#endif\n", +"#ifdef USEFOG\n", +"out float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE) || defined(USEDIFFUSE)\n", +"out float3 LightVector : TEXCOORD1,\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"out float3 CubeVector : TEXCOORD3,\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n", +"out float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n", +"out float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n", +"out float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n", +"#endif\n", +"#ifdef USESHADOWMAPORTHO\n", +"out float3 ShadowMapTC : TEXCOORD3, // CONFLICTS WITH USEREFLECTION!\n", +"#endif\n", +"out float4 gl_Position : POSITION\n", +")\n", +"{\n", +"#if defined(MODE_VERTEXCOLOR) || defined(USEVERTEXTEXTUREBLEND) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR) || defined(USEALPHAGENVERTEX)\n", +" gl_FrontColor = gl_Color;\n", +"#endif\n", +" // copy the surface texcoord\n", +" TexCoordBoth = mul(TexMatrix, gl_MultiTexCoord0);\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" TexCoordBoth.zw = mul(BackgroundTexMatrix, gl_MultiTexCoord0).xy;\n", +"#endif\n", +"#ifdef USELIGHTMAP\n", +" TexCoordLightmap = gl_MultiTexCoord4.xy;\n", +"#endif\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +" // transform vertex position into light attenuation/cubemap space\n", +" // (-1 to +1 across the light box)\n", +" CubeVector = mul(ModelToLight, gl_Vertex).xyz;\n", +"\n", +"# ifdef USEDIFFUSE\n", +" // transform unnormalized light direction into tangent space\n", +" // (we use unnormalized to ensure that it interpolates correctly and then\n", +" // normalize it per pixel)\n", +" float3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n", +" LightVector = float3(dot(lightminusvertex, gl_MultiTexCoord1.xyz), dot(lightminusvertex, gl_MultiTexCoord2.xyz), dot(lightminusvertex, gl_MultiTexCoord3.xyz));\n", +"# endif\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTDIRECTION) && defined(USEDIFFUSE)\n", +" LightVector = float3(dot(LightDir, gl_MultiTexCoord1.xyz), dot(LightDir, gl_MultiTexCoord2.xyz), dot(LightDir, gl_MultiTexCoord3.xyz));\n", +"#endif\n", +"\n", +" // transform unnormalized eye direction into tangent space\n", +"#ifdef USEEYEVECTOR\n", +" float3 EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n", +" EyeVector = float3(dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz), dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz));\n", +"#endif\n", +"\n", +"#ifdef USEFOG\n", +" EyeVectorModelSpaceFogPlaneVertexDist.xyz = EyePosition - gl_Vertex.xyz;\n", +" EyeVectorModelSpaceFogPlaneVertexDist.w = dot(FogPlane, gl_Vertex);\n", +"#endif\n", +"\n", +"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", +" VectorS = gl_MultiTexCoord1.xyz;\n", +" VectorT = gl_MultiTexCoord2.xyz;\n", +" VectorR = gl_MultiTexCoord3.xyz;\n", +"#endif\n", +"\n", +" // transform vertex to camera space, using ftransform to match non-VS rendering\n", +" gl_Position = mul(ModelViewProjectionMatrix, gl_Vertex);\n", +"\n", +"#ifdef USESHADOWMAPORTHO\n", +" ShadowMapTC = mul(ShadowMapMatrix, gl_Position).xyz;\n", +"#endif\n", +"\n", +"#ifdef USEREFLECTION\n", +" ModelViewProjectionPosition = gl_Position;\n", +"#endif\n", +"#ifdef USETRIPPY\n", +" gl_Position = TrippyVertex(gl_Position);\n", +"#endif\n", +"}\n", +"#endif // VERTEX_SHADER\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef FRAGMENT_SHADER\n", +"void main\n", +"(\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +"#ifdef HLSL\n", +"float2 Pixel : VPOS,\n", +"#else\n", +"float2 Pixel : WPOS,\n", +"#endif\n", +"#endif\n", +"float4 gl_FrontColor : COLOR,\n", +"float4 TexCoordBoth : TEXCOORD0,\n", +"#ifdef USELIGHTMAP\n", +"float2 TexCoordLightmap : TEXCOORD1,\n", +"#endif\n", +"#ifdef USEEYEVECTOR\n", +"float3 EyeVector : TEXCOORD2,\n", +"#endif\n", +"#ifdef USEREFLECTION\n", +"float4 ModelViewProjectionPosition : TEXCOORD3,\n", +"#endif\n", +"#ifdef USEFOG\n", +"float4 EyeVectorModelSpaceFogPlaneVertexDist : TEXCOORD4,\n", +"#endif\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_LIGHTDIRECTION)\n", +"float3 LightVector : TEXCOORD1,\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"float3 CubeVector : TEXCOORD3,\n", +"#endif\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"float4 ModelViewPosition : TEXCOORD0,\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_DEFERREDGEOMETRY) || defined(USEREFLECTCUBE)\n", +"float3 VectorS : TEXCOORD5, // direction of S texcoord (sometimes crudely called tangent)\n", +"float3 VectorT : TEXCOORD6, // direction of T texcoord (sometimes crudely called binormal)\n", +"float3 VectorR : TEXCOORD7, // direction of R texcoord (surface normal)\n", +"#endif\n", +"#ifdef USESHADOWMAPORTHO\n", +"float3 ShadowMapTC : TEXCOORD3, // CONFLICTS WITH USEREFLECTION!\n", +"#endif\n", +"\n", +"uniform sampler Texture_Normal : register(s0),\n", +"uniform sampler Texture_Color : register(s1),\n", +"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n", +"uniform sampler Texture_Gloss : register(s2),\n", +"#endif\n", +"#ifdef USEGLOW\n", +"uniform sampler Texture_Glow : register(s3),\n", +"#endif\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"uniform sampler Texture_SecondaryNormal : register(s4),\n", +"uniform sampler Texture_SecondaryColor : register(s5),\n", +"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n", +"uniform sampler Texture_SecondaryGloss : register(s6),\n", +"#endif\n", +"#ifdef USEGLOW\n", +"uniform sampler Texture_SecondaryGlow : register(s7),\n", +"#endif\n", +"#endif\n", +"#ifdef USECOLORMAPPING\n", +"uniform sampler Texture_Pants : register(s4),\n", +"uniform sampler Texture_Shirt : register(s7),\n", +"#endif\n", +"#ifdef USEFOG\n", +"uniform sampler Texture_FogHeightTexture : register(s14),\n", +"uniform sampler Texture_FogMask : register(s8),\n", +"#endif\n", +"#ifdef USELIGHTMAP\n", +"uniform sampler Texture_Lightmap : register(s9),\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n", +"uniform sampler Texture_Deluxemap : register(s10),\n", +"#endif\n", +"#ifdef USEREFLECTION\n", +"uniform sampler Texture_Reflection : register(s7),\n", +"#endif\n", +"\n", +"#ifdef MODE_DEFERREDLIGHTSOURCE\n", +"uniform sampler Texture_ScreenDepth : register(s13),\n", +"uniform sampler Texture_ScreenNormalMap : register(s14),\n", +"#endif\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +"uniform sampler Texture_ScreenDepth : register(s13),\n", +"uniform sampler Texture_ScreenNormalMap : register(s14),\n", +"uniform sampler Texture_ScreenDiffuse : register(s11),\n", +"uniform sampler Texture_ScreenSpecular : register(s12),\n", +"#endif\n", +"\n", +"#ifdef USECOLORMAPPING\n", +"uniform half3 Color_Pants : register(c7),\n", +"uniform half3 Color_Shirt : register(c8),\n", +"#endif\n", +"#ifdef USEFOG\n", +"uniform float3 FogColor : register(c16),\n", +"uniform float FogRangeRecip : register(c20),\n", +"uniform float FogPlaneViewDist : register(c19),\n", +"uniform float FogHeightFade : register(c17),\n", +"#endif\n", +"\n", +"#ifdef USEOFFSETMAPPING\n", +"uniform float4 OffsetMapping_ScaleSteps : register(c24),\n", +"uniform float OffsetMapping_Bias : register(c54),\n", +"#endif\n", +"\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +"uniform half2 PixelToScreenTexCoord : register(c42),\n", +"uniform half3 DeferredMod_Diffuse : register(c12),\n", +"uniform half3 DeferredMod_Specular : register(c13),\n", +"#endif\n", +"uniform half3 Color_Ambient : register(c3),\n", +"uniform half3 Color_Diffuse : register(c4),\n", +"uniform half3 Color_Specular : register(c5),\n", +"uniform half SpecularPower : register(c36),\n", +"#ifdef USEGLOW\n", +"uniform half3 Color_Glow : register(c6),\n", +"#endif\n", +"uniform half Alpha : register(c0),\n", +"#ifdef USEREFLECTION\n", +"uniform float4 DistortScaleRefractReflect : register(c14),\n", +"uniform float4 ScreenScaleRefractReflect : register(c32),\n", +"uniform float4 ScreenCenterRefractReflect : register(c31),\n", +"uniform half4 ReflectColor : register(c26),\n", +"#endif\n", +"#ifdef USEREFLECTCUBE\n", +"uniform float4x4 ModelToReflectCube : register(c48),\n", +"uniform sampler Texture_ReflectMask : register(s5),\n", +"uniform samplerCUBE Texture_ReflectCube : register(s6),\n", +"#endif\n", +"#ifdef MODE_LIGHTDIRECTION\n", +"uniform half3 LightColor : register(c21),\n", +"#endif\n", +"#ifdef MODE_LIGHTSOURCE\n", +"uniform half3 LightColor : register(c21),\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE)\n", +"uniform sampler Texture_Attenuation : register(s9),\n", +"uniform samplerCUBE Texture_Cube : register(s10),\n", +"#endif\n", +"\n", +"#if defined(MODE_LIGHTSOURCE) || defined(MODE_DEFERREDLIGHTSOURCE) || defined(USESHADOWMAPORTHO)\n", +"\n", +"#ifdef USESHADOWMAP2D\n", +"# ifdef USESHADOWSAMPLER\n", +"uniform sampler Texture_ShadowMap2D : register(s15),\n", +"# else\n", +"uniform sampler Texture_ShadowMap2D : register(s15),\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAPVSDCT\n", +"uniform samplerCUBE Texture_CubeProjection : register(s12),\n", +"#endif\n", +"\n", +"#if defined(USESHADOWMAP2D)\n", +"uniform float2 ShadowMap_TextureScale : register(c35),\n", +"uniform float4 ShadowMap_Parameters : register(c34),\n", +"#endif\n", +"#endif // !defined(MODE_LIGHTSOURCE) && !defined(MODE_DEFERREDLIGHTSOURCE) && !defined(USESHADOWMAPORTHO)\n", +"\n", +"out float4 dp_FragColor : COLOR\n", +")\n", +"{\n", +" float2 TexCoord = TexCoordBoth.xy;\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" float2 TexCoord2 = TexCoordBoth.zw;\n", +"#endif\n", +"#ifdef USEOFFSETMAPPING\n", +" // apply offsetmapping\n", +" float2 dPdx = ddx(TexCoord);\n", +" float2 dPdy = ddy(TexCoord);\n", +" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, OffsetMapping_Bias, OffsetMapping_LodDistance, EyeVector, Texture_Normal, dPdx, dPdy);\n", +"# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n", +"#else\n", +"# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n", +"#endif\n", +"\n", +" // combine the diffuse textures (base, pants, shirt)\n", +" half4 color = half4(offsetMappedTexture2D(Texture_Color));\n", +"#ifdef USEALPHAKILL\n", +" if (color.a < 0.5)\n", +" discard;\n", +"#endif\n", +" color.a *= Alpha;\n", +"#ifdef USECOLORMAPPING\n", +" color.rgb += half3(offsetMappedTexture2D(Texture_Pants).rgb) * Color_Pants + half3(offsetMappedTexture2D(Texture_Shirt).rgb) * Color_Shirt;\n", +"#endif\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +"#ifdef USEBOTHALPHAS\n", +" half4 color2 = half4(tex2D(Texture_SecondaryColor, TexCoord2));\n", +" half terrainblend = clamp(half(gl_FrontColor.a) * color.a, half(1.0 - color2.a), half(1.0));\n", +" color.rgb = lerp(color2.rgb, color.rgb, terrainblend);\n", +"#else\n", +" half terrainblend = clamp(half(gl_FrontColor.a) * color.a * 2.0 - 0.5, half(0.0), half(1.0));\n", +" //half terrainblend = min(half(gl_FrontColor.a) * color.a * 2.0, half(1.0));\n", +" //half terrainblend = half(gl_FrontColor.a) * color.a > 0.5;\n", +" color.rgb = half3(lerp(tex2D(Texture_SecondaryColor, TexCoord2).rgb, float3(color.rgb), terrainblend));\n", +" color.a = 1.0;\n", +" //color = half4(lerp(float4(1, 0, 0, 1), color, terrainblend));\n", +"#endif\n", +"#endif\n", +"#ifdef USEALPHAGENVERTEX\n", +" color.a *= gl_FrontColor.a;\n", +"#endif\n", +"\n", +" // get the surface normal\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" half3 surfacenormal = normalize(half3(lerp(tex2D(Texture_SecondaryNormal, TexCoord2).rgb, offsetMappedTexture2D(Texture_Normal).rgb, terrainblend)) - half3(0.5, 0.5, 0.5));\n", +"#else\n", +" half3 surfacenormal = half3(normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5, 0.5, 0.5)));\n", +"#endif\n", +"\n", +" // get the material colors\n", +" half3 diffusetex = color.rgb;\n", +"#if defined(USESPECULAR) || defined(USEDEFERREDLIGHTMAP)\n", +"# ifdef USEVERTEXTEXTUREBLEND\n", +" half4 glosstex = half4(lerp(tex2D(Texture_SecondaryGloss, TexCoord2), offsetMappedTexture2D(Texture_Gloss), terrainblend));\n", +"# else\n", +" half4 glosstex = half4(offsetMappedTexture2D(Texture_Gloss));\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USEREFLECTCUBE\n", +" float3 TangentReflectVector = reflect(-EyeVector, surfacenormal);\n", +" float3 ModelReflectVector = TangentReflectVector.x * VectorS + TangentReflectVector.y * VectorT + TangentReflectVector.z * VectorR;\n", +" float3 ReflectCubeTexCoord = mul(ModelToReflectCube, float4(ModelReflectVector, 0)).xyz;\n", +" diffusetex += half3(offsetMappedTexture2D(Texture_ReflectMask).rgb) * half3(texCUBE(Texture_ReflectCube, ReflectCubeTexCoord).rgb);\n", +"#endif\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTSOURCE\n", +" // light source\n", +"#ifdef USEDIFFUSE\n", +" half3 lightnormal = half3(normalize(LightVector));\n", +" half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n", +" color.rgb = diffusetex * (Color_Ambient + diffuse * Color_Diffuse);\n", +"#ifdef USESPECULAR\n", +"#ifdef USEEXACTSPECULARMATH\n", +" half specular = half(pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), 1.0 + SpecularPower * glosstex.a));\n", +"#else\n", +" half3 specularnormal = half3(normalize(lightnormal + half3(normalize(EyeVector))));\n", +" half specular = half(pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + SpecularPower * glosstex.a));\n", +"#endif\n", +" color.rgb += glosstex.rgb * (specular * Color_Specular);\n", +"#endif\n", +"#else\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"#endif\n", +" color.rgb *= LightColor;\n", +" color.rgb *= half(tex2D(Texture_Attenuation, float2(length(CubeVector), 0.0)).r);\n", +"#if defined(USESHADOWMAP2D)\n", +" color.rgb *= half(ShadowMapCompare(CubeVector, Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale\n", +"#ifdef USESHADOWMAPVSDCT\n", +", Texture_CubeProjection\n", +"#endif\n", +" ));\n", +"\n", +"#endif\n", +"# ifdef USECUBEFILTER\n", +" color.rgb *= half3(texCUBE(Texture_Cube, CubeVector).rgb);\n", +"# endif\n", +"\n", +"#ifdef USESHADOWMAP2D\n", +"#ifdef USESHADOWMAPVSDCT\n", +"// float3 shadowmaptc = GetShadowMapTC2D(CubeVector, ShadowMap_Parameters, Texture_CubeProjection);\n", +"#else\n", +"// float3 shadowmaptc = GetShadowMapTC2D(CubeVector, ShadowMap_Parameters);\n", +"#endif\n", +"// color.rgb = half3(tex2D(Texture_ShadowMap2D, float2(0.1,0.1)).rgb);\n", +"// color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale).rgb);\n", +"// color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale,1.0));\n", +"// color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n", +"// color.rgb = half3(tex2D(Texture_ShadowMap2D, float2(0.1,0.1)).rgb);\n", +"// color.rgb = half3(tex2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale).rgb);\n", +"// color.rgb = half3(shadowmaptc.xyz * float3(ShadowMap_TextureScale,1.0));\n", +"// color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n", +"// color.r = half(shadowmaptc.z - texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n", +"// color.r = half(shadowmaptc.z);\n", +"// color.r = half(texDepth2D(Texture_ShadowMap2D, shadowmaptc.xy * ShadowMap_TextureScale));\n", +"// color.r = half(shadowmaptc.z);\n", +"// color.r = 1;\n", +"// color.rgb = abs(CubeVector);\n", +"#endif\n", +"// color.rgb = half3(1,1,1);\n", +"#endif // MODE_LIGHTSOURCE\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTDIRECTION\n", +" #define SHADING\n", +" #ifdef USEDIFFUSE\n", +" half3 lightnormal = half3(normalize(LightVector));\n", +" #endif\n", +" #define lightcolor LightColor\n", +"#endif // MODE_LIGHTDIRECTION\n", +"#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", +" #define SHADING\n", +" // deluxemap lightmapping using light vectors in modelspace (q3map2 -light -deluxe)\n", +" half3 lightnormal_modelspace = half3(tex2D(Texture_Deluxemap, TexCoordLightmap).rgb) * 2.0 + half3(-1.0, -1.0, -1.0);\n", +" half3 lightcolor = half3(tex2D(Texture_Lightmap, TexCoordLightmap).rgb);\n", +" // convert modelspace light vector to tangentspace\n", +" half3 lightnormal = half3(dot(lightnormal_modelspace, half3(VectorS)), dot(lightnormal_modelspace, half3(VectorT)), dot(lightnormal_modelspace, half3(VectorR)));\n", +" // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n", +" // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n", +" // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n", +" // on that luxel, and NOT to its center, because recursive triangle subdivision is used\n", +" // to map the luxels to coordinates on the draw surfaces), which also causes\n", +" // deluxemaps to be wrong because light contributions from the wrong side of the surface\n", +" // are added up. To prevent divisions by zero or strong exaggerations, a max()\n", +" // nudge is done here at expense of some additional fps. This is ONLY needed for\n", +" // deluxemaps, tangentspace deluxemap avoid this problem by design.\n", +" lightcolor *= 1.0 / max(0.25, lightnormal.z);\n", +"#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", +"#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", +" #define SHADING\n", +" // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n", +" half3 lightnormal = half3(tex2D(Texture_Deluxemap, TexCoordLightmap).rgb) * 2.0 + half3(-1.0, -1.0, -1.0);\n", +" half3 lightcolor = half3(tex2D(Texture_Lightmap, TexCoordLightmap).rgb);\n", +"#endif\n", +"#if defined(MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP) || defined(MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR)\n", +" #define SHADING\n", +" // forced deluxemap on lightmapped/vertexlit surfaces\n", +" half3 lightnormal = half3(0.0, 0.0, 1.0);\n", +" #ifdef USELIGHTMAP\n", +" half3 lightcolor = half3(tex2D(Texture_Lightmap, TexCoordLightmap).rgb);\n", +" #else\n", +" half3 lightcolor = half3(gl_FrontColor.rgb);\n", +" #endif\n", +"#endif\n", +"#ifdef MODE_FAKELIGHT\n", +" #define SHADING\n", +" half3 lightnormal = half3(normalize(EyeVector));\n", +" half3 lightcolor = half3(1.0,1.0,1.0);\n", +"#endif // MODE_FAKELIGHT\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef MODE_LIGHTMAP\n", +" color.rgb = diffusetex * (Color_Ambient + half3(tex2D(Texture_Lightmap, TexCoordLightmap).rgb) * Color_Diffuse);\n", +"#endif // MODE_LIGHTMAP\n", +"#ifdef MODE_VERTEXCOLOR\n", +" color.rgb = diffusetex * (Color_Ambient + half3(gl_FrontColor.rgb) * Color_Diffuse);\n", +"#endif // MODE_VERTEXCOLOR\n", +"#ifdef MODE_FLATCOLOR\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"#endif // MODE_FLATCOLOR\n", +"\n", +"\n", +"\n", +"\n", +"#ifdef SHADING\n", +"# ifdef USEDIFFUSE\n", +" half diffuse = half(max(float(dot(surfacenormal, lightnormal)), 0.0));\n", +"# ifdef USESPECULAR\n", +"# ifdef USEEXACTSPECULARMATH\n", +" half specular = half(pow(half(max(float(dot(reflect(lightnormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), 1.0 + SpecularPower * glosstex.a));\n", +"# else\n", +" half3 specularnormal = half3(normalize(lightnormal + half3(normalize(EyeVector))));\n", +" half specular = half(pow(half(max(float(dot(surfacenormal, specularnormal)), 0.0)), 1.0 + SpecularPower * glosstex.a));\n", +"# endif\n", +" color.rgb = diffusetex * Color_Ambient + (diffusetex * Color_Diffuse * diffuse + glosstex.rgb * Color_Specular * specular) * lightcolor;\n", +"# else\n", +" color.rgb = diffusetex * (Color_Ambient + Color_Diffuse * diffuse * lightcolor);\n", +"# endif\n", +"# else\n", +" color.rgb = diffusetex * Color_Ambient;\n", +"# endif\n", +"#endif\n", +"\n", +"#ifdef USESHADOWMAPORTHO\n", +" color.rgb *= half(ShadowMapCompare(ShadowMapTC, Texture_ShadowMap2D, ShadowMap_Parameters, ShadowMap_TextureScale));\n", +"#endif\n", +"\n", +"#ifdef USEDEFERREDLIGHTMAP\n", +" float2 ScreenTexCoord = Pixel * PixelToScreenTexCoord;\n", +" color.rgb += diffusetex * half3(tex2D(Texture_ScreenDiffuse, ScreenTexCoord).rgb) * DeferredMod_Diffuse;\n", +" color.rgb += glosstex.rgb * half3(tex2D(Texture_ScreenSpecular, ScreenTexCoord).rgb) * DeferredMod_Specular;\n", +"// color.rgb = half3(tex2D(Texture_ScreenDepth, ScreenTexCoord).rgb);\n", +"// color.r = half(texDepth2D(Texture_ScreenDepth, ScreenTexCoord)) * 1.0;\n", +"#endif\n", +"\n", +"#ifdef USEGLOW\n", +"#ifdef USEVERTEXTEXTUREBLEND\n", +" color.rgb += half3(lerp(tex2D(Texture_SecondaryGlow, TexCoord2).rgb, offsetMappedTexture2D(Texture_Glow).rgb, terrainblend)) * Color_Glow;\n", +"#else\n", +" color.rgb += half3(offsetMappedTexture2D(Texture_Glow).rgb) * Color_Glow;\n", +"#endif\n", +"#endif\n", +"\n", +"#ifdef USEFOG\n", +" color.rgb = half3(FogVertex(color, FogColor, EyeVectorModelSpaceFogPlaneVertexDist.xyz, EyeVectorModelSpaceFogPlaneVertexDist.w, FogRangeRecip, FogPlaneViewDist, FogHeightFade, Texture_FogMask, Texture_FogHeightTexture));\n", +"#endif\n", +"\n", +" // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n", +"#ifdef USEREFLECTION\n", +" float4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n", +" //float4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5,0.5,0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n", +" float2 SafeScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW.zw + ScreenCenterRefractReflect.zw;\n", +" float2 ScreenTexCoord = SafeScreenTexCoord + float3(normalize(half3(offsetMappedTexture2D(Texture_Normal).rgb) - half3(0.5,0.5,0.5))).xy * DistortScaleRefractReflect.zw;\n", +" // FIXME temporary hack to detect the case that the reflection\n", +" // gets blackened at edges due to leaving the area that contains actual\n", +" // content.\n", +" // Remove this 'ack once we have a better way to stop this thing from\n", +" // 'appening.\n", +" float f = min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(0.01, -0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(-0.01, 0.01)).rgb) / 0.05);\n", +" f *= min(1.0, length(tex2D(Texture_Reflection, ScreenTexCoord + float2(-0.01, -0.01)).rgb) / 0.05);\n", +" ScreenTexCoord = lerp(SafeScreenTexCoord, ScreenTexCoord, f);\n", +" color.rgb = lerp(color.rgb, half3(tex2D(Texture_Reflection, ScreenTexCoord).rgb) * ReflectColor.rgb, ReflectColor.a);\n", +"#endif\n", +"\n", +" dp_FragColor = float4(color);\n", +"}\n", +"#endif // FRAGMENT_SHADER\n", +"\n", +"#endif // !MODE_DEFERREDLIGHTSOURCE\n", +"#endif // !MODE_DEFERREDGEOMETRY\n", +"#endif // !MODE_WATER\n", +"#endif // !MODE_REFRACTION\n", +"#endif // !MODE_BLOOMBLUR\n", +"#endif // !MODE_GENERIC\n", +"#endif // !MODE_POSTPROCESS\n", +"#endif // !MODE_DEPTH_OR_SHADOW\n", diff --git a/app/jni/snd_android.c b/app/jni/snd_android.c new file mode 100644 index 0000000..64f3e1c --- /dev/null +++ b/app/jni/snd_android.c @@ -0,0 +1,185 @@ +/* +Copyright (C) 2013 n0n3m4 +Copyright (C) 2004 Andreas Kirsch + +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 + +#include "snd_main.h" + + +static unsigned int audiopos = 0; +static unsigned int buffersize; +__attribute__((weak)) __dso_handle=0; + +extern void jni_initAudio(void *buffer, int size); +extern void jni_writeAudio(int offset, int length); + +void QC_GetAudio() +{ + int offset = (audiopos*4) & (buffersize - 1); + if (snd_renderbuffer!=NULL) + jni_writeAudio(offset, 2048*4); + audiopos+=2048; +} + +/* +==================== +SndSys_Init + +Create "snd_renderbuffer" with the proper sound format if the call is successful +May return a suggested format if the requested format isn't available +==================== +*/ +qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) +{ + + snd_threaded = false; + + Con_DPrint ("SndSys_Init: using the ANDROID module\n"); + + int wantspecfreq = requested->speed; + int wantspecformat = (requested->width); + int wantspecchannels = requested->channels; + + Con_Printf("Wanted audio Specification:\n" + "\tChannels : %i\n" + "\tFormat : 0x%X\n" + "\tFrequency : %i\n", + wantspecchannels, wantspecformat, wantspecfreq); + + int obtainspecchannels=2; + int obtainspecfreq=44100; + int obtainspecformat=2; + + Con_Printf("Obtained audio specification:\n" + "\tChannels : %i\n" + "\tFormat : 0x%X\n" + "\tFrequency : %i\n", + obtainspecchannels, obtainspecformat, obtainspecfreq); + + // If we haven't obtained what we wanted + if (wantspecfreq != obtainspecfreq || + wantspecformat != obtainspecformat || + wantspecchannels != obtainspecchannels) + { + // Pass the obtained format as a suggested format + if (suggested != NULL) + { + suggested->speed = obtainspecfreq; + suggested->width = obtainspecformat; + suggested->channels = obtainspecchannels; + } + + return false; + } + + snd_threaded = false; //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + snd_renderbuffer = Snd_CreateRingBuffer(requested, 16384, 0); + if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO) + Cvar_SetValueQuick (&snd_channellayout, SND_CHANNELLAYOUT_STANDARD); + + audiopos = 0; + buffersize=16384*2*2; + jni_initAudio(snd_renderbuffer->ring, buffersize); + + return true; +} + + +/* +==================== +SndSys_Shutdown + +Stop the sound card, delete "snd_renderbuffer" and free its other resources +==================== +*/ +void SndSys_Shutdown(void) +{ + if (snd_renderbuffer != NULL) + { + Mem_Free(snd_renderbuffer->ring); + Mem_Free(snd_renderbuffer); + snd_renderbuffer = NULL; + } +} + + +/* +==================== +SndSys_Submit + +Submit the contents of "snd_renderbuffer" to the sound card +==================== +*/ +void SndSys_Submit (void) +{ + // Nothing to do here (this sound module is callback-based) +} + + +/* +==================== +SndSys_GetSoundTime + +Returns the number of sample frames consumed since the sound started +==================== +*/ +unsigned int SndSys_GetSoundTime (void) +{ + return audiopos; +} + + +/* +==================== +SndSys_LockRenderBuffer + +Get the exclusive lock on "snd_renderbuffer" +==================== +*/ +qboolean SndSys_LockRenderBuffer (void) +{ + return true; +} + + +/* +==================== +SndSys_UnlockRenderBuffer + +Release the exclusive lock on "snd_renderbuffer" +==================== +*/ +void SndSys_UnlockRenderBuffer (void) +{ +} + +/* +==================== +SndSys_SendKeyEvents + +Send keyboard events originating from the sound system (e.g. MIDI) +==================== +*/ +void SndSys_SendKeyEvents(void) +{ + // not supported +} diff --git a/app/jni/snd_main.c b/app/jni/snd_main.c new file mode 100644 index 0000000..ab3ff1a --- /dev/null +++ b/app/jni/snd_main.c @@ -0,0 +1,2342 @@ +/* +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_main.c -- main control for any streaming sound output device + +#include "quakedef.h" + +#include "snd_main.h" +#include "snd_ogg.h" +#include "snd_modplug.h" +#include "csprogs.h" +#include "cl_collision.h" +#include "cdaudio.h" + + +#define SND_MIN_SPEED 8000 +#define SND_MAX_SPEED 192000 +#define SND_MIN_WIDTH 1 +#define SND_MAX_WIDTH 2 +#define SND_MIN_CHANNELS 1 +#define SND_MAX_CHANNELS 8 +#if SND_LISTENERS != 8 +# error this data only supports up to 8 channel, update it! +#endif + +speakerlayout_t snd_speakerlayout; + +// Our speaker layouts are based on ALSA. They differ from those +// Win32 and Mac OS X APIs use when there's more than 4 channels. +// (rear left + rear right, and front center + LFE are swapped). +#define SND_SPEAKERLAYOUTS (sizeof(snd_speakerlayouts) / sizeof(snd_speakerlayouts[0])) +static const speakerlayout_t snd_speakerlayouts[] = +{ + { + "surround71", 8, + { + {0, 45, 0.2, 0.2, 0.5}, // front left + {1, 315, 0.2, 0.2, 0.5}, // front right + {2, 135, 0.2, 0.2, 0.5}, // rear left + {3, 225, 0.2, 0.2, 0.5}, // rear right + {4, 0, 0.2, 0.2, 0.5}, // front center + {5, 0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) + {6, 90, 0.2, 0.2, 0.5}, // side left + {7, 180, 0.2, 0.2, 0.5}, // side right + } + }, + { + "surround51", 6, + { + {0, 45, 0.2, 0.2, 0.5}, // front left + {1, 315, 0.2, 0.2, 0.5}, // front right + {2, 135, 0.2, 0.2, 0.5}, // rear left + {3, 225, 0.2, 0.2, 0.5}, // rear right + {4, 0, 0.2, 0.2, 0.5}, // front center + {5, 0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + } + }, + { + // these systems sometimes have a subwoofer as well, but it has no + // channel of its own + "surround40", 4, + { + {0, 45, 0.3, 0.3, 0.8}, // front left + {1, 315, 0.3, 0.3, 0.8}, // front right + {2, 135, 0.3, 0.3, 0.8}, // rear left + {3, 225, 0.3, 0.3, 0.8}, // rear right + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + } + }, + { + // these systems sometimes have a subwoofer as well, but it has no + // channel of its own + "stereo", 2, + { + {0, 90, 0.5, 0.5, 1}, // side left + {1, 270, 0.5, 0.5, 1}, // side right + {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}, + } + }, + { + "mono", 1, + { + {0, 0, 0, 1, 1}, // center + {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}, + } + } +}; + + +// ======================================================================= +// Internal sound data & structures +// ======================================================================= + +channel_t channels[MAX_CHANNELS]; +unsigned int total_channels; + +snd_ringbuffer_t *snd_renderbuffer = NULL; +static unsigned int soundtime = 0; +static unsigned int oldpaintedtime = 0; +static unsigned int extrasoundtime = 0; +static double snd_starttime = 0.0; +qboolean snd_threaded = false; +qboolean snd_usethreadedmixing = false; + +vec3_t listener_origin; +matrix4x4_t listener_basematrix; +static unsigned char *listener_pvs = NULL; +static int listener_pvsbytes = 0; +matrix4x4_t listener_matrix[SND_LISTENERS]; +mempool_t *snd_mempool; + +// Linked list of known sfx +static sfx_t *known_sfx = NULL; + +static qboolean sound_spatialized = false; + +qboolean simsound = false; + +static qboolean recording_sound = false; + +int snd_blocked = 0; +static int current_swapstereo = false; +static int current_channellayout = SND_CHANNELLAYOUT_AUTO; +static int current_channellayout_used = SND_CHANNELLAYOUT_AUTO; + +static float spatialpower, spatialmin, spatialdiff, spatialoffset, spatialfactor; +typedef enum { SPATIAL_NONE, SPATIAL_LOG, SPATIAL_POW, SPATIAL_THRESH } spatialmethod_t; +spatialmethod_t spatialmethod; + +// Cvars declared in sound.h (part of the sound API) +cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"}; +cvar_t mastervolume = {CVAR_SAVE, "mastervolume", "0.7", "master volume"}; +cvar_t volume = {CVAR_SAVE, "volume", "0.7", "volume of sound effects"}; +cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"}; +cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"}; +cvar_t snd_soundradius = {CVAR_SAVE, "snd_soundradius", "1200", "radius of weapon sounds and other standard sound effects (monster idle noises are half this radius and flickering light noises are one third of this radius)"}; +cvar_t snd_attenuation_exponent = {CVAR_SAVE, "snd_attenuation_exponent", "1", "Exponent of (1-radius) in sound attenuation formula"}; +cvar_t snd_attenuation_decibel = {CVAR_SAVE, "snd_attenuation_decibel", "0", "Decibel sound attenuation per sound radius distance"}; +cvar_t snd_spatialization_min_radius = {CVAR_SAVE, "snd_spatialization_min_radius", "10000", "use minimum spatialization above to this radius"}; +cvar_t snd_spatialization_max_radius = {CVAR_SAVE, "snd_spatialization_max_radius", "100", "use maximum spatialization below this radius"}; +cvar_t snd_spatialization_min = {CVAR_SAVE, "snd_spatialization_min", "0.70", "minimum spatializazion of sounds"}; +cvar_t snd_spatialization_max = {CVAR_SAVE, "snd_spatialization_max", "0.95", "maximum spatialization of sounds"}; +cvar_t snd_spatialization_power = {CVAR_SAVE, "snd_spatialization_power", "0", "exponent of the spatialization falloff curve (0: logarithmic)"}; +cvar_t snd_spatialization_control = {CVAR_SAVE, "snd_spatialization_control", "0", "enable spatialization control (headphone friendly mode)"}; +cvar_t snd_spatialization_prologic = {CVAR_SAVE, "snd_spatialization_prologic", "0", "use dolby prologic (I, II or IIx) encoding (snd_channels must be 2)"}; +cvar_t snd_spatialization_prologic_frontangle = {CVAR_SAVE, "snd_spatialization_prologic_frontangle", "30", "the angle between the front speakers and the center speaker"}; +cvar_t snd_spatialization_occlusion = {CVAR_SAVE, "snd_spatialization_occlusion", "1", "enable occlusion testing on spatialized sounds, which simply quiets sounds that are blocked by the world; 1 enables PVS method, 2 enables LineOfSight method, 3 enables both"}; + +// Cvars declared in snd_main.h (shared with other snd_*.c files) +cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.15", "how much sound to mix ahead of time"}; +cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory); when set to 2, streaming is performed even if this would waste memory"}; +cvar_t snd_streaming_length = { CVAR_SAVE, "snd_streaming_length", "1", "decompress sounds completely if they are less than this play time when snd_streaming is 1"}; +cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"}; +extern cvar_t v_flipped; +cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"}; +cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"}; +cvar_t snd_maxchannelvolume = {CVAR_SAVE, "snd_maxchannelvolume", "10", "maximum volume of a single sound"}; +cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping. Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."}; +//cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping (when set to 2, use it even if output is floating point). Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."}; +cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_channel0volume = {CVAR_SAVE, "snd_channel0volume", "1", "volume multiplier of the auto-allocate entity channel"}; +cvar_t snd_channel1volume = {CVAR_SAVE, "snd_channel1volume", "1", "volume multiplier of the 1st entity channel"}; +cvar_t snd_channel2volume = {CVAR_SAVE, "snd_channel2volume", "1", "volume multiplier of the 2nd entity channel"}; +cvar_t snd_channel3volume = {CVAR_SAVE, "snd_channel3volume", "1", "volume multiplier of the 3rd entity channel"}; +cvar_t snd_channel4volume = {CVAR_SAVE, "snd_channel4volume", "1", "volume multiplier of the 4th entity channel"}; +cvar_t snd_channel5volume = {CVAR_SAVE, "snd_channel5volume", "1", "volume multiplier of the 5th entity channel"}; +cvar_t snd_channel6volume = {CVAR_SAVE, "snd_channel6volume", "1", "volume multiplier of the 6th entity channel"}; +cvar_t snd_channel7volume = {CVAR_SAVE, "snd_channel7volume", "1", "volume multiplier of the 7th entity channel"}; + +// Local cvars +static cvar_t nosound = {0, "nosound", "0", "disables sound"}; +static cvar_t snd_precache = {0, "snd_precache", "1", "loads sounds before they are used"}; +static cvar_t ambient_level = {0, "ambient_level", "0.3", "volume of environment noises (water and wind)"}; +static cvar_t ambient_fade = {0, "ambient_fade", "100", "rate of volume fading when moving from one environment to another"}; +static cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0", "disables extra sound mixer calls that are meant to reduce the chance of sound breakup at very low framerates"}; +static cvar_t snd_show = {0, "snd_show", "0", "shows some statistics about sound mixing"}; + +// Default sound format is 48KHz, 16-bit, stereo +// (48KHz because a lot of onboard sound cards sucks at any other speed) +static cvar_t snd_speed = {CVAR_SAVE, "snd_speed", "48000", "sound output frequency, in hertz"}; +static cvar_t snd_width = {CVAR_SAVE, "snd_width", "2", "sound output precision, in bytes (1 and 2 supported)"}; +static cvar_t snd_channels = {CVAR_SAVE, "snd_channels", "2", "number of channels for the sound output (2 for stereo; up to 8 supported for 3D sound)"}; + +static cvar_t snd_startloopingsounds = {0, "snd_startloopingsounds", "1", "whether to start sounds that would loop (you want this to be 1); existing sounds are not affected"}; +static cvar_t snd_startnonloopingsounds = {0, "snd_startnonloopingsounds", "1", "whether to start sounds that would not loop (you want this to be 1); existing sounds are not affected"}; + +// randomization +static cvar_t snd_identicalsoundrandomization_time = {0, "snd_identicalsoundrandomization_time", "0.1", "how much seconds to randomly skip (positive) or delay (negative) sounds when multiple identical sounds are started on the same frame"}; +static cvar_t snd_identicalsoundrandomization_tics = {0, "snd_identicalsoundrandomization_tics", "0", "if nonzero, how many tics to limit sound randomization as defined by snd_identicalsoundrandomization_time"}; + +// Ambient sounds +static sfx_t* ambient_sfxs [2] = { NULL, NULL }; +static const char* ambient_names [2] = { "sound/ambience/water1.wav", "sound/ambience/wind2.wav" }; + + +// ==================================================================== +// Functions +// ==================================================================== + +void S_FreeSfx (sfx_t *sfx, qboolean force); + +static void S_Play_Common (float fvol, float attenuation) +{ + int i, ch_ind; + char name [MAX_QPATH]; + sfx_t *sfx; + + i = 1; + while (i < Cmd_Argc ()) + { + // Get the name, and appends ".wav" as an extension if there's none + strlcpy (name, Cmd_Argv (i), sizeof (name)); + if (!strrchr (name, '.')) + strlcat (name, ".wav", sizeof (name)); + i++; + + // If we need to get the volume from the command line + if (fvol == -1.0f) + { + fvol = atof (Cmd_Argv (i)); + i++; + } + + sfx = S_PrecacheSound (name, true, true); + if (sfx) + { + ch_ind = S_StartSound (-1, 0, sfx, listener_origin, fvol, attenuation); + + // Free the sfx if the file didn't exist + if (!sfx->fetcher) + S_FreeSfx (sfx, false); + else + channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND; + } + } +} + +static void S_Play_f(void) +{ + S_Play_Common (1.0f, 1.0f); +} + +static void S_Play2_f(void) +{ + S_Play_Common (1.0f, 0.0f); +} + +static void S_PlayVol_f(void) +{ + S_Play_Common (-1.0f, 0.0f); +} + +static void S_SoundList_f (void) +{ + unsigned int i; + sfx_t *sfx; + unsigned int total; + + total = 0; + for (sfx = known_sfx, i = 0; sfx != NULL; sfx = sfx->next, i++) + { + if (sfx->fetcher != NULL) + { + unsigned int size; + + size = sfx->memsize; + Con_Printf ("%c%c%c(%5iHz %2db %6s) %8i : %s\n", + (sfx->loopstart < sfx->total_length) ? 'L' : ' ', + (sfx->flags & SFXFLAG_STREAMED) ? 'S' : ' ', + (sfx->flags & SFXFLAG_MENUSOUND) ? 'P' : ' ', + sfx->format.speed, + sfx->format.width * 8, + (sfx->format.channels == 1) ? "mono" : "stereo", + size, + sfx->name); + total += size; + } + else + Con_Printf (" ( unknown ) unloaded : %s\n", sfx->name); + } + Con_Printf("Total resident: %i\n", total); +} + + +static void S_SoundInfo_f(void) +{ + if (snd_renderbuffer == NULL) + { + Con_Print("sound system not started\n"); + return; + } + + Con_Printf("%5d speakers\n", snd_renderbuffer->format.channels); + Con_Printf("%5d frames\n", snd_renderbuffer->maxframes); + Con_Printf("%5d samplebits\n", snd_renderbuffer->format.width * 8); + Con_Printf("%5d speed\n", snd_renderbuffer->format.speed); + Con_Printf("%5u total_channels\n", total_channels); +} + + +int S_GetSoundRate(void) +{ + return snd_renderbuffer ? snd_renderbuffer->format.speed : 0; +} + +int S_GetSoundChannels(void) +{ + return snd_renderbuffer ? snd_renderbuffer->format.channels : 0; +} + + +static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_speed, qboolean fixed_width, qboolean fixed_channels) +{ + static const snd_format_t thresholds [] = + { + // speed width channels + { SND_MIN_SPEED, SND_MIN_WIDTH, SND_MIN_CHANNELS }, + { 11025, 1, 2 }, + { 22050, 2, 2 }, + { 44100, 2, 2 }, + { 48000, 2, 6 }, + { 96000, 2, 6 }, + { SND_MAX_SPEED, SND_MAX_WIDTH, SND_MAX_CHANNELS }, + }; + const unsigned int nb_thresholds = sizeof(thresholds) / sizeof(thresholds[0]); + unsigned int speed_level, width_level, channels_level; + + // If we have reached the minimum values, there's nothing more we can do + if ((format->speed == thresholds[0].speed || fixed_speed) && + (format->width == thresholds[0].width || fixed_width) && + (format->channels == thresholds[0].channels || fixed_channels)) + return false; + + // Check the min and max values + #define CHECK_BOUNDARIES(param) \ + if (format->param < thresholds[0].param) \ + { \ + format->param = thresholds[0].param; \ + return true; \ + } \ + if (format->param > thresholds[nb_thresholds - 1].param) \ + { \ + format->param = thresholds[nb_thresholds - 1].param; \ + return true; \ + } + CHECK_BOUNDARIES(speed); + CHECK_BOUNDARIES(width); + CHECK_BOUNDARIES(channels); + #undef CHECK_BOUNDARIES + + // Find the level of each parameter + #define FIND_LEVEL(param) \ + param##_level = 0; \ + while (param##_level < nb_thresholds - 1) \ + { \ + if (format->param <= thresholds[param##_level].param) \ + break; \ + \ + param##_level++; \ + } + FIND_LEVEL(speed); + FIND_LEVEL(width); + FIND_LEVEL(channels); + #undef FIND_LEVEL + + // Decrease the parameter with the highest level to the previous level + if (channels_level >= speed_level && channels_level >= width_level && !fixed_channels) + { + format->channels = thresholds[channels_level - 1].channels; + return true; + } + if (speed_level >= width_level && !fixed_speed) + { + format->speed = thresholds[speed_level - 1].speed; + return true; + } + + format->width = thresholds[width_level - 1].width; + return true; +} + + +#define SWAP_LISTENERS(l1, l2, tmpl) { tmpl = (l1); (l1) = (l2); (l2) = tmpl; } + +static void S_SetChannelLayout (void) +{ + unsigned int i; + listener_t swaplistener; + listener_t *listeners; + int layout; + + for (i = 0; i < SND_SPEAKERLAYOUTS; i++) + if (snd_speakerlayouts[i].channels == snd_renderbuffer->format.channels) + break; + if (i >= SND_SPEAKERLAYOUTS) + { + Con_Printf("S_SetChannelLayout: can't find the speaker layout for %hu channels. Defaulting to mono output\n", + snd_renderbuffer->format.channels); + i = SND_SPEAKERLAYOUTS - 1; + } + + snd_speakerlayout = snd_speakerlayouts[i]; + listeners = snd_speakerlayout.listeners; + + // Swap the left and right channels if snd_swapstereo is set + if (boolxor(snd_swapstereo.integer, v_flipped.integer)) + { + switch (snd_speakerlayout.channels) + { + case 8: + SWAP_LISTENERS(listeners[6], listeners[7], swaplistener); + // no break + case 4: + case 6: + SWAP_LISTENERS(listeners[2], listeners[3], swaplistener); + // no break + case 2: + SWAP_LISTENERS(listeners[0], listeners[1], swaplistener); + break; + + default: + case 1: + // Nothing to do + break; + } + } + + // Sanity check + if (snd_channellayout.integer < SND_CHANNELLAYOUT_AUTO || + snd_channellayout.integer > SND_CHANNELLAYOUT_ALSA) + Cvar_SetValueQuick (&snd_channellayout, SND_CHANNELLAYOUT_STANDARD); + + if (snd_channellayout.integer == SND_CHANNELLAYOUT_AUTO) + { + // If we're in the sound engine initialization + if (current_channellayout_used == SND_CHANNELLAYOUT_AUTO) + { + layout = SND_CHANNELLAYOUT_STANDARD; + Cvar_SetValueQuick (&snd_channellayout, layout); + } + else + layout = current_channellayout_used; + } + else + layout = snd_channellayout.integer; + + // Convert our layout (= ALSA) to the standard layout if necessary + if (snd_speakerlayout.channels == 6 || snd_speakerlayout.channels == 8) + { + if (layout == SND_CHANNELLAYOUT_STANDARD) + { + SWAP_LISTENERS(listeners[2], listeners[4], swaplistener); + SWAP_LISTENERS(listeners[3], listeners[5], swaplistener); + } + + Con_Printf("S_SetChannelLayout: using %s speaker layout for 3D sound\n", + (layout == SND_CHANNELLAYOUT_ALSA) ? "ALSA" : "standard"); + } + + current_swapstereo = boolxor(snd_swapstereo.integer, v_flipped.integer); + current_channellayout = snd_channellayout.integer; + current_channellayout_used = layout; +} + + +void S_Startup (void) +{ + qboolean fixed_speed, fixed_width, fixed_channels; + snd_format_t chosen_fmt; + static snd_format_t prev_render_format = {0, 0, 0}; + char* env; +#if _MSC_VER >= 1400 + size_t envlen; +#endif + int i; + + if (!snd_initialized.integer) + return; + + fixed_speed = false; + fixed_width = false; + fixed_channels = false; + + // Get the starting sound format from the cvars + chosen_fmt.speed = snd_speed.integer; + chosen_fmt.width = snd_width.integer; + chosen_fmt.channels = snd_channels.integer; + + // Check the environment variables to see if the player wants a particular sound format +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_CHANNELS"); +#else + env = getenv("QUAKE_SOUND_CHANNELS"); +#endif + if (env != NULL) + { + chosen_fmt.channels = atoi (env); +#if _MSC_VER >= 1400 + free(env); +#endif + fixed_channels = true; + } +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_SPEED"); +#else + env = getenv("QUAKE_SOUND_SPEED"); +#endif + if (env != NULL) + { + chosen_fmt.speed = atoi (env); +#if _MSC_VER >= 1400 + free(env); +#endif + fixed_speed = true; + } +#if _MSC_VER >= 1400 + _dupenv_s(&env, &envlen, "QUAKE_SOUND_SAMPLEBITS"); +#else + env = getenv("QUAKE_SOUND_SAMPLEBITS"); +#endif + if (env != NULL) + { + chosen_fmt.width = atoi (env) / 8; +#if _MSC_VER >= 1400 + free(env); +#endif + fixed_width = true; + } + + // Parse the command line to see if the player wants a particular sound format +// COMMANDLINEOPTION: Sound: -sndquad sets sound output to 4 channel surround + if (COM_CheckParm ("-sndquad") != 0) + { + chosen_fmt.channels = 4; + fixed_channels = true; + } +// COMMANDLINEOPTION: Sound: -sndstereo sets sound output to stereo + else if (COM_CheckParm ("-sndstereo") != 0) + { + chosen_fmt.channels = 2; + fixed_channels = true; + } +// COMMANDLINEOPTION: Sound: -sndmono sets sound output to mono + else if (COM_CheckParm ("-sndmono") != 0) + { + chosen_fmt.channels = 1; + fixed_channels = true; + } +// COMMANDLINEOPTION: Sound: -sndspeed chooses sound output rate (supported values are 48000, 44100, 32000, 24000, 22050, 16000, 11025 (quake), 8000) + i = COM_CheckParm ("-sndspeed"); + if (0 < i && i < com_argc - 1) + { + chosen_fmt.speed = atoi (com_argv[i + 1]); + fixed_speed = true; + } +// COMMANDLINEOPTION: Sound: -sndbits chooses 8 bit or 16 bit sound output + i = COM_CheckParm ("-sndbits"); + if (0 < i && i < com_argc - 1) + { + chosen_fmt.width = atoi (com_argv[i + 1]) / 8; + fixed_width = true; + } + +#if 0 + // LordHavoc: now you can with the resampler... + // You can't change sound speed after start time (not yet supported) + if (prev_render_format.speed != 0) + { + fixed_speed = true; + if (chosen_fmt.speed != prev_render_format.speed) + { + Con_Printf("S_Startup: sound speed has changed! This is NOT supported yet. Falling back to previous speed (%u Hz)\n", + prev_render_format.speed); + chosen_fmt.speed = prev_render_format.speed; + } + } +#endif + + // Sanity checks + if (chosen_fmt.speed < SND_MIN_SPEED) + { + chosen_fmt.speed = SND_MIN_SPEED; + fixed_speed = false; + } + else if (chosen_fmt.speed > SND_MAX_SPEED) + { + chosen_fmt.speed = SND_MAX_SPEED; + fixed_speed = false; + } + + if (chosen_fmt.width < SND_MIN_WIDTH) + { + chosen_fmt.width = SND_MIN_WIDTH; + fixed_width = false; + } + else if (chosen_fmt.width > SND_MAX_WIDTH) + { + chosen_fmt.width = SND_MAX_WIDTH; + fixed_width = false; + } + + if (chosen_fmt.channels < SND_MIN_CHANNELS) + { + chosen_fmt.channels = SND_MIN_CHANNELS; + fixed_channels = false; + } + else if (chosen_fmt.channels > SND_MAX_CHANNELS) + { + chosen_fmt.channels = SND_MAX_CHANNELS; + fixed_channels = false; + } + + // create the sound buffer used for sumitting the samples to the plaform-dependent module + if (!simsound) + { + snd_format_t suggest_fmt; + qboolean accepted; + + accepted = false; + do + { + Con_Printf("S_Startup: initializing sound output format: %dHz, %d bit, %d channels...\n", + chosen_fmt.speed, chosen_fmt.width * 8, + chosen_fmt.channels); + + memset(&suggest_fmt, 0, sizeof(suggest_fmt)); + accepted = SndSys_Init(&chosen_fmt, &suggest_fmt); + + if (!accepted) + { + Con_Printf("S_Startup: sound output initialization FAILED\n"); + + // If the module is suggesting another one + if (suggest_fmt.speed != 0) + { + memcpy(&chosen_fmt, &suggest_fmt, sizeof(chosen_fmt)); + Con_Printf (" Driver has suggested %dHz, %d bit, %d channels. Retrying...\n", + suggest_fmt.speed, suggest_fmt.width * 8, + suggest_fmt.channels); + } + // Else, try to find a less resource-demanding format + else if (!S_ChooseCheaperFormat (&chosen_fmt, fixed_speed, fixed_width, fixed_channels)) + break; + } + } while (!accepted); + + // If we haven't found a suitable format + if (!accepted) + { + Con_Print("S_Startup: SndSys_Init failed.\n"); + sound_spatialized = false; + return; + } + } + else + { + snd_renderbuffer = Snd_CreateRingBuffer(&chosen_fmt, 0, NULL); + Con_Print ("S_Startup: simulating sound output\n"); + } + + memcpy(&prev_render_format, &snd_renderbuffer->format, sizeof(prev_render_format)); + Con_Printf("Sound format: %dHz, %d channels, %d bits per sample\n", + chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8); + + // Update the cvars + if (snd_speed.integer != (int)chosen_fmt.speed) + Cvar_SetValueQuick(&snd_speed, chosen_fmt.speed); + if (snd_width.integer != chosen_fmt.width) + Cvar_SetValueQuick(&snd_width, chosen_fmt.width); + if (snd_channels.integer != chosen_fmt.channels) + Cvar_SetValueQuick(&snd_channels, chosen_fmt.channels); + + current_channellayout_used = SND_CHANNELLAYOUT_AUTO; + S_SetChannelLayout(); + + snd_starttime = realtime; + + // If the sound module has already run, add an extra time to make sure + // the sound time doesn't decrease, to not confuse playing SFXs + if (oldpaintedtime != 0) + { + // The extra time must be a multiple of the render buffer size + // to avoid modifying the current position in the buffer, + // some modules write directly to a shared (DMA) buffer + extrasoundtime = oldpaintedtime + snd_renderbuffer->maxframes - 1; + extrasoundtime -= extrasoundtime % snd_renderbuffer->maxframes; + Con_Printf("S_Startup: extra sound time = %u\n", extrasoundtime); + + soundtime = extrasoundtime; + } + else + extrasoundtime = 0; + snd_renderbuffer->startframe = soundtime; + snd_renderbuffer->endframe = soundtime; + recording_sound = false; +} + +void S_Shutdown(void) +{ + if (snd_renderbuffer == NULL) + return; + + oldpaintedtime = snd_renderbuffer->endframe; + + if (simsound) + { + Mem_Free(snd_renderbuffer->ring); + Mem_Free(snd_renderbuffer); + snd_renderbuffer = NULL; + } + else + SndSys_Shutdown(); + + sound_spatialized = false; +} + +static void S_Restart_f(void) +{ + // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches) + // So, refuse to do this if we are connected. + if(cls.state == ca_connected) + { + Con_Printf("snd_restart would wreak havoc if you do that while connected!\n"); + return; + } + + S_Shutdown(); + S_Startup(); +} + +/* +================ +S_Init +================ +*/ +void S_Init(void) +{ + Cvar_RegisterVariable(&volume); + Cvar_RegisterVariable(&bgmvolume); + Cvar_RegisterVariable(&mastervolume); + Cvar_RegisterVariable(&snd_staticvolume); + Cvar_RegisterVariable(&snd_entchannel0volume); + Cvar_RegisterVariable(&snd_entchannel1volume); + Cvar_RegisterVariable(&snd_entchannel2volume); + Cvar_RegisterVariable(&snd_entchannel3volume); + Cvar_RegisterVariable(&snd_entchannel4volume); + Cvar_RegisterVariable(&snd_entchannel5volume); + Cvar_RegisterVariable(&snd_entchannel6volume); + Cvar_RegisterVariable(&snd_entchannel7volume); + Cvar_RegisterVariable(&snd_worldchannel0volume); + Cvar_RegisterVariable(&snd_worldchannel1volume); + Cvar_RegisterVariable(&snd_worldchannel2volume); + Cvar_RegisterVariable(&snd_worldchannel3volume); + Cvar_RegisterVariable(&snd_worldchannel4volume); + Cvar_RegisterVariable(&snd_worldchannel5volume); + Cvar_RegisterVariable(&snd_worldchannel6volume); + Cvar_RegisterVariable(&snd_worldchannel7volume); + Cvar_RegisterVariable(&snd_playerchannel0volume); + Cvar_RegisterVariable(&snd_playerchannel1volume); + Cvar_RegisterVariable(&snd_playerchannel2volume); + Cvar_RegisterVariable(&snd_playerchannel3volume); + Cvar_RegisterVariable(&snd_playerchannel4volume); + Cvar_RegisterVariable(&snd_playerchannel5volume); + Cvar_RegisterVariable(&snd_playerchannel6volume); + Cvar_RegisterVariable(&snd_playerchannel7volume); + Cvar_RegisterVariable(&snd_csqcchannel0volume); + Cvar_RegisterVariable(&snd_csqcchannel1volume); + Cvar_RegisterVariable(&snd_csqcchannel2volume); + Cvar_RegisterVariable(&snd_csqcchannel3volume); + Cvar_RegisterVariable(&snd_csqcchannel4volume); + Cvar_RegisterVariable(&snd_csqcchannel5volume); + Cvar_RegisterVariable(&snd_csqcchannel6volume); + Cvar_RegisterVariable(&snd_csqcchannel7volume); + Cvar_RegisterVariable(&snd_channel0volume); + Cvar_RegisterVariable(&snd_channel1volume); + Cvar_RegisterVariable(&snd_channel2volume); + Cvar_RegisterVariable(&snd_channel3volume); + Cvar_RegisterVariable(&snd_channel4volume); + Cvar_RegisterVariable(&snd_channel5volume); + Cvar_RegisterVariable(&snd_channel6volume); + Cvar_RegisterVariable(&snd_channel7volume); + + Cvar_RegisterVariable(&snd_attenuation_exponent); + Cvar_RegisterVariable(&snd_attenuation_decibel); + + Cvar_RegisterVariable(&snd_spatialization_min_radius); + Cvar_RegisterVariable(&snd_spatialization_max_radius); + Cvar_RegisterVariable(&snd_spatialization_min); + Cvar_RegisterVariable(&snd_spatialization_max); + Cvar_RegisterVariable(&snd_spatialization_power); + Cvar_RegisterVariable(&snd_spatialization_control); + Cvar_RegisterVariable(&snd_spatialization_occlusion); + Cvar_RegisterVariable(&snd_spatialization_prologic); + Cvar_RegisterVariable(&snd_spatialization_prologic_frontangle); + + Cvar_RegisterVariable(&snd_speed); + Cvar_RegisterVariable(&snd_width); + Cvar_RegisterVariable(&snd_channels); + Cvar_RegisterVariable(&snd_mutewhenidle); + Cvar_RegisterVariable(&snd_maxchannelvolume); + Cvar_RegisterVariable(&snd_softclip); + + Cvar_RegisterVariable(&snd_startloopingsounds); + Cvar_RegisterVariable(&snd_startnonloopingsounds); + + Cvar_RegisterVariable(&snd_identicalsoundrandomization_time); + Cvar_RegisterVariable(&snd_identicalsoundrandomization_tics); + +// COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio) + if (COM_CheckParm("-nosound")) + { + // dummy out Play and Play2 because mods stuffcmd that + Cmd_AddCommand("play", Host_NoOperation_f, "does nothing because -nosound was specified"); + Cmd_AddCommand("play2", Host_NoOperation_f, "does nothing because -nosound was specified"); + return; + } + + snd_mempool = Mem_AllocPool("sound", 0, NULL); + +// COMMANDLINEOPTION: Sound: -simsound runs sound mixing but with no output + if (COM_CheckParm("-simsound")) + simsound = true; + + Cmd_AddCommand("play", S_Play_f, "play a sound at your current location (not heard by anyone else)"); + Cmd_AddCommand("play2", S_Play2_f, "play a sound globally throughout the level (not heard by anyone else)"); + Cmd_AddCommand("playvol", S_PlayVol_f, "play a sound at the specified volume level at your current location (not heard by anyone else)"); + Cmd_AddCommand("stopsound", S_StopAllSounds, "silence"); + Cmd_AddCommand("soundlist", S_SoundList_f, "list loaded sounds"); + Cmd_AddCommand("soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)"); + Cmd_AddCommand("snd_restart", S_Restart_f, "restart sound system"); + Cmd_AddCommand("snd_unloadallsounds", S_UnloadAllSounds_f, "unload all sound files"); + + Cvar_RegisterVariable(&nosound); + Cvar_RegisterVariable(&snd_precache); + Cvar_RegisterVariable(&snd_initialized); + Cvar_RegisterVariable(&snd_streaming); + Cvar_RegisterVariable(&snd_streaming_length); + Cvar_RegisterVariable(&ambient_level); + Cvar_RegisterVariable(&ambient_fade); + Cvar_RegisterVariable(&snd_noextraupdate); + Cvar_RegisterVariable(&snd_show); + Cvar_RegisterVariable(&_snd_mixahead); + Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring + Cvar_RegisterVariable(&snd_channellayout); + Cvar_RegisterVariable(&snd_soundradius); + + Cvar_SetValueQuick(&snd_initialized, true); + + known_sfx = NULL; + + total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics + memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); + + OGG_OpenLibrary (); + ModPlug_OpenLibrary (); +} + + +/* +================ +S_Terminate + +Shutdown and free all resources +================ +*/ +void S_Terminate (void) +{ + S_Shutdown (); + ModPlug_CloseLibrary (); + OGG_CloseLibrary (); + + // Free all SFXs + while (known_sfx != NULL) + S_FreeSfx (known_sfx, true); + + Cvar_SetValueQuick (&snd_initialized, false); + Mem_FreePool (&snd_mempool); +} + + +/* +================== +S_UnloadAllSounds_f +================== +*/ +void S_UnloadAllSounds_f (void) +{ + int i; + + // NOTE: we can't free all sounds if we are running a map (this frees sfx_t that are still referenced by precaches) + // So, refuse to do this if we are connected. + if(cls.state == ca_connected) + { + Con_Printf("snd_unloadallsounds would wreak havoc if you do that while connected!\n"); + return; + } + + // stop any active sounds + S_StopAllSounds(); + + // because the ambient sounds will be freed, clear the pointers + for (i = 0;i < (int)sizeof (ambient_sfxs) / (int)sizeof (ambient_sfxs[0]);i++) + ambient_sfxs[i] = NULL; + + // now free all sounds + while (known_sfx != NULL) + S_FreeSfx (known_sfx, true); +} + + +/* +================== +S_FindName +================== +*/ +sfx_t changevolume_sfx = {""}; +sfx_t *S_FindName (const char *name) +{ + sfx_t *sfx; + + if (!snd_initialized.integer) + return NULL; + + if(!strcmp(name, changevolume_sfx.name)) + return &changevolume_sfx; + + if (strlen (name) >= sizeof (sfx->name)) + { + Con_Printf ("S_FindName: sound name too long (%s)\n", name); + return NULL; + } + + // Look for this sound in the list of known sfx + // TODO: hash table search? + for (sfx = known_sfx; sfx != NULL; sfx = sfx->next) + if(!strcmp (sfx->name, name)) + return sfx; + + // check for # in the beginning, try lookup by soundindex + if (name[0] == '#' && name[1]) + { + int soundindex = atoi(name + 1); + if (soundindex > 0 && soundindex < MAX_SOUNDS) + if (cl.sound_precache[soundindex]->name[0]) + return cl.sound_precache[soundindex]; + } + + // Add a sfx_t struct for this sound + sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx)); + memset (sfx, 0, sizeof(*sfx)); + strlcpy (sfx->name, name, sizeof (sfx->name)); + sfx->memsize = sizeof(*sfx); + sfx->next = known_sfx; + known_sfx = sfx; + + return sfx; +} + + +/* +================== +S_FreeSfx +================== +*/ +void S_FreeSfx (sfx_t *sfx, qboolean force) +{ + unsigned int i; + + // Do not free a precached sound during purge + if (!force && (sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND))) + return; + + if (developer_loading.integer) + Con_Printf ("unloading sound %s\n", sfx->name); + + // Remove it from the list of known sfx + if (sfx == known_sfx) + known_sfx = known_sfx->next; + else + { + sfx_t *prev_sfx; + + for (prev_sfx = known_sfx; prev_sfx != NULL; prev_sfx = prev_sfx->next) + if (prev_sfx->next == sfx) + { + prev_sfx->next = sfx->next; + break; + } + if (prev_sfx == NULL) + { + Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name); + return; + } + } + + // Stop all channels using this sfx + for (i = 0; i < total_channels; i++) + { + if (channels[i].sfx == sfx) + { + Con_Printf("S_FreeSfx: stopping channel %i for sfx \"%s\"\n", i, sfx->name); + S_StopChannel (i, true, false); + } + } + + // Free it + if (sfx->fetcher != NULL && sfx->fetcher->freesfx != NULL) + sfx->fetcher->freesfx(sfx); + Mem_Free (sfx); +} + + +/* +================== +S_ClearUsed +================== +*/ +void S_ClearUsed (void) +{ + sfx_t *sfx; +// sfx_t *sfxnext; + unsigned int i; + + // Start the ambient sounds and make them loop + for (i = 0; i < sizeof (ambient_sfxs) / sizeof (ambient_sfxs[0]); i++) + { + // Precache it if it's not done (and pass false for levelsound because these are permanent) + if (ambient_sfxs[i] == NULL) + ambient_sfxs[i] = S_PrecacheSound (ambient_names[i], false, false); + if (ambient_sfxs[i] != NULL) + { + channels[i].sfx = ambient_sfxs[i]; + channels[i].sfx->flags |= SFXFLAG_MENUSOUND; + channels[i].flags |= CHANNELFLAG_FORCELOOP; + channels[i].basevolume = 0.0f; + channels[i].basespeed = channels[i].mixspeed = 1.0f; + } + } + + // Clear SFXFLAG_LEVELSOUND flag so that sounds not precached this level will be purged + for (sfx = known_sfx; sfx != NULL; sfx = sfx->next) + sfx->flags &= ~SFXFLAG_LEVELSOUND; +} + +/* +================== +S_PurgeUnused +================== +*/ +void S_PurgeUnused(void) +{ + sfx_t *sfx; + sfx_t *sfxnext; + + // Free all not-precached per-level sfx + for (sfx = known_sfx;sfx;sfx = sfxnext) + { + sfxnext = sfx->next; + if (!(sfx->flags & (SFXFLAG_LEVELSOUND | SFXFLAG_MENUSOUND))) + S_FreeSfx (sfx, false); + } +} + + +/* +================== +S_PrecacheSound +================== +*/ +sfx_t *S_PrecacheSound (const char *name, qboolean complain, qboolean levelsound) +{ + sfx_t *sfx; + + if (!snd_initialized.integer) + return NULL; + + if (name == NULL || name[0] == 0) + return NULL; + + sfx = S_FindName (name); + + if (sfx == NULL) + return NULL; + + // clear the FILEMISSING flag so that S_LoadSound will try again on a + // previously missing file + sfx->flags &= ~ SFXFLAG_FILEMISSING; + + // set a flag to indicate this has been precached for this level or permanently + if (levelsound) + sfx->flags |= SFXFLAG_LEVELSOUND; + else + sfx->flags |= SFXFLAG_MENUSOUND; + + if (!nosound.integer && snd_precache.integer) + S_LoadSound(sfx, complain); + + return sfx; +} + +/* +================== +S_SoundLength +================== +*/ + +float S_SoundLength(const char *name) +{ + sfx_t *sfx; + + if (!snd_initialized.integer) + return -1; + if (name == NULL || name[0] == 0) + return -1; + + sfx = S_FindName(name); + if (sfx == NULL) + return -1; + return sfx->total_length / (float) S_GetSoundRate(); +} + +/* +================== +S_IsSoundPrecached +================== +*/ +qboolean S_IsSoundPrecached (const sfx_t *sfx) +{ + return (sfx != NULL && sfx->fetcher != NULL) || (sfx == &changevolume_sfx); +} + +/* +================== +S_BlockSound +================== +*/ +void S_BlockSound (void) +{ + snd_blocked++; +} + + +/* +================== +S_UnblockSound +================== +*/ +void S_UnblockSound (void) +{ + snd_blocked--; +} + + +/* +================= +SND_PickChannel + +Picks a channel based on priorities, empty slots, number of channels +================= +*/ +static channel_t *SND_PickChannel(int entnum, int entchannel) +{ + int ch_idx; + int first_to_die; + int first_life_left, life_left; + channel_t* ch; + sfx_t *sfx; // use this instead of ch->sfx->, because that is volatile. + +// Check for replacement sound, or find the best one to replace + first_to_die = -1; + first_life_left = 0x7fffffff; + + // entity channels try to replace the existing sound on the channel + // channels <= 0 are autochannels + if (IS_CHAN_SINGLE(entchannel)) + { + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + ch = &channels[ch_idx]; + if (ch->entnum == entnum && ch->entchannel == entchannel) + { + // always override sound from same entity + S_StopChannel (ch_idx, true, false); + return &channels[ch_idx]; + } + } + } + + // there was no channel to override, so look for the first empty one + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + ch = &channels[ch_idx]; + sfx = ch->sfx; // fetch the volatile variable + if (!sfx) + { + // no sound on this channel + first_to_die = ch_idx; + goto emptychan_found; + } + + // don't let monster sounds override player sounds + if ((ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity()) && !(entnum == cl.viewentity || entnum == CL_VM_GetViewEntity())) + continue; + + // don't override looped sounds + if ((ch->flags & CHANNELFLAG_FORCELOOP) || sfx->loopstart < sfx->total_length) + continue; + life_left = (int)((double)sfx->total_length - ch->position); + + if (life_left < first_life_left) + { + first_life_left = life_left; + first_to_die = ch_idx; + } + } + + if (first_to_die == -1) + return NULL; + + S_StopChannel (first_to_die, true, false); + +emptychan_found: + return &channels[first_to_die]; +} + +/* +================= +SND_Spatialize + +Spatializes a channel +================= +*/ +extern cvar_t cl_gameplayfix_soundsmovewithentities; +static void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) +{ + int i; + double f; + float angle_side, angle_front, angle_factor, mixspeed; + vec_t dist, mastervol, intensity; + vec3_t source_vec; + char vabuf[1024]; + + // update sound origin if we know about the entity + if (ch->entnum > 0 && cls.state == ca_connected && cl_gameplayfix_soundsmovewithentities.integer) + { + if (ch->entnum >= MAX_EDICTS) + { + //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]); + + if (ch->entnum > MAX_EDICTS) + if (!CL_VM_GetEntitySoundOrigin(ch->entnum, ch->origin)) + ch->entnum = MAX_EDICTS; // entity was removed, disown sound + } + else if (cl.entities[ch->entnum].state_current.active) + { + dp_model_t *model; + //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]); + model = CL_GetModelByIndex(cl.entities[ch->entnum].state_current.modelindex); + if (model && model->soundfromcenter) + VectorMAM(0.5f, cl.entities[ch->entnum].render.mins, 0.5f, cl.entities[ch->entnum].render.maxs, ch->origin); + else + Matrix4x4_OriginFromMatrix(&cl.entities[ch->entnum].render.matrix, ch->origin); + } + else if (cl.csqc_server2csqcentitynumber[ch->entnum]) + { + //Con_Printf("-- entnum %i (client %i) origin %f %f %f neworigin %f %f %f\n", ch->entnum, cl.csqc_server2csqcentitynumber[ch->entnum], ch->origin[0], ch->origin[1], ch->origin[2], cl.entities[ch->entnum].state_current.origin[0], cl.entities[ch->entnum].state_current.origin[1], cl.entities[ch->entnum].state_current.origin[2]); + + if (!CL_VM_GetEntitySoundOrigin(cl.csqc_server2csqcentitynumber[ch->entnum] + MAX_EDICTS, ch->origin)) + ch->entnum = MAX_EDICTS; // entity was removed, disown sound + } + } + + mastervol = ch->basevolume; + mixspeed = ch->basespeed; + + // TODO: implement doppler based on origin change relative to viewer and time of recent origin changes + + // Adjust volume of static sounds + if (isstatic) + mastervol *= snd_staticvolume.value; + else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses + { + // old legacy separated cvars + if(ch->entnum >= MAX_EDICTS) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_csqcchannel0volume.value; break; + case 1: mastervol *= snd_csqcchannel1volume.value; break; + case 2: mastervol *= snd_csqcchannel2volume.value; break; + case 3: mastervol *= snd_csqcchannel3volume.value; break; + case 4: mastervol *= snd_csqcchannel4volume.value; break; + case 5: mastervol *= snd_csqcchannel5volume.value; break; + case 6: mastervol *= snd_csqcchannel6volume.value; break; + case 7: mastervol *= snd_csqcchannel7volume.value; break; + default: break; + } + } + else if(ch->entnum == 0) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_worldchannel0volume.value; break; + case 1: mastervol *= snd_worldchannel1volume.value; break; + case 2: mastervol *= snd_worldchannel2volume.value; break; + case 3: mastervol *= snd_worldchannel3volume.value; break; + case 4: mastervol *= snd_worldchannel4volume.value; break; + case 5: mastervol *= snd_worldchannel5volume.value; break; + case 6: mastervol *= snd_worldchannel6volume.value; break; + case 7: mastervol *= snd_worldchannel7volume.value; break; + default: break; + } + } + else if(ch->entnum > 0 && ch->entnum <= cl.maxclients) + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_playerchannel0volume.value; break; + case 1: mastervol *= snd_playerchannel1volume.value; break; + case 2: mastervol *= snd_playerchannel2volume.value; break; + case 3: mastervol *= snd_playerchannel3volume.value; break; + case 4: mastervol *= snd_playerchannel4volume.value; break; + case 5: mastervol *= snd_playerchannel5volume.value; break; + case 6: mastervol *= snd_playerchannel6volume.value; break; + case 7: mastervol *= snd_playerchannel7volume.value; break; + default: break; + } + } + else + { + switch(ch->entchannel) + { + case 0: mastervol *= snd_entchannel0volume.value; break; + case 1: mastervol *= snd_entchannel1volume.value; break; + case 2: mastervol *= snd_entchannel2volume.value; break; + case 3: mastervol *= snd_entchannel3volume.value; break; + case 4: mastervol *= snd_entchannel4volume.value; break; + case 5: mastervol *= snd_entchannel5volume.value; break; + case 6: mastervol *= snd_entchannel6volume.value; break; + case 7: mastervol *= snd_entchannel7volume.value; break; + default: break; + } + } + + switch(ch->entchannel) + { + case 0: mastervol *= snd_channel0volume.value; break; + case 1: mastervol *= snd_channel1volume.value; break; + case 2: mastervol *= snd_channel2volume.value; break; + case 3: mastervol *= snd_channel3volume.value; break; + case 4: mastervol *= snd_channel4volume.value; break; + case 5: mastervol *= snd_channel5volume.value; break; + case 6: mastervol *= snd_channel6volume.value; break; + case 7: mastervol *= snd_channel7volume.value; break; + default: mastervol *= Cvar_VariableValueOr(va(vabuf, sizeof(vabuf), "snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break; + } + } + + // If this channel does not manage its own volume (like CD tracks) + if (!(ch->flags & CHANNELFLAG_FULLVOLUME)) + mastervol *= volume.value; + + if(snd_maxchannelvolume.value > 0) + { + // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy) + mastervol = bound(0.0f, mastervol, 10.0f * snd_maxchannelvolume.value); + } + + // always apply "master" + mastervol *= mastervolume.value; + + // add in ReplayGain very late; prevent clipping when close + if(sfx) + if(sfx->volume_peak > 0) + { + // Replaygain support + // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol); + mastervol *= sfx->volume_mult; + if(snd_maxchannelvolume.value > 0) + { + if(mastervol * sfx->volume_peak > snd_maxchannelvolume.value) + mastervol = snd_maxchannelvolume.value / sfx->volume_peak; + } + // Con_DPrintf("%f\n", fvol); + } + + if(snd_maxchannelvolume.value > 0) + { + // clamp HERE to keep relative volumes of the channels correct + mastervol = min(mastervol, snd_maxchannelvolume.value); + } + + mastervol = max(0.0f, mastervol); + + ch->mixspeed = mixspeed; + + // anything coming from the view entity will always be full volume + // LordHavoc: make sounds with ATTN_NONE have no spatialization + if (ch->entnum == cl.viewentity || ch->entnum == CL_VM_GetViewEntity() || ch->distfade == 0) + { + ch->prologic_invert = 1; + if (snd_spatialization_prologic.integer != 0) + { + ch->volume[0] = mastervol * snd_speakerlayout.listeners[0].ambientvolume * sqrt(0.5); + ch->volume[1] = mastervol * snd_speakerlayout.listeners[1].ambientvolume * sqrt(0.5); + for (i = 2;i < SND_LISTENERS;i++) + ch->volume[i] = 0; + } + else + { + for (i = 0;i < SND_LISTENERS;i++) + ch->volume[i] = mastervol * snd_speakerlayout.listeners[i].ambientvolume; + } + } + else + { + // calculate stereo seperation and distance attenuation + VectorSubtract(listener_origin, ch->origin, source_vec); + dist = VectorLength(source_vec); + f = dist * ch->distfade; + + f = + ((snd_attenuation_exponent.value == 0) ? 1.0 : pow(1.0 - min(1.0, f), (double)snd_attenuation_exponent.value)) + * + ((snd_attenuation_decibel.value == 0) ? 1.0 : pow(0.1, 0.1 * snd_attenuation_decibel.value * f)); + + intensity = mastervol * f; + if (intensity > 0) + { + qboolean occluded = false; + if (snd_spatialization_occlusion.integer) + { + if(snd_spatialization_occlusion.integer & 1) + if(listener_pvs) + { + int cluster = cl.worldmodel->brush.PointInLeaf(cl.worldmodel, ch->origin)->clusterindex; + if(cluster >= 0 && cluster < 8 * listener_pvsbytes && !CHECKPVSBIT(listener_pvs, cluster)) + occluded = true; + } + + if(snd_spatialization_occlusion.integer & 2) + if(!occluded) + if(cl.worldmodel && cl.worldmodel->brush.TraceLineOfSight && !cl.worldmodel->brush.TraceLineOfSight(cl.worldmodel, listener_origin, ch->origin)) + occluded = true; + } + if(occluded) + intensity *= 0.5f; + + ch->prologic_invert = 1; + if (snd_spatialization_prologic.integer != 0) + { + if (dist == 0) + angle_factor = 0.5f; + else + { + Matrix4x4_Transform(&listener_basematrix, ch->origin, source_vec); + VectorNormalize(source_vec); + + switch(spatialmethod) + { + case SPATIAL_LOG: + if(dist == 0) + f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing + else + f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_POW: + f = (pow(dist, spatialpower) - spatialoffset) * spatialfactor; + f = spatialmin + spatialdiff * bound(0, f, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_THRESH: + f = spatialmin + spatialdiff * (dist < spatialoffset); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_NONE: + default: + break; + } + + // the z axis needs to be removed and normalized because otherwise the volume would get lower as the sound source goes higher or lower then normal + source_vec[2] = 0; + VectorNormalize(source_vec); + angle_side = acos(source_vec[0]) / M_PI * 180; // angle between 0 and 180 degrees + angle_front = asin(source_vec[1]) / M_PI * 180; // angle between -90 and 90 degrees + if (angle_side > snd_spatialization_prologic_frontangle.value) + { + ch->prologic_invert = -1; // this will cause the right channel to do a 180 degrees phase shift (turning the sound wave upside down), + // but the best would be 90 degrees phase shift left and a -90 degrees phase shift right. + angle_factor = (angle_side - snd_spatialization_prologic_frontangle.value) / (360 - 2 * snd_spatialization_prologic_frontangle.value); + // angle_factor is between 0 and 1 and represents the angle range from the front left, to all the surround speakers (amount may vary, + // 1 in prologic I 2 in prologic II and 3 or 4 in prologic IIx) to the front right speaker. + if (angle_front > 0) + angle_factor = 1 - angle_factor; + } + else + angle_factor = angle_front / snd_spatialization_prologic_frontangle.value / 2.0 + 0.5; + //angle_factor is between 0 and 1 and represents the angle range from the front left to the center to the front right speaker + } + + ch->volume[0] = intensity * sqrt(angle_factor); + ch->volume[1] = intensity * sqrt(1 - angle_factor); + for (i = 2;i < SND_LISTENERS;i++) + ch->volume[i] = 0; + } + else + { + for (i = 0;i < SND_LISTENERS;i++) + { + Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec); + VectorNormalize(source_vec); + + switch(spatialmethod) + { + case SPATIAL_LOG: + if(dist == 0) + f = spatialmin + spatialdiff * (spatialfactor < 0); // avoid log(0), but do the right thing + else + f = spatialmin + spatialdiff * bound(0, (log(dist) - spatialoffset) * spatialfactor, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_POW: + f = (pow(dist, spatialpower) - spatialoffset) * spatialfactor; + f = spatialmin + spatialdiff * bound(0, f, 1); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_THRESH: + f = spatialmin + spatialdiff * (dist < spatialoffset); + VectorScale(source_vec, f, source_vec); + break; + case SPATIAL_NONE: + default: + break; + } + + ch->volume[i] = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias); + } + } + } + else + for (i = 0;i < SND_LISTENERS;i++) + ch->volume[i] = 0; + } +} +static void SND_Spatialize(channel_t *ch, qboolean isstatic) +{ + sfx_t *sfx = ch->sfx; + SND_Spatialize_WithSfx(ch, isstatic, sfx); +} + + +// ======================================================================= +// Start a sound effect +// ======================================================================= + +static void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, vec3_t origin, float fvol, float attenuation, qboolean isstatic, int entnum, int entchannel, int startpos, float fspeed) +{ + if (!sfx) + { + Con_Printf("S_PlaySfxOnChannel called with NULL??\n"); + return; + } + + if ((sfx->loopstart < sfx->total_length) || (flags & CHANNELFLAG_FORCELOOP)) + { + if(!snd_startloopingsounds.integer) + return; + } + else + { + if(!snd_startnonloopingsounds.integer) + return; + } + + // Initialize the channel + // a crash was reported on an in-use channel, so check here... + if (target_chan->sfx) + { + int channelindex = (int)(target_chan - channels); + Con_Printf("S_PlaySfxOnChannel(%s): channel %i already in use?? Clearing.\n", sfx->name, channelindex); + S_StopChannel (channelindex, true, false); + } + // We MUST set sfx LAST because otherwise we could crash a threaded mixer + // (otherwise we'd have to call SndSys_LockRenderBuffer here) + memset (target_chan, 0, sizeof (*target_chan)); + VectorCopy (origin, target_chan->origin); + target_chan->flags = flags; + target_chan->position = startpos; // start of the sound + target_chan->entnum = entnum; + target_chan->entchannel = entchannel; + + // If it's a static sound + if (isstatic) + { + if (sfx->loopstart >= sfx->total_length && (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEWORLD)) + Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name); + target_chan->distfade = attenuation / (64.0f * snd_soundradius.value); + } + else + target_chan->distfade = attenuation / snd_soundradius.value; + + // set the listener volumes + S_SetChannelVolume(target_chan - channels, fvol); + S_SetChannelSpeed(target_chan - channels, fspeed); + SND_Spatialize_WithSfx (target_chan, isstatic, sfx); + + // finally, set the sfx pointer, so the channel becomes valid for playback + // and will be noticed by the mixer + target_chan->sfx = sfx; +} + + +int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags, float fspeed) +{ + channel_t *target_chan, *check, *ch; + int ch_idx, startpos, i; + + if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer) + return -1; + + if(sfx == &changevolume_sfx) + { + if (!IS_CHAN_SINGLE(entchannel)) + return -1; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + ch = &channels[ch_idx]; + if (ch->entnum == entnum && ch->entchannel == entchannel) + { + S_SetChannelVolume(ch_idx, fvol); + S_SetChannelSpeed(ch_idx, fspeed); + for(i = 1; i > 0 && (i <= flags || i <= (int) channels[ch_idx].flags); i <<= 1) + if((flags ^ channels[ch_idx].flags) & i) + S_SetChannelFlag(ch_idx, i, (flags & i) != 0); + ch->distfade = attenuation / snd_soundradius.value; + SND_Spatialize(ch, false); + return ch_idx; + } + } + return -1; + } + + if (sfx->fetcher == NULL) + return -1; + + // Pick a channel to play on + target_chan = SND_PickChannel(entnum, entchannel); + if (!target_chan) + return -1; + + // 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]; + startpos = (int)(startposition * sfx->format.speed); + if (startpos == 0) + { + 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->position == 0 && check->basespeed == fspeed) + { + // calculate max offset + float maxtime = snd_identicalsoundrandomization_time.value; + float maxtics = snd_identicalsoundrandomization_tics.value; + float maxticsdelta = ((cls.state == ca_connected) ? (maxtics * (cl.mtime[0] - cl.mtime[1])) : 0); + float maxdelta = 0; + if(maxticsdelta == 0 || fabs(maxticsdelta) > fabs(maxtime)) + maxdelta = maxtime; + else + maxdelta = fabs(maxticsdelta) * ((maxtime > 0) ? 1 : -1); + + // use negative pos offset to delay this sound effect + startpos = lhrandom(0, maxdelta * sfx->format.speed); + break; + } + } + } + + S_PlaySfxOnChannel (sfx, target_chan, flags, origin, fvol, attenuation, false, entnum, entchannel, startpos, fspeed); + + return (target_chan - channels); +} + +int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) +{ + return S_StartSound_StartPosition_Flags(entnum, entchannel, sfx, origin, fvol, attenuation, 0, CHANNELFLAG_NONE, 1.0f); +} + +void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx) +{ + channel_t *ch; + sfx_t *sfx; + + if (channel_ind >= total_channels) + return; + + // we have to lock an audio mutex to prevent crashes if an audio mixer + // thread is currently mixing this channel + // the SndSys_LockRenderBuffer function uses such a mutex in + // threaded sound backends + if (lockmutex && !simsound) + SndSys_LockRenderBuffer(); + + ch = &channels[channel_ind]; + sfx = ch->sfx; + if (sfx != NULL) + { + if (sfx->fetcher != NULL && sfx->fetcher->stopchannel != NULL) + sfx->fetcher->stopchannel(ch); + ch->fetcher_data = NULL; + ch->sfx = NULL; + if (freesfx) + S_FreeSfx(sfx, true); + } + if (lockmutex && !simsound) + SndSys_UnlockRenderBuffer(); +} + + +qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value) +{ + if (ch_ind >= total_channels) + return false; + + if (flag != CHANNELFLAG_FORCELOOP && + flag != CHANNELFLAG_PAUSED && + flag != CHANNELFLAG_FULLVOLUME && + flag != CHANNELFLAG_LOCALSOUND) + return false; + + if (value) + channels[ch_ind].flags |= flag; + else + channels[ch_ind].flags &= ~flag; + + return true; +} + +void S_StopSound(int entnum, int entchannel) +{ + unsigned int i; + + for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) + if (channels[i].entnum == entnum && channels[i].entchannel == entchannel) + { + S_StopChannel (i, true, false); + return; + } +} + +void S_StopAllSounds (void) +{ + unsigned int i; + + // TOCHECK: is this test necessary? + if (snd_renderbuffer == NULL) + return; + + // stop CD audio because it may be using a faketrack + CDAudio_Stop(); + + if (simsound || SndSys_LockRenderBuffer ()) + { + int clear; + size_t memsize; + + for (i = 0; i < total_channels; i++) + if (channels[i].sfx) + S_StopChannel (i, false, false); + + total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics + memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); + + // Mute the contents of the submittion buffer + clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0; + memsize = snd_renderbuffer->maxframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + memset(snd_renderbuffer->ring, clear, memsize); + + if (!simsound) + SndSys_UnlockRenderBuffer (); + } +} + +void S_PauseGameSounds (qboolean toggle) +{ + unsigned int i; + + for (i = 0; i < total_channels; i++) + { + channel_t *ch; + + ch = &channels[i]; + if (ch->sfx != NULL && ! (ch->flags & CHANNELFLAG_LOCALSOUND)) + S_SetChannelFlag (i, CHANNELFLAG_PAUSED, toggle); + } +} + +void S_SetChannelVolume(unsigned int ch_ind, float fvol) +{ + channels[ch_ind].basevolume = fvol; +} + +void S_SetChannelSpeed(unsigned int ch_ind, float fspeed) +{ + channels[ch_ind].basespeed = fspeed; +} + +float S_GetChannelPosition (unsigned int ch_ind) +{ + // note: this is NOT accurate yet + double s; + channel_t *ch = &channels[ch_ind]; + sfx_t *sfx = ch->sfx; + if (!sfx) + return -1; + + s = ch->position / sfx->format.speed; + /* + if(!snd_usethreadedmixing) + s += _snd_mixahead.value; + */ + return (float)s; +} + +float S_GetEntChannelPosition(int entnum, int entchannel) +{ + channel_t *ch; + unsigned int i; + + for (i = 0; i < total_channels; i++) + { + ch = &channels[i]; + if (ch->entnum == entnum && ch->entchannel == entchannel) + return S_GetChannelPosition(i); + } + return -1; // no playing sound in this channel +} + +/* +================= +S_StaticSound +================= +*/ +void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation) +{ + channel_t *target_chan; + + if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer) + return; + if (!sfx->fetcher) + { + Con_Printf ("S_StaticSound: \"%s\" hasn't been precached\n", sfx->name); + return; + } + + if (total_channels == MAX_CHANNELS) + { + Con_Print("S_StaticSound: total_channels == MAX_CHANNELS\n"); + return; + } + + target_chan = &channels[total_channels++]; + S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0, 1.0f); +} + + +/* +=================== +S_UpdateAmbientSounds +=================== +*/ +static void S_UpdateAmbientSounds (void) +{ + int i; + float vol; + float fade = (float)max(0.0, cl.time - cl.oldtime) * ambient_fade.value / 256.0f; + int ambient_channel; + channel_t *chan; + unsigned char ambientlevels[NUM_AMBIENTS]; + sfx_t *sfx; + + memset(ambientlevels, 0, sizeof(ambientlevels)); + if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint) + cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels)); + + // Calc ambient sound levels + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) + { + chan = &channels[ambient_channel]; + sfx = chan->sfx; // fetch the volatile variable + if (sfx == NULL || sfx->fetcher == NULL) + continue; + + i = ambientlevels[ambient_channel]; + if (i < 8) + i = 0; + vol = i * (1.0f / 256.0f); + + // Don't adjust volume too fast + if (chan->basevolume < vol) + { + chan->basevolume += fade; + if (chan->basevolume > vol) + chan->basevolume = vol; + } + else if (chan->basevolume > vol) + { + chan->basevolume -= fade; + if (chan->basevolume < vol) + chan->basevolume = vol; + } + + if (snd_spatialization_prologic.integer != 0) + { + chan->volume[0] = chan->basevolume * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[0].ambientvolume * sqrt(0.5); + chan->volume[1] = chan->basevolume * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[1].ambientvolume * sqrt(0.5); + for (i = 2;i < SND_LISTENERS;i++) + chan->volume[i] = 0.0f; + } + else + { + for (i = 0;i < SND_LISTENERS;i++) + chan->volume[i] = chan->basevolume * ambient_level.value * volume.value * mastervolume.value * snd_speakerlayout.listeners[i].ambientvolume; + } + } +} + +static void S_PaintAndSubmit (void) +{ + unsigned int newsoundtime, paintedtime, endtime, maxtime, usedframes; + int usesoundtimehack; + static int soundtimehack = -1; + static int oldsoundtime = 0; + + if (snd_renderbuffer == NULL || nosound.integer) + return; + + // Update sound time + snd_usethreadedmixing = false; + usesoundtimehack = true; + if (cls.timedemo) // SUPER NASTY HACK to mix non-realtime sound for more reliable benchmarking + { + usesoundtimehack = 1; + newsoundtime = (unsigned int)((double)cl.mtime[0] * (double)snd_renderbuffer->format.speed); + } + else if (cls.capturevideo.soundrate && !cls.capturevideo.realtime) // SUPER NASTY HACK to record non-realtime sound + { + usesoundtimehack = 2; + newsoundtime = (unsigned int)((double)cls.capturevideo.frame * (double)snd_renderbuffer->format.speed / (double)cls.capturevideo.framerate); + } + else if (simsound) + { + usesoundtimehack = 3; + newsoundtime = (unsigned int)((realtime - snd_starttime) * (double)snd_renderbuffer->format.speed); + } + else + { + snd_usethreadedmixing = snd_threaded && !cls.capturevideo.soundrate; + usesoundtimehack = 0; + newsoundtime = SndSys_GetSoundTime(); + } + // if the soundtimehack state changes we need to reset the soundtime + if (soundtimehack != usesoundtimehack) + { + snd_renderbuffer->startframe = snd_renderbuffer->endframe = soundtime = newsoundtime; + + // Mute the contents of the submission buffer + if (simsound || SndSys_LockRenderBuffer ()) + { + int clear; + size_t memsize; + + clear = (snd_renderbuffer->format.width == 1) ? 0x80 : 0; + memsize = snd_renderbuffer->maxframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + memset(snd_renderbuffer->ring, clear, memsize); + + if (!simsound) + SndSys_UnlockRenderBuffer (); + } + } + soundtimehack = usesoundtimehack; + + if (!soundtimehack && snd_blocked > 0) + return; + + if (snd_usethreadedmixing) + return; // the audio thread will mix its own data + + newsoundtime += extrasoundtime; + if (newsoundtime < soundtime) + { + if ((cls.capturevideo.soundrate != 0) != recording_sound) + { + unsigned int additionaltime; + + // add some time to extrasoundtime make newsoundtime higher + + // The extra time must be a multiple of the render buffer size + // to avoid modifying the current position in the buffer, + // some modules write directly to a shared (DMA) buffer + additionaltime = (soundtime - newsoundtime) + snd_renderbuffer->maxframes - 1; + additionaltime -= additionaltime % snd_renderbuffer->maxframes; + + extrasoundtime += additionaltime; + newsoundtime += additionaltime; + Con_DPrintf("S_PaintAndSubmit: new extra sound time = %u\n", + extrasoundtime); + } + else if (!soundtimehack) + Con_Printf("S_PaintAndSubmit: WARNING: newsoundtime < soundtime (%u < %u)\n", + newsoundtime, soundtime); + } + soundtime = newsoundtime; + recording_sound = (cls.capturevideo.soundrate != 0); + + // Lock submitbuffer + if (!simsound && !SndSys_LockRenderBuffer()) + { + // If the lock failed, stop here + Con_DPrint(">> S_PaintAndSubmit: SndSys_LockRenderBuffer() failed\n"); + return; + } + + // Check to make sure that we haven't overshot + paintedtime = snd_renderbuffer->endframe; + if (paintedtime < soundtime) + paintedtime = soundtime; + + // mix ahead of current position + if (soundtimehack) + endtime = soundtime + (unsigned int)(_snd_mixahead.value * (float)snd_renderbuffer->format.speed); + else + endtime = soundtime + (unsigned int)(max(_snd_mixahead.value * (float)snd_renderbuffer->format.speed, min(3 * (soundtime - oldsoundtime), 0.3 * (float)snd_renderbuffer->format.speed))); + usedframes = snd_renderbuffer->endframe - snd_renderbuffer->startframe; + maxtime = paintedtime + snd_renderbuffer->maxframes - usedframes; + endtime = min(endtime, maxtime); + + while (paintedtime < endtime) + { + unsigned int startoffset; + unsigned int nbframes; + + // see how much we can fit in the paint buffer + nbframes = endtime - paintedtime; + // limit to the end of the ring buffer (in case of wrapping) + startoffset = paintedtime % snd_renderbuffer->maxframes; + nbframes = min(nbframes, snd_renderbuffer->maxframes - startoffset); + + // mix into the buffer + S_MixToBuffer(&snd_renderbuffer->ring[startoffset * snd_renderbuffer->format.width * snd_renderbuffer->format.channels], nbframes); + + paintedtime += nbframes; + snd_renderbuffer->endframe = paintedtime; + } + if (!simsound) + SndSys_UnlockRenderBuffer(); + + // Remove outdated samples from the ring buffer, if any + if (snd_renderbuffer->startframe < soundtime) + snd_renderbuffer->startframe = soundtime; + + if (simsound) + snd_renderbuffer->startframe = snd_renderbuffer->endframe; + else + SndSys_Submit(); + + oldsoundtime = soundtime; + + cls.soundstats.latency_milliseconds = (snd_renderbuffer->endframe - snd_renderbuffer->startframe) * 1000 / snd_renderbuffer->format.speed; + R_TimeReport("audiomix"); +} + +/* +============ +S_Update + +Called once each time through the main loop +============ +*/ +void S_Update(const matrix4x4_t *listenermatrix) +{ + unsigned int i, j, k; + channel_t *ch, *combine; + matrix4x4_t rotatematrix; + + if (snd_renderbuffer == NULL || nosound.integer) + return; + + { + double mindist_trans, maxdist_trans; + + spatialmin = snd_spatialization_min.value; + spatialdiff = snd_spatialization_max.value - spatialmin; + + if(snd_spatialization_control.value) + { + spatialpower = snd_spatialization_power.value; + + if(spatialpower == 0) + { + spatialmethod = SPATIAL_LOG; + mindist_trans = log(max(1, snd_spatialization_min_radius.value)); + maxdist_trans = log(max(1, snd_spatialization_max_radius.value)); + } + else + { + spatialmethod = SPATIAL_POW; + mindist_trans = pow(snd_spatialization_min_radius.value, spatialpower); + maxdist_trans = pow(snd_spatialization_max_radius.value, spatialpower); + } + + if(mindist_trans - maxdist_trans == 0) + { + spatialmethod = SPATIAL_THRESH; + mindist_trans = snd_spatialization_min_radius.value; + } + else + { + spatialoffset = mindist_trans; + spatialfactor = 1 / (maxdist_trans - mindist_trans); + } + } + else + spatialmethod = SPATIAL_NONE; + + } + + // If snd_swapstereo or snd_channellayout has changed, recompute the channel layout + if (current_swapstereo != boolxor(snd_swapstereo.integer, v_flipped.integer) || + current_channellayout != snd_channellayout.integer) + S_SetChannelLayout(); + + Matrix4x4_Invert_Simple(&listener_basematrix, listenermatrix); + Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin); + if (cl.worldmodel && cl.worldmodel->brush.FatPVS && cl.worldmodel->brush.num_pvsclusterbytes && cl.worldmodel->brush.PointInLeaf) + { + if(cl.worldmodel->brush.num_pvsclusterbytes != listener_pvsbytes) + { + if(listener_pvs) + Mem_Free(listener_pvs); + listener_pvsbytes = cl.worldmodel->brush.num_pvsclusterbytes; + listener_pvs = (unsigned char *) Mem_Alloc(snd_mempool, listener_pvsbytes); + } + cl.worldmodel->brush.FatPVS(cl.worldmodel, listener_origin, 2, listener_pvs, listener_pvsbytes, 0); + } + else + { + if(listener_pvs) + { + Mem_Free(listener_pvs); + listener_pvs = NULL; + } + listener_pvsbytes = 0; + } + + // calculate the current matrices + for (j = 0;j < SND_LISTENERS;j++) + { + Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, -snd_speakerlayout.listeners[j].yawangle, 0, 1); + Matrix4x4_Concat(&listener_matrix[j], &rotatematrix, &listener_basematrix); + // I think this should now do this: + // 1. create a rotation matrix for rotating by e.g. -90 degrees CCW + // (note: the matrix will rotate the OBJECT, not the VIEWER, so its + // angle has to be taken negative) + // 2. create a transform which first rotates and moves its argument + // into the player's view coordinates (using basematrix which is + // an inverted "absolute" listener matrix), then applies the + // rotation matrix for the ear + // Isn't Matrix4x4_CreateFromQuakeEntity a bit misleading because this + // does not actually refer to an entity? + } + + // update general area ambient sound sources + S_UpdateAmbientSounds (); + + combine = NULL; + R_TimeReport("audioprep"); + + // update spatialization for static and dynamic sounds + cls.soundstats.totalsounds = 0; + cls.soundstats.mixedsounds = 0; + ch = channels+NUM_AMBIENTS; + for (i=NUM_AMBIENTS ; isfx) + continue; + cls.soundstats.totalsounds++; + + // respatialize channel + SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); + + // 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) + { + // no need to merge silent channels + for (j = 0;j < SND_LISTENERS;j++) + if (ch->volume[j]) + break; + if (j == SND_LISTENERS) + continue; + // if the last combine chosen isn't suitable, find a new one + if (!(combine && combine != ch && combine->sfx == ch->sfx)) + { + // search for one + combine = NULL; + for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++) + { + if (channels[j].sfx == ch->sfx) + { + combine = channels + j; + break; + } + } + } + if (combine && combine != ch && combine->sfx == ch->sfx) + { + for (j = 0;j < SND_LISTENERS;j++) + { + combine->volume[j] += ch->volume[j]; + ch->volume[j] = 0; + } + } + } + for (k = 0;k < SND_LISTENERS;k++) + if (ch->volume[k]) + break; + if (k < SND_LISTENERS) + cls.soundstats.mixedsounds++; + } + R_TimeReport("audiospatialize"); + + sound_spatialized = true; + + // debugging output + if (snd_show.integer) + Con_Printf("----(%u)----\n", cls.soundstats.mixedsounds); + + S_PaintAndSubmit(); +} + +void S_ExtraUpdate (void) +{ + if (snd_noextraupdate.integer || !sound_spatialized) + return; + + S_PaintAndSubmit(); +} + +qboolean S_LocalSound (const char *sound) +{ + sfx_t *sfx; + int ch_ind; + + if (!snd_initialized.integer || nosound.integer) + return true; + + sfx = S_PrecacheSound (sound, true, false); + if (!sfx) + { + Con_Printf("S_LocalSound: can't precache %s\n", sound); + return false; + } + + // menu sounds must not be freed on level change + sfx->flags |= SFXFLAG_MENUSOUND; + + // fun fact: in Quake 1, this used -1 "replace any entity channel", + // which we no longer support anyway + // changed by Black in r4297 "Changed S_LocalSound to play multiple sounds at a time." + ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0); + if (ch_ind < 0) + return false; + + channels[ch_ind].flags |= CHANNELFLAG_LOCALSOUND; + return true; +} diff --git a/app/jni/snd_main.h b/app/jni/snd_main.h new file mode 100644 index 0000000..527ce49 --- /dev/null +++ b/app/jni/snd_main.h @@ -0,0 +1,213 @@ +/* +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 SND_MAIN_H +#define SND_MAIN_H + +#include "sound.h" + + +typedef struct snd_format_s +{ + unsigned int speed; + unsigned short width; + unsigned short channels; +} snd_format_t; + +typedef struct snd_buffer_s +{ + snd_format_t format; + unsigned int nbframes; // current size, in sample frames + unsigned int maxframes; // max size (buffer size), in sample frames + unsigned char samples[4]; // variable sized +} snd_buffer_t; + +typedef struct snd_ringbuffer_s +{ + snd_format_t format; + unsigned char* ring; + unsigned int maxframes; // max size (buffer size), in sample frames + unsigned int startframe; // index of the first frame in the buffer + // if startframe == endframe, the bufffer is empty + unsigned int endframe; // index of the first EMPTY frame in the "ring" buffer + // may be smaller than startframe if the "ring" buffer has wrapped +} snd_ringbuffer_t; + +// sfx_t flags +#define SFXFLAG_NONE 0 +#define SFXFLAG_FILEMISSING (1 << 0) // wasn't able to load the associated sound file +#define SFXFLAG_LEVELSOUND (1 << 1) // the sfx is part of the server or client precache list for this level +#define SFXFLAG_STREAMED (1 << 2) // informative only. You shouldn't need to know that +#define SFXFLAG_MENUSOUND (1 << 3) // not freed during level change (menu sounds, music, etc) + +typedef struct snd_fetcher_s snd_fetcher_t; +struct sfx_s +{ + char name[MAX_QPATH]; + sfx_t *next; + size_t memsize; // total memory used (including sfx_t and fetcher data) + + snd_format_t format; // format describing the audio data that fetcher->getsamplesfloat will return + unsigned int flags; // cf SFXFLAG_* defines + unsigned int loopstart; // in sample frames. equals total_length if not looped + unsigned int total_length; // in sample frames + const snd_fetcher_t *fetcher; + void *fetcher_data; // Per-sfx data for the sound fetching functions + + float volume_mult; // for replay gain (multiplier to apply) + float volume_peak; // for replay gain (highest peak); if set to 0, ReplayGain isn't supported +}; + +// maximum supported speakers constant +#define SND_LISTENERS 8 + +typedef struct channel_s +{ + // provided sound information + sfx_t *sfx; // pointer to sound sample being used + float basevolume; // 0-1 master volume + unsigned int flags; // cf CHANNELFLAG_* defines + int entnum; // makes sound follow entity origin (allows replacing interrupting existing sound on same id) + int entchannel; // which channel id on the entity + vec3_t origin; // origin of sound effect + vec_t distfade; // distance multiplier (attenuation/clipK) + void *fetcher_data; // Per-channel data for the sound fetching function + int prologic_invert;// whether a sound is played on the surround channels in prologic + float basespeed; // playback rate multiplier for pitch variation + + // these are often updated while mixer is running, glitching should be minimized (mismatched channel volumes from spatialization is okay) + // spatialized playback speed (speed * doppler ratio) + float mixspeed; + // spatialized volume per speaker (mastervol * distanceattenuation * channelvolume cvars) + float volume[SND_LISTENERS]; + + // updated ONLY by mixer + // position in sfx, starts at 0, loops or stops at sfx->total_length + double position; +} channel_t; + +// Sound fetching functions +// "start" is both an input and output parameter: it returns the actual start time of the sound buffer +typedef void (*snd_fetcher_getsamplesfloat_t) (channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat); +typedef void (*snd_fetcher_stopchannel_t) (channel_t *ch); +typedef void (*snd_fetcher_freesfx_t) (sfx_t *sfx); +struct snd_fetcher_s +{ + snd_fetcher_getsamplesfloat_t getsamplesfloat; + snd_fetcher_stopchannel_t stopchannel; + snd_fetcher_freesfx_t freesfx; +}; + +extern unsigned int total_channels; +extern channel_t channels[MAX_CHANNELS]; + +extern snd_ringbuffer_t *snd_renderbuffer; +extern qboolean snd_threaded; // enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo) +extern qboolean snd_usethreadedmixing; // if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderbuffer->endframe, instead the audio thread will call S_MixToBuffer as needed + +extern cvar_t _snd_mixahead; +extern cvar_t snd_swapstereo; +extern cvar_t snd_streaming; +extern cvar_t snd_streaming_length; + +#define SND_CHANNELLAYOUT_AUTO 0 +#define SND_CHANNELLAYOUT_STANDARD 1 +#define SND_CHANNELLAYOUT_ALSA 2 +extern cvar_t snd_channellayout; + +extern int snd_blocked; // counter. When > 0, we stop submitting sound to the audio device + +extern mempool_t *snd_mempool; + +// If simsound is true, the sound card is not initialized and no sound is submitted to it. +// More generally, all arch-dependent operations are skipped or emulated. +// Used for isolating performance in the renderer. +extern qboolean simsound; + + +#define STREAM_BUFFERSIZE 16384 // in sampleframes + + +// ==================================================================== +// Architecture-independent functions +// ==================================================================== + +void S_MixToBuffer(void *stream, unsigned int frames); + +qboolean S_LoadSound (sfx_t *sfx, qboolean complain); + +snd_buffer_t *Snd_CreateSndBuffer (const unsigned char *samples, unsigned int sampleframes, const snd_format_t* in_format, unsigned int sb_speed); +qboolean Snd_AppendToSndBuffer (snd_buffer_t* sb, const unsigned char *samples, unsigned int sampleframes, const snd_format_t* format); + +// If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself +// (if "sampleframes" is 0, the function chooses the size). +snd_ringbuffer_t *Snd_CreateRingBuffer (const snd_format_t* format, unsigned int sampleframes, void* buffer); + + +// ==================================================================== +// Architecture-dependent functions +// ==================================================================== + +// Create "snd_renderbuffer" with the proper sound format if the call is successful +// May return a suggested format if the requested format isn't available +qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested); + +// Stop the sound card, delete "snd_renderbuffer" and free its other resources +void SndSys_Shutdown (void); + +// Submit the contents of "snd_renderbuffer" to the sound card +void SndSys_Submit (void); + +// Returns the number of sample frames consumed since the sound started +unsigned int SndSys_GetSoundTime (void); + +// Get the exclusive lock on "snd_renderbuffer" +qboolean SndSys_LockRenderBuffer (void); + +// Release the exclusive lock on "snd_renderbuffer" +void SndSys_UnlockRenderBuffer (void); + +// if the sound system can generate events, send them +void SndSys_SendKeyEvents(void); + +// exported for capturevideo so ogg can see all channels +typedef struct portable_samplepair_s +{ + float sample[SND_LISTENERS]; +} portable_sampleframe_t; + +typedef struct listener_s +{ + int channel_unswapped; // for un-swapping + float yawangle; + float dotscale; + float dotbias; + float ambientvolume; +} +listener_t; +typedef struct speakerlayout_s +{ + const char *name; + unsigned int channels; + listener_t listeners[SND_LISTENERS]; +} +speakerlayout_t; + +#endif diff --git a/app/jni/snd_mem.c b/app/jni/snd_mem.c new file mode 100644 index 0000000..635bdd3 --- /dev/null +++ b/app/jni/snd_mem.c @@ -0,0 +1,388 @@ +/* +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 "snd_main.h" +#include "snd_ogg.h" +#include "snd_wav.h" +#include "snd_modplug.h" + + +/* +==================== +Snd_CreateRingBuffer + +If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself +(if "sampleframes" is 0, the function chooses the size). +==================== +*/ +snd_ringbuffer_t *Snd_CreateRingBuffer (const snd_format_t* format, unsigned int sampleframes, void* buffer) +{ + snd_ringbuffer_t *ringbuffer; + + // If the caller provides a buffer, it must give us its size + if (sampleframes == 0 && buffer != NULL) + return NULL; + + ringbuffer = (snd_ringbuffer_t*)Mem_Alloc(snd_mempool, sizeof (*ringbuffer)); + memset(ringbuffer, 0, sizeof(*ringbuffer)); + memcpy(&ringbuffer->format, format, sizeof(ringbuffer->format)); + + // If we haven't been given a buffer + if (buffer == NULL) + { + unsigned int maxframes; + size_t memsize; + + if (sampleframes == 0) + maxframes = (format->speed + 1) / 2; // Make the sound buffer large enough for containing 0.5 sec of sound + else + maxframes = sampleframes; + + memsize = maxframes * format->width * format->channels; + ringbuffer->ring = (unsigned char *) Mem_Alloc(snd_mempool, memsize); + ringbuffer->maxframes = maxframes; + } + else + { + ringbuffer->ring = (unsigned char *) buffer; + ringbuffer->maxframes = sampleframes; + } + + return ringbuffer; +} + + +/* +==================== +Snd_CreateSndBuffer +==================== +*/ +snd_buffer_t *Snd_CreateSndBuffer (const unsigned char *samples, unsigned int sampleframes, const snd_format_t* in_format, unsigned int sb_speed) +{ + size_t newsampleframes, memsize; + snd_buffer_t* sb; + + newsampleframes = (size_t) ceil((double)sampleframes * (double)sb_speed / (double)in_format->speed); + + memsize = newsampleframes * in_format->channels * in_format->width; + memsize += sizeof (*sb) - sizeof (sb->samples); + + sb = (snd_buffer_t*)Mem_Alloc (snd_mempool, memsize); + sb->format.channels = in_format->channels; + sb->format.width = in_format->width; + sb->format.speed = sb_speed; + sb->maxframes = newsampleframes; + sb->nbframes = 0; + + if (!Snd_AppendToSndBuffer (sb, samples, sampleframes, in_format)) + { + Mem_Free (sb); + return NULL; + } + + return sb; +} + + +/* +==================== +Snd_AppendToSndBuffer +==================== +*/ +qboolean Snd_AppendToSndBuffer (snd_buffer_t* sb, const unsigned char *samples, unsigned int sampleframes, const snd_format_t* format) +{ + size_t srclength, outcount; + unsigned char *out_data; + + //Con_DPrintf("ResampleSfx: %d samples @ %dHz -> %d samples @ %dHz\n", + // sampleframes, format->speed, outcount, sb->format.speed); + + // If the formats are incompatible + if (sb->format.channels != format->channels || sb->format.width != format->width) + { + Con_Print("AppendToSndBuffer: incompatible sound formats!\n"); + return false; + } + + outcount = (size_t) ((double)sampleframes * (double)sb->format.speed / (double)format->speed); + + // If the sound buffer is too short + if (outcount > sb->maxframes - sb->nbframes) + { + Con_Print("AppendToSndBuffer: sound buffer too short!\n"); + return false; + } + + out_data = &sb->samples[sb->nbframes * sb->format.width * sb->format.channels]; + srclength = sampleframes * format->channels; + + // Trivial case (direct transfer) + if (format->speed == sb->format.speed) + { + if (format->width == 1) + { + size_t i; + + for (i = 0; i < srclength; i++) + ((signed char*)out_data)[i] = samples[i] - 128; + } + else // if (format->width == 2) + memcpy (out_data, samples, srclength * format->width); + } + + // General case (linear interpolation with a fixed-point fractional + // step, 18-bit integer part and 14-bit fractional part) + // Can handle up to 2^18 (262144) samples per second (> 96KHz stereo) +# define FRACTIONAL_BITS 14 +# define FRACTIONAL_MASK ((1 << FRACTIONAL_BITS) - 1) +# define INTEGER_BITS (sizeof(samplefrac)*8 - FRACTIONAL_BITS) + else + { + const unsigned int fracstep = (unsigned int)((double)format->speed / sb->format.speed * (1 << FRACTIONAL_BITS)); + size_t remain_in = srclength, total_out = 0; + unsigned int samplefrac; + const unsigned char *in_ptr = samples; + unsigned char *out_ptr = out_data; + + // Check that we can handle one second of that sound + if (format->speed * format->channels > (1 << INTEGER_BITS)) + { + Con_Printf ("ResampleSfx: sound quality too high for resampling (%uHz, %u channel(s))\n", + format->speed, format->channels); + return 0; + } + + // We work 1 sec at a time to make sure we don't accumulate any + // significant error when adding "fracstep" over several seconds, and + // also to be able to handle very long sounds. + while (total_out < outcount) + { + size_t tmpcount, interpolation_limit, i, j; + unsigned int srcsample; + + samplefrac = 0; + + // If more than 1 sec of sound remains to be converted + if (outcount - total_out > sb->format.speed) + { + tmpcount = sb->format.speed; + interpolation_limit = tmpcount; // all samples can be interpolated + } + else + { + tmpcount = outcount - total_out; + interpolation_limit = (int)ceil((double)(((remain_in / format->channels) - 1) << FRACTIONAL_BITS) / fracstep); + if (interpolation_limit > tmpcount) + interpolation_limit = tmpcount; + } + + // 16 bit samples + if (format->width == 2) + { + const short* in_ptr_short; + + // Interpolated part + for (i = 0; i < interpolation_limit; i++) + { + srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels; + in_ptr_short = &((const short*)in_ptr)[srcsample]; + + for (j = 0; j < format->channels; j++) + { + int a, b; + + a = *in_ptr_short; + b = *(in_ptr_short + format->channels); + *((short*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a; + + in_ptr_short++; + out_ptr += sizeof (short); + } + + samplefrac += fracstep; + } + + // Non-interpolated part + for (/* nothing */; i < tmpcount; i++) + { + srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels; + in_ptr_short = &((const short*)in_ptr)[srcsample]; + + for (j = 0; j < format->channels; j++) + { + *((short*)out_ptr) = *in_ptr_short; + + in_ptr_short++; + out_ptr += sizeof (short); + } + + samplefrac += fracstep; + } + } + // 8 bit samples + else // if (format->width == 1) + { + const unsigned char* in_ptr_byte; + + // Convert up to 1 sec of sound + for (i = 0; i < interpolation_limit; i++) + { + srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels; + in_ptr_byte = &((const unsigned char*)in_ptr)[srcsample]; + + for (j = 0; j < format->channels; j++) + { + int a, b; + + a = *in_ptr_byte - 128; + b = *(in_ptr_byte + format->channels) - 128; + *((signed char*)out_ptr) = (((b - a) * (samplefrac & FRACTIONAL_MASK)) >> FRACTIONAL_BITS) + a; + + in_ptr_byte++; + out_ptr += sizeof (signed char); + } + + samplefrac += fracstep; + } + + // Non-interpolated part + for (/* nothing */; i < tmpcount; i++) + { + srcsample = (samplefrac >> FRACTIONAL_BITS) * format->channels; + in_ptr_byte = &((const unsigned char*)in_ptr)[srcsample]; + + for (j = 0; j < format->channels; j++) + { + *((signed char*)out_ptr) = *in_ptr_byte - 128; + + in_ptr_byte++; + out_ptr += sizeof (signed char); + } + + samplefrac += fracstep; + } + } + + // Update the counters and the buffer position + remain_in -= format->speed * format->channels; + in_ptr += format->speed * format->channels * format->width; + total_out += tmpcount; + } + } + + sb->nbframes += outcount; + return true; +} + + +//============================================================================= + +/* +============== +S_LoadSound +============== +*/ +qboolean S_LoadSound (sfx_t *sfx, qboolean complain) +{ + char namebuffer[MAX_QPATH + 16]; + size_t len; + + // See if already loaded + if (sfx->fetcher != NULL) + return true; + + // If we weren't able to load it previously, no need to retry + // Note: S_PrecacheSound clears this flag to cause a retry + if (sfx->flags & SFXFLAG_FILEMISSING) + return false; + + // No sound? + if (snd_renderbuffer == NULL) + return false; + + // Initialize volume peak to 0; if ReplayGain is supported, the loader will change this away + sfx->volume_peak = 0.0; + + if (developer_loading.integer) + Con_Printf("loading sound %s\n", sfx->name); + + SCR_PushLoadingScreen(true, sfx->name, 1); + + // LordHavoc: if the sound filename does not begin with sound/, try adding it + if (strncasecmp(sfx->name, "sound/", 6)) + { + dpsnprintf (namebuffer, sizeof(namebuffer), "sound/%s", sfx->name); + len = strlen(namebuffer); + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav")) + { + if (S_LoadWavFile (namebuffer, sfx)) + goto loaded; + memcpy (namebuffer + len - 3, "ogg", 4); + } + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg")) + { + if (OGG_LoadVorbisFile (namebuffer, sfx)) + goto loaded; + } + else + { + if (ModPlug_LoadModPlugFile (namebuffer, sfx)) + goto loaded; + } + } + + // LordHavoc: then try without the added sound/ as wav and ogg + dpsnprintf (namebuffer, sizeof(namebuffer), "%s", sfx->name); + len = strlen(namebuffer); + // request foo.wav: tries foo.wav, then foo.ogg + // request foo.ogg: tries foo.ogg only + // request foo.mod: tries foo.mod only + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav")) + { + if (S_LoadWavFile (namebuffer, sfx)) + goto loaded; + memcpy (namebuffer + len - 3, "ogg", 4); + } + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg")) + { + if (OGG_LoadVorbisFile (namebuffer, sfx)) + goto loaded; + } + else + { + if (ModPlug_LoadModPlugFile (namebuffer, sfx)) + goto loaded; + } + + // Can't load the sound! + sfx->flags |= SFXFLAG_FILEMISSING; + if (complain) + Con_DPrintf("failed to load sound \"%s\"\n", sfx->name); + + SCR_PopLoadingScreen(false); + return false; + +loaded: + SCR_PopLoadingScreen(false); + return true; +} diff --git a/app/jni/snd_mix.c b/app/jni/snd_mix.c new file mode 100644 index 0000000..2274f35 --- /dev/null +++ b/app/jni/snd_mix.c @@ -0,0 +1,532 @@ +/* +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 "snd_main.h" + +extern cvar_t snd_softclip; + +static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE]; +static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE]; + +extern speakerlayout_t snd_speakerlayout; // for querying the listeners + +static void S_CaptureAVISound(const portable_sampleframe_t *paintbuffer, size_t length) +{ + size_t i; + unsigned int j; + + if (!cls.capturevideo.active) + return; + + // undo whatever swapping the channel layout (swapstereo, ALSA) did + for(j = 0; j < snd_speakerlayout.channels; ++j) + { + unsigned int j0 = snd_speakerlayout.listeners[j].channel_unswapped; + for(i = 0; i < length; ++i) + paintbuffer_unswapped[i].sample[j0] = paintbuffer[i].sample[j]; + } + + SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length); +} + +extern cvar_t snd_softclip; + +static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int channels) +{ + int i; + + if((snd_softclip.integer == 1 && width <= 2) || snd_softclip.integer > 1) + { + portable_sampleframe_t *p = painted_ptr; + +#if 0 +/* Soft clipping, the sound of a dream, thanks to Jon Wattes + post to Musicdsp.org */ +#define SOFTCLIP(x) (x) = sin(bound(-M_PI/2, (x), M_PI/2)) * 0.25 +#endif + + // let's do a simple limiter instead, seems to sound better + static float maxvol = 0; + maxvol = max(1.0f, maxvol * (1.0f - nbframes / (0.4f * snd_renderbuffer->format.speed))); +#define SOFTCLIP(x) if(fabs(x)>maxvol) maxvol=fabs(x); (x) /= maxvol; + + if (channels == 8) // 7.1 surround + { + for (i = 0;i < nbframes;i++, p++) + { + SOFTCLIP(p->sample[0]); + SOFTCLIP(p->sample[1]); + SOFTCLIP(p->sample[2]); + SOFTCLIP(p->sample[3]); + SOFTCLIP(p->sample[4]); + SOFTCLIP(p->sample[5]); + SOFTCLIP(p->sample[6]); + SOFTCLIP(p->sample[7]); + } + } + else if (channels == 6) // 5.1 surround + { + for (i = 0; i < nbframes; i++, p++) + { + SOFTCLIP(p->sample[0]); + SOFTCLIP(p->sample[1]); + SOFTCLIP(p->sample[2]); + SOFTCLIP(p->sample[3]); + SOFTCLIP(p->sample[4]); + SOFTCLIP(p->sample[5]); + } + } + else if (channels == 4) // 4.0 surround + { + for (i = 0; i < nbframes; i++, p++) + { + SOFTCLIP(p->sample[0]); + SOFTCLIP(p->sample[1]); + SOFTCLIP(p->sample[2]); + SOFTCLIP(p->sample[3]); + } + } + else if (channels == 2) // 2.0 stereo + { + for (i = 0; i < nbframes; i++, p++) + { + SOFTCLIP(p->sample[0]); + SOFTCLIP(p->sample[1]); + } + } + else if (channels == 1) // 1.0 mono + { + for (i = 0; i < nbframes; i++, p++) + { + SOFTCLIP(p->sample[0]); + } + } +#undef SOFTCLIP + } +} + +static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels) +{ + int i, val; + + // FIXME: add 24bit and 32bit float formats + // FIXME: optimize with SSE intrinsics? + if (width == 2) // 16bit + { + short *snd_out = (short*)rb_ptr; + if (channels == 8) // 7.1 surround + { + for (i = 0;i < nbframes;i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[6] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[7] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + } + } + else if (channels == 6) // 5.1 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + } + } + else if (channels == 4) // 4.0 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + } + } + else if (channels == 2) // 2.0 stereo + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767); + } + } + else if (channels == 1) // 1.0 mono + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 16384.0f);*snd_out++ = bound(-32768, val, 32767); + } + } + + // noise is really really annoying + if (cls.timedemo) + memset(rb_ptr, 0, nbframes * channels * width); + } + else // 8bit + { + unsigned char *snd_out = (unsigned char*)rb_ptr; + if (channels == 8) // 7.1 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[6] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[7] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + } + } + else if (channels == 6) // 5.1 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + } + } + else if (channels == 4) // 4.0 surround + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + } + } + else if (channels == 2) // 2.0 stereo + { + for (i = 0; i < nbframes; i++, painted_ptr++) + { + val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255); + } + } + else if (channels == 1) // 1.0 mono + { + for (i = 0;i < nbframes;i++, painted_ptr++) + { + val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 64.0f) + 128; *snd_out++ = bound(0, val, 255); + } + } + + // noise is really really annoying + if (cls.timedemo) + memset(rb_ptr, 128, nbframes * channels); + } +} + + +/* +=============================================================================== + +CHANNEL MIXING + +=============================================================================== +*/ + +void S_MixToBuffer(void *stream, unsigned int bufferframes) +{ + int channelindex; + channel_t *ch; + int totalmixframes; + unsigned char *outbytes = (unsigned char *) stream; + sfx_t *sfx; + portable_sampleframe_t *paint; + int wantframes; + int i; + int count; + int fetched; + int fetch; + int istartframe; + int iendframe; + int ilengthframes; + int totallength; + int loopstart; + int indexfrac; + int indexfracstep; +#define S_FETCHBUFFERSIZE 4096 + float fetchsampleframes[S_FETCHBUFFERSIZE*2]; + const float *fetchsampleframe; + float vol[SND_LISTENERS]; + float lerp[2]; + float sample[3]; + double posd; + double speedd; + float maxvol; + qboolean looping; + qboolean silent; + + // mix as many times as needed to fill the requested buffer + while (bufferframes) + { + // limit to the size of the paint buffer + totalmixframes = min(bufferframes, PAINTBUFFER_SIZE); + + // clear the paint buffer + memset(paintbuffer, 0, totalmixframes * sizeof(paintbuffer[0])); + + // paint in the channels. + // channels with zero volumes still advance in time but don't paint. + ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int + for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++) + { + sfx = ch->sfx; + if (sfx == NULL) + continue; + if (!S_LoadSound (sfx, true)) + continue; + if (ch->flags & CHANNELFLAG_PAUSED) + continue; + if (!sfx->total_length) + continue; + + // copy the channel information to the stack for reference, otherwise the + // values might change during a mix if the spatializer is updating them + // (note: this still may get some old and some new values!) + posd = ch->position; + speedd = ch->mixspeed * sfx->format.speed / snd_renderbuffer->format.speed; + for (i = 0;i < SND_LISTENERS;i++) + vol[i] = ch->volume[i]; + + // check total volume level, because we can skip some code on silent sounds but other code must still run (position updates mainly) + maxvol = 0; + for (i = 0;i < SND_LISTENERS;i++) + if(vol[i] > maxvol) + maxvol = vol[i]; + switch(snd_renderbuffer->format.width) + { + case 1: // 8bpp + silent = maxvol < (1.0f / (256.0f)); + // so silent it has zero effect + break; + case 2: // 16bpp + silent = maxvol < (1.0f / (65536.0f)); + // so silent it has zero effect + break; + default: // floating point + silent = maxvol < 1.0e-13f; + // 130 dB is difference between hearing + // threshold and a jackhammer from + // working distance. + // therefore, anyone who turns up + // volume so much they notice this + // cutoff, likely already has their + // ear-drums blown out anyway. + break; + } + + // when doing prologic mixing, some channels invert one side + if (ch->prologic_invert == -1) + vol[1] *= -1.0f; + + // get some sfx info in a consistent form + totallength = sfx->total_length; + loopstart = (int)sfx->loopstart < totallength ? (int)sfx->loopstart : ((ch->flags & CHANNELFLAG_FORCELOOP) ? 0 : totallength); + looping = loopstart < totallength; + + // do the actual paint now (may skip work if silent) + paint = paintbuffer; + istartframe = 0; + for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count) + { + // check if this is a delayed sound + if (posd < 0) + { + // for a delayed sound we have to eat into the delay first + count = (int)floor(-posd / speedd) + 1; + count = bound(1, count, wantframes); + // let the for loop iterator apply the skip + continue; + } + + // compute a fetch size that won't overflow our buffer + count = wantframes; + for (;;) + { + istartframe = (int)floor(posd); + iendframe = (int)floor(posd + (count-1) * speedd); + ilengthframes = count > 1 ? (iendframe - istartframe + 2) : 2; + if (ilengthframes <= S_FETCHBUFFERSIZE) + break; + // reduce count by 25% and try again + count -= count >> 2; + } + + // zero whole fetch buffer for safety + // (floating point noise from uninitialized memory = HORRIBLE) + // otherwise we would only need to clear the excess + if (!silent) + memset(fetchsampleframes, 0, ilengthframes*sfx->format.channels*sizeof(fetchsampleframes[0])); + + // if looping, do multiple fetches + fetched = 0; + for (;;) + { + fetch = min(ilengthframes - fetched, totallength - istartframe); + if (fetch > 0) + { + if (!silent) + sfx->fetcher->getsamplesfloat(ch, sfx, istartframe, fetch, fetchsampleframes + fetched*sfx->format.channels); + istartframe += fetch; + fetched += fetch; + } + if (istartframe == totallength && looping && fetched < ilengthframes) + { + // loop and fetch some more + posd += loopstart - totallength; + istartframe = loopstart; + } + else + { + break; + } + } + + // set up our fixedpoint resampling variables (float to int conversions are expensive so do not do one per sampleframe) + fetchsampleframe = fetchsampleframes; + indexfrac = (int)floor((posd - floor(posd)) * 65536.0); + indexfracstep = (int)floor(speedd * 65536.0); + if (!silent) + { + if (sfx->format.channels == 2) + { + // music is stereo +#if SND_LISTENERS != 8 +#error the following code only supports up to 8 channels, update it +#endif + if (snd_speakerlayout.channels > 2) + { + // surround mixing + for (i = 0;i < count;i++, paint++) + { + lerp[1] = indexfrac * (1.0f / 65536.0f); + lerp[0] = 1.0f - lerp[1]; + sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1]; + sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1]; + sample[2] = (sample[0] + sample[1]) * 0.5f; + paint->sample[0] += sample[0] * vol[0]; + paint->sample[1] += sample[1] * vol[1]; + paint->sample[2] += sample[0] * vol[2]; + paint->sample[3] += sample[1] * vol[3]; + paint->sample[4] += sample[2] * vol[4]; + paint->sample[5] += sample[2] * vol[5]; + paint->sample[6] += sample[0] * vol[6]; + paint->sample[7] += sample[1] * vol[7]; + indexfrac += indexfracstep; + fetchsampleframe += 2 * (indexfrac >> 16); + indexfrac &= 0xFFFF; + } + } + else + { + // stereo mixing + for (i = 0;i < count;i++, paint++) + { + lerp[1] = indexfrac * (1.0f / 65536.0f); + lerp[0] = 1.0f - lerp[1]; + sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1]; + sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1]; + paint->sample[0] += sample[0] * vol[0]; + paint->sample[1] += sample[1] * vol[1]; + indexfrac += indexfracstep; + fetchsampleframe += 2 * (indexfrac >> 16); + indexfrac &= 0xFFFF; + } + } + } + else if (sfx->format.channels == 1) + { + // most sounds are mono +#if SND_LISTENERS != 8 +#error the following code only supports up to 8 channels, update it +#endif + if (snd_speakerlayout.channels > 2) + { + // surround mixing + for (i = 0;i < count;i++, paint++) + { + lerp[1] = indexfrac * (1.0f / 65536.0f); + lerp[0] = 1.0f - lerp[1]; + sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1]; + paint->sample[0] += sample[0] * vol[0]; + paint->sample[1] += sample[0] * vol[1]; + paint->sample[2] += sample[0] * vol[2]; + paint->sample[3] += sample[0] * vol[3]; + paint->sample[4] += sample[0] * vol[4]; + paint->sample[5] += sample[0] * vol[5]; + paint->sample[6] += sample[0] * vol[6]; + paint->sample[7] += sample[0] * vol[7]; + indexfrac += indexfracstep; + fetchsampleframe += (indexfrac >> 16); + indexfrac &= 0xFFFF; + } + } + else + { + // stereo mixing + for (i = 0;i < count;i++, paint++) + { + lerp[1] = indexfrac * (1.0f / 65536.0f); + lerp[0] = 1.0f - lerp[1]; + sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1]; + paint->sample[0] += sample[0] * vol[0]; + paint->sample[1] += sample[0] * vol[1]; + indexfrac += indexfracstep; + fetchsampleframe += (indexfrac >> 16); + indexfrac &= 0xFFFF; + } + } + } + } + } + ch->position = posd; + if (!looping && istartframe == totallength) + S_StopChannel(ch - channels, false, false); + } + + S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels); + + if (!snd_usethreadedmixing) + S_CaptureAVISound(paintbuffer, totalmixframes); + + S_ConvertPaintBuffer(paintbuffer, outbytes, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels); + + // advance the output pointer + outbytes += totalmixframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + bufferframes -= totalmixframes; + } +} diff --git a/app/jni/snd_modplug.c b/app/jni/snd_modplug.c new file mode 100644 index 0000000..6dc3fce --- /dev/null +++ b/app/jni/snd_modplug.c @@ -0,0 +1,432 @@ +/* + Copyright (C) 2003-2005 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + + +#include "quakedef.h" +#include "snd_main.h" +#include "snd_modplug.h" + +#ifdef SND_MODPLUG_STATIC + +#include +qboolean ModPlug_OpenLibrary (void) +{ + return true; // statically linked +} +void ModPlug_CloseLibrary (void) +{ +} +#define modplug_dll 1 +#define qModPlug_Load ModPlug_Load +#define qModPlug_Unload ModPlug_Unload +#define qModPlug_Read ModPlug_Read +#define qModPlug_Seek ModPlug_Seek +#define qModPlug_GetSettings ModPlug_GetSettings +#define qModPlug_SetSettings ModPlug_SetSettings +#define qModPlug_SetMasterVolume ModPlug_SetMasterVolume + +#else +// BEGIN SECTION FROM modplug.h + + /* + * This source code is public domain. + * + * Authors: Kenton Varda (C interface wrapper) + */ + + enum _ModPlug_Flags + { + MODPLUG_ENABLE_OVERSAMPLING = 1 << 0, /* Enable oversampling (*highly* recommended) */ + MODPLUG_ENABLE_NOISE_REDUCTION = 1 << 1, /* Enable noise reduction */ + MODPLUG_ENABLE_REVERB = 1 << 2, /* Enable reverb */ + MODPLUG_ENABLE_MEGABASS = 1 << 3, /* Enable megabass */ + MODPLUG_ENABLE_SURROUND = 1 << 4 /* Enable surround sound. */ + }; + + enum _ModPlug_ResamplingMode + { + MODPLUG_RESAMPLE_NEAREST = 0, /* No interpolation (very fast, extremely bad sound quality) */ + MODPLUG_RESAMPLE_LINEAR = 1, /* Linear interpolation (fast, good quality) */ + MODPLUG_RESAMPLE_SPLINE = 2, /* Cubic spline interpolation (high quality) */ + MODPLUG_RESAMPLE_FIR = 3 /* 8-tap fir filter (extremely high quality) */ + }; + + typedef struct _ModPlug_Settings + { + int mFlags; /* One or more of the MODPLUG_ENABLE_* flags above, bitwise-OR'ed */ + + /* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then + * down-mixes to the settings you choose. */ + int mChannels; /* Number of channels - 1 for mono or 2 for stereo */ + int mBits; /* Bits per sample - 8, 16, or 32 */ + int mFrequency; /* Sampling rate - 11025, 22050, or 44100 */ + int mResamplingMode; /* One of MODPLUG_RESAMPLE_*, above */ + + int mStereoSeparation; /* Stereo separation, 1 - 256 */ + int mMaxMixChannels; /* Maximum number of mixing channels (polyphony), 32 - 256 */ + + int mReverbDepth; /* Reverb level 0(quiet)-100(loud) */ + int mReverbDelay; /* Reverb delay in ms, usually 40-200ms */ + int mBassAmount; /* XBass level 0(quiet)-100(loud) */ + int mBassRange; /* XBass cutoff in Hz 10-100 */ + int mSurroundDepth; /* Surround level 0(quiet)-100(heavy) */ + int mSurroundDelay; /* Surround delay in ms, usually 5-40ms */ + int mLoopCount; /* Number of times to loop. Zero prevents looping. + -1 loops forever. */ + } ModPlug_Settings; + + struct _ModPlugFile; + typedef struct _ModPlugFile ModPlugFile; + +// END SECTION FROM modplug.h + +static ModPlugFile* (*qModPlug_Load) (const void* data, int size); +static void (*qModPlug_Unload) (ModPlugFile* file); +static int (*qModPlug_Read) (ModPlugFile* file, void* buffer, int size); +static void (*qModPlug_Seek) (ModPlugFile* file, int millisecond); +static void (*qModPlug_GetSettings) (ModPlug_Settings* settings); +static void (*qModPlug_SetSettings) (const ModPlug_Settings* settings); +typedef void (ModPlug_SetMasterVolume_t) (ModPlugFile* file,unsigned int cvol) ; +ModPlug_SetMasterVolume_t *qModPlug_SetMasterVolume; + + +static dllfunction_t modplugfuncs[] = +{ + {"ModPlug_Load", (void **) &qModPlug_Load}, + {"ModPlug_Unload", (void **) &qModPlug_Unload}, + {"ModPlug_Read", (void **) &qModPlug_Read}, + {"ModPlug_Seek", (void **) &qModPlug_Seek}, + {"ModPlug_GetSettings", (void **) &qModPlug_GetSettings}, + {"ModPlug_SetSettings", (void **) &qModPlug_SetSettings}, + {NULL, NULL} +}; + +// Handles for the modplug and modplugfile DLLs +static dllhandle_t modplug_dll = NULL; + +/* +================================================================= + + DLL load & unload + +================================================================= +*/ + +/* +==================== +ModPlug_OpenLibrary + +Try to load the modplugFile DLL +==================== +*/ +qboolean ModPlug_OpenLibrary (void) +{ + const char* dllnames_modplug [] = + { +#if defined(WIN32) + "libmodplug-1.dll", + "modplug.dll", +#elif defined(MACOSX) + "libmodplug.dylib", +#else + "libmodplug.so.1", + "libmodplug.so", +#endif + NULL + }; + + // Already loaded? + if (modplug_dll) + return true; + +// COMMANDLINEOPTION: Sound: -nomodplug disables modplug sound support + if (COM_CheckParm("-nomodplug")) + return false; + + // Load the DLLs + // We need to load both by hand because some OSes seem to not load + // the modplug DLL automatically when loading the modplugFile DLL + if(Sys_LoadLibrary (dllnames_modplug, &modplug_dll, modplugfuncs)) + { + qModPlug_SetMasterVolume = (ModPlug_SetMasterVolume_t *) Sys_GetProcAddress(modplug_dll, "ModPlug_SetMasterVolume"); + if(!qModPlug_SetMasterVolume) + Con_Print("Warning: modplug volume control not supported. Try getting a newer version of libmodplug.\n"); + return true; + } + else + return false; +} + + +/* +==================== +ModPlug_CloseLibrary + +Unload the modplugFile DLL +==================== +*/ +void ModPlug_CloseLibrary (void) +{ + Sys_UnloadLibrary (&modplug_dll); +} +#endif + + +/* +================================================================= + + modplug decoding + +================================================================= +*/ + +// Per-sfx data structure +typedef struct +{ + unsigned char *file; + size_t filesize; +} modplug_stream_persfx_t; + +// Per-channel data structure +typedef struct +{ + ModPlugFile *mf; + int bs; + int buffer_firstframe; + int buffer_numframes; + unsigned char buffer[STREAM_BUFFERSIZE*4]; +} modplug_stream_perchannel_t; + + +/* +==================== +ModPlug_GetSamplesFloat +==================== +*/ +static void ModPlug_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat) +{ + modplug_stream_perchannel_t* per_ch = (modplug_stream_perchannel_t *)ch->fetcher_data; + modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data; + int newlength, done, ret; + int f = sfx->format.width * sfx->format.channels; // bytes per frame + short *buf; + int i, len; + + // If there's no fetcher structure attached to the channel yet + if (per_ch == NULL) + { + per_ch = (modplug_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch)); + + // Open it with the modplugFile API + per_ch->mf = qModPlug_Load(per_sfx->file, per_sfx->filesize); + if (!per_ch->mf) + { + // we can't call Con_Printf here, not thread safe +// Con_Printf("error while reading ModPlug stream \"%s\"\n", per_sfx->name); + Mem_Free(per_ch); + return; + } + +#ifndef SND_MODPLUG_STATIC + if(qModPlug_SetMasterVolume) +#endif + qModPlug_SetMasterVolume(per_ch->mf, 512); // max volume, DP scales down! + + per_ch->bs = 0; + + per_ch->buffer_firstframe = 0; + per_ch->buffer_numframes = 0; + ch->fetcher_data = per_ch; + } + + // if the request is too large for our buffer, loop... + while (numsampleframes * f > (int)sizeof(per_ch->buffer)) + { + done = sizeof(per_ch->buffer) / f; + ModPlug_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat); + firstsampleframe += done; + numsampleframes -= done; + outsamplesfloat += done * sfx->format.channels; + } + + // seek if the request is before the current buffer (loop back) + // seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while) + // do not seek if the request overlaps the buffer end at all (expected behavior) + if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe) + { + // we expect to decode forward from here so this will be our new buffer start + per_ch->buffer_firstframe = firstsampleframe; + per_ch->buffer_numframes = 0; + // we don't actually seek - we don't care much about timing on silent mod music streams and looping never happens + //qModPlug_Seek(per_ch->mf, firstsampleframe * 1000.0 / sfx->format.speed); + } + + // decompress the file as needed + if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes) + { + // first slide the buffer back, discarding any data preceding the range we care about + int offset = firstsampleframe - per_ch->buffer_firstframe; + int keeplength = per_ch->buffer_numframes - offset; + if (keeplength > 0) + memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels); + per_ch->buffer_firstframe = firstsampleframe; + per_ch->buffer_numframes -= offset; + // decompress as much as we can fit in the buffer + newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f; + done = 0; + while (newlength > done && (ret = qModPlug_Read(per_ch->mf, (void *)((unsigned char *)per_ch->buffer + done), (int)(newlength - done))) > 0) + done += ret; + // clear the missing space if any + if (done < newlength) + { + memset(per_ch->buffer + done, 0, newlength - done); + // Argh. We didn't get as many samples as we wanted. Probably + // libmodplug forgot what mLoopCount==-1 means... basically, this means + // we can't loop like this. Try to let DP fix it later... + sfx->total_length = firstsampleframe + done / f; + sfx->loopstart = 0; + // can't Con_Printf from this thread + //if (newlength != done) + // Con_DPrintf("ModPlug_Fetch: wanted: %d, got: %d\n", newlength, done); + } + // we now have more data in the buffer + per_ch->buffer_numframes += done / f; + } + + // convert the sample format for the caller + buf = (short *)(per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f); + len = numsampleframes * sfx->format.channels; + for (i = 0;i < len;i++) + outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f); +} + + +/* +==================== +ModPlug_StopChannel +==================== +*/ +static void ModPlug_StopChannel(channel_t *ch) +{ + modplug_stream_perchannel_t *per_ch = (modplug_stream_perchannel_t *)ch->fetcher_data; + + if (per_ch != NULL) + { + // Free the modplug decoder + qModPlug_Unload(per_ch->mf); + + Mem_Free(per_ch); + } +} + + +/* +==================== +ModPlug_FreeSfx +==================== +*/ +static void ModPlug_FreeSfx (sfx_t *sfx) +{ + modplug_stream_persfx_t* per_sfx = (modplug_stream_persfx_t *)sfx->fetcher_data; + + // Free the modplug file + Mem_Free(per_sfx->file); + + // Free the stream structure + Mem_Free(per_sfx); +} + + +static const snd_fetcher_t modplug_fetcher = { ModPlug_GetSamplesFloat, ModPlug_StopChannel, ModPlug_FreeSfx }; + + +/* +==================== +ModPlug_LoadmodplugFile + +Load an modplug file into memory +==================== +*/ +qboolean ModPlug_LoadModPlugFile (const char *filename, sfx_t *sfx) +{ + unsigned char *data; + fs_offset_t filesize; + ModPlugFile *mf; + modplug_stream_persfx_t* per_sfx; + ModPlug_Settings s; + + if (!modplug_dll) + return false; + + // Already loaded? + if (sfx->fetcher != NULL) + return true; + + // Load the file + data = FS_LoadFile (filename, snd_mempool, false, &filesize); + if (data == NULL) + return false; + + if (developer_loading.integer >= 2) + Con_Printf ("Loading ModPlug file \"%s\"\n", filename); + + qModPlug_GetSettings(&s); + s.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION | MODPLUG_ENABLE_REVERB; + s.mChannels = 2; + s.mBits = 16; + s.mFrequency = 44100; + s.mResamplingMode = MODPLUG_RESAMPLE_SPLINE; + s.mLoopCount = -1; + qModPlug_SetSettings(&s); + + // Open it with the modplugFile API + if (!(mf = qModPlug_Load (data, filesize))) + { + Con_Printf ("error while opening ModPlug file \"%s\"\n", filename); + Mem_Free(data); + return false; + } + +#ifndef SND_MODPLUG_STATIC + if(qModPlug_SetMasterVolume) +#endif + qModPlug_SetMasterVolume(mf, 512); // max volume, DP scales down! + + if (developer_loading.integer >= 2) + Con_Printf ("\"%s\" will be streamed\n", filename); + per_sfx = (modplug_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx)); + per_sfx->file = data; + per_sfx->filesize = filesize; + sfx->memsize += sizeof(*per_sfx); + sfx->memsize += filesize; + sfx->format.speed = 44100; // modplug always works at that rate + sfx->format.width = 2; // We always work with 16 bits samples + sfx->format.channels = 2; // stereo rulez ;) (MAYBE default to mono because Amiga MODs sound better then?) + sfx->fetcher_data = per_sfx; + sfx->fetcher = &modplug_fetcher; + sfx->flags |= SFXFLAG_STREAMED; + sfx->total_length = 1<<30; // 2147384647; // they always loop (FIXME this breaks after 6 hours, we need support for a real "infinite" value!) + sfx->loopstart = sfx->total_length; // modplug does it + + return true; +} diff --git a/app/jni/snd_modplug.h b/app/jni/snd_modplug.h new file mode 100644 index 0000000..0811080 --- /dev/null +++ b/app/jni/snd_modplug.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2003 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef SND_ModPlug_H +#define SND_ModPlug_H + + +qboolean ModPlug_OpenLibrary (void); +void ModPlug_CloseLibrary (void); +qboolean ModPlug_LoadModPlugFile (const char *filename, sfx_t *sfx); + + +#endif diff --git a/app/jni/snd_ogg.c b/app/jni/snd_ogg.c new file mode 100644 index 0000000..683d421 --- /dev/null +++ b/app/jni/snd_ogg.c @@ -0,0 +1,718 @@ +/* + Copyright (C) 2003-2005 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + + +#include "quakedef.h" +#include "snd_main.h" +#include "snd_ogg.h" +#include "snd_wav.h" + +#ifdef LINK_TO_LIBVORBIS +#define OV_EXCLUDE_STATIC_CALLBACKS +#include +#include + +#define qov_clear ov_clear +#define qov_info ov_info +#define qov_comment ov_comment +#define qov_open_callbacks ov_open_callbacks +#define qov_pcm_seek ov_pcm_seek +#define qov_pcm_total ov_pcm_total +#define qov_read ov_read +#define qvorbis_comment_query vorbis_comment_query + +qboolean OGG_OpenLibrary (void) {return true;} +void OGG_CloseLibrary (void) {} +#else + +/* +================================================================= + + Minimal set of definitions from the Ogg Vorbis lib + (C) COPYRIGHT 1994-2001 by the XIPHOPHORUS Company + http://www.xiph.org/ + + WARNING: for a matter of simplicity, several pointer types are + casted to "void*", and most enumerated values are not included + +================================================================= +*/ + +#ifdef _MSC_VER +typedef __int64 ogg_int64_t; +#else +typedef long long ogg_int64_t; +#endif + +typedef struct +{ + size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); + int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*close_func) (void *datasource); + long (*tell_func) (void *datasource); +} ov_callbacks; + +typedef struct +{ + unsigned char *data; + int storage; + int fill; + int returned; + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +typedef struct +{ + int version; + int channels; + long rate; + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + long bitrate_window; + void *codec_setup; +} vorbis_info; + +typedef struct +{ + unsigned char *body_data; + long body_storage; + long body_fill; + long body_returned; + int *lacing_vals; + ogg_int64_t *granule_vals; + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + unsigned char header[282]; + int header_fill; + int e_o_s; + int b_o_s; + long serialno; + long pageno; + ogg_int64_t packetno; + ogg_int64_t granulepos; +} ogg_stream_state; + +typedef struct +{ + int analysisp; + vorbis_info *vi; + float **pcm; + float **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + int preextrapolate; + int eofflag; + long lW; + long W; + long nW; + long centerW; + ogg_int64_t granulepos; + ogg_int64_t sequence; + ogg_int64_t glue_bits; + ogg_int64_t time_bits; + ogg_int64_t floor_bits; + ogg_int64_t res_bits; + void *backend_state; +} vorbis_dsp_state; + +typedef struct +{ + long endbyte; + int endbit; + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +typedef struct +{ + float **pcm; + oggpack_buffer opb; + long lW; + long W; + long nW; + int pcmend; + int mode; + int eofflag; + ogg_int64_t granulepos; + ogg_int64_t sequence; + vorbis_dsp_state *vd; + void *localstore; + long localtop; + long localalloc; + long totaluse; + void *reap; // VOIDED POINTER + long glue_bits; + long time_bits; + long floor_bits; + long res_bits; + void *internal; +} vorbis_block; + +typedef struct +{ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; +} vorbis_comment; + +typedef struct +{ + void *datasource; + int seekable; + ogg_int64_t offset; + ogg_int64_t end; + ogg_sync_state oy; + int links; + ogg_int64_t *offsets; + ogg_int64_t *dataoffsets; + long *serialnos; + ogg_int64_t *pcmlengths; + vorbis_info *vi; + vorbis_comment *vc; + ogg_int64_t pcm_offset; + int ready_state; + long current_serialno; + int current_link; + double bittrack; + double samptrack; + ogg_stream_state os; + vorbis_dsp_state vd; + vorbis_block vb; + ov_callbacks callbacks; +} OggVorbis_File; + + +/* +================================================================= + + DarkPlaces definitions + +================================================================= +*/ + +// Functions exported from the vorbisfile library +static int (*qov_clear) (OggVorbis_File *vf); +static vorbis_info* (*qov_info) (OggVorbis_File *vf,int link); +static vorbis_comment* (*qov_comment) (OggVorbis_File *vf,int link); +static char * (*qvorbis_comment_query) (vorbis_comment *vc, const char *tag, int count); +static int (*qov_open_callbacks) (void *datasource, OggVorbis_File *vf, + char *initial, long ibytes, + ov_callbacks callbacks); +static int (*qov_pcm_seek) (OggVorbis_File *vf,ogg_int64_t pos); +static ogg_int64_t (*qov_pcm_total) (OggVorbis_File *vf,int i); +static long (*qov_read) (OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream); + +static dllfunction_t vorbisfilefuncs[] = +{ + {"ov_clear", (void **) &qov_clear}, + {"ov_info", (void **) &qov_info}, + {"ov_comment", (void **) &qov_comment}, + {"ov_open_callbacks", (void **) &qov_open_callbacks}, + {"ov_pcm_seek", (void **) &qov_pcm_seek}, + {"ov_pcm_total", (void **) &qov_pcm_total}, + {"ov_read", (void **) &qov_read}, + {NULL, NULL} +}; + +static dllfunction_t vorbisfuncs[] = +{ + {"vorbis_comment_query", (void **) &qvorbis_comment_query}, + {NULL, NULL} +}; + +// Handles for the Vorbis and Vorbisfile DLLs +static dllhandle_t vo_dll = NULL; +static dllhandle_t vf_dll = NULL; + + +/* +================================================================= + + DLL load & unload + +================================================================= +*/ + +/* +==================== +OGG_OpenLibrary + +Try to load the VorbisFile DLL +==================== +*/ +qboolean OGG_OpenLibrary (void) +{ + const char* dllnames_vo [] = + { +#if defined(WIN32) + "libvorbis-0.dll", + "libvorbis.dll", + "vorbis.dll", +#elif defined(MACOSX) + "libvorbis.dylib", +#else + "libvorbis.so.0", + "libvorbis.so", +#endif + NULL + }; + const char* dllnames_vf [] = + { +#if defined(WIN32) + "libvorbisfile-3.dll", + "libvorbisfile.dll", + "vorbisfile.dll", +#elif defined(MACOSX) + "libvorbisfile.dylib", +#else + "libvorbisfile.so.3", + "libvorbisfile.so", +#endif + NULL + }; + + // Already loaded? + if (vf_dll) + return true; + +// COMMANDLINEOPTION: Sound: -novorbis disables ogg vorbis sound support + if (COM_CheckParm("-novorbis")) + return false; + + // Load the DLLs + // We need to load both by hand because some OSes seem to not load + // the vorbis DLL automatically when loading the VorbisFile DLL + return Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs) && Sys_LoadLibrary (dllnames_vf, &vf_dll, vorbisfilefuncs); +} + + +/* +==================== +OGG_CloseLibrary + +Unload the VorbisFile DLL +==================== +*/ +void OGG_CloseLibrary (void) +{ + Sys_UnloadLibrary (&vf_dll); + Sys_UnloadLibrary (&vo_dll); +} + +#endif + +/* +================================================================= + + Ogg Vorbis decoding + +================================================================= +*/ + +typedef struct +{ + unsigned char *buffer; + ogg_int64_t ind, buffsize; +} ov_decode_t; + +static size_t ovcb_read (void *ptr, size_t size, size_t nb, void *datasource) +{ + ov_decode_t *ov_decode = (ov_decode_t*)datasource; + size_t remain, len; + + remain = ov_decode->buffsize - ov_decode->ind; + len = size * nb; + if (remain < len) + len = remain - remain % size; + + memcpy (ptr, ov_decode->buffer + ov_decode->ind, len); + ov_decode->ind += len; + + return len / size; +} + +static int ovcb_seek (void *datasource, ogg_int64_t offset, int whence) +{ + ov_decode_t *ov_decode = (ov_decode_t*)datasource; + + switch (whence) + { + case SEEK_SET: + break; + case SEEK_CUR: + offset += ov_decode->ind; + break; + case SEEK_END: + offset += ov_decode->buffsize; + break; + default: + return -1; + } + if (offset < 0 || offset > ov_decode->buffsize) + return -1; + + ov_decode->ind = offset; + return 0; +} + +static int ovcb_close (void *ov_decode) +{ + return 0; +} + +static long ovcb_tell (void *ov_decode) +{ + return ((ov_decode_t*)ov_decode)->ind; +} + +// Per-sfx data structure +typedef struct +{ + unsigned char *file; + size_t filesize; +} ogg_stream_persfx_t; + +// Per-channel data structure +typedef struct +{ + OggVorbis_File vf; + ov_decode_t ov_decode; + int bs; + int buffer_firstframe; + int buffer_numframes; + unsigned char buffer[STREAM_BUFFERSIZE*4]; +} ogg_stream_perchannel_t; + + +static const ov_callbacks callbacks = {ovcb_read, ovcb_seek, ovcb_close, ovcb_tell}; + +/* +==================== +OGG_GetSamplesFloat +==================== +*/ +static void OGG_GetSamplesFloat (channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat) +{ + ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data; + ogg_stream_persfx_t *per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data; + int f = sfx->format.width * sfx->format.channels; // bytes per frame in the buffer + short *buf; + int i, len; + int newlength, done, ret; + + // if this channel does not yet have a channel fetcher, make one + if (per_ch == NULL) + { + // allocate a struct to keep track of our file position and buffer + per_ch = (ogg_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch)); + // begin decoding the file + per_ch->ov_decode.buffer = per_sfx->file; + per_ch->ov_decode.ind = 0; + per_ch->ov_decode.buffsize = per_sfx->filesize; + if (qov_open_callbacks(&per_ch->ov_decode, &per_ch->vf, NULL, 0, callbacks) < 0) + { + // this never happens - this function succeeded earlier on the same data + Mem_Free(per_ch); + return; + } + per_ch->bs = 0; + per_ch->buffer_firstframe = 0; + per_ch->buffer_numframes = 0; + // attach the struct to our channel + ch->fetcher_data = (void *)per_ch; + } + + // if the request is too large for our buffer, loop... + while (numsampleframes * f > (int)sizeof(per_ch->buffer)) + { + done = sizeof(per_ch->buffer) / f; + OGG_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat); + firstsampleframe += done; + numsampleframes -= done; + outsamplesfloat += done * sfx->format.channels; + } + + // seek if the request is before the current buffer (loop back) + // seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while) + // do not seek if the request overlaps the buffer end at all (expected behavior) + if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe) + { + // we expect to decode forward from here so this will be our new buffer start + per_ch->buffer_firstframe = firstsampleframe; + per_ch->buffer_numframes = 0; + ret = qov_pcm_seek(&per_ch->vf, (ogg_int64_t)firstsampleframe); + if (ret != 0) + { + // LordHavoc: we can't Con_Printf here, not thread safe... + //Con_Printf("OGG_FetchSound: qov_pcm_seek(..., %d) returned %d\n", firstsampleframe, ret); + return; + } + } + + // decompress the file as needed + if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes) + { + // first slide the buffer back, discarding any data preceding the range we care about + int offset = firstsampleframe - per_ch->buffer_firstframe; + int keeplength = per_ch->buffer_numframes - offset; + if (keeplength > 0) + memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels); + per_ch->buffer_firstframe = firstsampleframe; + per_ch->buffer_numframes -= offset; + // decompress as much as we can fit in the buffer + newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f; + done = 0; + while (newlength > done && (ret = qov_read(&per_ch->vf, (char *)per_ch->buffer + per_ch->buffer_numframes * f + done, (int)(newlength - done), mem_bigendian, 2, 1, &per_ch->bs)) > 0) + done += ret; + // clear the missing space if any + if (done < newlength) + memset(per_ch->buffer + done, 0, newlength - done); + // we now have more data in the buffer + per_ch->buffer_numframes += done / f; + } + + // convert the sample format for the caller + buf = (short *)((char *)per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f); + len = numsampleframes * sfx->format.channels; + for (i = 0;i < len;i++) + outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f); +} + + +/* +==================== +OGG_StopChannel +==================== +*/ +static void OGG_StopChannel(channel_t *ch) +{ + ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data; + if (per_ch != NULL) + { + // release the vorbis decompressor + qov_clear(&per_ch->vf); + Mem_Free(per_ch); + } +} + + +/* +==================== +OGG_FreeSfx +==================== +*/ +static void OGG_FreeSfx(sfx_t *sfx) +{ + ogg_stream_persfx_t *per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data; + // free the complete file we were keeping around + Mem_Free(per_sfx->file); + // free the file information structure + Mem_Free(per_sfx); +} + + +static const snd_fetcher_t ogg_fetcher = {OGG_GetSamplesFloat, OGG_StopChannel, OGG_FreeSfx}; + +static void OGG_DecodeTags(vorbis_comment *vc, unsigned int *start, unsigned int *length, unsigned int numsamples, double *peak, double *gaindb) +{ + const char *startcomment = NULL, *lengthcomment = NULL, *endcomment = NULL, *thiscomment = NULL; + + *start = numsamples; + *length = numsamples; + *peak = 0.0; + *gaindb = 0.0; + + if(!vc) + return; + + thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_PEAK", 0); + if(thiscomment) + *peak = atof(thiscomment); + thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_GAIN", 0); + if(thiscomment) + *gaindb = atof(thiscomment); + + startcomment = qvorbis_comment_query(vc, "LOOP_START", 0); // DarkPlaces, and some Japanese app + if(startcomment) + { + endcomment = qvorbis_comment_query(vc, "LOOP_END", 0); + if(!endcomment) + lengthcomment = qvorbis_comment_query(vc, "LOOP_LENGTH", 0); + } + else + { + startcomment = qvorbis_comment_query(vc, "LOOPSTART", 0); // RPG Maker VX + if(startcomment) + { + lengthcomment = qvorbis_comment_query(vc, "LOOPLENGTH", 0); + if(!lengthcomment) + endcomment = qvorbis_comment_query(vc, "LOOPEND", 0); + } + else + { + startcomment = qvorbis_comment_query(vc, "LOOPPOINT", 0); // Sonic Robo Blast 2 + } + } + + if(startcomment) + { + *start = (unsigned int) bound(0, atof(startcomment), numsamples); + if(endcomment) + *length = (unsigned int) bound(0, atof(endcomment), numsamples); + else if(lengthcomment) + *length = (unsigned int) bound(0, *start + atof(lengthcomment), numsamples); + } +} + +/* +==================== +OGG_LoadVorbisFile + +Load an Ogg Vorbis file into memory +==================== +*/ +qboolean OGG_LoadVorbisFile(const char *filename, sfx_t *sfx) +{ + unsigned char *data; + fs_offset_t filesize; + ov_decode_t ov_decode; + OggVorbis_File vf; + vorbis_info *vi; + vorbis_comment *vc; + double peak, gaindb; + +#ifndef LINK_TO_LIBVORBIS + if (!vf_dll) + return false; +#endif + + // Return if already loaded + if (sfx->fetcher != NULL) + return true; + + // Load the file completely + data = FS_LoadFile(filename, snd_mempool, false, &filesize); + if (data == NULL) + return false; + + if (developer_loading.integer >= 2) + Con_Printf("Loading Ogg Vorbis file \"%s\"\n", filename); + + // Open it with the VorbisFile API + ov_decode.buffer = data; + ov_decode.ind = 0; + ov_decode.buffsize = filesize; + if (qov_open_callbacks(&ov_decode, &vf, NULL, 0, callbacks) < 0) + { + Con_Printf("error while opening Ogg Vorbis file \"%s\"\n", filename); + Mem_Free(data); + return false; + } + + // Get the stream information + vi = qov_info(&vf, -1); + if (vi->channels < 1 || vi->channels > 2) + { + Con_Printf("%s has an unsupported number of channels (%i)\n", + sfx->name, vi->channels); + qov_clear (&vf); + Mem_Free(data); + return false; + } + + sfx->format.speed = vi->rate; + sfx->format.channels = vi->channels; + sfx->format.width = 2; // We always work with 16 bits samples + + sfx->total_length = qov_pcm_total(&vf, -1); + + if (snd_streaming.integer && (snd_streaming.integer >= 2 || sfx->total_length > max(sizeof(ogg_stream_perchannel_t), snd_streaming_length.value * sfx->format.speed))) + { + // large sounds use the OGG fetcher to decode the file on demand (but the entire file is held in memory) + ogg_stream_persfx_t* per_sfx; + if (developer_loading.integer >= 2) + Con_Printf("Ogg sound file \"%s\" will be streamed\n", filename); + per_sfx = (ogg_stream_persfx_t *)Mem_Alloc(snd_mempool, sizeof(*per_sfx)); + sfx->memsize += sizeof (*per_sfx); + per_sfx->file = data; + per_sfx->filesize = filesize; + sfx->memsize += filesize; + sfx->fetcher_data = per_sfx; + sfx->fetcher = &ogg_fetcher; + sfx->flags |= SFXFLAG_STREAMED; + vc = qov_comment(&vf, -1); + OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb); + qov_clear(&vf); + } + else + { + // small sounds are entirely loaded and use the PCM fetcher + char *buff; + ogg_int64_t len; + ogg_int64_t done; + int bs; + long ret; + if (developer_loading.integer >= 2) + Con_Printf ("Ogg sound file \"%s\" will be cached\n", filename); + len = sfx->total_length * sfx->format.channels * sfx->format.width; + sfx->flags &= ~SFXFLAG_STREAMED; + sfx->memsize += len; + sfx->fetcher = &wav_fetcher; + sfx->fetcher_data = Mem_Alloc(snd_mempool, (size_t)len); + buff = (char *)sfx->fetcher_data; + done = 0; + bs = 0; + while ((ret = qov_read(&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0) + done += ret; + vc = qov_comment(&vf, -1); + OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb); + qov_clear(&vf); + Mem_Free(data); + } + + if(peak) + { + sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f))); + sfx->volume_peak = peak; + if (developer_loading.integer >= 2) + Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak %f)\n", filename, sfx->volume_mult, sfx->volume_peak); + } + else if(gaindb != 0) + { + sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f))); + sfx->volume_peak = 1.0; // if peak is not defined, we won't trust it + if (developer_loading.integer >= 2) + Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak not defined and assumed to be %f)\n", filename, sfx->volume_mult, sfx->volume_peak); + } + + return true; +} diff --git a/app/jni/snd_ogg.h b/app/jni/snd_ogg.h new file mode 100644 index 0000000..f8c5fe7 --- /dev/null +++ b/app/jni/snd_ogg.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2003 Mathieu Olivier + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef SND_OGG_H +#define SND_OGG_H + + +qboolean OGG_OpenLibrary (void); +void OGG_CloseLibrary (void); +qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx); + + +#endif diff --git a/app/jni/snd_wav.c b/app/jni/snd_wav.c new file mode 100644 index 0000000..6f86191 --- /dev/null +++ b/app/jni/snd_wav.c @@ -0,0 +1,348 @@ +/* + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + + +#include "quakedef.h" +#include "snd_main.h" +#include "snd_wav.h" + + +typedef struct wavinfo_s +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + + +static unsigned char *data_p; +static unsigned char *iff_end; +static unsigned char *last_chunk; +static unsigned char *iff_data; +static int iff_chunk_len; + + +static short GetLittleShort(void) +{ + short val; + + val = BuffLittleShort (data_p); + data_p += 2; + + return val; +} + +static int GetLittleLong(void) +{ + int val = 0; + + val = BuffLittleLong (data_p); + data_p += 4; + + return val; +} + +static void FindNextChunk(const 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 (data_p + iff_chunk_len > iff_end) + { + // truncated chunk! + data_p = NULL; + return; + } + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!strncmp((const char *)data_p, name, 4)) + return; + } +} + +static void FindChunk(const char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +/* +static 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 +============ +*/ +static wavinfo_t GetWavinfo (char *name, unsigned char *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 && !strncmp((const char *)data_p+8, "WAVE", 4))) + { + Con_Print("Missing RIFF/WAVE chunks\n"); + return info; + } + + // get "fmt " chunk + iff_data = data_p + 12; + //DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + Con_Print("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + Con_Print("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(); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp ((const char *)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; + } + } + } + else + info.loopstart = -1; + + // find data chunk + FindChunk("data"); + if (!data_p) + { + Con_Print("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong () / info.width / info.channels; + + if (info.samples) + { + if (samples < info.samples) + { + Con_Printf ("Sound %s has a bad loop length\n", name); + info.samples = samples; + } + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + + +/* +==================== +WAV_GetSamplesFloat +==================== +*/ +static void WAV_GetSamplesFloat(channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat) +{ + int i, len = numsampleframes * sfx->format.channels; + if (sfx->format.width == 2) + { + const short *bufs = (const short *)sfx->fetcher_data + firstsampleframe * sfx->format.channels; + for (i = 0;i < len;i++) + outsamplesfloat[i] = bufs[i] * (1.0f / 32768.0f); + } + else + { + const signed char *bufb = (const signed char *)sfx->fetcher_data + firstsampleframe * sfx->format.channels; + for (i = 0;i < len;i++) + outsamplesfloat[i] = bufb[i] * (1.0f / 128.0f); + } +} + +/* +==================== +WAV_FreeSfx +==================== +*/ +static void WAV_FreeSfx(sfx_t *sfx) +{ + // free the loaded sound data + Mem_Free(sfx->fetcher_data); +} + +const snd_fetcher_t wav_fetcher = { WAV_GetSamplesFloat, NULL, WAV_FreeSfx }; + + +/* +============== +S_LoadWavFile +============== +*/ +qboolean S_LoadWavFile (const char *filename, sfx_t *sfx) +{ + fs_offset_t filesize; + unsigned char *data; + wavinfo_t info; + int i, len; + const unsigned char *inb; + unsigned char *outb; + + // Already loaded? + if (sfx->fetcher != NULL) + return true; + + // Load the file + data = FS_LoadFile(filename, snd_mempool, false, &filesize); + if (!data) + return false; + + // Don't try to load it if it's not a WAV file + if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4)) + { + Mem_Free(data); + return false; + } + + if (developer_loading.integer >= 2) + Con_Printf ("Loading WAV file \"%s\"\n", filename); + + info = GetWavinfo (sfx->name, data, (int)filesize); + if (info.channels < 1 || info.channels > 2) // Stereo sounds are allowed (intended for music) + { + Con_Printf("%s has an unsupported number of channels (%i)\n",sfx->name, info.channels); + Mem_Free(data); + return false; + } + //if (info.channels == 2) + // Log_Printf("stereosounds.log", "%s\n", sfx->name); + + sfx->format.speed = info.rate; + sfx->format.width = info.width; + sfx->format.channels = info.channels; + sfx->fetcher = &wav_fetcher; + sfx->fetcher_data = Mem_Alloc(snd_mempool, info.samples * sfx->format.width * sfx->format.channels); + sfx->total_length = info.samples; + sfx->memsize += filesize; + len = info.samples * sfx->format.channels * sfx->format.width; + inb = data + info.dataofs; + outb = (unsigned char *)sfx->fetcher_data; + if (info.width == 2) + { + if (mem_bigendian) + { + // we have to byteswap the data at load (better than doing it while mixing) + for (i = 0;i < len;i += 2) + { + outb[i] = inb[i+1]; + outb[i+1] = inb[i]; + } + } + else + { + // we can just copy it straight + memcpy(outb, inb, len); + } + } + else + { + // convert unsigned byte sound data to signed bytes for quicker mixing + for (i = 0;i < len;i++) + outb[i] = inb[i] - 0x80; + } + + if (info.loopstart < 0) + sfx->loopstart = sfx->total_length; + else + sfx->loopstart = info.loopstart; + sfx->loopstart = min(sfx->loopstart, sfx->total_length); + sfx->flags &= ~SFXFLAG_STREAMED; + + return true; +} diff --git a/app/jni/snd_wav.h b/app/jni/snd_wav.h new file mode 100644 index 0000000..89c7ee5 --- /dev/null +++ b/app/jni/snd_wav.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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + + +#ifndef SND_WAV_H +#define SND_WAV_H + + +extern const snd_fetcher_t wav_fetcher; + +qboolean S_LoadWavFile (const char *filename, sfx_t *sfx); + + +#endif diff --git a/app/jni/snprintf.c b/app/jni/snprintf.c new file mode 100644 index 0000000..810cccd --- /dev/null +++ b/app/jni/snprintf.c @@ -0,0 +1,1025 @@ +/* + * snprintf.c - a portable implementation of snprintf + * + * AUTHOR + * Mark Martinec , April 1999. + * + * Copyright 1999, Mark Martinec. All rights reserved. + * + * TERMS AND CONDITIONS + * This program is free software; you can redistribute it and/or modify + * it under the terms of the "Frontier Artistic License" which comes + * with this Kit. + * + * 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 Frontier Artistic License for more details. + * + * You should have received a copy of the Frontier Artistic License + * with this Kit in the file named LICENSE.txt . + * If not, I'll be glad to provide one. + * + * FEATURES + * - careful adherence to specs regarding flags, field width and precision; + * - good performance for large string handling (large format, large + * argument or large paddings). Performance is similar to system's sprintf + * and in several cases significantly better (make sure you compile with + * optimizations turned on, tell the compiler the code is strict ANSI + * if necessary to give it more freedom for optimizations); + * - return value semantics per ISO/IEC 9899:1999 ("ISO C99"); + * - written in standard ISO/ANSI C - requires an ANSI C compiler. + * + * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES + * + * This snprintf only supports the following conversion specifiers: + * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) + * with flags: '-', '+', ' ', '0' and '#'. + * An asterisk is supported for field width as well as precision. + * + * Length modifiers 'h' (short int), 'l' (long int), + * and 'll' (long long int) are supported. + * NOTE: + * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the + * length modifier 'll' is recognized but treated the same as 'l', + * which may cause argument value truncation! Defining + * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also + * handles length modifier 'll'. long long int is a language extension + * which may not be portable. + * + * Conversion of numeric data (conversion specifiers d, u, o, x, X, p) + * with length modifiers (none or h, l, ll) is left to the system routine + * sprintf, but all handling of flags, field width and precision as well as + * c and s conversions is done very carefully by this portable routine. + * If a string precision (truncation) is specified (e.g. %.8s) it is + * guaranteed the string beyond the specified precision will not be referenced. + * + * Length modifiers h, l and ll are ignored for c and s conversions (data + * types wint_t and wchar_t are not supported). + * + * The following common synonyms for conversion characters are supported: + * - i is a synonym for d + * - D is a synonym for ld, explicit length modifiers are ignored + * - U is a synonym for lu, explicit length modifiers are ignored + * - O is a synonym for lo, explicit length modifiers are ignored + * The D, O and U conversion characters are nonstandard, they are supported + * for backward compatibility only, and should not be used for new code. + * + * The following is specifically NOT supported: + * - flag ' (thousands' grouping character) is recognized but ignored + * - numeric conversion specifiers: f, e, E, g, G and synonym F, + * as well as the new a and A conversion specifiers + * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead) + * - wide character/string conversions: lc, ls, and nonstandard + * synonyms C and S + * - writeback of converted string length: conversion character n + * - the n$ specification for direct reference to n-th argument + * - locales + * + * It is permitted for str_m to be zero, and it is permitted to specify NULL + * pointer for resulting string argument if str_m is zero (as per ISO C99). + * + * The return value is the number of characters which would be generated + * for the given input, excluding the trailing null. If this value + * is greater or equal to str_m, not all characters from the result + * have been stored in str, output bytes beyond the (str_m-1) -th character + * are discarded. If str_m is greater than zero it is guaranteed + * the resulting string will be null-terminated. + * + * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1, + * but is different from some older and vendor implementations, + * and is also different from XPG, XSH5, SUSv2 specifications. + * For historical discussion on changes in the semantics and standards + * of snprintf see printf(3) man page in the Linux programmers manual. + * + * Routines asprintf and vasprintf return a pointer (in the ptr argument) + * to a buffer sufficiently large to hold the resulting string. This pointer + * should be passed to free(3) to release the allocated storage when it is + * no longer needed. If sufficient space cannot be allocated, these functions + * will return -1 and set ptr to be a NULL pointer. These two routines are a + * GNU C library extensions (glibc). + * + * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf, + * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1 + * characters into the allocated output string, the last character in the + * allocated buffer then gets the terminating null. If the formatted string + * length (the return value) is greater than or equal to the str_m argument, + * the resulting string was truncated and some of the formatted characters + * were discarded. These routines present a handy way to limit the amount + * of allocated memory to some sane value. + * + * AVAILABILITY + * http://www.ijs.si/software/snprintf/ + * + * REVISION HISTORY + * 1999-04 V0.9 Mark Martinec + * - initial version, some modifications after comparing printf + * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10, + * and checking how Perl handles sprintf (differently!); + * 1999-04-09 V1.0 Mark Martinec + * - added main test program, fixed remaining inconsistencies, + * added optional (long long int) support; + * 1999-04-12 V1.1 Mark Martinec + * - support the 'p' conversion (pointer to void); + * - if a string precision is specified + * make sure the string beyond the specified precision + * will not be referenced (e.g. by strlen); + * 1999-04-13 V1.2 Mark Martinec + * - support synonyms %D=%ld, %U=%lu, %O=%lo; + * - speed up the case of long format string with few conversions; + * 1999-06-30 V1.3 Mark Martinec + * - fixed runaway loop (eventually crashing when str_l wraps + * beyond 2^31) while copying format string without + * conversion specifiers to a buffer that is too short + * (thanks to Edwin Young for + * spotting the problem); + * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) + * to snprintf.h + * 2000-02-14 V2.0 (never released) Mark Martinec + * - relaxed license terms: The Artistic License now applies. + * You may still apply the GNU GENERAL PUBLIC LICENSE + * as was distributed with previous versions, if you prefer; + * - changed REVISION HISTORY dates to use ISO 8601 date format; + * - added vsnprintf (patch also independently proposed by + * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01) + * 2000-06-27 V2.1 Mark Martinec + * - removed POSIX check for str_m<1; value 0 for str_m is + * allowed by ISO C99 (and GNU C library 2.1) - (pointed out + * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie). + * Besides relaxed license this change in standards adherence + * is the main reason to bump up the major version number; + * - added nonstandard routines asnprintf, vasnprintf, asprintf, + * vasprintf that dynamically allocate storage for the + * resulting string; these routines are not compiled by default, + * see comments where NEED_V?ASN?PRINTF macros are defined; + * - autoconf contributed by Caolan McNamara + * 2000-10-06 V2.2 Mark Martinec + * - BUG FIX: the %c conversion used a temporary variable + * that was no longer in scope when referenced, + * possibly causing incorrect resulting character; + * - BUG FIX: make precision and minimal field width unsigned + * to handle huge values (2^31 <= n < 2^32) correctly; + * also be more careful in the use of signed/unsigned/size_t + * internal variables - probably more careful than many + * vendor implementations, but there may still be a case + * where huge values of str_m, precision or minimal field + * could cause incorrect behaviour; + * - use separate variables for signed/unsigned arguments, + * and for short/int, long, and long long argument lengths + * to avoid possible incompatibilities on certain + * computer architectures. Also use separate variable + * arg_sign to hold sign of a numeric argument, + * to make code more transparent; + * - some fiddling with zero padding and "0x" to make it + * Linux compatible; + * - systematically use macros fast_memcpy and fast_memset + * instead of case-by-case hand optimization; determine some + * breakeven string lengths for different architectures; + * - terminology change: 'format' -> 'conversion specifier', + * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")', + * 'alternative form' -> 'alternate form', + * 'data type modifier' -> 'length modifier'; + * - several comments rephrased and new ones added; + * - make compiler not complain about 'credits' defined but + * not used; + */ + + +/* Define HAVE_SNPRINTF if your system already has snprintf and vsnprintf. + * + * If HAVE_SNPRINTF is defined this module will not produce code for + * snprintf and vsnprintf, unless PREFER_PORTABLE_SNPRINTF is defined as well, + * causing this portable version of snprintf to be called portable_snprintf + * (and portable_vsnprintf). + */ +#define HAVE_SNPRINTF + +/* Define PREFER_PORTABLE_SNPRINTF if your system does have snprintf and + * vsnprintf but you would prefer to use the portable routine(s) instead. + * In this case the portable routine is declared as portable_snprintf + * (and portable_vsnprintf) and a macro 'snprintf' (and 'vsnprintf') + * is defined to expand to 'portable_v?snprintf' - see file snprintf.h . + * Defining this macro is only useful if HAVE_SNPRINTF is also defined, + * but does does no harm if defined nevertheless. + */ +#define PREFER_PORTABLE_SNPRINTF + +/* Define SNPRINTF_LONGLONG_SUPPORT if you want to support + * data type (long long int) and length modifier 'll' (e.g. %lld). + * If undefined, 'll' is recognized but treated as a single 'l'. + * + * If the system's sprintf does not handle 'll' + * the SNPRINTF_LONGLONG_SUPPORT must not be defined! + * + * This is off by default as (long long int) is a language extension. + */ +/* #define SNPRINTF_LONGLONG_SUPPORT */ + +/* Define NEED_SNPRINTF_ONLY if you only need snprintf, and not vsnprintf. + * If NEED_SNPRINTF_ONLY is defined, the snprintf will be defined directly, + * otherwise both snprintf and vsnprintf routines will be defined + * and snprintf will be a simple wrapper around vsnprintf, at the expense + * of an extra procedure call. + */ +/* #define NEED_SNPRINTF_ONLY */ + +/* Define NEED_V?ASN?PRINTF macros if you need library extension + * routines asprintf, vasprintf, asnprintf, vasnprintf respectively, + * and your system library does not provide them. They are all small + * wrapper routines around portable_vsnprintf. Defining any of the four + * NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY + * and turns on PREFER_PORTABLE_SNPRINTF. + * + * Watch for name conflicts with the system library if these routines + * are already present there. + * + * NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as + * specified by C99, to be able to traverse the same list of arguments twice. + * I don't know of any other standard and portable way of achieving the same. + * With some versions of gcc you may use __va_copy(). You might even get away + * with "ap2 = ap", in this case you must not call va_end(ap2) ! + * #define va_copy(ap2,ap) ap2 = ap + */ +/* #define NEED_ASPRINTF */ +/* #define NEED_ASNPRINTF */ +/* #define NEED_VASPRINTF */ +/* #define NEED_VASNPRINTF */ + + +/* Define the following macros if desired: + * SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE, + * HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE, + * DIGITAL_UNIX_COMPATIBLE, DIGITAL_UNIX_BUG_COMPATIBLE, + * PERL_COMPATIBLE, PERL_BUG_COMPATIBLE, + * + * - For portable applications it is best not to rely on peculiarities + * of a given implementation so it may be best not to define any + * of the macros that select compatibility and to avoid features + * that vary among the systems. + * + * - Selecting compatibility with more than one operating system + * is not strictly forbidden but is not recommended. + * + * - 'x'_BUG_COMPATIBLE implies 'x'_COMPATIBLE . + * + * - 'x'_COMPATIBLE refers to (and enables) a behaviour that is + * documented in a sprintf man page on a given operating system + * and actually adhered to by the system's sprintf (but not on + * most other operating systems). It may also refer to and enable + * a behaviour that is declared 'undefined' or 'implementation specific' + * in the man page but a given implementation behaves predictably + * in a certain way. + * + * - 'x'_BUG_COMPATIBLE refers to (and enables) a behaviour of system's sprintf + * that contradicts the sprintf man page on the same operating system. + * + * - I do not claim that the 'x'_COMPATIBLE and 'x'_BUG_COMPATIBLE + * conditionals take into account all idiosyncrasies of a particular + * implementation, there may be other incompatibilities. + */ + + + +/* ============================================= */ +/* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */ +/* ============================================= */ + +#define PORTABLE_SNPRINTF_VERSION_MAJOR 2 +#define PORTABLE_SNPRINTF_VERSION_MINOR 2 + +#if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) +# if defined(NEED_SNPRINTF_ONLY) +# undef NEED_SNPRINTF_ONLY +# endif +# if !defined(PREFER_PORTABLE_SNPRINTF) +# define PREFER_PORTABLE_SNPRINTF +# endif +#endif + +#if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) +#define SOLARIS_COMPATIBLE +#endif + +#if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) +#define HPUX_COMPATIBLE +#endif + +#if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) +#define DIGITAL_UNIX_COMPATIBLE +#endif + +#if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) +#define PERL_COMPATIBLE +#endif + +#if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) +#define LINUX_COMPATIBLE +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef isdigit +#undef isdigit +#endif +#define isdigit(c) ((c) >= '0' && (c) <= '9') + +/* For copying strings longer or equal to 'breakeven_point' + * it is more efficient to call memcpy() than to do it inline. + * The value depends mostly on the processor architecture, + * but also on the compiler and its optimization capabilities. + * The value is not critical, some small value greater than zero + * will be just fine if you don't care to squeeze every drop + * of performance out of the code. + * + * Small values favor memcpy, large values favor inline code. + */ +#if defined(__alpha__) || defined(__alpha) +# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */ +#endif +#if defined(__i386__) || defined(__i386) +# define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */ +#endif +#if defined(__hppa) +# define breakeven_point 10 /* HP-PA - gcc */ +#endif +#if defined(__sparc__) || defined(__sparc) +# define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ +#endif + +/* some other values of possible interest: */ +/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ +/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ + +#ifndef breakeven_point +# define breakeven_point 6 /* some reasonable one-size-fits-all value */ +#endif + +#define fast_memcpy(d,s,n) \ + { register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memcpy((d), (s), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const char *ss; \ + for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } + +#define fast_memset(d,c,n) \ + { register size_t nn = (size_t)(n); \ + if (nn >= breakeven_point) memset((d), (int)(c), nn); \ + else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ + register char *dd; register const int cc=(int)(c); \ + for (dd=(d); nn>0; nn--) *dd++ = cc; } } + +/* prototypes */ + +#if defined(NEED_ASPRINTF) +int asprintf (char **ptr, const char *fmt, /*args*/ ...); +#endif +#if defined(NEED_VASPRINTF) +int vasprintf (char **ptr, const char *fmt, va_list ap); +#endif +#if defined(NEED_ASNPRINTF) +int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); +#endif +#if defined(NEED_VASNPRINTF) +int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); +#endif + +#if defined(HAVE_SNPRINTF) +/* declare our portable snprintf routine under name portable_snprintf */ +/* declare our portable vsnprintf routine under name portable_vsnprintf */ +#else +/* declare our portable routines under names snprintf and vsnprintf */ +#define portable_snprintf snprintf +#if !defined(NEED_SNPRINTF_ONLY) +#define portable_vsnprintf vsnprintf +#endif +#endif + +#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); +#if !defined(NEED_SNPRINTF_ONLY) +int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); +#endif +#endif + +/* declarations */ + +static char credits[] = "\n\ +@(#)snprintf.c, v2.2: Mark Martinec, \n\ +@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\ +@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n"; + +#if defined(NEED_ASPRINTF) +int asprintf(char **ptr, const char *fmt, /*args*/ ...) { + va_list ap; + size_t str_m; + int str_l; + + *ptr = NULL; + va_start(ap, fmt); /* measure the required size */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); + va_end(ap); + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + *ptr = (char *) malloc(str_m = (size_t)str_l + 1); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2; + va_start(ap, fmt); + str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + va_end(ap); + assert(str_l2 == str_l); + } + return str_l; +} +#endif + +#if defined(NEED_VASPRINTF) +int vasprintf(char **ptr, const char *fmt, va_list ap) { + size_t str_m; + int str_l; + + *ptr = NULL; + { va_list ap2; + va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ + va_end(ap2); + } + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + *ptr = (char *) malloc(str_m = (size_t)str_l + 1); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + assert(str_l2 == str_l); + } + return str_l; +} +#endif + +#if defined(NEED_ASNPRINTF) +int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { + va_list ap; + int str_l; + + *ptr = NULL; + va_start(ap, fmt); /* measure the required size */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); + va_end(ap); + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ + /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ + if (str_m == 0) { /* not interested in resulting string, just return size */ + } else { + *ptr = (char *) malloc(str_m); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2; + va_start(ap, fmt); + str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + va_end(ap); + assert(str_l2 == str_l); + } + } + return str_l; +} +#endif + +#if defined(NEED_VASNPRINTF) +int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) { + int str_l; + + *ptr = NULL; + { va_list ap2; + va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ + str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ + va_end(ap2); + } + assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ + if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ + /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ + if (str_m == 0) { /* not interested in resulting string, just return size */ + } else { + *ptr = (char *) malloc(str_m); + if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } + else { + int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); + assert(str_l2 == str_l); + } + } + return str_l; +} +#endif + +/* + * If the system does have snprintf and the portable routine is not + * specifically required, this module produces no code for snprintf/vsnprintf. + */ +#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) + +#if !defined(NEED_SNPRINTF_ONLY) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { + va_list ap; + int str_l; + + va_start(ap, fmt); + str_l = portable_vsnprintf(str, str_m, fmt, ap); + va_end(ap); + return str_l; +} +#endif + +#if defined(NEED_SNPRINTF_ONLY) +int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { +#else +int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { +#endif + +#if defined(NEED_SNPRINTF_ONLY) + va_list ap; +#endif + size_t str_l = 0; + const char *p = fmt; + +/* In contrast with POSIX, the ISO C99 now says + * that str can be NULL and str_m can be 0. + * This is more useful than the old: if (str_m < 1) return -1; */ + +#if defined(NEED_SNPRINTF_ONLY) + va_start(ap, fmt); +#endif + if (!p) p = ""; + while (*p) { + if (*p != '%') { + /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */ + /* but the following code achieves better performance for cases + * where format string is long and contains few conversions */ + const char *q = strchr(p+1,'%'); + size_t n = !q ? strlen(p) : (q-p); + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, p, (n>avail?avail:n)); + } + p += n; str_l += n; + } else { + const char *starting_p; + size_t min_field_width = 0, precision = 0; + int zero_padding = 0, precision_specified = 0, justify_left = 0; + int alternate_form = 0, force_sign = 0; + int space_for_positive = 1; /* If both the ' ' and '+' flags appear, + the ' ' flag should be ignored. */ + char length_modifier = '\0'; /* allowed values: \0, h, l, L */ + char tmp[32];/* temporary buffer for simple numeric->string conversion */ + + const char *str_arg; /* string address in case of string argument */ + size_t str_arg_l; /* natural field width of arg without padding + and sign */ + unsigned char uchar_arg; + /* unsigned char argument value - only defined for c conversion. + N.B. standard explicitly states the char argument for + the c conversion is unsigned */ + + size_t number_of_zeros_to_pad = 0; + /* number of zeros to be inserted for numeric conversions + as required by the precision or minimal field width */ + + size_t zero_padding_insertion_ind = 0; + /* index into tmp where zero padding is to be inserted */ + + char fmt_spec = '\0'; + /* current conversion specifier character */ + + str_arg = credits;/* just to make compiler happy (defined but not used)*/ + str_arg = NULL; + starting_p = p; p++; /* skip '%' */ + /* parse flags */ + while (*p == '0' || *p == '-' || *p == '+' || + *p == ' ' || *p == '#' || *p == '\'') { + switch (*p) { + case '0': zero_padding = 1; break; + case '-': justify_left = 1; break; + case '+': force_sign = 1; space_for_positive = 0; break; + case ' ': force_sign = 1; + /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ +#ifdef PERL_COMPATIBLE + /* ... but in Perl the last of ' ' and '+' applies */ + space_for_positive = 1; +#endif + break; + case '#': alternate_form = 1; break; + case '\'': break; + } + p++; + } + /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */ + + /* parse field width */ + if (*p == '*') { + int j; + p++; j = va_arg(ap, int); + if (j >= 0) min_field_width = j; + else { min_field_width = -j; justify_left = 1; } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + min_field_width = uj; + } + /* parse precision */ + if (*p == '.') { + p++; precision_specified = 1; + if (*p == '*') { + int j = va_arg(ap, int); + p++; + if (j >= 0) precision = j; + else { + precision_specified = 0; precision = 0; + /* NOTE: + * Solaris 2.6 man page claims that in this case the precision + * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page + * claim that this case should be treated as unspecified precision, + * which is what we do here. + */ + } + } else if (isdigit((int)(*p))) { + /* size_t could be wider than unsigned int; + make sure we treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); + precision = uj; + } + } + /* parse 'h', 'l' and 'll' length modifiers */ + if (*p == 'h' || *p == 'l') { + length_modifier = *p; p++; + if (length_modifier == 'l' && *p == 'l') { /* double l = long long */ +#ifdef SNPRINTF_LONGLONG_SUPPORT + length_modifier = '2'; /* double l encoded as '2' */ +#else + length_modifier = 'l'; /* treat it as a single 'l' */ +#endif + p++; + } + } + fmt_spec = *p; + /* common synonyms: */ + switch (fmt_spec) { + case 'i': fmt_spec = 'd'; break; + case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + default: break; + } + /* get parameter value, do initial processing */ + switch (fmt_spec) { + case '%': /* % behaves similar to 's' regarding flags and field widths */ + case 'c': /* c behaves similar to 's' regarding flags and field widths */ + case 's': + length_modifier = '\0'; /* wint_t and wchar_t not supported */ + /* the result of zero padding flag with non-numeric conversion specifier*/ + /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ + /* Digital Unix and Linux does not. */ +#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) + zero_padding = 0; /* turn zero padding off for string conversions */ +#endif + str_arg_l = 1; + switch (fmt_spec) { + case '%': + str_arg = p; break; + case 'c': { + int j = va_arg(ap, int); + uchar_arg = (unsigned char) j; /* standard demands unsigned char */ + str_arg = (const char *) &uchar_arg; + break; + } + case 's': + str_arg = va_arg(ap, const char *); + if (!str_arg) str_arg_l = 0; + /* make sure not to address string beyond the specified precision !!! */ + else if (!precision_specified) str_arg_l = strlen(str_arg); + /* truncate string if necessary as requested by precision */ + else if (precision == 0) str_arg_l = 0; + else { + /* memchr on HP does not like n > 2^31 !!! */ + const char *q = memchr(str_arg, '\0', + precision <= 0x7fffffff ? precision : 0x7fffffff); + str_arg_l = !q ? precision : (q-str_arg); + } + break; + default: break; + } + break; + case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { + /* NOTE: the u, o, x, X and p conversion specifiers imply + the value is unsigned; d implies a signed value */ + + int arg_sign = 0; + /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), + +1 if greater than zero (or nonzero for unsigned arguments), + -1 if negative (unsigned argument is never negative) */ + + int int_arg = 0; unsigned int uint_arg = 0; + /* only defined for length modifier h, or for no length modifiers */ + + long int long_arg = 0; unsigned long int ulong_arg = 0; + /* only defined for length modifier l */ + + void *ptr_arg = NULL; + /* pointer argument value -only defined for p conversion */ + +#ifdef SNPRINTF_LONGLONG_SUPPORT + long long int long_long_arg = 0; + unsigned long long int ulong_long_arg = 0; + /* only defined for length modifier ll */ +#endif + if (fmt_spec == 'p') { + /* HPUX 10: An l, h, ll or L before any other conversion character + * (other than d, i, u, o, x, or X) is ignored. + * Digital Unix: + * not specified, but seems to behave as HPUX does. + * Solaris: If an h, l, or L appears before any other conversion + * specifier (other than d, i, u, o, x, or X), the behavior + * is undefined. (Actually %hp converts only 16-bits of address + * and %llp treats address as 64-bit data which is incompatible + * with (void *) argument on a 32-bit system). + */ +#ifdef SOLARIS_COMPATIBLE +# ifdef SOLARIS_BUG_COMPATIBLE + /* keep length modifiers even if it represents 'll' */ +# else + if (length_modifier == '2') length_modifier = '\0'; +# endif +#else + length_modifier = '\0'; +#endif + ptr_arg = va_arg(ap, void *); + if (ptr_arg != NULL) arg_sign = 1; + } else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': + /* It is non-portable to specify a second argument of char or short + * to va_arg, because arguments seen by the called function + * are not char or short. C converts char and short arguments + * to int before passing them to a function. + */ + int_arg = va_arg(ap, int); + if (int_arg > 0) arg_sign = 1; + else if (int_arg < 0) arg_sign = -1; + break; + case 'l': + long_arg = va_arg(ap, long int); + if (long_arg > 0) arg_sign = 1; + else if (long_arg < 0) arg_sign = -1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + long_long_arg = va_arg(ap, long long int); + if (long_long_arg > 0) arg_sign = 1; + else if (long_long_arg < 0) arg_sign = -1; + break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': + uint_arg = va_arg(ap, unsigned int); + if (uint_arg) arg_sign = 1; + break; + case 'l': + ulong_arg = va_arg(ap, unsigned long int); + if (ulong_arg) arg_sign = 1; + break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': + ulong_long_arg = va_arg(ap, unsigned long long int); + if (ulong_long_arg) arg_sign = 1; + break; +#endif + } + } + str_arg = tmp; str_arg_l = 0; + /* NOTE: + * For d, i, u, o, x, and X conversions, if precision is specified, + * the '0' flag should be ignored. This is so with Solaris 2.6, + * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. + */ +#ifndef PERL_COMPATIBLE + if (precision_specified) zero_padding = 0; +#endif + if (fmt_spec == 'd') { + if (force_sign && arg_sign >= 0) + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; + /* leave negative numbers for sprintf to handle, + to avoid handling tricky cases like (short int)(-32768) */ +#ifdef LINUX_COMPATIBLE + } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; +#endif + } else if (alternate_form) { + if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) + { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } + /* alternate form should have no effect for p conversion, but ... */ +#ifdef HPUX_COMPATIBLE + else if (fmt_spec == 'p' + /* HPUX 10: for an alternate form of p conversion, + * a nonzero result is prefixed by 0x. */ +#ifndef HPUX_BUG_COMPATIBLE + /* Actually it uses 0x prefix even for a zero value. */ + && arg_sign != 0 +#endif + ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } +#endif + } + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) precision = 1; /* default precision is 1 */ + if (precision == 0 && arg_sign == 0 +#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) + && fmt_spec != 'p' + /* HPUX 10 man page claims: With conversion character p the result of + * converting a zero value with a precision of zero is a null string. + * Actually HP returns all zeroes, and Linux returns "(nil)". */ +#endif + ) { + /* converted to null string */ + /* When zero value is formatted with an explicit precision 0, + the resulting formatted string is empty (d, i, u, o, x, X, p). */ + } else { + char f[5]; int f_l = 0; + f[f_l++] = '%'; /* construct a simple format string for sprintf */ + if (!length_modifier) { } + else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } + else f[f_l++] = length_modifier; + f[f_l++] = fmt_spec; f[f_l++] = '\0'; + if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg); + else if (fmt_spec == 'd') { /* signed */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break; +#endif + } + } else { /* unsigned */ + switch (length_modifier) { + case '\0': + case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break; + case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break; +#ifdef SNPRINTF_LONGLONG_SUPPORT + case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; +#endif + } + } + /* include the optional minus sign and possible "0x" + in the region before the zero padding insertion point */ + if (zero_padding_insertion_ind < str_arg_l && + tmp[zero_padding_insertion_ind] == '-') { + zero_padding_insertion_ind++; + } + if (zero_padding_insertion_ind+1 < str_arg_l && + tmp[zero_padding_insertion_ind] == '0' && + (tmp[zero_padding_insertion_ind+1] == 'x' || + tmp[zero_padding_insertion_ind+1] == 'X') ) { + zero_padding_insertion_ind += 2; + } + } + { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; + if (alternate_form && fmt_spec == 'o' +#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ + && (str_arg_l > 0) +#endif +#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ +#else + /* unless zero is already the first character */ + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0') +#endif + ) { /* assure leading zero for alternate-form octal numbers */ + if (!precision_specified || precision < num_of_digits+1) { + /* precision is increased to force the first character to be zero, + except if a zero value is formatted with an explicit precision + of zero */ + precision = num_of_digits+1; precision_specified = 1; + } + } + /* zero padding to specified precision? */ + if (num_of_digits < precision) + number_of_zeros_to_pad = precision - num_of_digits; + } + /* zero padding to specified minimal field width? */ + if (!justify_left && zero_padding) { + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) number_of_zeros_to_pad += n; + } + break; + } + default: /* unrecognized conversion specifier, keep format string as-is*/ + zero_padding = 0; /* turn zero padding off for non-numeric convers. */ +#ifndef DIGITAL_UNIX_COMPATIBLE + justify_left = 1; min_field_width = 0; /* reset flags */ +#endif +#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) + /* keep the entire format string unchanged */ + str_arg = starting_p; str_arg_l = p - starting_p; + /* well, not exactly so for Linux, which does something inbetween, + * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ +#else + /* discard the unrecognized conversion, just keep * + * the unrecognized conversion character */ + str_arg = p; str_arg_l = 0; +#endif + if (*p) str_arg_l++; /* include invalid conversion specifier unchanged + if not at end-of-string */ + break; + } + if (*p) p++; /* step over the just processed conversion specifier */ + /* insert padding to the left as requested by min_field_width; + this does not include the zero padding in case of numerical conversions*/ + if (!justify_left) { /* left padding with blank or zero */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n)); + } + str_l += n; + } + } + /* zero padding as requested by the precision or by the minimal field width + * for numeric conversions required? */ + if (number_of_zeros_to_pad <= 0) { + /* will not copy first part of numeric right now, * + * force it to be copied later in its entirety */ + zero_padding_insertion_ind = 0; + } else { + /* insert first part of numerics (sign or '0x') before zero padding */ + int n = zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg, (n>avail?avail:n)); + } + str_l += n; + } + /* insert zero padding as requested by the precision or min field width */ + n = number_of_zeros_to_pad; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, '0', (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert formatted string + * (or as-is conversion specifier for unknown conversions) */ + { int n = str_arg_l - zero_padding_insertion_ind; + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, + (n>avail?avail:n)); + } + str_l += n; + } + } + /* insert right padding */ + if (justify_left) { /* right blank padding to the field width */ + int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); + if (n > 0) { + if (str_l < str_m) { + size_t avail = str_m-str_l; + fast_memset(str+str_l, ' ', (n>avail?avail:n)); + } + str_l += n; + } + } + } + } +#if defined(NEED_SNPRINTF_ONLY) + va_end(ap); +#endif + if (str_m > 0) { /* make sure the string is null-terminated + even at the expense of overwriting the last character + (shouldn't happen, but just in case) */ + str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; + } + /* Return the number of characters formatted (excluding trailing null + * character), that is, the number of characters that would have been + * written to the buffer if it were large enough. + * + * The value of str_l should be returned, but str_l is of unsigned type + * size_t, and snprintf is int, possibly leading to an undetected + * integer overflow, resulting in a negative return value, which is illegal. + * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. + * Should errno be set to EOVERFLOW and EOF returned in this case??? + */ + return (int) str_l; +} +#endif diff --git a/app/jni/snprintf.h b/app/jni/snprintf.h new file mode 100644 index 0000000..3fd85d4 --- /dev/null +++ b/app/jni/snprintf.h @@ -0,0 +1,26 @@ +#ifndef _PORTABLE_SNPRINTF_H_ +#define _PORTABLE_SNPRINTF_H_ + +#define PORTABLE_SNPRINTF_VERSION_MAJOR 2 +#define PORTABLE_SNPRINTF_VERSION_MINOR 2 + +#ifdef HAVE_SNPRINTF +#include +#else +extern int snprintf(char *, size_t, const char *, /*args*/ ...); +extern int vsnprintf(char *, size_t, const char *, va_list); +#endif + +#if defined(HAVE_SNPRINTF) && defined(PREFER_PORTABLE_SNPRINTF) +extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); +extern int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); +//#define snprintf portable_snprintf +//#define vsnprintf portable_vsnprintf +#endif + +extern int asprintf (char **ptr, const char *fmt, /*args*/ ...); +extern int vasprintf (char **ptr, const char *fmt, va_list ap); +extern int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); +extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap); + +#endif diff --git a/app/jni/sound.h b/app/jni/sound.h new file mode 100644 index 0000000..512ae9c --- /dev/null +++ b/app/jni/sound.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. + +*/ + +#ifndef SOUND_H +#define SOUND_H + +#include "matrixlib.h" + + +// ==================================================================== +// Constants +// ==================================================================== + +#define DEFAULT_SOUND_PACKET_VOLUME 255 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +// Channel flags +// These channel flags can be used for sound() builtins, with SOUNDFLAG_* names +#define CHANNELFLAG_NONE 0 +#define CHANNELFLAG_RELIABLE (1 << 0) // send as reliable message (only used on server) +#define CHANNELFLAG_FORCELOOP (1 << 1) // force looping even if the sound is not looped +#define CHANNELFLAG_LOCALSOUND (1 << 2) // INTERNAL USE. Not settable by S_SetChannelFlag +#define CHANNELFLAG_PAUSED (1 << 3) // pause status +#define CHANNELFLAG_FULLVOLUME (1 << 4) // isn't affected by the general volume + +// ==================================================================== +// Types and variables +// ==================================================================== + +typedef struct sfx_s sfx_t; + +extern cvar_t mastervolume; +extern cvar_t bgmvolume; +extern cvar_t volume; +extern cvar_t snd_initialized; +extern cvar_t snd_staticvolume; +extern cvar_t snd_mutewhenidle; + + +// ==================================================================== +// Functions +// ==================================================================== + +void S_Init (void); +void S_Terminate (void); + +void S_Startup (void); +void S_Shutdown (void); +void S_UnloadAllSounds_f (void); + +void S_Update(const matrix4x4_t *listenermatrix); +void S_ExtraUpdate (void); + +sfx_t *S_PrecacheSound (const char *sample, qboolean complain, qboolean levelsound); +float S_SoundLength(const char *name); +void S_ClearUsed (void); +void S_PurgeUnused (void); +qboolean S_IsSoundPrecached (const sfx_t *sfx); +sfx_t *S_FindName(const char *name); + +// these define the "engine" channel namespace +#define CHAN_MIN_AUTO -128 +#define CHAN_MAX_AUTO 0 +#define CHAN_MIN_SINGLE 1 +#define CHAN_MAX_SINGLE 127 +#define IS_CHAN_AUTO(n) ((n) >= CHAN_MIN_AUTO && (n) <= CHAN_MAX_AUTO) +#define IS_CHAN_SINGLE(n) ((n) >= CHAN_MIN_SINGLE && (n) <= CHAN_MAX_SINGLE) +#define IS_CHAN(n) (IS_CHAN_AUTO(n) || IS_CHAN_SINGLE(n)) + +// engine channel == network channel +#define CHAN_ENGINE2NET(c) (c) +#define CHAN_NET2ENGINE(c) (c) + +// engine view of channel encodes the auto flag into the channel number (see CHAN_ constants below) +// user view uses the flags bitmask for it +#define CHAN_USER2ENGINE(c) (c) +#define CHAN_ENGINE2USER(c) (c) +#define CHAN_ENGINE2CVAR(c) (abs(c)) + +// S_StartSound returns the channel index, or -1 if an error occurred +int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); +int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition, int flags, float fspeed); +qboolean S_LocalSound (const char *s); + +void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation); +void S_StopSound (int entnum, int entchannel); +void S_StopAllSounds (void); +void S_PauseGameSounds (qboolean toggle); + +void S_StopChannel (unsigned int channel_ind, qboolean lockmutex, qboolean freesfx); +qboolean S_SetChannelFlag (unsigned int ch_ind, unsigned int flag, qboolean value); +void S_SetChannelVolume (unsigned int ch_ind, float fvol); +void S_SetChannelSpeed (unsigned int ch_ind, float fspeed); +float S_GetChannelPosition (unsigned int ch_ind); +float S_GetEntChannelPosition(int entnum, int entchannel); + +void S_BlockSound (void); +void S_UnblockSound (void); + +int S_GetSoundRate (void); +int S_GetSoundChannels (void); + +#endif diff --git a/app/jni/spritegn.h b/app/jni/spritegn.h new file mode 100644 index 0000000..b2d2e3b --- /dev/null +++ b/app/jni/spritegn.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. + +*/ +// +// 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. * +// ********************************************************** + +#ifndef SPRITEGEN_H +#define SPRITEGEN_H + +//------------------------------------------------------- +// 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 +// +//------------------------------------------------------- + +#define SPRITE_VERSION 1 +#define SPRITEHL_VERSION 2 +#define SPRITE32_VERSION 32 + +#define SPRITE2_VERSION 2 + +typedef struct dsprite_s +{ + int ident; + int version; + int type; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +typedef struct dspritehl_s +{ + int ident; + int version; + int type; + int rendermode; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dspritehl_t; + +typedef struct dsprite2frame_s +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[64]; // name of pcx file +} dsprite2frame_t; + +typedef struct dsprite2_s +{ + int ident; + int version; + int numframes; + dsprite2frame_t frames[1]; // variable sized +} dsprite2_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 +#define SPR_LABEL 5 +#define SPR_LABEL_SCALE 6 +#define SPR_OVERHEAD 7 + +#define SPRHL_OPAQUE 0 +#define SPRHL_ADDITIVE 1 +#define SPRHL_INDEXALPHA 2 +#define SPRHL_ALPHATEST 3 + +typedef struct dspriteframe_s { + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct dspritegroup_s { + int numframes; +} dspritegroup_t; + +typedef struct dspriteinterval_s { + float interval; +} dspriteinterval_t; + +typedef enum spriteframetype_e { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; + +typedef struct dspriteframetype_s { + spriteframetype_t type; +} dspriteframetype_t; + +#endif + diff --git a/app/jni/sv_demo.c b/app/jni/sv_demo.c new file mode 100644 index 0000000..cc94a2c --- /dev/null +++ b/app/jni/sv_demo.c @@ -0,0 +1,99 @@ +#include "quakedef.h" +#include "sv_demo.h" + +extern cvar_t sv_autodemo_perclient_discardable; + +void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrack) +{ + prvm_prog_t *prog = SVVM_prog; + char name[MAX_QPATH]; + + if(client->sv_demo_file != NULL) + return; // we already have a demo + + strlcpy(name, filename, sizeof(name)); + FS_DefaultExtension(name, ".dem", sizeof(name)); + + Con_Printf("Recording demo for # %d (%s) to %s\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress, name); + + // Reset discardable flag for every new demo. + PRVM_serveredictfloat(client->edict, discardabledemo) = 0; + + client->sv_demo_file = FS_OpenRealFile(name, "wb", false); + if(!client->sv_demo_file) + { + Con_Print("ERROR: couldn't open.\n"); + return; + } + + FS_Printf(client->sv_demo_file, "%i\n", forcetrack); +} + +void SV_WriteDemoMessage(client_t *client, sizebuf_t *sendbuffer, qboolean clienttoserver) +{ + prvm_prog_t *prog = SVVM_prog; + int len, i; + float f; + int temp; + + if(client->sv_demo_file == NULL) + return; + if(sendbuffer->cursize == 0) + return; + + temp = sendbuffer->cursize | (clienttoserver ? DEMOMSG_CLIENT_TO_SERVER : 0); + len = LittleLong(temp); + FS_Write(client->sv_demo_file, &len, 4); + for(i = 0; i < 3; ++i) + { + f = LittleFloat(PRVM_serveredictvector(client->edict, v_angle)[i]); + FS_Write(client->sv_demo_file, &f, 4); + } + FS_Write(client->sv_demo_file, sendbuffer->data, sendbuffer->cursize); +} + +void SV_StopDemoRecording(client_t *client) +{ + prvm_prog_t *prog = SVVM_prog; + sizebuf_t buf; + unsigned char bufdata[64]; + + if(client->sv_demo_file == NULL) + return; + + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + SZ_Clear(&buf); + MSG_WriteByte(&buf, svc_disconnect); + SV_WriteDemoMessage(client, &buf, false); + + if (sv_autodemo_perclient_discardable.integer && PRVM_serveredictfloat(client->edict, discardabledemo)) + { + FS_RemoveOnClose(client->sv_demo_file); + Con_Printf("Stopped recording discardable demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress); + } + else + Con_Printf("Stopped recording demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress); + + FS_Close(client->sv_demo_file); + client->sv_demo_file = NULL; +} + +void SV_WriteNetnameIntoDemo(client_t *client) +{ + // This "pseudo packet" is written so a program can easily find out whose demo this is + sizebuf_t buf; + unsigned char bufdata[128]; + + if(client->sv_demo_file == NULL) + return; + + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + SZ_Clear(&buf); + MSG_WriteByte(&buf, svc_stufftext); + MSG_WriteUnterminatedString(&buf, "\n// this demo contains the point of view of: "); + MSG_WriteUnterminatedString(&buf, client->name); + MSG_WriteString(&buf, "\n"); + SV_WriteDemoMessage(client, &buf, false); +} diff --git a/app/jni/sv_demo.h b/app/jni/sv_demo.h new file mode 100644 index 0000000..65c1924 --- /dev/null +++ b/app/jni/sv_demo.h @@ -0,0 +1,9 @@ +#ifndef SV_DEMO_H +#define SV_DEMO_H + +void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrack); +void SV_WriteDemoMessage(client_t *client, sizebuf_t *sendbuffer, qboolean clienttoserver); +void SV_StopDemoRecording(client_t *client); +void SV_WriteNetnameIntoDemo(client_t *client); + +#endif diff --git a/app/jni/sv_main.c b/app/jni/sv_main.c new file mode 100644 index 0000000..6b7973c --- /dev/null +++ b/app/jni/sv_main.c @@ -0,0 +1,4033 @@ +/* +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" +#include "sv_demo.h" +#include "libcurl.h" +#include "csprogs.h" +#include "thread.h" + +static void SV_SaveEntFile_f(void); +static void SV_StartDownload_f(void); +static void SV_Download_f(void); +static void SV_VM_Setup(void); +extern cvar_t net_connecttimeout; + +cvar_t sv_worldmessage = {CVAR_READONLY, "sv_worldmessage", "", "title of current level"}; +cvar_t sv_worldname = {CVAR_READONLY, "sv_worldname", "", "name of current worldmodel"}; +cvar_t sv_worldnamenoextension = {CVAR_READONLY, "sv_worldnamenoextension", "", "name of current worldmodel without extension"}; +cvar_t sv_worldbasename = {CVAR_READONLY, "sv_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; + +cvar_t sv_disablenotify = {0, "sv_disablenotify", "1", "suppress broadcast prints when certain cvars are changed (CVAR_NOTIFY flag in engine code)"}; +cvar_t coop = {0, "coop","0", "coop mode, 0 = no coop, 1 = coop mode, multiple players playing through the singleplayer game (coop mode also shuts off deathmatch)"}; +cvar_t deathmatch = {0, "deathmatch","0", "deathmatch mode, values depend on mod but typically 0 = no deathmatch, 1 = normal deathmatch with respawning weapons, 2 = weapons stay (players can only pick up new weapons)"}; +cvar_t fraglimit = {CVAR_NOTIFY, "fraglimit","0", "ends level if this many frags is reached by any player"}; +cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"}; +cvar_t noexit = {CVAR_NOTIFY, "noexit","0", "kills anyone attempting to use an exit"}; +cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"}; +cvar_t pausable = {0, "pausable","1", "allow players to pause or not (otherwise, only the server admin can)"}; +cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"}; +cvar_t samelevel = {CVAR_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"}; +cvar_t skill = {0, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"}; +cvar_t slowmo = {0, "slowmo", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"}; + +cvar_t sv_accelerate = {0, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"}; +cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"}; +cvar_t sv_airaccel_qw = {0, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration; when < 0, the speed is clamped against the maximum allowed forward speed after the move"}; +cvar_t sv_airaccel_qw_stretchfactor = {0, "sv_airaccel_qw_stretchfactor", "0", "when set, the maximum acceleration increase the player may get compared to forward-acceleration when strafejumping"}; +cvar_t sv_airaccel_sideways_friction = {0, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging); when < 0, only so much friction is applied that braking (by accelerating backwards) cannot be stronger"}; +cvar_t sv_airaccelerate = {0, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"}; +cvar_t sv_airstopaccelerate = {0, "sv_airstopaccelerate", "0", "when set, replacement for sv_airaccelerate when moving backwards"}; +cvar_t sv_airspeedlimit_nonqw = {0, "sv_airspeedlimit_nonqw", "0", "when set, this is a soft speed limit while in air when using airaccel_qw not equal to 1"}; +cvar_t sv_airstrafeaccelerate = {0, "sv_airstrafeaccelerate", "0", "when set, replacement for sv_airaccelerate when just strafing"}; +cvar_t sv_maxairstrafespeed = {0, "sv_maxairstrafespeed", "0", "when set, replacement for sv_maxairspeed when just strafing"}; +cvar_t sv_airstrafeaccel_qw = {0, "sv_airstrafeaccel_qw", "0", "when set, replacement for sv_airaccel_qw when just strafing"}; +cvar_t sv_aircontrol = {0, "sv_aircontrol", "0", "CPMA-style air control"}; +cvar_t sv_aircontrol_power = {0, "sv_aircontrol_power", "2", "CPMA-style air control exponent"}; +cvar_t sv_aircontrol_penalty = {0, "sv_aircontrol_penalty", "0", "deceleration while using CPMA-style air control"}; +cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"}; +cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"}; +cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"}; +cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"}; +cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"}; +cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "128", "minimum areagrid cell size, smaller values work better for lots of small objects, higher values for large objects"}; +cvar_t sv_checkforpacketsduringsleep = {0, "sv_checkforpacketsduringsleep", "0", "uses select() function to wait between frames which can be interrupted by packets being received, instead of Sleep()/usleep()/SDL_Sleep() functions which do not check for packets"}; +cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"}; +cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"}; +cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"}; +cvar_t sv_clmovement_inputtimeout = {0, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"}; +cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"}; +cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; +cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"}; +cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; +cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"}; +cvar_t sv_cullentities_trace_delay_players = {0, "sv_cullentities_trace_delay_players", "0.2", "number of seconds until the entity gets actually culled if it is a player entity"}; +cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"}; +cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"}; +cvar_t sv_cullentities_trace_prediction_time = {0, "sv_cullentities_trace_prediction_time", "0.2", "how many seconds of prediction to use"}; +cvar_t sv_cullentities_trace_entityocclusion = {0, "sv_cullentities_trace_entityocclusion", "0", "also check if doors and other bsp models are in the way"}; +cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "2", "number of samples to test for entity culling"}; +cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"}; +cvar_t sv_cullentities_trace_samples_players = {0, "sv_cullentities_trace_samples_players", "8", "number of samples to test for entity culling when the entity is a player entity"}; +cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"}; +cvar_t sv_echobprint = {CVAR_SAVE, "sv_echobprint", "1", "prints gamecode bprint() calls to server console"}; +cvar_t sv_edgefriction = {0, "edgefriction", "1", "how much you slow down when nearing a ledge you might fall off, multiplier of sv_friction (Quake used 2, QuakeWorld used 1 due to a bug in physics code)"}; +cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"}; +cvar_t sv_fixedframeratesingleplayer = {0, "sv_fixedframeratesingleplayer", "1", "allows you to use server-style timing system in singleplayer (don't run faster than sys_ticrate)"}; +cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"}; +cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"}; +cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"}; +cvar_t sv_gameplayfix_consistentplayerprethink = {0, "sv_gameplayfix_consistentplayerprethink", "0", "improves fairness in multiplayer by running all PlayerPreThink functions (which fire weapons) before performing physics, then running all PlayerPostThink functions"}; +cvar_t sv_gameplayfix_delayprojectiles = {0, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"}; +cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"}; +cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {0, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"}; +cvar_t sv_gameplayfix_easierwaterjump = {0, "sv_gameplayfix_easierwaterjump", "1", "changes water jumping to make it easier to get out of water (exactly like in QuakeWorld)"}; +cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"}; +cvar_t sv_gameplayfix_gravityunaffectedbyticrate = {0, "sv_gameplayfix_gravityunaffectedbyticrate", "0", "fix some ticrate issues in physics."}; +cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"}; +cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"}; +cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"}; +cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {0, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"}; +cvar_t sv_gameplayfix_nudgeoutofsolid = {0, "sv_gameplayfix_nudgeoutofsolid", "0", "attempts to fix physics errors (where an object ended up in solid for some reason)"}; +cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {0, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"}; +cvar_t sv_gameplayfix_q2airaccelerate = {0, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"}; +cvar_t sv_gameplayfix_nogravityonground = {0, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"}; +cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"}; +cvar_t sv_gameplayfix_slidemoveprojectiles = {0, "sv_gameplayfix_slidemoveprojectiles", "1", "allows MOVETYPE_FLY/FLYMISSILE/TOSS/BOUNCE/BOUNCEMISSILE entities to finish their move in a frame even if they hit something, fixes 'gravity accumulation' bug for grenades on steep slopes"}; +cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"}; +cvar_t sv_gameplayfix_stepmultipletimes = {0, "sv_gameplayfix_stepmultipletimes", "0", "applies step-up onto a ledge more than once in a single frame, when running quickly up stairs"}; +cvar_t sv_gameplayfix_nostepmoveonsteepslopes = {0, "sv_gameplayfix_nostepmoveonsteepslopes", "0", "crude fix which prevents MOVETYPE_STEP (not swimming or flying) to move on slopes whose angle is bigger than 45 degree"}; +cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"}; +cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"}; +cvar_t sv_gameplayfix_downtracesupportsongroundflag = {0, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps)"}; +cvar_t sv_gameplayfix_q1bsptracelinereportstexture = {0, "sv_gameplayfix_q1bsptracelinereportstexture", "1", "enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately"}; +cvar_t sv_gameplayfix_unstickplayers = {0, "sv_gameplayfix_unstickplayers", "1", "big hack to try and fix the rare case of MOVETYPE_WALK entities getting stuck in the world clipping hull."}; +cvar_t sv_gameplayfix_unstickentities = {0, "sv_gameplayfix_unstickentities", "1", "hack to check if entities are crossing world collision hull and try to move them to the right position"}; +cvar_t sv_gameplayfix_fixedcheckwatertransition = {0, "sv_gameplayfix_fixedcheckwatertransition", "1", "fix two very stupid bugs in SV_CheckWaterTransition when watertype is CONTENTS_EMPTY (the bugs causes waterlevel to be 1 on first frame, -1 on second frame - the fix makes it 0 on both frames)"}; +cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"}; +cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"}; +cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping"}; +cvar_t sv_jumpvelocity = {0, "sv_jumpvelocity", "270", "cvar that can be used by QuakeC code for jump velocity"}; +cvar_t sv_maxairspeed = {0, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"}; +cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "1000000", "upper limit on client rate cvar, should reflect your network connection quality"}; +cvar_t sv_maxspeed = {CVAR_NOTIFY, "sv_maxspeed", "320", "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)"}; +cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"}; +cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"}; +cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"}; +cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" }; +cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"}; +cvar_t sv_random_seed = {0, "sv_random_seed", "", "random seed; when set, on every map start this random seed is used to initialize the random number generator. Don't touch it unless for benchmarking or debugging"}; +cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"}; +cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"}; +cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"}; +cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"}; +cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"}; +cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"}; +cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"}; +cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"}; +cvar_t sv_warsowbunny_airforwardaccel = {0, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"}; +cvar_t sv_warsowbunny_accel = {0, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"}; +cvar_t sv_warsowbunny_topspeed = {0, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"}; +cvar_t sv_warsowbunny_turnaccel = {0, "sv_warsowbunny_turnaccel", "0", "max sharpness of turns (also master switch for the sv_warsowbunny_* mode; set this to 9 to enable)"}; +cvar_t sv_warsowbunny_backtosideratio = {0, "sv_warsowbunny_backtosideratio", "0.8", "lower values make it easier to change direction without losing speed; the drawback is \"understeering\" in sharp turns"}; +cvar_t sv_onlycsqcnetworking = {0, "sv_onlycsqcnetworking", "0", "disables legacy entity networking code for higher performance (except on clients, which can still be legacy)"}; +cvar_t sv_areadebug = {0, "sv_areadebug", "0", "disables physics culling for debugging purposes (only for development)"}; +cvar_t sys_ticrate = {CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"}; +cvar_t teamplay = {CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"}; +cvar_t timelimit = {CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"}; +cvar_t sv_threaded = {0, "sv_threaded", "0", "enables a separate thread for server code, improving performance, especially when hosting a game while playing, EXPERIMENTAL, may be crashy"}; + +cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"}; +cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"}; +cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"}; +cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"}; +cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"}; +cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"}; +cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"}; +cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"}; +cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"}; +cvar_t temp1 = {0, "temp1","0", "general cvar for mods to use, in stock id1 this selects which death animation to use on players (0 = random death, other values select specific death scenes)"}; + +cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"}; +cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"}; + +cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"}; +cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" }; +cvar_t sv_autodemo_perclient_discardable = {CVAR_SAVE, "sv_autodemo_perclient_discardable", "0", "Allow game code to decide whether a demo should be kept or discarded."}; + +cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; + +server_t sv; +server_static_t svs; + +mempool_t *sv_mempool = NULL; + +extern cvar_t slowmo; +extern float scr_centertime_off; + +// MUST match effectnameindex_t in client.h +static const char *standardeffectnames[EFFECT_TOTAL] = +{ + "", + "TE_GUNSHOT", + "TE_GUNSHOTQUAD", + "TE_SPIKE", + "TE_SPIKEQUAD", + "TE_SUPERSPIKE", + "TE_SUPERSPIKEQUAD", + "TE_WIZSPIKE", + "TE_KNIGHTSPIKE", + "TE_EXPLOSION", + "TE_EXPLOSIONQUAD", + "TE_TAREXPLOSION", + "TE_TELEPORT", + "TE_LAVASPLASH", + "TE_SMALLFLASH", + "TE_FLAMEJET", + "EF_FLAME", + "TE_BLOOD", + "TE_SPARK", + "TE_PLASMABURN", + "TE_TEI_G3", + "TE_TEI_SMOKE", + "TE_TEI_BIGEXPLOSION", + "TE_TEI_PLASMAHIT", + "EF_STARDUST", + "TR_ROCKET", + "TR_GRENADE", + "TR_BLOOD", + "TR_WIZSPIKE", + "TR_SLIGHTBLOOD", + "TR_KNIGHTSPIKE", + "TR_VORESPIKE", + "TR_NEHAHRASMOKE", + "TR_NEXUIZPLASMA", + "TR_GLOWTRAIL", + "SVC_PARTICLE" +}; + +#define SV_REQFUNCS 0 +#define sv_reqfuncs NULL + +//#define SV_REQFUNCS (sizeof(sv_reqfuncs) / sizeof(const char *)) +//static const char *sv_reqfuncs[] = { +//}; + +#define SV_REQFIELDS (sizeof(sv_reqfields) / sizeof(prvm_required_field_t)) + +prvm_required_field_t sv_reqfields[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) +#define PRVM_DECLARE_serverglobalvector(x) +#define PRVM_DECLARE_serverglobalstring(x) +#define PRVM_DECLARE_serverglobaledict(x) +#define PRVM_DECLARE_serverglobalfunction(x) +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) {ev_float, #x}, +#define PRVM_DECLARE_serverfieldvector(x) {ev_vector, #x}, +#define PRVM_DECLARE_serverfieldstring(x) {ev_string, #x}, +#define PRVM_DECLARE_serverfieldedict(x) {ev_entity, #x}, +#define PRVM_DECLARE_serverfieldfunction(x) {ev_function, #x}, +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + +#define SV_REQGLOBALS (sizeof(sv_reqglobals) / sizeof(prvm_required_field_t)) + +prvm_required_field_t sv_reqglobals[] = +{ +#define PRVM_DECLARE_serverglobalfloat(x) {ev_float, #x}, +#define PRVM_DECLARE_serverglobalvector(x) {ev_vector, #x}, +#define PRVM_DECLARE_serverglobalstring(x) {ev_string, #x}, +#define PRVM_DECLARE_serverglobaledict(x) {ev_entity, #x}, +#define PRVM_DECLARE_serverglobalfunction(x) {ev_function, #x}, +#define PRVM_DECLARE_clientglobalfloat(x) +#define PRVM_DECLARE_clientglobalvector(x) +#define PRVM_DECLARE_clientglobalstring(x) +#define PRVM_DECLARE_clientglobaledict(x) +#define PRVM_DECLARE_clientglobalfunction(x) +#define PRVM_DECLARE_menuglobalfloat(x) +#define PRVM_DECLARE_menuglobalvector(x) +#define PRVM_DECLARE_menuglobalstring(x) +#define PRVM_DECLARE_menuglobaledict(x) +#define PRVM_DECLARE_menuglobalfunction(x) +#define PRVM_DECLARE_serverfieldfloat(x) +#define PRVM_DECLARE_serverfieldvector(x) +#define PRVM_DECLARE_serverfieldstring(x) +#define PRVM_DECLARE_serverfieldedict(x) +#define PRVM_DECLARE_serverfieldfunction(x) +#define PRVM_DECLARE_clientfieldfloat(x) +#define PRVM_DECLARE_clientfieldvector(x) +#define PRVM_DECLARE_clientfieldstring(x) +#define PRVM_DECLARE_clientfieldedict(x) +#define PRVM_DECLARE_clientfieldfunction(x) +#define PRVM_DECLARE_menufieldfloat(x) +#define PRVM_DECLARE_menufieldvector(x) +#define PRVM_DECLARE_menufieldstring(x) +#define PRVM_DECLARE_menufieldedict(x) +#define PRVM_DECLARE_menufieldfunction(x) +#define PRVM_DECLARE_serverfunction(x) +#define PRVM_DECLARE_clientfunction(x) +#define PRVM_DECLARE_menufunction(x) +#define PRVM_DECLARE_field(x) +#define PRVM_DECLARE_global(x) +#define PRVM_DECLARE_function(x) +#include "prvm_offsets.h" +#undef PRVM_DECLARE_serverglobalfloat +#undef PRVM_DECLARE_serverglobalvector +#undef PRVM_DECLARE_serverglobalstring +#undef PRVM_DECLARE_serverglobaledict +#undef PRVM_DECLARE_serverglobalfunction +#undef PRVM_DECLARE_clientglobalfloat +#undef PRVM_DECLARE_clientglobalvector +#undef PRVM_DECLARE_clientglobalstring +#undef PRVM_DECLARE_clientglobaledict +#undef PRVM_DECLARE_clientglobalfunction +#undef PRVM_DECLARE_menuglobalfloat +#undef PRVM_DECLARE_menuglobalvector +#undef PRVM_DECLARE_menuglobalstring +#undef PRVM_DECLARE_menuglobaledict +#undef PRVM_DECLARE_menuglobalfunction +#undef PRVM_DECLARE_serverfieldfloat +#undef PRVM_DECLARE_serverfieldvector +#undef PRVM_DECLARE_serverfieldstring +#undef PRVM_DECLARE_serverfieldedict +#undef PRVM_DECLARE_serverfieldfunction +#undef PRVM_DECLARE_clientfieldfloat +#undef PRVM_DECLARE_clientfieldvector +#undef PRVM_DECLARE_clientfieldstring +#undef PRVM_DECLARE_clientfieldedict +#undef PRVM_DECLARE_clientfieldfunction +#undef PRVM_DECLARE_menufieldfloat +#undef PRVM_DECLARE_menufieldvector +#undef PRVM_DECLARE_menufieldstring +#undef PRVM_DECLARE_menufieldedict +#undef PRVM_DECLARE_menufieldfunction +#undef PRVM_DECLARE_serverfunction +#undef PRVM_DECLARE_clientfunction +#undef PRVM_DECLARE_menufunction +#undef PRVM_DECLARE_field +#undef PRVM_DECLARE_global +#undef PRVM_DECLARE_function +}; + + + +//============================================================================ + +static void SV_AreaStats_f(void) +{ + World_PrintAreaStats(&sv.world, "server"); +} + +/* +=============== +SV_Init +=============== +*/ +void SV_Init (void) +{ + // init the csqc progs cvars, since they are updated/used by the server code + // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black] + extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat + extern cvar_t csqc_progcrc; + extern cvar_t csqc_progsize; + extern cvar_t csqc_usedemoprogs; + + Cvar_RegisterVariable(&sv_worldmessage); + Cvar_RegisterVariable(&sv_worldname); + Cvar_RegisterVariable(&sv_worldnamenoextension); + Cvar_RegisterVariable(&sv_worldbasename); + + Cvar_RegisterVariable (&csqc_progname); + Cvar_RegisterVariable (&csqc_progcrc); + Cvar_RegisterVariable (&csqc_progsize); + Cvar_RegisterVariable (&csqc_usedemoprogs); + + Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)"); + Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces"); + Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)"); + Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server"); + + Cvar_RegisterVariable (&sv_disablenotify); + Cvar_RegisterVariable (&coop); + Cvar_RegisterVariable (&deathmatch); + Cvar_RegisterVariable (&fraglimit); + Cvar_RegisterVariable (&gamecfg); + Cvar_RegisterVariable (&noexit); + Cvar_RegisterVariable (&nomonsters); + Cvar_RegisterVariable (&pausable); + Cvar_RegisterVariable (&pr_checkextension); + Cvar_RegisterVariable (&samelevel); + Cvar_RegisterVariable (&skill); + Cvar_RegisterVariable (&slowmo); + Cvar_RegisterVariable (&sv_accelerate); + Cvar_RegisterVariable (&sv_aim); + Cvar_RegisterVariable (&sv_airaccel_qw); + Cvar_RegisterVariable (&sv_airaccel_qw_stretchfactor); + Cvar_RegisterVariable (&sv_airaccel_sideways_friction); + Cvar_RegisterVariable (&sv_airaccelerate); + Cvar_RegisterVariable (&sv_airstopaccelerate); + Cvar_RegisterVariable (&sv_airstrafeaccelerate); + Cvar_RegisterVariable (&sv_maxairstrafespeed); + Cvar_RegisterVariable (&sv_airstrafeaccel_qw); + Cvar_RegisterVariable (&sv_airspeedlimit_nonqw); + Cvar_RegisterVariable (&sv_aircontrol); + Cvar_RegisterVariable (&sv_aircontrol_power); + Cvar_RegisterVariable (&sv_aircontrol_penalty); + Cvar_RegisterVariable (&sv_allowdownloads); + Cvar_RegisterVariable (&sv_allowdownloads_archive); + Cvar_RegisterVariable (&sv_allowdownloads_config); + Cvar_RegisterVariable (&sv_allowdownloads_dlcache); + Cvar_RegisterVariable (&sv_allowdownloads_inarchive); + Cvar_RegisterVariable (&sv_areagrid_mingridsize); + Cvar_RegisterVariable (&sv_checkforpacketsduringsleep); + Cvar_RegisterVariable (&sv_clmovement_enable); + Cvar_RegisterVariable (&sv_clmovement_minping); + Cvar_RegisterVariable (&sv_clmovement_minping_disabletime); + Cvar_RegisterVariable (&sv_clmovement_inputtimeout); + Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels); + Cvar_RegisterVariable (&sv_cullentities_pvs); + Cvar_RegisterVariable (&sv_cullentities_stats); + Cvar_RegisterVariable (&sv_cullentities_trace); + Cvar_RegisterVariable (&sv_cullentities_trace_delay); + Cvar_RegisterVariable (&sv_cullentities_trace_delay_players); + Cvar_RegisterVariable (&sv_cullentities_trace_enlarge); + Cvar_RegisterVariable (&sv_cullentities_trace_entityocclusion); + Cvar_RegisterVariable (&sv_cullentities_trace_prediction); + Cvar_RegisterVariable (&sv_cullentities_trace_prediction_time); + Cvar_RegisterVariable (&sv_cullentities_trace_samples); + Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra); + Cvar_RegisterVariable (&sv_cullentities_trace_samples_players); + Cvar_RegisterVariable (&sv_debugmove); + Cvar_RegisterVariable (&sv_echobprint); + Cvar_RegisterVariable (&sv_edgefriction); + Cvar_RegisterVariable (&sv_entpatch); + Cvar_RegisterVariable (&sv_fixedframeratesingleplayer); + Cvar_RegisterVariable (&sv_freezenonclients); + Cvar_RegisterVariable (&sv_friction); + Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies); + Cvar_RegisterVariable (&sv_gameplayfix_consistentplayerprethink); + Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles); + Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid); + Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect); + Cvar_RegisterVariable (&sv_gameplayfix_easierwaterjump); + Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox); + Cvar_RegisterVariable (&sv_gameplayfix_gravityunaffectedbyticrate); + Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes); + Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe); + Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse); + Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse_allowsuspendeditems); + Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid); + Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_separation); + Cvar_RegisterVariable (&sv_gameplayfix_q2airaccelerate); + Cvar_RegisterVariable (&sv_gameplayfix_nogravityonground); + Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox); + Cvar_RegisterVariable (&sv_gameplayfix_slidemoveprojectiles); + Cvar_RegisterVariable (&sv_gameplayfix_stepdown); + Cvar_RegisterVariable (&sv_gameplayfix_stepmultipletimes); + Cvar_RegisterVariable (&sv_gameplayfix_nostepmoveonsteepslopes); + Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels); + Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag); + Cvar_RegisterVariable (&sv_gameplayfix_downtracesupportsongroundflag); + Cvar_RegisterVariable (&sv_gameplayfix_q1bsptracelinereportstexture); + Cvar_RegisterVariable (&sv_gameplayfix_unstickplayers); + Cvar_RegisterVariable (&sv_gameplayfix_unstickentities); + Cvar_RegisterVariable (&sv_gameplayfix_fixedcheckwatertransition); + Cvar_RegisterVariable (&sv_gravity); + Cvar_RegisterVariable (&sv_idealpitchscale); + Cvar_RegisterVariable (&sv_jumpstep); + Cvar_RegisterVariable (&sv_jumpvelocity); + Cvar_RegisterVariable (&sv_maxairspeed); + Cvar_RegisterVariable (&sv_maxrate); + Cvar_RegisterVariable (&sv_maxspeed); + Cvar_RegisterVariable (&sv_maxvelocity); + Cvar_RegisterVariable (&sv_nostep); + Cvar_RegisterVariable (&sv_playerphysicsqc); + Cvar_RegisterVariable (&sv_progs); + Cvar_RegisterVariable (&sv_protocolname); + Cvar_RegisterVariable (&sv_random_seed); + Cvar_RegisterVariable (&sv_ratelimitlocalplayer); + Cvar_RegisterVariable (&sv_sound_land); + Cvar_RegisterVariable (&sv_sound_watersplash); + Cvar_RegisterVariable (&sv_stepheight); + Cvar_RegisterVariable (&sv_stopspeed); + Cvar_RegisterVariable (&sv_wallfriction); + Cvar_RegisterVariable (&sv_wateraccelerate); + Cvar_RegisterVariable (&sv_waterfriction); + Cvar_RegisterVariable (&sv_warsowbunny_airforwardaccel); + Cvar_RegisterVariable (&sv_warsowbunny_accel); + Cvar_RegisterVariable (&sv_warsowbunny_topspeed); + Cvar_RegisterVariable (&sv_warsowbunny_turnaccel); + Cvar_RegisterVariable (&sv_warsowbunny_backtosideratio); + Cvar_RegisterVariable (&sv_onlycsqcnetworking); + Cvar_RegisterVariable (&sv_areadebug); + Cvar_RegisterVariable (&sys_ticrate); + Cvar_RegisterVariable (&teamplay); + Cvar_RegisterVariable (&timelimit); + Cvar_RegisterVariable (&sv_threaded); + + Cvar_RegisterVariable (&saved1); + Cvar_RegisterVariable (&saved2); + Cvar_RegisterVariable (&saved3); + Cvar_RegisterVariable (&saved4); + Cvar_RegisterVariable (&savedgamecfg); + Cvar_RegisterVariable (&scratch1); + Cvar_RegisterVariable (&scratch2); + Cvar_RegisterVariable (&scratch3); + Cvar_RegisterVariable (&scratch4); + Cvar_RegisterVariable (&temp1); + + // LordHavoc: Nehahra uses these to pass data around cutscene demos + Cvar_RegisterVariable (&nehx00); + Cvar_RegisterVariable (&nehx01); + Cvar_RegisterVariable (&nehx02); + Cvar_RegisterVariable (&nehx03); + Cvar_RegisterVariable (&nehx04); + Cvar_RegisterVariable (&nehx05); + Cvar_RegisterVariable (&nehx06); + Cvar_RegisterVariable (&nehx07); + Cvar_RegisterVariable (&nehx08); + Cvar_RegisterVariable (&nehx09); + Cvar_RegisterVariable (&nehx10); + Cvar_RegisterVariable (&nehx11); + Cvar_RegisterVariable (&nehx12); + Cvar_RegisterVariable (&nehx13); + Cvar_RegisterVariable (&nehx14); + Cvar_RegisterVariable (&nehx15); + Cvar_RegisterVariable (&nehx16); + Cvar_RegisterVariable (&nehx17); + Cvar_RegisterVariable (&nehx18); + Cvar_RegisterVariable (&nehx19); + Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well + + Cvar_RegisterVariable (&sv_autodemo_perclient); + Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat); + Cvar_RegisterVariable (&sv_autodemo_perclient_discardable); + + Cvar_RegisterVariable (&halflifebsp); + + sv_mempool = Mem_AllocPool("server", 0, NULL); +} + +static void SV_SaveEntFile_f(void) +{ + char vabuf[1024]; + if (!sv.active || !sv.worldmodel) + { + Con_Print("Not running a server\n"); + return; + } + FS_WriteFile(va(vabuf, sizeof(vabuf), "%s.ent", sv.worldnamenoextension), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities)); +} + + +/* +============================================================================= + +EVENT MESSAGES + +============================================================================= +*/ + +/* +================== +SV_StartParticle + +Make sure the event gets sent to all clients +================== +*/ +void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count) +{ + int i; + + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18) + return; + MSG_WriteByte (&sv.datagram, svc_particle); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); + for (i=0 ; i<3 ; i++) + MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127)); + MSG_WriteByte (&sv.datagram, count); + MSG_WriteByte (&sv.datagram, color); + SV_FlushBroadcastMessages(); +} + +/* +================== +SV_StartEffect + +Make sure the event gets sent to all clients +================== +*/ +void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate) +{ + if (modelindex >= 256 || startframe >= 256) + { + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19) + return; + MSG_WriteByte (&sv.datagram, svc_effect2); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); + MSG_WriteShort (&sv.datagram, modelindex); + MSG_WriteShort (&sv.datagram, startframe); + MSG_WriteByte (&sv.datagram, framecount); + MSG_WriteByte (&sv.datagram, framerate); + } + else + { + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17) + return; + MSG_WriteByte (&sv.datagram, svc_effect); + MSG_WriteCoord (&sv.datagram, org[0], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[1], sv.protocol); + MSG_WriteCoord (&sv.datagram, org[2], sv.protocol); + MSG_WriteByte (&sv.datagram, modelindex); + MSG_WriteByte (&sv.datagram, startframe); + MSG_WriteByte (&sv.datagram, framecount); + MSG_WriteByte (&sv.datagram, framerate); + } + SV_FlushBroadcastMessages(); +} + +/* +================== +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 +already 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 (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation, qboolean reliable, float speed) +{ + prvm_prog_t *prog = SVVM_prog; + sizebuf_t *dest; + int sound_num, field_mask, i, ent, speed4000; + + dest = (reliable ? &sv.reliable_datagram : &sv.datagram); + + if (volume < 0 || volume > 255) + { + Con_Printf ("SV_StartSound: volume = %i\n", volume); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation); + return; + } + + if (!IS_CHAN(channel)) + { + Con_Printf ("SV_StartSound: channel = %i\n", channel); + return; + } + + channel = CHAN_ENGINE2NET(channel); + + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21) + return; + +// find precache number for sound + sound_num = SV_SoundIndex(sample, 1); + if (!sound_num) + return; + + ent = PRVM_NUM_FOR_EDICT(entity); + + speed4000 = (int)floor(speed * 4000.0f + 0.5f); + field_mask = 0; + if (volume != DEFAULT_SOUND_PACKET_VOLUME) + field_mask |= SND_VOLUME; + if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) + field_mask |= SND_ATTENUATION; + if (speed4000 && speed4000 != 4000) + field_mask |= SND_SPEEDUSHORT4000; + if (ent >= 8192 || channel < 0 || channel > 7) + field_mask |= SND_LARGEENTITY; + if (sound_num >= 256) + field_mask |= SND_LARGESOUND; + +// directed messages go only to the entity they are targeted on + MSG_WriteByte (dest, svc_sound); + MSG_WriteByte (dest, field_mask); + if (field_mask & SND_VOLUME) + MSG_WriteByte (dest, volume); + if (field_mask & SND_ATTENUATION) + MSG_WriteByte (dest, (int)(attenuation*64)); + if (field_mask & SND_SPEEDUSHORT4000) + MSG_WriteShort (dest, speed4000); + if (field_mask & SND_LARGEENTITY) + { + MSG_WriteShort (dest, ent); + MSG_WriteChar (dest, channel); + } + else + MSG_WriteShort (dest, (ent<<3) | channel); + if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2) + MSG_WriteShort (dest, sound_num); + else + MSG_WriteByte (dest, sound_num); + for (i = 0;i < 3;i++) + MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol); + + // TODO do we have to do anything here when dest is &sv.reliable_datagram? + if(!reliable) + SV_FlushBroadcastMessages(); +} + +/* +================== +SV_StartPointSound + +Nearly the same logic as SV_StartSound, except an origin +instead of an entity is provided and channel is omitted. + +The entity sent to the client is 0 (world) and the channel +is 0 (CHAN_AUTO). SND_LARGEENTITY will never occur in this +function, therefore the check for it is omitted. + +================== +*/ +void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation, float speed) +{ + int sound_num, field_mask, i, speed4000; + + if (volume < 0 || volume > 255) + { + Con_Printf ("SV_StartPointSound: volume = %i\n", volume); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation); + return; + } + + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21) + return; + + // find precache number for sound + sound_num = SV_SoundIndex(sample, 1); + if (!sound_num) + return; + + speed4000 = (int)(speed * 40.0f); + field_mask = 0; + if (volume != DEFAULT_SOUND_PACKET_VOLUME) + field_mask |= SND_VOLUME; + if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) + field_mask |= SND_ATTENUATION; + if (sound_num >= 256) + field_mask |= SND_LARGESOUND; + if (speed4000 && speed4000 != 4000) + field_mask |= SND_SPEEDUSHORT4000; + +// directed messages go only to the entity they are targeted on + MSG_WriteByte (&sv.datagram, svc_sound); + MSG_WriteByte (&sv.datagram, field_mask); + if (field_mask & SND_VOLUME) + MSG_WriteByte (&sv.datagram, volume); + if (field_mask & SND_ATTENUATION) + MSG_WriteByte (&sv.datagram, (int)(attenuation*64)); + if (field_mask & SND_SPEEDUSHORT4000) + MSG_WriteShort (&sv.datagram, speed4000); + // Always write entnum 0 for the world entity + MSG_WriteShort (&sv.datagram, (0<<3) | 0); + if (field_mask & SND_LARGESOUND) + MSG_WriteShort (&sv.datagram, sound_num); + else + MSG_WriteByte (&sv.datagram, sound_num); + for (i = 0;i < 3;i++) + MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol); + SV_FlushBroadcastMessages(); +} + +/* +============================================================================== + +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) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + char message[128]; + char vabuf[1024]; + + // we know that this client has a netconnection and thus is not a bot + + // edicts get reallocated on level changes, so we need to update it here + client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1); + + // clear cached stuff that depends on the level + client->weaponmodel[0] = 0; + client->weaponmodelindex = 0; + + // LordHavoc: clear entityframe tracking + client->latestframenum = 0; + + // initialize the movetime, so a speedhack can't make use of the time before this client joined + client->cmd.time = sv.time; + + if (client->entitydatabase) + EntityFrame_FreeDatabase(client->entitydatabase); + if (client->entitydatabase4) + EntityFrame4_FreeDatabase(client->entitydatabase4); + if (client->entitydatabase5) + EntityFrame5_FreeDatabase(client->entitydatabase5); + + memset(client->stats, 0, sizeof(client->stats)); + memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits)); + + if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3) + { + if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) + client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool); + else if (sv.protocol == PROTOCOL_DARKPLACES4) + client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool); + else + client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool); + } + + // reset csqc entity versions + for (i = 0;i < prog->max_edicts;i++) + { + client->csqcentityscope[i] = 0; + client->csqcentitysendflags[i] = 0xFFFFFF; + client->csqcentityglobalhistory[i] = 0; + } + for (i = 0;i < NUM_CSQCENTITYDB_FRAMES;i++) + { + client->csqcentityframehistory[i].num = 0; + client->csqcentityframehistory[i].framenum = -1; + } + client->csqcnumedicts = 0; + client->csqcentityframehistory_next = 0; + + SZ_Clear (&client->netconnection->message); + MSG_WriteByte (&client->netconnection->message, svc_print); + dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)\n", gamename, buildstring, prog->filecrc); + MSG_WriteString (&client->netconnection->message,message); + + SV_StopDemoRecording(client); // to split up demos into different files + if(sv_autodemo_perclient.integer && client->netconnection) + { + char demofile[MAX_OSPATH]; + char ipaddress[MAX_QPATH]; + size_t i; + + // start a new demo file + LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true); + for(i = 0; ipaddress[i]; ++i) + if(!isalnum(ipaddress[i])) + ipaddress[i] = '-'; + dpsnprintf (demofile, sizeof(demofile), "%s_%s_%d_%s.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), sv.worldbasename, PRVM_NUM_FOR_EDICT(client->edict), ipaddress); + + SV_StartDemoRecording(client, demofile, -1); + } + + //[515]: init csprogs according to version of svprogs, check the crc, etc. + if (sv.csqc_progname[0]) + { + Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); + MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progname %s\n", sv.csqc_progname)); + MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progsize %i\n", sv.csqc_progsize)); + MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "csqc_progcrc %i\n", sv.csqc_progcrc)); + + if(client->sv_demo_file != NULL) + { + int i; + static char buf[NET_MAXMESSAGE]; + sizebuf_t sb; + + sb.data = (unsigned char *) buf; + sb.maxsize = sizeof(buf); + i = 0; + while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, i++, &sb, sv.protocol)) + SV_WriteDemoMessage(client, &sb, false); + } + + //[515]: init stufftext string (it is sent before svc_serverinfo) + if (PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd))) + { + MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, va(vabuf, sizeof(vabuf), "%s\n", PRVM_GetString(prog, PRVM_serverglobalstring(SV_InitCmd)))); + } + } + + //if (sv_allowdownloads.integer) + // always send the info that the server supports the protocol, even if downloads are forbidden + // only because of that, the CSQC exception can work + { + MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 2\n"); + } + + // send at this time so it's guaranteed to get executed at the right time + { + client_t *save; + save = host_client; + host_client = client; + Curl_SendRequirements(); + host_client = save; + } + + MSG_WriteByte (&client->netconnection->message, svc_serverinfo); + MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol)); + MSG_WriteByte (&client->netconnection->message, svs.maxclients); + + if (!coop.integer && deathmatch.integer) + MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH); + else + MSG_WriteByte (&client->netconnection->message, GAME_COOP); + + MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message))); + + for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++) + MSG_WriteString (&client->netconnection->message, sv.model_precache[i]); + MSG_WriteByte (&client->netconnection->message, 0); + + for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++) + MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]); + MSG_WriteByte (&client->netconnection->message, 0); + +// send music + MSG_WriteByte (&client->netconnection->message, svc_cdtrack); + MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds)); + MSG_WriteByte (&client->netconnection->message, (int)PRVM_serveredictfloat(prog->edicts, sounds)); + +// set view +// store this in clientcamera, too + client->clientcamera = PRVM_NUM_FOR_EDICT(client->edict); + MSG_WriteByte (&client->netconnection->message, svc_setview); + MSG_WriteShort (&client->netconnection->message, client->clientcamera); + + MSG_WriteByte (&client->netconnection->message, svc_signonnum); + MSG_WriteByte (&client->netconnection->message, 1); + + client->prespawned = false; // need prespawn, spawn, etc + client->spawned = false; // need prespawn, spawn, etc + client->begun = false; // need prespawn, spawn, etc + client->sendsignon = 1; // send this message, and increment to 2, 2 will be set to 0 by the prespawn command + + // clear movement info until client enters the new level properly + memset(&client->cmd, 0, sizeof(client->cmd)); + client->movesequence = 0; + client->movement_highestsequence_seen = 0; + memset(&client->movement_count, 0, sizeof(client->movement_count)); +#ifdef NUM_PING_TIMES + for (i = 0;i < NUM_PING_TIMES;i++) + client->ping_times[i] = 0; + client->num_pings = 0; +#endif + client->ping = 0; + + // allow the client some time to send his keepalives, even if map loading took ages + client->netconnection->timeout = realtime + net_connecttimeout.value; +} + +/* +================ +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, netconn_t *netconnection) +{ + prvm_prog_t *prog = SVVM_prog; + client_t *client; + int i; + + client = svs.clients + clientnum; + +// set up the client_t + if (sv.loadgame) + { + float backupparms[NUM_SPAWN_PARMS]; + memcpy(backupparms, client->spawn_parms, sizeof(backupparms)); + memset(client, 0, sizeof(*client)); + memcpy(client->spawn_parms, backupparms, sizeof(backupparms)); + } + else + memset(client, 0, sizeof(*client)); + client->active = true; + client->netconnection = netconnection; + + Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient"); + + if(client->netconnection && client->netconnection->crypto.authenticated) + { + Con_Printf("%s connection to %s has been established: client is %s@%.*s, I am %.*s@%.*s\n", + client->netconnection->crypto.use_aes ? "Encrypted" : "Authenticated", + client->netconnection->address, + client->netconnection->crypto.client_idfp[0] ? client->netconnection->crypto.client_idfp : "-", + crypto_keyfp_recommended_length, client->netconnection->crypto.client_keyfp[0] ? client->netconnection->crypto.client_keyfp : "-", + crypto_keyfp_recommended_length, client->netconnection->crypto.server_idfp[0] ? client->netconnection->crypto.server_idfp : "-", + crypto_keyfp_recommended_length, client->netconnection->crypto.server_keyfp[0] ? client->netconnection->crypto.server_keyfp : "-" + ); + } + + strlcpy(client->name, "unconnected", sizeof(client->name)); + strlcpy(client->old_name, "unconnected", sizeof(client->old_name)); + client->prespawned = false; + client->spawned = false; + client->begun = false; + client->edict = PRVM_EDICT_NUM(clientnum+1); + if (client->netconnection) + client->netconnection->message.allowoverflow = true; // we can catch it + // prepare the unreliable message buffer + client->unreliablemsg.data = client->unreliablemsg_data; + client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data); + // updated by receiving "rate" command from client, this is also the default if not using a DP client + client->rate = 1000000000; + // no limits for local player + if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP) + client->rate = 1000000000; + client->connecttime = realtime; + + if (!sv.loadgame) + { + // call the progs to get default spawn parms for the new client + // set self to world to intentionally cause errors with broken SetNewParms code in some mods + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = 0; + prog->ExecuteProgram(prog, PRVM_serverfunction(SetNewParms), "QC function SetNewParms is missing"); + for (i=0 ; ispawn_parms[i] = (&PRVM_serverglobalfloat(parm1))[i]; + + // set up the entity for this client (including .colormap, .team, etc) + PRVM_ED_ClearEdict(prog, client->edict); + } + + // don't call SendServerinfo for a fresh botclient because its fields have + // not been set up by the qc yet + if (client->netconnection) + SV_SendServerinfo (client); + else + client->prespawned = client->spawned = client->begun = true; +} + + +/* +=============================================================================== + +FRAME UPDATES + +=============================================================================== +*/ + +/* +============================================================================= + +The PVS must include a small area around the client to allow head bobbing +or other small motion on the client side. Otherwise, a bob might cause an +entity that should be visible to not show up, especially when the bob +crosses a waterline. + +============================================================================= +*/ + +static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + unsigned int sendflags; + unsigned int version; + unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius; + unsigned int customizeentityforclient; + unsigned int sendentity; + float f; + prvm_vec_t *v; + vec3_t cullmins, cullmaxs; + dp_model_t *model; + + // fast path for games that do not use legacy entity networking + // note: still networks clients even if they are legacy + sendentity = PRVM_serveredictfunction(ent, SendEntity); + if (sv_onlycsqcnetworking.integer && !sendentity && enumber > svs.maxclients) + return false; + + // this 2 billion unit check is actually to detect NAN origins + // (we really don't want to send those) + if (!(VectorLength2(PRVM_serveredictvector(ent, origin)) < 2000000000.0*2000000000.0)) + return false; + + // EF_NODRAW prevents sending for any reason except for your own + // client, so we must keep all clients in this superset + effects = (unsigned)PRVM_serveredictfloat(ent, effects); + + // we can omit invisible entities with no effects that are not clients + // LordHavoc: this could kill tags attached to an invisible entity, I + // just hope we never have to support that case + i = (int)PRVM_serveredictfloat(ent, modelindex); + modelindex = (i >= 1 && i < MAX_MODELS && PRVM_serveredictstring(ent, model) && *PRVM_GetString(prog, PRVM_serveredictstring(ent, model)) && sv.models[i]) ? i : 0; + + flags = 0; + i = (int)(PRVM_serveredictfloat(ent, glow_size) * 0.25f); + glowsize = (unsigned char)bound(0, i, 255); + if (PRVM_serveredictfloat(ent, glow_trail)) + flags |= RENDER_GLOWTRAIL; + if (PRVM_serveredictedict(ent, viewmodelforclient)) + flags |= RENDER_VIEWMODEL; + + v = PRVM_serveredictvector(ent, color); + f = v[0]*256; + light[0] = (unsigned short)bound(0, f, 65535); + f = v[1]*256; + light[1] = (unsigned short)bound(0, f, 65535); + f = v[2]*256; + light[2] = (unsigned short)bound(0, f, 65535); + f = PRVM_serveredictfloat(ent, light_lev); + light[3] = (unsigned short)bound(0, f, 65535); + lightstyle = (unsigned char)PRVM_serveredictfloat(ent, style); + lightpflags = (unsigned char)PRVM_serveredictfloat(ent, pflags); + + if (gamemode == GAME_TENEBRAE) + { + // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW + if (effects & 16) + { + effects &= ~16; + lightpflags |= PFLAGS_FULLDYNAMIC; + } + // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE + if (effects & 32) + { + effects &= ~32; + light[0] = (int)(0.2*256); + light[1] = (int)(1.0*256); + light[2] = (int)(0.2*256); + light[3] = 200; + lightpflags |= PFLAGS_FULLDYNAMIC; + } + } + + specialvisibilityradius = 0; + if (lightpflags & PFLAGS_FULLDYNAMIC) + specialvisibilityradius = max(specialvisibilityradius, light[3]); + if (glowsize) + specialvisibilityradius = max(specialvisibilityradius, glowsize * 4); + if (flags & RENDER_GLOWTRAIL) + specialvisibilityradius = max(specialvisibilityradius, 100); + if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST)) + { + if (effects & EF_BRIGHTFIELD) + specialvisibilityradius = max(specialvisibilityradius, 80); + if (effects & EF_MUZZLEFLASH) + specialvisibilityradius = max(specialvisibilityradius, 100); + if (effects & EF_BRIGHTLIGHT) + specialvisibilityradius = max(specialvisibilityradius, 400); + if (effects & EF_DIMLIGHT) + specialvisibilityradius = max(specialvisibilityradius, 200); + if (effects & EF_RED) + specialvisibilityradius = max(specialvisibilityradius, 200); + if (effects & EF_BLUE) + specialvisibilityradius = max(specialvisibilityradius, 200); + if (effects & EF_FLAME) + specialvisibilityradius = max(specialvisibilityradius, 250); + if (effects & EF_STARDUST) + specialvisibilityradius = max(specialvisibilityradius, 100); + } + + // early culling checks + // (final culling is done by SV_MarkWriteEntityStateToClient) + customizeentityforclient = PRVM_serveredictfunction(ent, customizeentityforclient); + if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius)) + return false; + + *cs = defaultstate; + cs->active = ACTIVE_NETWORK; + cs->number = enumber; + VectorCopy(PRVM_serveredictvector(ent, origin), cs->origin); + VectorCopy(PRVM_serveredictvector(ent, angles), cs->angles); + cs->flags = flags; + cs->effects = effects; + cs->colormap = (unsigned)PRVM_serveredictfloat(ent, colormap); + cs->modelindex = modelindex; + cs->skin = (unsigned)PRVM_serveredictfloat(ent, skin); + cs->frame = (unsigned)PRVM_serveredictfloat(ent, frame); + cs->viewmodelforclient = PRVM_serveredictedict(ent, viewmodelforclient); + cs->exteriormodelforclient = PRVM_serveredictedict(ent, exteriormodeltoclient); + cs->nodrawtoclient = PRVM_serveredictedict(ent, nodrawtoclient); + cs->drawonlytoclient = PRVM_serveredictedict(ent, drawonlytoclient); + cs->customizeentityforclient = customizeentityforclient; + cs->tagentity = PRVM_serveredictedict(ent, tag_entity); + cs->tagindex = (unsigned char)PRVM_serveredictfloat(ent, tag_index); + cs->glowsize = glowsize; + cs->traileffectnum = PRVM_serveredictfloat(ent, traileffectnum); + + // don't need to init cs->colormod because the defaultstate did that for us + //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32; + v = PRVM_serveredictvector(ent, colormod); + if (VectorLength2(v)) + { + i = (int)(v[0] * 32.0f);cs->colormod[0] = bound(0, i, 255); + i = (int)(v[1] * 32.0f);cs->colormod[1] = bound(0, i, 255); + i = (int)(v[2] * 32.0f);cs->colormod[2] = bound(0, i, 255); + } + + // don't need to init cs->glowmod because the defaultstate did that for us + //cs->glowmod[0] = cs->glowmod[1] = cs->glowmod[2] = 32; + v = PRVM_serveredictvector(ent, glowmod); + if (VectorLength2(v)) + { + i = (int)(v[0] * 32.0f);cs->glowmod[0] = bound(0, i, 255); + i = (int)(v[1] * 32.0f);cs->glowmod[1] = bound(0, i, 255); + i = (int)(v[2] * 32.0f);cs->glowmod[2] = bound(0, i, 255); + } + + cs->modelindex = modelindex; + + cs->alpha = 255; + f = (PRVM_serveredictfloat(ent, alpha) * 255.0f); + if (f) + { + i = (int)f; + cs->alpha = (unsigned char)bound(0, i, 255); + } + // halflife + f = (PRVM_serveredictfloat(ent, renderamt)); + if (f) + { + i = (int)f; + cs->alpha = (unsigned char)bound(0, i, 255); + } + + cs->scale = 16; + f = (PRVM_serveredictfloat(ent, scale) * 16.0f); + if (f) + { + i = (int)f; + cs->scale = (unsigned char)bound(0, i, 255); + } + + cs->glowcolor = 254; + f = PRVM_serveredictfloat(ent, glow_color); + if (f) + cs->glowcolor = (int)f; + + if (PRVM_serveredictfloat(ent, fullbright)) + cs->effects |= EF_FULLBRIGHT; + + f = PRVM_serveredictfloat(ent, modelflags); + if (f) + cs->effects |= ((unsigned int)f & 0xff) << 24; + + if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP) + cs->flags |= RENDER_STEP; + if (cs->number != sv.writeentitiestoclient_cliententitynumber && (cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767) + cs->flags |= RENDER_LOWPRECISION; + if (PRVM_serveredictfloat(ent, colormap) >= 1024) + cs->flags |= RENDER_COLORMAPPED; + if (cs->viewmodelforclient) + cs->flags |= RENDER_VIEWMODEL; // show relative to the view + + if (PRVM_serveredictfloat(ent, sendcomplexanimation)) + { + cs->flags |= RENDER_COMPLEXANIMATION; + if (PRVM_serveredictfloat(ent, skeletonindex) >= 1) + cs->skeletonobject = ent->priv.server->skeleton; + cs->framegroupblend[0].frame = PRVM_serveredictfloat(ent, frame); + cs->framegroupblend[1].frame = PRVM_serveredictfloat(ent, frame2); + cs->framegroupblend[2].frame = PRVM_serveredictfloat(ent, frame3); + cs->framegroupblend[3].frame = PRVM_serveredictfloat(ent, frame4); + cs->framegroupblend[0].start = PRVM_serveredictfloat(ent, frame1time); + cs->framegroupblend[1].start = PRVM_serveredictfloat(ent, frame2time); + cs->framegroupblend[2].start = PRVM_serveredictfloat(ent, frame3time); + cs->framegroupblend[3].start = PRVM_serveredictfloat(ent, frame4time); + cs->framegroupblend[1].lerp = PRVM_serveredictfloat(ent, lerpfrac); + cs->framegroupblend[2].lerp = PRVM_serveredictfloat(ent, lerpfrac3); + cs->framegroupblend[3].lerp = PRVM_serveredictfloat(ent, lerpfrac4); + cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp; + cs->frame = 0; // don't need the legacy frame + } + + cs->light[0] = light[0]; + cs->light[1] = light[1]; + cs->light[2] = light[2]; + cs->light[3] = light[3]; + cs->lightstyle = lightstyle; + cs->lightpflags = lightpflags; + + cs->specialvisibilityradius = specialvisibilityradius; + + // calculate the visible box of this entity (don't use the physics box + // as that is often smaller than a model, and would not count + // specialvisibilityradius) + if ((model = SV_GetModelByIndex(modelindex)) && (model->type != mod_null)) + { + float scale = cs->scale * (1.0f / 16.0f); + if (cs->angles[0] || cs->angles[2]) // pitch and roll + { + VectorMA(cs->origin, scale, model->rotatedmins, cullmins); + VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs); + } + else if (cs->angles[1] || ((effects | model->effects) & EF_ROTATE)) + { + VectorMA(cs->origin, scale, model->yawmins, cullmins); + VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs); + } + else + { + VectorMA(cs->origin, scale, model->normalmins, cullmins); + VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs); + } + } + else + { + // if there is no model (or it could not be loaded), use the physics box + VectorAdd(cs->origin, PRVM_serveredictvector(ent, mins), cullmins); + VectorAdd(cs->origin, PRVM_serveredictvector(ent, maxs), cullmaxs); + } + if (specialvisibilityradius) + { + cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius); + cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius); + cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius); + cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius); + cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius); + cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius); + } + + // calculate center of bbox for network prioritization purposes + VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter); + + // if culling box has moved, update pvs cluster links + if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs)) + { + VectorCopy(cullmins, ent->priv.server->cullmins); + VectorCopy(cullmaxs, ent->priv.server->cullmaxs); + // a value of -1 for pvs_numclusters indicates that the links are not + // cached, and should be re-tested each time, this is the case if the + // culling box touches too many pvs clusters to store, or if the world + // model does not support FindBoxClusters + ent->priv.server->pvs_numclusters = -1; + if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters) + { + i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist); + if (i <= MAX_ENTITYCLUSTERS) + ent->priv.server->pvs_numclusters = i; + } + } + + // we need to do some csqc entity upkeep here + // get self.SendFlags and clear them + // (to let the QC know that they've been read) + if (sendentity) + { + sendflags = (unsigned int)PRVM_serveredictfloat(ent, SendFlags); + PRVM_serveredictfloat(ent, SendFlags) = 0; + // legacy self.Version system + if ((version = (unsigned int)PRVM_serveredictfloat(ent, Version))) + { + if (sv.csqcentityversion[enumber] != version) + sendflags = 0xFFFFFF; + sv.csqcentityversion[enumber] = version; + } + // move sendflags into the per-client sendflags + if (sendflags) + for (i = 0;i < svs.maxclients;i++) + svs.clients[i].csqcentitysendflags[enumber] |= sendflags; + // mark it as inactive for non-csqc networking + cs->active = ACTIVE_SHARED; + } + + return true; +} + +static void SV_PrepareEntitiesForSending(void) +{ + prvm_prog_t *prog = SVVM_prog; + int e; + prvm_edict_t *ent; + // send all entities that touch the pvs + sv.numsendentities = 0; + sv.sendentitiesindex[0] = NULL; + memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex)); + for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent)) + { + if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e)) + { + sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities; + sv.numsendentities++; + } + } +} + +#define MAX_LINEOFSIGHTTRACES 64 + +qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs) +{ + prvm_prog_t *prog = SVVM_prog; + float pitchsign; + float alpha; + float starttransformed[3], endtransformed[3]; + int blocked = 0; + int traceindex; + int originalnumtouchedicts; + int numtouchedicts = 0; + int touchindex; + matrix4x4_t matrix, imatrix; + dp_model_t *model; + prvm_edict_t *touch; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + vec3_t boxmins, boxmaxs; + vec3_t clipboxmins, clipboxmaxs; + vec3_t endpoints[MAX_LINEOFSIGHTTRACES]; + + numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES); + + // expand the box a little + boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0]; + boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0]; + boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1]; + boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1]; + boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2]; + boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2]; + + VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, endpoints[0]); + for (traceindex = 1;traceindex < numtraces;traceindex++) + VectorSet(endpoints[traceindex], lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2])); + + // calculate sweep box for the entire swarm of traces + VectorCopy(eye, clipboxmins); + VectorCopy(eye, clipboxmaxs); + for (traceindex = 0;traceindex < numtraces;traceindex++) + { + clipboxmins[0] = min(clipboxmins[0], endpoints[traceindex][0]); + clipboxmins[1] = min(clipboxmins[1], endpoints[traceindex][1]); + clipboxmins[2] = min(clipboxmins[2], endpoints[traceindex][2]); + clipboxmaxs[0] = max(clipboxmaxs[0], endpoints[traceindex][0]); + clipboxmaxs[1] = max(clipboxmaxs[1], endpoints[traceindex][1]); + clipboxmaxs[2] = max(clipboxmaxs[2], endpoints[traceindex][2]); + } + + // get the list of entities in the sweep box + if (sv_cullentities_trace_entityocclusion.integer) + numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + // iterate the entities found in the sweep box and filter them + originalnumtouchedicts = numtouchedicts; + numtouchedicts = 0; + for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++) + { + touch = touchedicts[touchindex]; + if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP) + continue; + model = SV_GetModelFromEdict(touch); + if (!model || !model->brush.TraceLineOfSight) + continue; + // skip obviously transparent entities + alpha = PRVM_serveredictfloat(touch, alpha); + if (alpha && alpha < 1) + continue; + if ((int)PRVM_serveredictfloat(touch, effects) & EF_ADDITIVE) + continue; + touchedicts[numtouchedicts++] = touch; + } + + // now that we have a filtered list of "interesting" entities, fire each + // ray against all of them, this gives us an early-out case when something + // is visible (which it often is) + + for (traceindex = 0;traceindex < numtraces;traceindex++) + { + // check world occlusion + if (sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight) + if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, eye, endpoints[traceindex])) + continue; + for (touchindex = 0;touchindex < numtouchedicts;touchindex++) + { + touch = touchedicts[touchindex]; + model = SV_GetModelFromEdict(touch); + if(model && model->brush.TraceLineOfSight) + { + // get the entity matrix + pitchsign = SV_GetPitchSign(prog, touch); + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + // see if the ray hits this entity + Matrix4x4_Transform(&imatrix, eye, starttransformed); + Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed); + if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed)) + { + blocked++; + break; + } + } + } + // check if the ray was blocked + if (touchindex < numtouchedicts) + continue; + // return if the ray was not blocked + return true; + } + + // no rays survived + return false; +} + +static void SV_MarkWriteEntityStateToClient(entity_state_t *s) +{ + prvm_prog_t *prog = SVVM_prog; + int isbmodel; + dp_model_t *model; + prvm_edict_t *ed; + if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark) + return; + sv.sententitiesconsideration[s->number] = sv.sententitiesmark; + sv.writeentitiestoclient_stats_totalentities++; + + if (s->customizeentityforclient) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = s->number; + PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber; + prog->ExecuteProgram(prog, s->customizeentityforclient, "customizeentityforclient: NULL function"); + if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number)) + return; + } + + // never reject player + if (s->number != sv.writeentitiestoclient_cliententitynumber) + { + // check various rejection conditions + if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber) + return; + if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber) + return; + if (s->effects & EF_NODRAW) + return; + // LordHavoc: only send entities with a model or important effects + if (!s->modelindex && s->specialvisibilityradius == 0) + return; + + isbmodel = (model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*'; + // viewmodels don't have visibility checking + if (s->viewmodelforclient) + { + if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber) + return; + } + else if (s->tagentity) + { + // tag attached entities simply check their parent + if (!sv.sendentitiesindex[s->tagentity]) + return; + SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity]); + if (sv.sententities[s->tagentity] != sv.sententitiesmark) + return; + } + // always send world submodels in newer protocols because they don't + // generate much traffic (in old protocols they hog bandwidth) + // but only if sv_cullentities_nevercullbmodels is off + else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)) + { + // entity has survived every check so far, check if visible + ed = PRVM_EDICT_NUM(s->number); + + // if not touching a visible leaf + if (sv_cullentities_pvs.integer && !r_novis.integer && !r_trippy.integer && sv.writeentitiestoclient_pvsbytes) + { + if (ed->priv.server->pvs_numclusters < 0) + { + // entity too big for clusters list + if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv.writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs)) + { + sv.writeentitiestoclient_stats_culled_pvs++; + return; + } + } + else + { + int i; + // check cached clusters list + for (i = 0;i < ed->priv.server->pvs_numclusters;i++) + if (CHECKPVSBIT(sv.writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i])) + break; + if (i == ed->priv.server->pvs_numclusters) + { + sv.writeentitiestoclient_stats_culled_pvs++; + return; + } + } + } + + // or not seen by random tracelines + if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer) + { + int samples = + s->number <= svs.maxclients + ? sv_cullentities_trace_samples_players.integer + : + s->specialvisibilityradius + ? sv_cullentities_trace_samples_extra.integer + : sv_cullentities_trace_samples.integer; + float enlarge = sv_cullentities_trace_enlarge.value; + + if(samples > 0) + { + int eyeindex; + for (eyeindex = 0;eyeindex < sv.writeentitiestoclient_numeyes;eyeindex++) + if(SV_CanSeeBox(samples, enlarge, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs)) + break; + if(eyeindex < sv.writeentitiestoclient_numeyes) + svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] = + realtime + ( + s->number <= svs.maxclients + ? sv_cullentities_trace_delay_players.value + : sv_cullentities_trace_delay.value + ); + else if (realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number]) + { + sv.writeentitiestoclient_stats_culled_trace++; + return; + } + } + } + } + } + + // this just marks it for sending + // FIXME: it would be more efficient to send here, but the entity + // compressor isn't that flexible + sv.writeentitiestoclient_stats_visibleentities++; + sv.sententities[s->number] = sv.sententitiesmark; +} + +#if MAX_LEVELNETWORKEYES > 0 +#define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals +static void SV_AddCameraEyes(void) +{ + prvm_prog_t *prog = SVVM_prog; + int e, i, j, k; + prvm_edict_t *ed; + static int cameras[MAX_LEVELNETWORKEYES]; + static vec3_t camera_origins[MAX_LEVELNETWORKEYES]; + static int eye_levels[MAX_CLIENTNETWORKEYES]; + int n_cameras = 0; + vec3_t mi, ma; + + for(i = 0; i < sv.writeentitiestoclient_numeyes; ++i) + eye_levels[i] = 0; + + // check line of sight to portal entities and add them to PVS + for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed)) + { + if (!ed->priv.server->free) + { + if(PRVM_serveredictfunction(ed, camera_transform)) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = e; + PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber; + VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_serverglobalvector(trace_endpos)); + VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_G_VECTOR(OFS_PARM0)); + VectorClear(PRVM_G_VECTOR(OFS_PARM1)); + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing"); + if(!VectorCompare(PRVM_serverglobalvector(trace_endpos), sv.writeentitiestoclient_eyes[0])) + { + VectorCopy(PRVM_serverglobalvector(trace_endpos), camera_origins[n_cameras]); + cameras[n_cameras] = e; + ++n_cameras; + if(n_cameras >= MAX_LEVELNETWORKEYES) + break; + } + } + } + } + + if(!n_cameras) + return; + + // i is loop counter, is reset to 0 when an eye got added + // j is camera index to check + for(i = 0, j = 0; sv.writeentitiestoclient_numeyes < MAX_CLIENTNETWORKEYES && i < n_cameras; ++i, ++j, j %= n_cameras) + { + if(!cameras[j]) + continue; + ed = PRVM_EDICT_NUM(cameras[j]); + VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, mins), mi); + VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, maxs), ma); + for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k) + if(eye_levels[k] <= MAX_EYE_RECURSION) + { + if(SV_CanSeeBox(sv_cullentities_trace_samples.integer, sv_cullentities_trace_enlarge.value, sv.writeentitiestoclient_eyes[k], mi, ma)) + { + eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1; + VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]); + // Con_Printf("added eye %d: %f %f %f because we can see %f %f %f .. %f %f %f from eye %d\n", j, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][0], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][1], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][2], mi[0], mi[1], mi[2], ma[0], ma[1], ma[2], k); + sv.writeentitiestoclient_numeyes++; + cameras[j] = 0; + i = 0; + break; + } + } + } +} +#else +void SV_AddCameraEyes(void) +{ +} +#endif + +static void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize) +{ + prvm_prog_t *prog = SVVM_prog; + qboolean need_empty = false; + int i, numsendstates, numcsqcsendstates; + entity_state_t *s; + prvm_edict_t *camera; + qboolean success; + vec3_t eye; + + // if there isn't enough space to accomplish anything, skip it + if (msg->cursize + 25 > maxsize) + return; + + sv.writeentitiestoclient_msg = msg; + sv.writeentitiestoclient_clientnumber = client - svs.clients; + + sv.writeentitiestoclient_stats_culled_pvs = 0; + sv.writeentitiestoclient_stats_culled_trace = 0; + sv.writeentitiestoclient_stats_visibleentities = 0; + sv.writeentitiestoclient_stats_totalentities = 0; + sv.writeentitiestoclient_numeyes = 0; + + // get eye location + sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes + camera = PRVM_EDICT_NUM( client->clientcamera ); + VectorAdd(PRVM_serveredictvector(camera, origin), PRVM_serveredictvector(clent, view_ofs), eye); + sv.writeentitiestoclient_pvsbytes = 0; + // get the PVS values for the eye location, later FatPVS calls will merge + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, eye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0); + + // add the eye to a list for SV_CanSeeBox tests + VectorCopy(eye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]); + sv.writeentitiestoclient_numeyes++; + + // calculate predicted eye origin for SV_CanSeeBox tests + if (sv_cullentities_trace_prediction.integer) + { + vec_t predtime = bound(0, host_client->ping, sv_cullentities_trace_prediction_time.value); + vec3_t predeye; + VectorMA(eye, predtime, PRVM_serveredictvector(camera, velocity), predeye); + if (SV_CanSeeBox(1, 0, eye, predeye, predeye)) + { + VectorCopy(predeye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]); + sv.writeentitiestoclient_numeyes++; + } + //if (!sv.writeentitiestoclient_useprediction) + // Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n"); + } + + SV_AddCameraEyes(); + + // build PVS from the new eyes + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + for(i = 1; i < sv.writeentitiestoclient_numeyes; ++i) + sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_eyes[i], 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0); + + sv.sententitiesmark++; + + for (i = 0;i < sv.numsendentities;i++) + SV_MarkWriteEntityStateToClient(sv.sendentities + i); + + numsendstates = 0; + numcsqcsendstates = 0; + for (i = 0;i < sv.numsendentities;i++) + { + s = &sv.sendentities[i]; + if (sv.sententities[s->number] == sv.sententitiesmark) + { + if(s->active == ACTIVE_NETWORK) + { + if (s->exteriormodelforclient) + { + if (s->exteriormodelforclient == sv.writeentitiestoclient_cliententitynumber) + s->flags |= RENDER_EXTERIORMODEL; + else + s->flags &= ~RENDER_EXTERIORMODEL; + } + sv.writeentitiestoclient_sendstates[numsendstates++] = s; + } + else if(sv.sendentities[i].active == ACTIVE_SHARED) + sv.writeentitiestoclient_csqcsendstates[numcsqcsendstates++] = s->number; + else + Con_Printf("entity %d is in sv.sendentities and marked, but not active, please breakpoint me\n", s->number); + } + } + + if (sv_cullentities_stats.integer) + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv.writeentitiestoclient_stats_totalentities, sv.writeentitiestoclient_stats_visibleentities, sv.writeentitiestoclient_stats_culled_pvs + sv.writeentitiestoclient_stats_culled_trace, sv.writeentitiestoclient_stats_culled_pvs, sv.writeentitiestoclient_stats_culled_trace); + + if(client->entitydatabase5) + need_empty = EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, client->entitydatabase5->latestframenum + 1); + else + EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, 0); + + // force every 16th frame to be not empty (or cl_movement replay takes + // too long) + // BTW, this should normally not kick in any more due to the check + // below, except if the client stopped sending movement frames + if(client->num_skippedentityframes >= 16) + need_empty = true; + + // help cl_movement a bit more + if(client->movesequence != client->lastmovesequence) + need_empty = true; + client->lastmovesequence = client->movesequence; + + if (client->entitydatabase5) + success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty); + else if (client->entitydatabase4) + { + success = EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates); + Protocol_WriteStatsReliable(); + } + else if (client->entitydatabase) + { + success = EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1); + Protocol_WriteStatsReliable(); + } + else + { + success = EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates); + Protocol_WriteStatsReliable(); + } + + if(success) + client->num_skippedentityframes = 0; + else + ++client->num_skippedentityframes; +} + +/* +============= +SV_CleanupEnts + +============= +*/ +static void SV_CleanupEnts (void) +{ + prvm_prog_t *prog = SVVM_prog; + int e; + prvm_edict_t *ent; + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (e=1 ; enum_edicts ; e++, ent = PRVM_NEXT_EDICT(ent)) + PRVM_serveredictfloat(ent, effects) = (int)PRVM_serveredictfloat(ent, effects) & ~EF_MUZZLEFLASH; +} + +/* +================== +SV_WriteClientdataToMessage + +================== +*/ +void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats) +{ + prvm_prog_t *prog = SVVM_prog; + int bits; + int i; + prvm_edict_t *other; + int items; + vec3_t punchvector; + int viewzoom; + const char *s; + float *statsf = (float *)stats; + float gravity; + +// +// send a damage message +// + if (PRVM_serveredictfloat(ent, dmg_take) || PRVM_serveredictfloat(ent, dmg_save)) + { + other = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, dmg_inflictor)); + MSG_WriteByte (msg, svc_damage); + MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save)); + MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take)); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol); + + PRVM_serveredictfloat(ent, dmg_take) = 0; + PRVM_serveredictfloat(ent, 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(PRVM_serveredictfloat(ent, fixangle)) + { + // angle fixing was requested by global thinking code... + // so store the current angles for later use + VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles); + host_client->fixangle_angles_set = TRUE; + + // and clear fixangle for the next frame + PRVM_serveredictfloat(ent, fixangle) = 0; + } + + if (host_client->fixangle_angles_set) + { + MSG_WriteByte (msg, svc_setangle); + for (i=0 ; i < 3 ; i++) + MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol); + host_client->fixangle_angles_set = FALSE; + } + + // the runes are in serverflags, pack them into the items value, also pack + // in the items2 value for mission pack huds + // (used only in the mission packs, which do not use serverflags) + items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23) | ((int)PRVM_serverglobalfloat(serverflags) << 28); + + VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector); + + // cache weapon model name and index in client struct to save time + // (this search can be almost 1% of cpu time!) + s = PRVM_GetString(prog, PRVM_serveredictstring(ent, weaponmodel)); + if (strcmp(s, client->weaponmodel)) + { + strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel)); + client->weaponmodelindex = SV_ModelIndex(s, 1); + } + + viewzoom = (int)(PRVM_serveredictfloat(ent, viewzoom) * 255.0f); + if (viewzoom == 0) + viewzoom = 255; + + bits = 0; + + if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) + bits |= SU_ONGROUND; + if (PRVM_serveredictfloat(ent, waterlevel) >= 2) + bits |= SU_INWATER; + if (PRVM_serveredictfloat(ent, idealpitch)) + bits |= SU_IDEALPITCH; + + for (i=0 ; i<3 ; i++) + { + if (PRVM_serveredictvector(ent, punchangle)[i]) + bits |= (SU_PUNCH1<weaponmodelindex; + stats[STAT_HEALTH] = (int)PRVM_serveredictfloat(ent, health); + stats[STAT_AMMO] = (int)PRVM_serveredictfloat(ent, currentammo); + stats[STAT_SHELLS] = (int)PRVM_serveredictfloat(ent, ammo_shells); + stats[STAT_NAILS] = (int)PRVM_serveredictfloat(ent, ammo_nails); + stats[STAT_ROCKETS] = (int)PRVM_serveredictfloat(ent, ammo_rockets); + stats[STAT_CELLS] = (int)PRVM_serveredictfloat(ent, ammo_cells); + stats[STAT_ACTIVEWEAPON] = (int)PRVM_serveredictfloat(ent, weapon); + stats[STAT_VIEWZOOM] = viewzoom; + stats[STAT_TOTALSECRETS] = (int)PRVM_serverglobalfloat(total_secrets); + stats[STAT_TOTALMONSTERS] = (int)PRVM_serverglobalfloat(total_monsters); + // the QC bumps these itself by sending svc_'s, so we have to keep them + // zero or they'll be corrected by the engine + //stats[STAT_SECRETS] = PRVM_serverglobalfloat(found_secrets); + //stats[STAT_MONSTERS] = PRVM_serverglobalfloat(killed_monsters); + + // movement settings for prediction + // note: these are not sent in protocols with lower MAX_CL_STATS limits + stats[STAT_MOVEFLAGS] = MOVEFLAG_VALID + | (sv_gameplayfix_q2airaccelerate.integer ? MOVEFLAG_Q2AIRACCELERATE : 0) + | (sv_gameplayfix_nogravityonground.integer ? MOVEFLAG_NOGRAVITYONGROUND : 0) + | (sv_gameplayfix_gravityunaffectedbyticrate.integer ? MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE : 0) + ; + statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value; + statsf[STAT_MOVEVARS_TIMESCALE] = slowmo.value; + statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value; + statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value; + statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value; + statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this + statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value; + statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value; + statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value; + statsf[STAT_MOVEVARS_ENTGRAVITY] = gravity; + statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value; + statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value; + statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value; + statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value; + statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value; + statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR] = sv_airaccel_qw_stretchfactor.value; + statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value; + statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value; + statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value; + statsf[STAT_MOVEVARS_AIRSTOPACCELERATE] = sv_airstopaccelerate.value; + statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value; + statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value; + statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW] = sv_airstrafeaccel_qw.value; + statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value; + statsf[STAT_MOVEVARS_AIRCONTROL_POWER] = sv_aircontrol_power.value; + statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY] = sv_aircontrol_penalty.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value; + statsf[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW] = sv_airspeedlimit_nonqw.value; + statsf[STAT_FRAGLIMIT] = fraglimit.value; + statsf[STAT_TIMELIMIT] = timelimit.value; + + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + { + if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT; + bits |= SU_ITEMS; + if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME; + if (stats[STAT_ARMOR]) bits |= SU_ARMOR; + bits |= SU_WEAPON; + // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom? + if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + if (viewzoom != 255) + bits |= SU_VIEWZOOM; + } + + if (bits >= 65536) + bits |= SU_EXTEND1; + if (bits >= 16777216) + bits |= SU_EXTEND2; + + // send the data + MSG_WriteByte (msg, svc_clientdata); + MSG_WriteShort (msg, bits); + if (bits & SU_EXTEND1) + MSG_WriteByte(msg, bits >> 16); + if (bits & SU_EXTEND2) + MSG_WriteByte(msg, bits >> 24); + + if (bits & SU_VIEWHEIGHT) + MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]); + + if (bits & SU_IDEALPITCH) + MSG_WriteChar (msg, (int)PRVM_serveredictfloat(ent, idealpitch)); + + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1<begun || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0]))) + continue; + SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize); + client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize; + } + SZ_Clear(&sv.datagram); +} + +static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize, int maxsize2) +{ + // scan the splitpoints to find out how many we can fit in + int numsegments, j, split; + if (!client->unreliablemsg_splitpoints) + return; + // always accept the first one if it's within 1024 bytes, this ensures + // that very big datagrams which are over the rate limit still get + // through, just to keep it working + for (numsegments = 1;numsegments < client->unreliablemsg_splitpoints;numsegments++) + if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize) + break; + // the first segment gets an exemption from the rate limiting, otherwise + // it could get dropped consistently due to a low rate limit + if (numsegments == 1) + maxsize = maxsize2; + // some will fit, so add the ones that will fit + split = client->unreliablemsg_splitpoint[numsegments-1]; + // note this discards ones that were accepted by the segments scan but + // can not fit, such as a really huge first one that will never ever + // fit in a packet... + if (msg->cursize + split <= maxsize) + SZ_Write(msg, client->unreliablemsg.data, split); + // remove the part we sent, keeping any remaining data + client->unreliablemsg.cursize -= split; + if (client->unreliablemsg.cursize > 0) + memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize); + // adjust remaining splitpoints + client->unreliablemsg_splitpoints -= numsegments; + for (j = 0;j < client->unreliablemsg_splitpoints;j++) + client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split; +} + +/* +======================= +SV_SendClientDatagram +======================= +*/ +static void SV_SendClientDatagram (client_t *client) +{ + int clientrate, maxrate, maxsize, maxsize2, downloadsize; + sizebuf_t msg; + int stats[MAX_CL_STATS]; + static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; + + // obey rate limit by limiting packet frequency if the packet size + // limiting fails + // (usually this is caused by reliable messages) + if (!NetConn_CanSend(client->netconnection)) + return; + + // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates + maxrate = max(NET_MINRATE, sv_maxrate.integer); + if (sv_maxrate.integer != maxrate) + Cvar_SetValueQuick(&sv_maxrate, maxrate); + + // clientrate determines the 'cleartime' of a packet + // (how long to wait before sending another, based on this packet's size) + clientrate = bound(NET_MINRATE, client->rate, maxrate); + + switch (sv.protocol) + { + case PROTOCOL_QUAKE: + case PROTOCOL_QUAKEDP: + case PROTOCOL_NEHAHRAMOVIE: + case PROTOCOL_NEHAHRABJP: + case PROTOCOL_NEHAHRABJP2: + case PROTOCOL_NEHAHRABJP3: + case PROTOCOL_QUAKEWORLD: + // no packet size limit support on Quake protocols because it just + // causes missing entities/effects + // packets are simply sent less often to obey the rate limit + maxsize = 1024; + maxsize2 = 1024; + break; + case PROTOCOL_DARKPLACES1: + case PROTOCOL_DARKPLACES2: + case PROTOCOL_DARKPLACES3: + case PROTOCOL_DARKPLACES4: + // no packet size limit support on DP1-4 protocols because they kick + // the client off if they overflow, and miss effects + // packets are simply sent less often to obey the rate limit + maxsize = sizeof(sv_sendclientdatagram_buf); + maxsize2 = sizeof(sv_sendclientdatagram_buf); + break; + default: + // DP5 and later protocols support packet size limiting which is a + // better method than limiting packet frequency as QW does + // + // at very low rates (or very small sys_ticrate) the packet size is + // not reduced below 128, but packets may be sent less often + maxsize = (int)(clientrate * sys_ticrate.value); + maxsize = bound(128, maxsize, 1400); + maxsize2 = 1400; + // csqc entities can easily exceed 128 bytes, so disable throttling in + // mods that use csqc (they are likely to use less bandwidth anyway) + if (sv.csqc_progsize > 0) + maxsize = maxsize2; + break; + } + + if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer) + { + // for good singleplayer, send huge packets + maxsize = sizeof(sv_sendclientdatagram_buf); + maxsize2 = sizeof(sv_sendclientdatagram_buf); + // never limit frequency in singleplayer + clientrate = 1000000000; + } + + // while downloading, limit entity updates to half the packet + // (any leftover space will be used for downloading) + if (host_client->download_file) + maxsize /= 2; + + msg.data = sv_sendclientdatagram_buf; + msg.maxsize = sizeof(sv_sendclientdatagram_buf); + msg.cursize = 0; + msg.allowoverflow = false; + + if (host_client->begun) + { + // the player is in the game + MSG_WriteByte (&msg, svc_time); + MSG_WriteFloat (&msg, sv.time); + + // add the client specific data to the datagram + SV_WriteClientdataToMessage (client, client->edict, &msg, stats); + // now update the stats[] array using any registered custom fields + VM_SV_UpdateCustomStats(client, client->edict, &msg, stats); + // set host_client->statsdeltabits + Protocol_UpdateClientStats (stats); + + // add as many queued unreliable messages (effects) as we can fit + // limit effects to half of the remaining space + if (client->unreliablemsg.cursize) + SV_WriteUnreliableMessages (client, &msg, maxsize/2, maxsize2); + + // now write as many entities as we can fit, and also sends stats + SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize); + } + else if (realtime > client->keepalivetime) + { + // the player isn't totally in the game yet + // send small keepalive messages if too much time has passed + // (may also be sending downloads) + client->keepalivetime = realtime + 5; + MSG_WriteChar (&msg, svc_nop); + } + + // if a download is active, see if there is room to fit some download data + // in this packet + downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7; + if (host_client->download_file && host_client->download_started && downloadsize > 0) + { + fs_offset_t downloadstart; + unsigned char data[1400]; + downloadstart = FS_Tell(host_client->download_file); + downloadsize = min(downloadsize, (int)sizeof(data)); + downloadsize = FS_Read(host_client->download_file, data, downloadsize); + // note this sends empty messages if at the end of the file, which is + // necessary to keep the packet loss logic working + // (the last blocks may be lost and need to be re-sent, and that will + // only occur if the client acks the empty end messages, revealing + // a gap in the download progress, causing the last blocks to be + // sent again) + MSG_WriteChar (&msg, svc_downloaddata); + MSG_WriteLong (&msg, downloadstart); + MSG_WriteShort (&msg, downloadsize); + if (downloadsize > 0) + SZ_Write (&msg, data, downloadsize); + } + + // reliable only if none is in progress + if(client->sendsignon != 2 && !client->netconnection->sendMessageLength) + SV_WriteDemoMessage(client, &(client->netconnection->message), false); + // unreliable + SV_WriteDemoMessage(client, &msg, false); + +// send the datagram + NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->sendsignon == 2); + if (client->sendsignon == 1 && !client->netconnection->message.cursize) + client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase) +} + +/* +======================= +SV_UpdateToReliableMessages +======================= +*/ +static void SV_UpdateToReliableMessages (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, j; + client_t *client; + const char *name; + const char *model; + const char *skin; + int clientcamera; + +// check for changes to be sent over the reliable streams + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + // update the host_client fields we care about according to the entity fields + host_client->edict = PRVM_EDICT_NUM(i+1); + + // DP_SV_CLIENTNAME + name = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, netname)); + if (name == NULL) + name = ""; + // always point the string back at host_client->name to keep it safe + strlcpy (host_client->name, name, sizeof (host_client->name)); + PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name); + if (strcmp(host_client->old_name, host_client->name)) + { + if (host_client->begun) + SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name); + strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name)); + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatename); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteString (&sv.reliable_datagram, host_client->name); + SV_WriteNetnameIntoDemo(host_client); + } + + // DP_SV_CLIENTCOLORS + host_client->colors = (int)PRVM_serveredictfloat(host_client->edict, clientcolors); + if (host_client->old_colors != host_client->colors) + { + host_client->old_colors = host_client->colors; + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteByte (&sv.reliable_datagram, host_client->colors); + } + + // NEXUIZ_PLAYERMODEL + model = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playermodel)); + if (model == NULL) + model = ""; + // always point the string back at host_client->name to keep it safe + strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel)); + PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel); + + // NEXUIZ_PLAYERSKIN + skin = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playerskin)); + if (skin == NULL) + skin = ""; + // always point the string back at host_client->name to keep it safe + strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin)); + PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin); + + // TODO: add an extension name for this [1/17/2008 Black] + clientcamera = PRVM_serveredictedict(host_client->edict, clientcamera); + if (clientcamera > 0) + { + int oldclientcamera = host_client->clientcamera; + if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->priv.required->free) + clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict); + host_client->clientcamera = clientcamera; + + if (oldclientcamera != host_client->clientcamera && host_client->netconnection) + { + MSG_WriteByte(&host_client->netconnection->message, svc_setview); + MSG_WriteShort(&host_client->netconnection->message, host_client->clientcamera); + } + } + + // frags + host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags); + if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) + if(!host_client->begun && host_client->netconnection) + host_client->frags = -666; + if (host_client->old_frags != host_client->frags) + { + host_client->old_frags = host_client->frags; + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteShort (&sv.reliable_datagram, host_client->frags); + } + } + + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) + if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet + SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); + + SZ_Clear (&sv.reliable_datagram); +} + + +/* +======================= +SV_SendClientMessages +======================= +*/ +void SV_SendClientMessages(void) +{ + int i, prepared = false; + + if (sv.protocol == PROTOCOL_QUAKEWORLD) + Sys_Error("SV_SendClientMessages: no quakeworld support\n"); + + SV_FlushBroadcastMessages(); + +// update frags, names, etc + SV_UpdateToReliableMessages(); + +// build individual updates + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + if (!host_client->active) + continue; + if (!host_client->netconnection) + continue; + + if (host_client->netconnection->message.overflowed) + { + SV_DropClient (true); // if the message couldn't send, kick off + continue; + } + + if (!prepared) + { + prepared = true; + // only prepare entities once per frame + SV_PrepareEntitiesForSending(); + } + SV_SendClientDatagram(host_client); + } + +// clear muzzle flashes + SV_CleanupEnts(); +} + +static void SV_StartDownload_f(void) +{ + if (host_client->download_file) + host_client->download_started = true; +} + +/* + * Compression extension negotiation: + * + * Server to client: + * cl_serverextension_download 2 + * + * Client to server: + * download + * e.g. + * download maps/map1.bsp lzo deflate huffman + * + * Server to client: + * cl_downloadbegin + * e.g. + * cl_downloadbegin 123456 maps/map1.bsp deflate + * + * The server may choose not to compress the file by sending no compression name, like: + * cl_downloadbegin 345678 maps/map1.bsp + * + * NOTE: the "download" command may only specify compression algorithms if + * cl_serverextension_download is 2! + * If cl_serverextension_download has a different value, the client must + * assume this extension is not supported! + */ + +static void Download_CheckExtensions(void) +{ + int i; + int argc = Cmd_Argc(); + + // first reset them all + host_client->download_deflate = false; + + for(i = 2; i < argc; ++i) + { + if(!strcmp(Cmd_Argv(i), "deflate")) + { + host_client->download_deflate = true; + break; + } + } +} + +static void SV_Download_f(void) +{ + const char *whichpack, *whichpack2, *extension; + qboolean is_csqc; // so we need to check only once + + if (Cmd_Argc() < 2) + { + SV_ClientPrintf("usage: download {}*\n"); + SV_ClientPrintf(" supported extensions: deflate\n"); + return; + } + + if (FS_CheckNastyPath(Cmd_Argv(1), false)) + { + SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1)); + return; + } + + if (host_client->download_file) + { + // at this point we'll assume the previous download should be aborted + Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name); + Host_ClientCommands("\nstopdownload\n"); + + // close the file and reset variables + FS_Close(host_client->download_file); + host_client->download_file = NULL; + host_client->download_name[0] = 0; + host_client->download_expectedposition = 0; + host_client->download_started = false; + } + + is_csqc = (sv.csqc_progname[0] && strcmp(Cmd_Argv(1), sv.csqc_progname) == 0); + + if (!sv_allowdownloads.integer && !is_csqc) + { + SV_ClientPrintf("Downloads are disabled on this server\n"); + Host_ClientCommands("\nstopdownload\n"); + return; + } + + Download_CheckExtensions(); + + strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name)); + extension = FS_FileExtension(host_client->download_name); + + // host_client is asking to download a specified file + if (developer_extra.integer) + Con_DPrintf("Download request for %s by %s\n", host_client->download_name, host_client->name); + + if(is_csqc) + { + char extensions[MAX_QPATH]; // make sure this can hold all extensions + extensions[0] = '\0'; + + if(host_client->download_deflate) + strlcat(extensions, " deflate", sizeof(extensions)); + + Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name); + + if(host_client->download_deflate && svs.csqc_progdata_deflated) + host_client->download_file = FS_FileFromData(svs.csqc_progdata_deflated, svs.csqc_progsize_deflated, true); + else + host_client->download_file = FS_FileFromData(svs.csqc_progdata, sv.csqc_progsize, true); + + // no, no space is needed between %s and %s :P + Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); + + host_client->download_expectedposition = 0; + host_client->download_started = false; + host_client->sendsignon = true; // make sure this message is sent + return; + } + + if (!FS_FileExists(host_client->download_name)) + { + SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + + // check if the user is trying to download part of registered Quake(r) + whichpack = FS_WhichPack(host_client->download_name); + whichpack2 = FS_WhichPack("gfx/pop.lmp"); + if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name)) + { + SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + + // check if the server has forbidden archive downloads entirely + if (!sv_allowdownloads_inarchive.integer) + { + whichpack = FS_WhichPack(host_client->download_name); + if (whichpack) + { + SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack); + Host_ClientCommands("\nstopdownload\n"); + return; + } + } + + if (!sv_allowdownloads_config.integer) + { + if (!strcasecmp(extension, "cfg")) + { + SV_ClientPrintf("Download rejected: file \"%s\" is a .cfg file which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + } + + if (!sv_allowdownloads_dlcache.integer) + { + if (!strncasecmp(host_client->download_name, "dlcache/", 8)) + { + SV_ClientPrintf("Download rejected: file \"%s\" is in the dlcache/ directory which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + } + + if (!sv_allowdownloads_archive.integer) + { + if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) + { + SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + } + + host_client->download_file = FS_OpenVirtualFile(host_client->download_name, true); + if (!host_client->download_file) + { + SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + return; + } + + if (FS_FileSize(host_client->download_file) > 1<<30) + { + SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + FS_Close(host_client->download_file); + host_client->download_file = NULL; + return; + } + + if (FS_FileSize(host_client->download_file) < 0) + { + SV_ClientPrintf("Download rejected: file \"%s\" is not a regular file\n", host_client->download_name); + Host_ClientCommands("\nstopdownload\n"); + FS_Close(host_client->download_file); + host_client->download_file = NULL; + return; + } + + Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name); + + /* + * we can only do this if we would actually deflate on the fly + * which we do not (yet)! + { + char extensions[MAX_QPATH]; // make sure this can hold all extensions + extensions[0] = '\0'; + + if(host_client->download_deflate) + strlcat(extensions, " deflate", sizeof(extensions)); + + // no, no space is needed between %s and %s :P + Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); + } + */ + Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name); + + host_client->download_expectedposition = 0; + host_client->download_started = false; + host_client->sendsignon = true; // make sure this message is sent + + // the rest of the download process is handled in SV_SendClientDatagram + // and other code dealing with svc_downloaddata and clc_ackdownloaddata + // + // no svc_downloaddata messages will be sent until sv_startdownload is + // sent by the client +} + +/* +============================================================================== + +SERVER SPAWNING + +============================================================================== +*/ + +/* +================ +SV_ModelIndex + +================ +*/ +int SV_ModelIndex(const char *s, int precachemode) +{ + int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_MODELS); + char filename[MAX_QPATH]; + if (!s || !*s) + return 0; + // testing + //if (precachemode == 2) + // return 0; + strlcpy(filename, s, sizeof(filename)); + for (i = 2;i < limit;i++) + { + if (!sv.model_precache[i][0]) + { + if (precachemode) + { + if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)) + { + Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename); + return 0; + } + if (precachemode == 1) + Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename); + strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i])); + if (sv.state == ss_loading) + { + // running from SV_SpawnServer which is launched from the client console command interpreter + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL); + } + else + { + if (svs.threaded) + { + // this is running on the server thread, we can't load a model here (it would crash on renderer calls), so only look it up, the svc_precache will cause it to be loaded when it reaches the client + sv.models[i] = Mod_FindName (sv.model_precache[i], s[0] == '*' ? sv.worldname : NULL); + } + else + { + // running single threaded, so we can load the model here + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL); + } + MSG_WriteByte(&sv.reliable_datagram, svc_precache); + MSG_WriteShort(&sv.reliable_datagram, i); + MSG_WriteString(&sv.reliable_datagram, filename); + } + return i; + } + Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename); + return 0; + } + if (!strcmp(sv.model_precache[i], filename)) + return i; + } + Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS); + return 0; +} + +/* +================ +SV_SoundIndex + +================ +*/ +int SV_SoundIndex(const char *s, int precachemode) +{ + int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_SOUNDS); + char filename[MAX_QPATH]; + if (!s || !*s) + return 0; + // testing + //if (precachemode == 2) + // return 0; + strlcpy(filename, s, sizeof(filename)); + for (i = 1;i < limit;i++) + { + if (!sv.sound_precache[i][0]) + { + if (precachemode) + { + if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)) + { + Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename); + return 0; + } + if (precachemode == 1) + Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename); + strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i])); + if (sv.state != ss_loading) + { + MSG_WriteByte(&sv.reliable_datagram, svc_precache); + MSG_WriteShort(&sv.reliable_datagram, i + 32768); + MSG_WriteString(&sv.reliable_datagram, filename); + } + return i; + } + Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename); + return 0; + } + if (!strcmp(sv.sound_precache[i], filename)) + return i; + } + Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS); + return 0; +} + +/* +================ +SV_ParticleEffectIndex + +================ +*/ +int SV_ParticleEffectIndex(const char *name) +{ + int i, argc, linenumber, effectnameindex; + int filepass; + fs_offset_t filesize; + unsigned char *filedata; + const char *text; + const char *textstart; + //const char *textend; + char argv[16][1024]; + char filename[MAX_QPATH]; + if (!sv.particleeffectnamesloaded) + { + sv.particleeffectnamesloaded = true; + memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname)); + for (i = 0;i < EFFECT_TOTAL;i++) + strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i])); + for (filepass = 0;;filepass++) + { + if (filepass == 0) + dpsnprintf(filename, sizeof(filename), "effectinfo.txt"); + else if (filepass == 1) + dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", sv.worldnamenoextension); + else + break; + filedata = FS_LoadFile(filename, tempmempool, true, &filesize); + if (!filedata) + continue; + textstart = (const char *)filedata; + //textend = (const char *)filedata + filesize; + text = textstart; + for (linenumber = 1;;linenumber++) + { + argc = 0; + for (;;) + { + if (!COM_ParseToken_Simple(&text, true, false, true) || !strcmp(com_token, "\n")) + break; + if (argc < 16) + { + strlcpy(argv[argc], com_token, sizeof(argv[argc])); + argc++; + } + } + if (com_token[0] == 0) + break; // if the loop exited and it's not a \n, it's EOF + if (argc < 1) + continue; + if (!strcmp(argv[0], "effect")) + { + if (argc == 2) + { + for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++) + { + if (sv.particleeffectname[effectnameindex][0]) + { + if (!strcmp(sv.particleeffectname[effectnameindex], argv[1])) + break; + } + else + { + strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex])); + break; + } + } + // if we run out of names, abort + if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME) + { + Con_Printf("%s:%i: too many effects!\n", filename, linenumber); + break; + } + } + } + } + Mem_Free(filedata); + } + } + // search for the name + for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++) + if (!strcmp(sv.particleeffectname[effectnameindex], name)) + return effectnameindex; + // return 0 if we couldn't find it + return 0; +} + +dp_model_t *SV_GetModelByIndex(int modelindex) +{ + return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL; +} + +dp_model_t *SV_GetModelFromEdict(prvm_edict_t *ed) +{ + prvm_prog_t *prog = SVVM_prog; + int modelindex; + if (!ed || ed->priv.server->free) + return NULL; + modelindex = (int)PRVM_serveredictfloat(ed, modelindex); + return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL; +} + +/* +================ +SV_CreateBaseline + +================ +*/ +static void SV_CreateBaseline (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, entnum, large; + prvm_edict_t *svent; + + // LordHavoc: clear *all* baselines (not just active ones) + for (entnum = 0;entnum < prog->max_edicts;entnum++) + { + // get the current server version + svent = PRVM_EDICT_NUM(entnum); + + // LordHavoc: always clear state values, whether the entity is in use or not + svent->priv.server->baseline = defaultstate; + + if (svent->priv.server->free) + continue; + if (entnum > svs.maxclients && !PRVM_serveredictfloat(svent, modelindex)) + continue; + + // create entity baseline + VectorCopy (PRVM_serveredictvector(svent, origin), svent->priv.server->baseline.origin); + VectorCopy (PRVM_serveredictvector(svent, angles), svent->priv.server->baseline.angles); + svent->priv.server->baseline.frame = (int)PRVM_serveredictfloat(svent, frame); + svent->priv.server->baseline.skin = (int)PRVM_serveredictfloat(svent, skin); + if (entnum > 0 && entnum <= svs.maxclients) + { + svent->priv.server->baseline.colormap = entnum; + svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1); + } + else + { + svent->priv.server->baseline.colormap = 0; + svent->priv.server->baseline.modelindex = (int)PRVM_serveredictfloat(svent, modelindex); + } + + large = false; + if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00) + { + large = true; + if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + large = false; + } + + // add to the message + if (large) + MSG_WriteByte (&sv.signon, svc_spawnbaseline2); + else + MSG_WriteByte (&sv.signon, svc_spawnbaseline); + MSG_WriteShort (&sv.signon, entnum); + + if (large) + { + MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex); + MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame); + } + else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + { + MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex); + MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame); + } + else + { + MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex); + MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame); + } + MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap); + MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol); + MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol); + } + } +} + +/* +================ +SV_Prepare_CSQC + +Load csprogs.dat and comperss it so it doesn't need to be +reloaded on request. +================ +*/ +static void SV_Prepare_CSQC(void) +{ + fs_offset_t progsize; + + if(svs.csqc_progdata) + { + Con_DPrintf("Unloading old CSQC data.\n"); + Mem_Free(svs.csqc_progdata); + if(svs.csqc_progdata_deflated) + Mem_Free(svs.csqc_progdata_deflated); + } + + svs.csqc_progdata = NULL; + svs.csqc_progdata_deflated = NULL; + + sv.csqc_progname[0] = 0; + svs.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize); + + if(progsize > 0) + { + size_t deflated_size; + + sv.csqc_progsize = (int)progsize; + sv.csqc_progcrc = CRC_Block(svs.csqc_progdata, progsize); + strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname)); + Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); + + Con_DPrint("Compressing csprogs.dat\n"); + //unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool); + svs.csqc_progdata_deflated = FS_Deflate(svs.csqc_progdata, progsize, &deflated_size, -1, sv_mempool); + svs.csqc_progsize_deflated = (int)deflated_size; + if(svs.csqc_progdata_deflated) + { + Con_DPrintf("Deflated: %g%%\n", 100.0 - 100.0 * (deflated_size / (float)progsize)); + Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)svs.csqc_progsize_deflated); + } + else + Con_DPrintf("Cannot compress - need zlib for this. Using uncompressed progs only.\n"); + } +} + +/* +================ +SV_SaveSpawnparms + +Grabs the current state of each client for saving across the +transition to another level +================ +*/ +void SV_SaveSpawnparms (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i, j; + + svs.serverflags = (int)PRVM_serverglobalfloat(serverflags); + + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + if (!host_client->active) + continue; + + // call the progs to get default spawn parms for the new client + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(SetChangeParms), "QC function SetChangeParms is missing"); + for (j=0 ; jspawn_parms[j] = (&PRVM_serverglobalfloat(parm1))[j]; + } +} + +/* +================ +SV_SpawnServer + +This is called at the start of each level +================ +*/ + +void SV_SpawnServer (const char *server) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *ent; + int i; + char *entities; + dp_model_t *worldmodel; + char modelname[sizeof(sv.worldname)]; + char vabuf[1024]; + + Con_DPrintf("SpawnServer: %s\n", server); + + dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server); + + if (!FS_FileExists(modelname)) + { + dpsnprintf (modelname, sizeof(modelname), "maps/%s", server); + if (!FS_FileExists(modelname)) + { + Con_Printf("SpawnServer: no map file named maps/%s.bsp\n", server); + return; + } + } + +// SV_LockThreadMutex(); + + if(cls.state == ca_dedicated) + Sys_MakeProcessNice(); + + if (cls.state != ca_dedicated) + { + SCR_BeginLoadingPlaque(false); + S_StopAllSounds(); + } + + if(sv.active) + { + World_End(&sv.world); + if(PRVM_serverfunction(SV_Shutdown)) + { + func_t s = PRVM_serverfunction(SV_Shutdown); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again + prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); + } + } + + // free q3 shaders so that any newly downloaded shaders will be active + Mod_FreeQ3Shaders(); + + worldmodel = Mod_ForName(modelname, false, developer.integer > 0, NULL); + if (!worldmodel || !worldmodel->TraceBox) + { + Con_Printf("Couldn't load map %s\n", modelname); + + if(cls.state == ca_dedicated) + Sys_MakeProcessMean(); + +// SV_UnlockThreadMutex(); + + return; + } + + Collision_Cache_Reset(true); + + // let's not have any servers with no name + if (hostname.string[0] == 0) + Cvar_Set ("hostname", "UNNAMED"); + scr_centertime_off = 0; + + svs.changelevel_issued = false; // now safe to issue another + + // make the map a required file for clients + Curl_ClearRequirements(); + Curl_RequireFile(modelname); + +// +// tell all connected clients that we are going to a new level +// + if (sv.active) + { + client_t *client; + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (client->netconnection) + { + MSG_WriteByte(&client->netconnection->message, svc_stufftext); + MSG_WriteString(&client->netconnection->message, "reconnect\n"); + } + } + } + else + { + // open server port + //NetConn_OpenServerPorts(true); + + //Just use the loop connection + NetConn_OpenServerPorts(0); + } + +// +// make cvars consistant +// + if (coop.integer) + Cvar_SetValue ("deathmatch", 0); + // LordHavoc: it can be useful to have skills outside the range 0-3... + //current_skill = bound(0, (int)(skill.value + 0.5), 3); + //Cvar_SetValue ("skill", (float)current_skill); + current_skill = (int)(skill.value + 0.5); + +// +// set up the new server +// + memset (&sv, 0, sizeof(sv)); + // if running a local client, make sure it doesn't try to access the last + // level's data which is no longer valiud + cls.signon = 0; + + Cvar_SetValue("halflifebsp", worldmodel->brush.ishlbsp); + + if(*sv_random_seed.string) + { + srand(sv_random_seed.integer); + Con_Printf("NOTE: random seed is %d; use for debugging/benchmarking only!\nUnset sv_random_seed to get real random numbers again.\n", sv_random_seed.integer); + } + + SV_VM_Setup(); + + sv.active = true; + + // set level base name variables for later use + strlcpy (sv.name, server, sizeof (sv.name)); + strlcpy(sv.worldname, modelname, sizeof(sv.worldname)); + FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension)); + strlcpy(sv.worldbasename, !strncmp(sv.worldnamenoextension, "maps/", 5) ? sv.worldnamenoextension + 5 : sv.worldnamenoextension, sizeof(sv.worldbasename)); + //Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); // set later after QC is spawned + Cvar_SetQuick(&sv_worldname, sv.worldname); + Cvar_SetQuick(&sv_worldnamenoextension, sv.worldnamenoextension); + Cvar_SetQuick(&sv_worldbasename, sv.worldbasename); + + sv.protocol = Protocol_EnumForName(sv_protocolname.string); + if (sv.protocol == PROTOCOL_UNKNOWN) + { + char buffer[1024]; + Protocol_Names(buffer, sizeof(buffer)); + Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer); + sv.protocol = PROTOCOL_QUAKE; + } + +// load progs to get entity field count + //PR_LoadProgs ( sv_progs.string ); + + 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; + +// leave slots at start for clients only + //prog->num_edicts = svs.maxclients+1; + + sv.state = ss_loading; + prog->allowworldwrites = true; + sv.paused = false; + + sv.time = 1.0; + + Mod_ClearUsed(); + worldmodel->used = true; + + sv.worldmodel = worldmodel; + sv.models[1] = sv.worldmodel; + +// +// clear world interaction links +// + World_SetSize(&sv.world, sv.worldname, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs, prog); + World_Start(&sv.world); + + strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0])); + + strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0])); + strlcpy(sv.model_precache[1], sv.worldname, sizeof(sv.model_precache[1])); + for (i = 1;i < sv.worldmodel->brush.numsubmodels && i+1 < MAX_MODELS;i++) + { + dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i); + sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.worldname); + } + if(i < sv.worldmodel->brush.numsubmodels) + Con_Printf("Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS); + +// +// load the rest of the entities +// + // AK possible hack since num_edicts is still 0 + ent = PRVM_EDICT_NUM(0); + memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); + ent->priv.server->free = false; + PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(prog, sv.worldname); + PRVM_serveredictfloat(ent, modelindex) = 1; // world model + PRVM_serveredictfloat(ent, solid) = SOLID_BSP; + PRVM_serveredictfloat(ent, movetype) = MOVETYPE_PUSH; + VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, mins)); + VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, maxs)); + VectorCopy(sv.world.mins, PRVM_serveredictvector(ent, absmin)); + VectorCopy(sv.world.maxs, PRVM_serveredictvector(ent, absmax)); + + if (coop.value) + PRVM_serverglobalfloat(coop) = coop.integer; + else + PRVM_serverglobalfloat(deathmatch) = deathmatch.integer; + + PRVM_serverglobalstring(mapname) = PRVM_SetEngineString(prog, sv.name); + +// serverflags are for cross level information (sigils) + PRVM_serverglobalfloat(serverflags) = svs.serverflags; + + // we need to reset the spawned flag on all connected clients here so that + // their thinks don't run during startup (before PutClientInServer) + // we also need to set up the client entities now + // and we need to set the ->edict pointers to point into the progs edicts + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + host_client->begun = false; + host_client->edict = PRVM_EDICT_NUM(i + 1); + PRVM_ED_ClearEdict(prog, host_client->edict); + } + + // load replacement entity file if found + if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.ent", sv.worldnamenoextension), tempmempool, true, NULL))) + { + Con_Printf("Loaded %s.ent\n", sv.worldnamenoextension); + PRVM_ED_LoadFromFile(prog, entities); + Mem_Free(entities); + } + else + PRVM_ED_LoadFromFile(prog, sv.worldmodel->brush.entities); + + + // LordHavoc: clear world angles (to fix e3m3.bsp) + VectorClear(PRVM_serveredictvector(prog->edicts, angles)); + +// all setup is completed, any further precache statements are errors +// sv.state = ss_active; // LordHavoc: workaround for svc_precache bug + prog->allowworldwrites = false; + +// run two frames to allow everything to settle + sv.time = 1.0001; + for (i = 0;i < 2;i++) + { + sv.frametime = 0.1; + SV_Physics (); + } + + if (cls.state == ca_dedicated) + Mod_PurgeUnused(); + +// create a baseline for more efficient communications + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + SV_CreateBaseline (); + + sv.state = ss_active; // LordHavoc: workaround for svc_precache bug + +// send serverinfo to all connected clients, and set up botclients coming back from a level change + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + { + host_client->clientconnectcalled = false; // do NOT call ClientDisconnect if he drops before ClientConnect! + if (!host_client->active) + continue; + if (host_client->netconnection) + SV_SendServerinfo(host_client); + else + { + int j; + // if client is a botclient coming from a level change, we need to + // set up client info that normally requires networking + + // copy spawn parms out of the client_t + for (j=0 ; j< NUM_SPAWN_PARMS ; j++) + (&PRVM_serverglobalfloat(parm1))[j] = host_client->spawn_parms[j]; + + // call the spawn function + host_client->clientconnectcalled = true; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing"); + prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing"); + host_client->begun = true; + } + } + + // update the map title cvar + strlcpy(sv.worldmessage, PRVM_GetString(prog, PRVM_serveredictstring(prog->edicts, message)), sizeof(sv.worldmessage)); // map title (not related to filename) + Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); + + Con_DPrint("Server spawned.\n"); + NetConn_Heartbeat (2); + + if(cls.state == ca_dedicated) + Sys_MakeProcessMean(); + +// SV_UnlockThreadMutex(); +} + +///////////////////////////////////////////////////// +// SV VM stuff + +static void SVVM_begin_increase_edicts(prvm_prog_t *prog) +{ + // links don't survive the transition, so unlink everything + World_UnlinkAll(&sv.world); +} + +static void SVVM_end_increase_edicts(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + + // link every entity except world + for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++) + if (!ent->priv.server->free) + SV_LinkEdict(ent); +} + +static void SVVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e) +{ + // LordHavoc: for consistency set these here + int num = PRVM_NUM_FOR_EDICT(e) - 1; + + e->priv.server->move = false; // don't move on first frame + + if (num >= 0 && num < svs.maxclients) + { + // set colormap and team on newly created player entity + PRVM_serveredictfloat(e, colormap) = num + 1; + PRVM_serveredictfloat(e, team) = (svs.clients[num].colors & 15) + 1; + // set netname/clientcolors back to client values so that + // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately + // reset them + PRVM_serveredictstring(e, netname) = PRVM_SetEngineString(prog, svs.clients[num].name); + PRVM_serveredictfloat(e, clientcolors) = svs.clients[num].colors; + // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN + PRVM_serveredictstring(e, playermodel) = PRVM_SetEngineString(prog, svs.clients[num].playermodel); + PRVM_serveredictstring(e, playerskin) = PRVM_SetEngineString(prog, svs.clients[num].playerskin); + // Assign netaddress (IP Address, etc) + if(svs.clients[num].netconnection != NULL) + { + // Acquire Readable Address + LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false); + PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString(prog, svs.clients[num].netaddress); + } + else + PRVM_serveredictstring(e, netaddress) = PRVM_SetEngineString(prog, "null/botclient"); + if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_idfp[0]) + PRVM_serveredictstring(e, crypto_idfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_idfp); + else + PRVM_serveredictstring(e, crypto_idfp) = 0; + if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_keyfp[0]) + PRVM_serveredictstring(e, crypto_keyfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_keyfp); + else + PRVM_serveredictstring(e, crypto_keyfp) = 0; + if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.server_keyfp[0]) + PRVM_serveredictstring(e, crypto_mykeyfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.server_keyfp); + else + PRVM_serveredictstring(e, crypto_mykeyfp) = 0; + if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.use_aes) + PRVM_serveredictstring(e, crypto_encryptmethod) = PRVM_SetEngineString(prog, "AES128"); + else + PRVM_serveredictstring(e, crypto_encryptmethod) = 0; + if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated) + PRVM_serveredictstring(e, crypto_signmethod) = PRVM_SetEngineString(prog, "HMAC-SHA256"); + else + PRVM_serveredictstring(e, crypto_signmethod) = 0; + } +} + +static void SVVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed) +{ + int i; + int e; + + World_UnlinkEdict(ed); // unlink from world bsp + + PRVM_serveredictstring(ed, model) = 0; + PRVM_serveredictfloat(ed, takedamage) = 0; + PRVM_serveredictfloat(ed, modelindex) = 0; + PRVM_serveredictfloat(ed, colormap) = 0; + PRVM_serveredictfloat(ed, skin) = 0; + PRVM_serveredictfloat(ed, frame) = 0; + VectorClear(PRVM_serveredictvector(ed, origin)); + VectorClear(PRVM_serveredictvector(ed, angles)); + PRVM_serveredictfloat(ed, nextthink) = -1; + PRVM_serveredictfloat(ed, solid) = 0; + + VM_RemoveEdictSkeleton(prog, ed); + World_Physics_RemoveFromEntity(&sv.world, ed); + World_Physics_RemoveJointFromEntity(&sv.world, ed); + + // make sure csqc networking is aware of the removed entity + e = PRVM_NUM_FOR_EDICT(ed); + sv.csqcentityversion[e] = 0; + for (i = 0;i < svs.maxclients;i++) + { + if (svs.clients[i].csqcentityscope[e]) + svs.clients[i].csqcentityscope[e] = 1; // removed, awaiting send + svs.clients[i].csqcentitysendflags[e] = 0xFFFFFF; + } +} + +static void SVVM_count_edicts(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ent; + int active, models, solid, step; + + active = models = solid = step = 0; + for (i=0 ; inum_edicts ; i++) + { + ent = PRVM_EDICT_NUM(i); + if (ent->priv.server->free) + continue; + active++; + if (PRVM_serveredictfloat(ent, solid)) + solid++; + if (PRVM_serveredictstring(ent, model)) + models++; + if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP) + step++; + } + + Con_Printf("num_edicts:%3i\n", prog->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); +} + +static qboolean SVVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent) +{ + // remove things from different skill levels or deathmatch + if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC + { + if (deathmatch.integer) + { + if (((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_DEATHMATCH)) + { + return false; + } + } + else if ((current_skill <= 0 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_EASY )) + || (current_skill == 1 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_MEDIUM)) + || (current_skill >= 2 && ((int)PRVM_serveredictfloat(ent, spawnflags) & SPAWNFLAG_NOT_HARD ))) + { + return false; + } + } + return true; +} + +static void SV_VM_Setup(void) +{ + prvm_prog_t *prog = SVVM_prog; + PRVM_Prog_Init(prog); + + // allocate the mempools + // TODO: move the magic numbers/constants into #defines [9/13/2006 Black] + prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL); + prog->builtins = vm_sv_builtins; + prog->numbuiltins = vm_sv_numbuiltins; + prog->max_edicts = 512; + if (sv.protocol == PROTOCOL_QUAKE) + prog->limit_edicts = 640; // before quake mission pack 1 this was 512 + else if (sv.protocol == PROTOCOL_QUAKEDP) + prog->limit_edicts = 2048; // guessing + else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE) + prog->limit_edicts = 2048; // guessing! + else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + prog->limit_edicts = 4096; // guessing! + else + prog->limit_edicts = MAX_EDICTS; + prog->reserved_edicts = svs.maxclients; + prog->edictprivate_size = sizeof(edict_engineprivate_t); + prog->name = "server"; + prog->extensionstring = vm_sv_extensions; + prog->loadintoworld = true; + + // all callbacks must be defined (pointers are not checked before calling) + prog->begin_increase_edicts = SVVM_begin_increase_edicts; + prog->end_increase_edicts = SVVM_end_increase_edicts; + prog->init_edict = SVVM_init_edict; + prog->free_edict = SVVM_free_edict; + prog->count_edicts = SVVM_count_edicts; + prog->load_edict = SVVM_load_edict; + prog->init_cmd = SVVM_init_cmd; + prog->reset_cmd = SVVM_reset_cmd; + prog->error_cmd = Host_Error; + prog->ExecuteProgram = SVVM_ExecuteProgram; + + PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals); + + // some mods compiled with scrambling compilers lack certain critical + // global names and field names such as "self" and "time" and "nextthink" + // so we have to set these offsets manually, matching the entvars_t + // but we only do this if the prog header crc matches, otherwise it's totally freeform + if (prog->progs_crc == PROGHEADER_CRC || prog->progs_crc == PROGHEADER_CRC_TENEBRAE) + { + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, modelindex); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmin); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, absmax); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ltime); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movetype); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, solid); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, origin); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, oldorigin); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, velocity); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, avelocity); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, punchangle); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, model); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, skin); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, effects); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, mins); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, maxs); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, size); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, touch); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, use); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, blocked); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, health); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frags); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weapon); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponmodel); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, weaponframe); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, currentammo); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_shells); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_nails); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_rockets); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ammo_cells); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, items); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, takedamage); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, deadflag); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, view_ofs); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button0); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button1); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, button2); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, impulse); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, fixangle); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, v_angle); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, idealpitch); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, netname); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, enemy); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, flags); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, colormap); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, team); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, max_health); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, teleport_time); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armortype); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, armorvalue); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, waterlevel); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, watertype); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, aiment); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, goalentity); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, spawnflags); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, target); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, targetname); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_take); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_save); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, dmg_inflictor); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, owner); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, movedir); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, message); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, sounds); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise1); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise2); + PRVM_ED_FindFieldOffset_FromStruct(entvars_t, noise3); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, other); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, world); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, frametime); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, force_retouch); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, mapname); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, deathmatch); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, coop); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, teamplay); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, serverflags); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_secrets); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, total_monsters); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, found_secrets); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, killed_monsters); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm1); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm2); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm3); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm4); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm5); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm6); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm7); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm8); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm9); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm10); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm11); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm12); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm13); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm14); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm15); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, parm16); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater); + PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, msg_entity); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, main); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, StartFrame); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPreThink); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PlayerPostThink); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientKill); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientConnect); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, PutClientInServer); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, ClientDisconnect); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetNewParms); +// PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, SetChangeParms); + } + else + Con_DPrintf("%s: %s system vars have been modified (CRC %i != engine %i), will not load in other engines", prog->name, sv_progs.string, prog->progs_crc, PROGHEADER_CRC); + + // OP_STATE is always supported on server because we add fields/globals for it + prog->flag |= PRVM_OP_STATE; + + VM_CustomStats_Clear();//[515]: csqc + + SV_Prepare_CSQC(); +} + +extern cvar_t host_maxwait; +extern cvar_t host_framerate; +static int SV_ThreadFunc(void *voiddata) +{ + prvm_prog_t *prog = SVVM_prog; + qboolean playing = false; + double sv_timer = 0; + double sv_deltarealtime, sv_oldrealtime, sv_realtime; + double wait; + int i; + char vabuf[1024]; + sv_realtime = Sys_DirtyTime(); + while (!svs.threadstop) + { + // FIXME: we need to handle Host_Error in the server thread somehow +// if (setjmp(sv_abortframe)) +// continue; // something bad happened in the server game + + sv_oldrealtime = sv_realtime; + sv_realtime = Sys_DirtyTime(); + sv_deltarealtime = sv_realtime - sv_oldrealtime; + if (sv_deltarealtime < 0 || sv_deltarealtime >= 1800) sv_deltarealtime = 0; + + sv_timer += sv_deltarealtime; + + svs.perf_acc_realtime += sv_deltarealtime; + + // at this point we start doing real server work, and must block on any client activity pertaining to the server (such as executing SV_SpawnServer) + SV_LockThreadMutex(); + + // Look for clients who have spawned + playing = false; + if (sv.active) + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if(host_client->begun) + if(host_client->netconnection) + playing = true; + if(sv.time < 10) + { + // don't accumulate time for the first 10 seconds of a match + // so things can settle + svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; + } + else if(svs.perf_acc_realtime > 5) + { + svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime; + svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime; + if(svs.perf_acc_offset_samples > 0) + { + svs.perf_offset_max = svs.perf_acc_offset_max; + svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples; + svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); + } + if(svs.perf_lost > 0 && developer_extra.integer) + if(playing) + Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; + } + + // get new packets + if (sv.active) + NetConn_ServerFrame(); + + // if the accumulators haven't become positive yet, wait a while + wait = sv_timer * -1000000.0; + if (wait >= 1) + { + double time0, delta; + SV_UnlockThreadMutex(); // don't keep mutex locked while sleeping + if (host_maxwait.value <= 0) + wait = min(wait, 1000000.0); + else + wait = min(wait, host_maxwait.value * 1000.0); + if(wait < 1) + wait = 1; // because we cast to int + time0 = Sys_DirtyTime(); + Sys_Sleep((int)wait); + delta = Sys_DirtyTime() - time0;if (delta < 0 || delta >= 1800) delta = 0; + svs.perf_acc_sleeptime += delta; + continue; + } + + if (sv.active && sv_timer > 0) + { + // execute one server frame + double advancetime; + float offset; + + if (sys_ticrate.value <= 0) + advancetime = min(sv_timer, 0.1); // don't step more than 100ms + else + advancetime = sys_ticrate.value; + + if(advancetime > 0) + { + offset = sv_timer + (Sys_DirtyTime() - sv_realtime); // LordHavoc: FIXME: I don't understand this line + ++svs.perf_acc_offset_samples; + svs.perf_acc_offset += offset; + svs.perf_acc_offset_squared += offset * offset; + if(svs.perf_acc_offset_max < offset) + svs.perf_acc_offset_max = offset; + } + + // only advance time if not paused + // the game also pauses in singleplayer when menu or console is used + sv.frametime = advancetime * slowmo.value; + if (host_framerate.value) + sv.frametime = host_framerate.value; + if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) + sv.frametime = 0; + + sv_timer -= advancetime; + + // move things around and think unless paused + if (sv.frametime) + SV_Physics(); + + // send all messages to the clients + SV_SendClientMessages(); + + if (sv.paused == 1 && sv_realtime > sv.pausedstart && sv.pausedstart > 0) + { + PRVM_serverglobalfloat(time) = sv.time; + prog->globals.fp[OFS_PARM0] = sv_realtime - sv.pausedstart; + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing"); + } + + // send an heartbeat if enough time has passed since the last one + NetConn_Heartbeat(0); + + } + + // we're back to safe code now + SV_UnlockThreadMutex(); + + // if there is some time remaining from this frame, reset the timers + if (sv_timer >= 0) + { + svs.perf_acc_lost += sv_timer; + sv_timer = 0; + } + } + return 0; +} + +void SV_StartThread(void) +{ + if (!sv_threaded.integer || !Thread_HasThreads()) + return; + svs.threaded = true; + svs.threadstop = false; + svs.threadmutex = Thread_CreateMutex(); + svs.thread = Thread_CreateThread(SV_ThreadFunc, NULL); +} + +void SV_StopThread(void) +{ + if (!svs.threaded) + return; + svs.threadstop = true; + Thread_WaitThread(svs.thread, 0); + Thread_DestroyMutex(svs.threadmutex); + svs.threaded = false; +} diff --git a/app/jni/sv_move.c b/app/jni/sv_move.c new file mode 100644 index 0000000..13b96c7 --- /dev/null +++ b/app/jni/sv_move.c @@ -0,0 +1,448 @@ +/* +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" +#include "prvm_cmds.h" + +/* +============= +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 (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins); + VectorAdd (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, 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_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY))) + 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] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*sv_stepheight.value; + trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(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_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent)); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value) + return false; + } + + c_yes++; + return true; +} + + +/* +============= +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 and false is returned +============= +*/ +qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace) +{ + prvm_prog_t *prog = SVVM_prog; + float dz; + vec3_t oldorg, neworg, end, traceendpos, entorigin, entmins, entmaxs; + trace_t trace; + int i; + prvm_edict_t *enemy; + +// try the move + VectorCopy (PRVM_serveredictvector(ent, origin), oldorg); + VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg); + VectorCopy(PRVM_serveredictvector(ent, mins), entmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs); + +// flying monsters don't step up + if ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (PRVM_serveredictvector(ent, origin), move, neworg); + if (noenemy) + enemy = prog->edicts; + else + { + enemy = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)); + if (i == 0 && enemy != prog->edicts) + { + dz = PRVM_serveredictvector(ent, origin)[2] - PRVM_serveredictvector(enemy, origin)[2]; + if (dz > 40) + neworg[2] -= 8; + if (dz < 30) + neworg[2] += 8; + } + } + VectorCopy(PRVM_serveredictvector(ent, origin), entorigin); + trace = SV_TraceBox(entorigin, entmins, entmaxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); + + if (trace.fraction == 1) + { + VectorCopy(trace.endpos, traceendpos); + if (((int)PRVM_serveredictfloat(ent, flags) & FL_SWIM) && !(SV_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK)) + return false; // swim monster left water + + VectorCopy (traceendpos, PRVM_serveredictvector(ent, origin)); + if (relink) + { + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + } + return true; + } + + if (enemy == prog->edicts) + break; + } + + return false; + } + +// push down from a step height above the wished position + neworg[2] += sv_stepheight.value; + VectorCopy (neworg, end); + end[2] -= sv_stepheight.value*2; + + trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); + + if (trace.startsolid) + { + neworg[2] -= sv_stepheight.value; + trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); + if (trace.startsolid) + return false; + } + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND ) + { + VectorAdd (PRVM_serveredictvector(ent, origin), move, PRVM_serveredictvector(ent, origin)); + if (relink) + { + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + } + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND; + return true; + } + + return false; // walked off an edge + } + +// check point traces down for dangling corners + VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin)); + + if (!SV_CheckBottom (ent)) + { + if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + { + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + } + return true; + } + VectorCopy (oldorg, PRVM_serveredictvector(ent, origin)); + return false; + } + + if ( (int)PRVM_serveredictfloat(ent, flags) & FL_PARTIALGROUND ) + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_PARTIALGROUND; + +// gameplayfix: check if reached pretty steep plane and bail + if ( ! ( (int)PRVM_serveredictfloat(ent, flags) & (FL_SWIM | FL_FLY) ) && sv_gameplayfix_nostepmoveonsteepslopes.integer ) + { + if (trace.plane.normal[ 2 ] < 0.5) + { + VectorCopy (oldorg, PRVM_serveredictvector(ent, origin)); + return false; + } + } + + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + +// the move is ok + if (relink) + { + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + } + return true; +} + + +//============================================================================ + +/* +====================== +SV_StepDirection + +Turns to the movement direction, and walks the current distance if +facing it. + +====================== +*/ +static qboolean SV_StepDirection (prvm_edict_t *ent, float yaw, float dist) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t move, oldorigin; + float delta; + + PRVM_serveredictfloat(ent, ideal_yaw) = yaw; + VM_changeyaw(prog); + + yaw = yaw*M_PI*2 / 360; + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + VectorCopy (PRVM_serveredictvector(ent, origin), oldorigin); + if (SV_movestep (ent, move, false, false, false)) + { + delta = PRVM_serveredictvector(ent, angles)[YAW] - PRVM_serveredictfloat(ent, ideal_yaw); + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step + VectorCopy (oldorigin, PRVM_serveredictvector(ent, origin)); + } + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + return true; + } + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + + return false; +} + +/* +====================== +SV_FixCheckBottom + +====================== +*/ +static void SV_FixCheckBottom (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_PARTIALGROUND; +} + + + +/* +================ +SV_NewChaseDir + +================ +*/ +#define DI_NODIR -1 +static void SV_NewChaseDir (prvm_edict_t *actor, prvm_edict_t *enemy, float dist) +{ + prvm_prog_t *prog = SVVM_prog; + float deltax,deltay; + float d[3]; + float tdir, olddir, turnaround; + + olddir = ANGLEMOD((int)(PRVM_serveredictfloat(actor, ideal_yaw)/45)*45); + turnaround = ANGLEMOD(olddir - 180); + + deltax = PRVM_serveredictvector(enemy, origin)[0] - PRVM_serveredictvector(actor, origin)[0]; + deltay = PRVM_serveredictvector(enemy, origin)[1] - PRVM_serveredictvector(actor, 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 = d[2] == 90 ? 45 : 315; + else + tdir = d[2] == 90 ? 135 : 215; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + +// try other directions + if ( ((rand()&3) & 1) || fabs(deltay)>fabs(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; + + PRVM_serveredictfloat(actor, 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); + +} + +/* +====================== +SV_CloseEnough + +====================== +*/ +static qboolean SV_CloseEnough (prvm_edict_t *ent, prvm_edict_t *goal, float dist) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (goal->priv.server->areamins[i] > ent->priv.server->areamaxs[i] + dist) + return false; + if (goal->priv.server->areamaxs[i] < ent->priv.server->areamins[i] - dist) + return false; + } + return true; +} + +/* +====================== +SV_MoveToGoal + +====================== +*/ +void VM_SV_MoveToGoal(prvm_prog_t *prog) +{ + prvm_edict_t *ent, *goal; + float dist; + + VM_SAFEPARMCOUNT(1, SV_MoveToGoal); + + ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self)); + goal = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, goalentity)); + dist = PRVM_G_FLOAT(OFS_PARM0); + + if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; + } + +// if the next step hits the enemy, return immediately + if ( PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, enemy)) != prog->edicts && SV_CloseEnough (ent, goal, dist) ) + return; + +// bump around... + if ( (rand()&3)==1 || + !SV_StepDirection (ent, PRVM_serveredictfloat(ent, ideal_yaw), dist)) + { + SV_NewChaseDir (ent, goal, dist); + } +} + diff --git a/app/jni/sv_phys.c b/app/jni/sv_phys.c new file mode 100644 index 0000000..e88baa2 --- /dev/null +++ b/app/jni/sv_phys.c @@ -0,0 +1,3227 @@ +/* +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" +#include "prvm_cmds.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. + +*/ + +#define MOVE_EPSILON 0.01 + +void SV_Physics_Toss (prvm_edict_t *ent); + +int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent) +{ + dp_model_t *model; + if ( + (model = SV_GetModelFromEdict(ent)) + ? + model->type == mod_alias + : + ( + (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC) + || + ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32))) + ) + ) + return -1; + return 1; +} + +/* +=============================================================================== + +LINE TESTING IN HULLS + +=============================================================================== +*/ + +int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict) +{ + prvm_prog_t *prog = SVVM_prog; + if (passedict) + { + int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask); + if (dphitcontentsmask) + return dphitcontentsmask; + else if (PRVM_serveredictfloat(passedict, solid) == SOLID_SLIDEBOX) + { + if ((int)PRVM_serveredictfloat(passedict, flags) & FL_MONSTER) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP; + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP; + } + else if (PRVM_serveredictfloat(passedict, solid) == SOLID_CORPSE) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; + else if (PRVM_serveredictfloat(passedict, solid) == SOLID_TRIGGER) + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY; + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; + } + else + return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE; +} + +/* +================== +SV_TracePoint +================== +*/ +trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +{ + prvm_prog_t *prog = SVVM_prog; + int i, bodysupercontents; + int passedictprog; + float pitchsign = 1; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may differ from vec_t + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + + //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask); + + VectorCopy(start, clipstart); + VectorClear(clipmins2); + VectorClear(clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]); +#endif + + // clip to world + Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog->edicts; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + if (passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = PRVM_EDICT_TO_PROG(passedict); + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0; + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_serveredictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + { + model = SV_GetModelFromEdict(touch); + pitchsign = SV_GetPitchSign(prog, touch); + } + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch); + VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend); + VectorCopy(PRVM_serveredictvector(touch, mins), touchmins); + VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs); + if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask); + else + Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask); + + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP); + } + +finished: + return cliptrace; +} + +/* +================== +SV_TraceLine +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#else +trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#endif +{ + prvm_prog_t *prog = SVVM_prog; + int i, bodysupercontents; + int passedictprog; + float pitchsign = 1; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may differ from vec_t + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if (VectorCompare(start, pEnd)) + return SV_TracePoint(start, type, passedict, hitsupercontentsmask); + + if(collision_endposnudge.value > 0) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#else + if (VectorCompare(start, end)) + return SV_TracePoint(start, type, passedict, hitsupercontentsmask); +#endif + + //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask); + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); + VectorClear(clipmins2); + VectorClear(clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog->edicts; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + if (passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = PRVM_EDICT_TO_PROG(passedict); + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0; + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_serveredictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + { + model = SV_GetModelFromEdict(touch); + pitchsign = SV_GetPitchSign(prog, touch); + } + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch); + VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend); + VectorCopy(PRVM_serveredictvector(touch, mins), touchmins); + VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs); + if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask); + else + Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false); + + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + +/* +================== +SV_Move +================== +*/ +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND +#if COLLISIONPARANOID >= 1 +trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#else +trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#endif +#else +#if COLLISIONPARANOID >= 1 +trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#else +trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +#endif +#endif +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t hullmins, hullmaxs; + int i, bodysupercontents; + int passedictprog; + float pitchsign = 1; + qboolean pointtrace; + prvm_edict_t *traceowner, *touch; + trace_t trace; + // temporary storage because prvm_vec_t may differ from vec_t + vec3_t touchmins, touchmaxs; + // bounding box of entire move area + vec3_t clipboxmins, clipboxmaxs; + // size of the moving object + vec3_t clipmins, clipmaxs; + // size when clipping against monsters + vec3_t clipmins2, clipmaxs2; + // start and end origin of move + vec3_t clipstart, clipend; + // trace results + trace_t cliptrace; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + vec3_t end; + vec_t len = 0; + + if (VectorCompare(mins, maxs)) + { + vec3_t shiftstart, shiftend; + VectorAdd(start, mins, shiftstart); + VectorAdd(pEnd, mins, shiftend); + if (VectorCompare(start, pEnd)) + trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask); + else + trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask); + VectorSubtract(trace.endpos, mins, trace.endpos); + return trace; + } + + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + { + // TRICK: make the trace 1 qu longer! + VectorSubtract(pEnd, start, end); + len = VectorNormalizeLength(end); + VectorMA(pEnd, collision_endposnudge.value, end, end); + } + else + VectorCopy(pEnd, end); +#else + if (VectorCompare(mins, maxs)) + { + vec3_t shiftstart, shiftend; + VectorAdd(start, mins, shiftstart); + VectorAdd(end, mins, shiftend); + if (VectorCompare(start, end)) + trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask); + else + trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask); + VectorSubtract(trace.endpos, mins, trace.endpos); + return trace; + } +#endif + + VectorCopy(start, clipstart); + VectorCopy(end, clipend); + VectorCopy(mins, clipmins); + VectorCopy(maxs, clipmaxs); + VectorCopy(mins, clipmins2); + VectorCopy(maxs, clipmaxs2); +#if COLLISIONPARANOID >= 3 + Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]); +#endif + + // clip to world + Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask); + cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid; + if (cliptrace.startsolid || cliptrace.fraction < 1) + cliptrace.ent = prog->edicts; + if (type == MOVE_WORLDONLY) + goto finished; + + if (type == MOVE_MISSILE) + { + // LordHavoc: modified this, was = -15, now -= 15 + for (i = 0;i < 3;i++) + { + clipmins2[i] -= 15; + clipmaxs2[i] += 15; + } + } + + // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp + if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize) + sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs); + else + { + VectorCopy(clipmins, hullmins); + VectorCopy(clipmaxs, hullmaxs); + } + + // create the bounding box of the entire move + for (i = 0;i < 3;i++) + { + clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1; + clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1; + } + + // debug override to test against everything + if (sv_debugmove.integer) + { + clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999; + clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999; + } + + // if the passedict is world, make it NULL (to avoid two checks each time) + if (passedict == prog->edicts) + passedict = NULL; + // precalculate prog value for passedict for comparisons + passedictprog = PRVM_EDICT_TO_PROG(passedict); + // figure out whether this is a point trace for comparisons + pointtrace = VectorCompare(clipmins, clipmaxs); + // precalculate passedict's owner edict pointer for comparisons + traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0; + + // clip to entities + // because this uses World_EntitiestoBox, we know all entity boxes overlap + // the clip region, so we can skip culling checks in the loop below + numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX) + continue; + if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP) + continue; + + if (passedict) + { + // don't clip against self + if (passedict == touch) + continue; + // don't clip owned entities against owner + if (traceowner == touch) + continue; + // don't clip owner against owned entities + if (passedictprog == PRVM_serveredictedict(touch, owner)) + continue; + // don't clip points against points (they can't collide) + if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER))) + continue; + } + + bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY; + + // might interact, so do an exact clip + model = NULL; + if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL) + { + model = SV_GetModelFromEdict(touch); + pitchsign = SV_GetPitchSign(prog, touch); + } + if (model) + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1); + else + Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch); + VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend); + VectorCopy(PRVM_serveredictvector(touch, mins), touchmins); + VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs); + if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER) + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask); + else + Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask); + + Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP); + } + +finished: +#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND + if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) + Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd); +#endif + return cliptrace; +} + +#if COLLISIONPARANOID >= 1 +trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask) +{ + int endstuck; + trace_t trace; + vec3_t temp; + trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask); + if (passedict) + { + VectorCopy(trace.endpos, temp); + endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid; +#if COLLISIONPARANOID < 3 + if (trace.startsolid || endstuck) +#endif + Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, PRVM_serveredictvector(passedict, origin)[0], PRVM_serveredictvector(passedict, origin)[1], PRVM_serveredictvector(passedict, origin)[2], end[0] - PRVM_serveredictvector(passedict, origin)[0], end[1] - PRVM_serveredictvector(passedict, origin)[1], end[2] - PRVM_serveredictvector(passedict, origin)[2], trace.fraction, trace.endpos[0] - PRVM_serveredictvector(passedict, origin)[0], trace.endpos[1] - PRVM_serveredictvector(passedict, origin)[1], trace.endpos[2] - PRVM_serveredictvector(passedict, origin)[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : ""); + } + return trace; +} +#endif + +int SV_PointSuperContents(const vec3_t point) +{ + prvm_prog_t *prog = SVVM_prog; + int supercontents = 0; + int i; + prvm_edict_t *touch; + vec3_t transformed; + // matrices to transform into/out of other entity's space + matrix4x4_t matrix, imatrix; + // model of other entity + dp_model_t *model; + int frame; + // list of entities to test for collisions + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + + // get world supercontents at this point + if (sv.worldmodel && sv.worldmodel->PointSuperContents) + supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point); + + // if sv_gameplayfix_swiminbmodels is off we're done + if (!sv_gameplayfix_swiminbmodels.integer) + return supercontents; + + // get list of entities at this point + numtouchedicts = SV_EntitiesInBox(point, point, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + + // we only care about SOLID_BSP for pointcontents + if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP) + continue; + + // might interact, so do an exact clip + model = SV_GetModelFromEdict(touch); + if (!model || !model->PointSuperContents) + continue; + Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1); + Matrix4x4_Invert_Simple(&imatrix, &matrix); + Matrix4x4_Transform(&imatrix, point, transformed); + frame = (int)PRVM_serveredictfloat(touch, frame); + supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed); + } + + return supercontents; +} + +/* +=============================================================================== + +Linking entities into the world culling system + +=============================================================================== +*/ + +int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t paddedmins, paddedmaxs; + if (maxedicts < 1 || resultedicts == NULL) + return 0; + // LordHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination) + //VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1); + //VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1); + VectorCopy(mins, paddedmins); + VectorCopy(maxs, paddedmaxs); + if (sv_areadebug.integer) + { + int numresultedicts = 0; + int edictindex; + prvm_edict_t *ed; + for (edictindex = 1;edictindex < prog->num_edicts;edictindex++) + { + ed = PRVM_EDICT_NUM(edictindex); + if (!ed->priv.required->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs)) + { + resultedicts[numresultedicts++] = ed; + if (numresultedicts == maxedicts) + break; + } + } + return numresultedicts; + } + else + return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts); +} + +void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobalfloat(trace_allsolid) = false; + PRVM_serverglobalfloat(trace_startsolid) = false; + PRVM_serverglobalfloat(trace_fraction) = 1; + PRVM_serverglobalfloat(trace_inwater) = false; + PRVM_serverglobalfloat(trace_inopen) = true; + VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos)); + VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1); + PRVM_serverglobalfloat(trace_plane_dist) = 0; + PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent); + PRVM_serverglobalfloat(trace_dpstartcontents) = 0; + PRVM_serverglobalfloat(trace_dphitcontents) = 0; + PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0; + PRVM_serverglobalstring(trace_dphittexturename) = 0; + prog->ExecuteProgram(prog, PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing"); +} + +void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int i, numtouchedicts, old_self, old_other; + prvm_edict_t *touch; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + + if (ent == prog->edicts) + return; // don't add the world + + if (ent->priv.server->free) + return; + + if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT) + return; + + // build a list of edicts to touch, because the link loop can be corrupted + // by IncreaseEdicts called during touch functions + numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + + old_self = PRVM_serverglobaledict(self); + old_other = PRVM_serverglobaledict(other); + for (i = 0;i < numtouchedicts;i++) + { + touch = touchedicts[i]; + if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch)) + { + SV_LinkEdict_TouchAreaGrid_Call(touch, ent); + } + } + PRVM_serverglobaledict(self) = old_self; + PRVM_serverglobaledict(other) = old_other; +} + +static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs) +{ + vec3_t v, u; + matrix4x4_t m; + Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0); + + v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u); + VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs); + v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; + v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u); + if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2]; + if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2]; +} + +/* +=============== +SV_LinkEdict + +=============== +*/ +void SV_LinkEdict (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + dp_model_t *model; + vec3_t mins, maxs, entmins, entmaxs, entangles; + int modelindex; + + if (ent == prog->edicts) + return; // don't add the world + + if (ent->priv.server->free) + return; + + modelindex = (int)PRVM_serveredictfloat(ent, modelindex); + if (modelindex < 0 || modelindex >= MAX_MODELS) + { + Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent)); + modelindex = 0; + } + model = SV_GetModelByIndex(modelindex); + + VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent); + VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend); + +// set the abs box + + if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS) + { + // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors + // TODO special handling for spheres? + VectorCopy(PRVM_serveredictvector(ent, mins), entmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs); + VectorCopy(PRVM_serveredictvector(ent, angles), entangles); + RotateBBox(entmins, entmaxs, entangles, mins, maxs); + VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins); + VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs); + } + else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP) + { + if (model != NULL) + { + if (!model->TraceBox) + Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent)); + + if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2]) + { + VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins); + VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs); + } + else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1]) + { + VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins); + VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs); + } + else + { + VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins); + VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs); + } + } + else + { + // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily + VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins); + VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs); + } + } + else + { + VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins); + VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs); + } + +// +// to make items easier to pick up and allow them to be grabbed off +// of shelves, the abs sizes are expanded +// + if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM) + { + mins[0] -= 15; + mins[1] -= 15; + mins[2] -= 1; + maxs[0] += 15; + maxs[1] += 15; + maxs[2] += 1; + } + else + { + // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + mins[0] -= 1; + mins[1] -= 1; + mins[2] -= 1; + maxs[0] += 1; + maxs[1] += 1; + maxs[2] += 1; + } + + VectorCopy(mins, PRVM_serveredictvector(ent, absmin)); + VectorCopy(maxs, PRVM_serveredictvector(ent, absmax)); + + World_LinkEdict(&sv.world, ent, mins, maxs); +} + +/* +=============================================================================== + +Utility functions + +=============================================================================== +*/ + +/* +============ +SV_TestEntityPosition + +returns true if the entity is in solid currently +============ +*/ +static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset) +{ + prvm_prog_t *prog = SVVM_prog; + int contents; + vec3_t org, entorigin, entmins, entmaxs; + trace_t trace; + contents = SV_GenericHitSuperContentsMask(ent); + VectorAdd(PRVM_serveredictvector(ent, origin), offset, org); + VectorCopy(PRVM_serveredictvector(ent, origin), entorigin); + VectorCopy(PRVM_serveredictvector(ent, mins), entmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs); + trace = SV_TraceBox(org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents); + if (trace.startsupercontents & contents) + return true; + else + { + if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs))) + { + // q1bsp/hlbsp use hulls and if the entity does not exactly match + // a hull size it is incorrectly tested, so this code tries to + // 'fix' it slightly... + // FIXME: this breaks entities larger than the hull size + int i; + vec3_t v, m1, m2, s; + VectorAdd(org, entmins, m1); + VectorAdd(org, entmaxs, m2); + VectorSubtract(m2, m1, s); +#define EPSILON (1.0f / 32.0f) + if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;} + if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;} + if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;} + for (i = 0;i < 8;i++) + { + v[0] = (i & 1) ? m2[0] : m1[0]; + v[1] = (i & 2) ? m2[1] : m1[1]; + v[2] = (i & 4) ? m2[2] : m1[2]; + if (SV_PointSuperContents(v) & contents) + return true; + } + } + } + // if the trace found a better position for the entity, move it there + if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001) + { +#if 0 + // please switch back to this code when trace.endpos sometimes being in solid bug is fixed + VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin)); +#else + // verify if the endpos is REALLY outside solid + VectorCopy(trace.endpos, org); + trace = SV_TraceBox(org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, contents); + if(trace.startsolid) + Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n"); + else + VectorCopy(org, PRVM_serveredictvector(ent, origin)); +#endif + } + return false; +} + +// DRESK - Support for Entity Contents Transition Event +/* +================ +SV_CheckContentsTransition + +returns true if entity had a valid contentstransition function call +================ +*/ +static int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents) +{ + prvm_prog_t *prog = SVVM_prog; + int bValidFunctionCall; + + // Default Valid Function Call to False + bValidFunctionCall = false; + + if(PRVM_serveredictfloat(ent, watertype) != nContents) + { // Changed Contents + // Acquire Contents Transition Function from QC + if(PRVM_serveredictfunction(ent, contentstransition)) + { // Valid Function; Execute + // Assign Valid Function + bValidFunctionCall = true; + // Prepare Parameters (Original Contents, New Contents) + // Original Contents + PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype); + // New Contents + PRVM_G_FLOAT(OFS_PARM1) = nContents; + // Assign Self + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + // Set Time + PRVM_serverglobalfloat(time) = sv.time; + // Execute VM Function + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function"); + } + } + + // Return if Function Call was Valid + return bValidFunctionCall; +} + + +/* +================ +SV_CheckVelocity +================ +*/ +void SV_CheckVelocity (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + float wishspeed; + +// +// bound velocity +// + for (i=0 ; i<3 ; i++) + { + if (PRVM_IS_NAN(PRVM_serveredictvector(ent, velocity)[i])) + { + Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname))); + PRVM_serveredictvector(ent, velocity)[i] = 0; + } + if (PRVM_IS_NAN(PRVM_serveredictvector(ent, origin)[i])) + { + Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname))); + PRVM_serveredictvector(ent, origin)[i] = 0; + } + } + + // LordHavoc: a hack to ensure that the (rather silly) id1 quakec + // player_run/player_stand1 does not horribly malfunction if the + // velocity becomes a denormalized float + if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001) + VectorClear(PRVM_serveredictvector(ent, velocity)); + + // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster + wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity)); + if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value) + { + wishspeed = sv_maxvelocity.value / sqrt(wishspeed); + PRVM_serveredictvector(ent, velocity)[0] *= wishspeed; + PRVM_serveredictvector(ent, velocity)[1] *= wishspeed; + PRVM_serveredictvector(ent, velocity)[2] *= wishspeed; + } +} + +/* +============= +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. +============= +*/ +static qboolean SV_RunThink (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int iterations; + + // don't let things stay in the past. + // it is possible to start that way by a trigger with a local time. + if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime) + return true; + + for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++) + { + PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink)); + PRVM_serveredictfloat(ent, nextthink) = 0; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts); + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing"); + // mods often set nextthink to time to cause a think every frame, + // we don't want to loop in that case, so exit if the new nextthink is + // <= the time the qc was told, also exit if it is past the end of the + // frame + if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer) + break; + } + return !ent->priv.server->free; +} + +/* +================== +SV_Impact + +Two entities have touched, so run their touch functions +================== +*/ +static void SV_Impact (prvm_edict_t *e1, trace_t *trace) +{ + prvm_prog_t *prog = SVVM_prog; + int restorevm_tempstringsbuf_cursize; + int old_self, old_other; + prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; + + old_self = PRVM_serverglobaledict(self); + old_other = PRVM_serverglobaledict(other); + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + + VM_SetTraceGlobals(prog, trace); + + if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2); + prog->ExecuteProgram(prog, PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing"); + } + + if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1); + VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos)); + VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal)); + PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist; + PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1); + PRVM_serverglobalfloat(trace_dpstartcontents) = 0; + PRVM_serverglobalfloat(trace_dphitcontents) = 0; + PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0; + PRVM_serverglobalstring(trace_dphittexturename) = 0; + prog->ExecuteProgram(prog, PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing"); + } + + PRVM_serverglobaledict(self) = old_self; + PRVM_serverglobaledict(other) = old_other; + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; +} + + +/* +================== +ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 +static void ClipVelocity (prvm_vec3_t in, vec3_t normal, prvm_vec3_t out, prvm_vec_t overbounce) +{ + int i; + float backoff; + + backoff = -DotProduct (in, normal) * overbounce; + VectorMA(in, backoff, normal, out); + + for (i = 0;i < 3;i++) + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; +} + + +/* +============ +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 +8 = teleported by touch method +If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored +============ +*/ +static float SV_Gravity (prvm_edict_t *ent); +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean dolink); +#define MAX_CLIP_PLANES 5 +static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight) +{ + prvm_prog_t *prog = SVVM_prog; + int blocked, bumpcount; + int i, j, numplanes; + float d, time_left, gravity; + vec3_t dir, push, planes[MAX_CLIP_PLANES]; + prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity; +#if 0 + vec3_t end; +#endif + trace_t trace; + if (time <= 0) + return 0; + gravity = 0; + + VectorCopy(PRVM_serveredictvector(ent, velocity), restore_velocity); + + if(applygravity) + { + gravity = SV_Gravity(ent); + + if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) + { + if (sv_gameplayfix_gravityunaffectedbyticrate.integer) + PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f; + else + PRVM_serveredictvector(ent, velocity)[2] -= gravity; + } + } + + blocked = 0; + VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity); + VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity); + numplanes = 0; + time_left = time; + for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++) + { + if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2]) + break; + + VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push); + if(!SV_PushEntity(&trace, ent, push, false)) + { + // we got teleported by a touch function + // let's abort the move + blocked |= 8; + break; + } + + // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity + // abort move if we're stuck in the world (and didn't make it out) + if (trace.worldstartsolid && trace.allsolid) + { + VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity)); + return 3; + } + + if (trace.fraction == 1) + break; + if (trace.plane.normal[2]) + { + if (trace.plane.normal[2] > 0.7) + { + // floor + blocked |= 1; + + if (!trace.ent) + { + Con_Printf ("SV_FlyMove: !trace.ent"); + trace.ent = prog->edicts; + } + + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + } + } + else if (stepheight) + { + // step - handle it immediately + vec3_t org; + vec3_t steppush; + trace_t steptrace; + trace_t steptrace2; + trace_t steptrace3; + //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + VectorSet(steppush, 0, 0, stepheight); + VectorCopy(PRVM_serveredictvector(ent, origin), org); + if(!SV_PushEntity(&steptrace, ent, steppush, false)) + { + blocked |= 8; + break; + } + //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + if(!SV_PushEntity(&steptrace2, ent, push, false)) + { + blocked |= 8; + break; + } + //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]); + if(!SV_PushEntity(&steptrace3, ent, steppush, false)) + { + blocked |= 8; + break; + } + //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + // accept the new position if it made some progress... + if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125) + { + //Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]); + trace = steptrace2; + VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos); + time_left *= 1 - trace.fraction; + numplanes = 0; + continue; + } + else + { + //Con_Printf("REJECTED (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]); + VectorCopy(org, PRVM_serveredictvector(ent, origin)); + } + } + else + { + // step - return it to caller + blocked |= 2; + // save the trace for player extrafriction + if (stepnormal) + VectorCopy(trace.plane.normal, stepnormal); + } + if (trace.fraction >= 0.001) + { + // actually covered some distance + VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity); + numplanes = 0; + } + + time_left *= 1 - trace.fraction; + + // clipped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { + // this shouldn't really happen + VectorClear(PRVM_serveredictvector(ent, velocity)); + blocked = 3; + break; + } + + /* + for (i = 0;i < numplanes;i++) + if (DotProduct(trace.plane.normal, planes[i]) > 0.99) + break; + if (i < numplanes) + { + VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity)); + continue; + } + */ + + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // modify original_velocity so it parallels all of the clip planes + for (i = 0;i < numplanes;i++) + { + ClipVelocity(original_velocity, planes[i], new_velocity, 1); + for (j = 0;j < numplanes;j++) + { + if (j != i) + { + // not ok + if (DotProduct(new_velocity, planes[j]) < 0) + break; + } + } + if (j == numplanes) + break; + } + + if (i != numplanes) + { + // go along this plane + VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity)); + } + else + { + // go along the crease + if (numplanes != 2) + { + VectorClear(PRVM_serveredictvector(ent, velocity)); + blocked = 7; + break; + } + CrossProduct(planes[0], planes[1], dir); + // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners + VectorNormalize(dir); + d = DotProduct(dir, PRVM_serveredictvector(ent, velocity)); + VectorScale(dir, d, PRVM_serveredictvector(ent, velocity)); + } + + // if current velocity is against the original velocity, + // stop dead to avoid tiny occilations in sloping corners + if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0) + { + VectorClear(PRVM_serveredictvector(ent, velocity)); + break; + } + } + + //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, PRVM_serveredictvector(ent, velocity)[0], PRVM_serveredictvector(ent, velocity)[1], PRVM_serveredictvector(ent, velocity)[2]); + + /* + if ((blocked & 1) == 0 && bumpcount > 1) + { + // LordHavoc: fix the 'fall to your death in a wedge corner' glitch + // flag ONGROUND if there's ground under it + trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask); + } + */ + + // LordHavoc: this came from QW and allows you to get out of water more easily + if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8)) + VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity)); + + if(applygravity) + { + if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) + { + if (sv_gameplayfix_gravityunaffectedbyticrate.integer) + PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f; + } + } + + return blocked; +} + +/* +============ +SV_Gravity + +============ +*/ +static float SV_Gravity (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + float ent_gravity; + + ent_gravity = PRVM_serveredictfloat(ent, gravity); + if (!ent_gravity) + ent_gravity = 1.0f; + return ent_gravity * sv_gravity.value * sv.frametime; +} + + +/* +=============================================================================== + +PUSHMOVE + +=============================================================================== +*/ + +static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot) +{ + prvm_prog_t *prog = SVVM_prog; + int bump; + trace_t stucktrace; + vec3_t stuckorigin; + vec3_t stuckmins, stuckmaxs; + vec3_t goodmins, goodmaxs; + vec3_t testorigin; + vec_t nudge; + vec3_t move; + VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin); + VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs); + VectorCopy(pivot, goodmins); + VectorCopy(pivot, goodmaxs); + for (bump = 0;bump < 6;bump++) + { + int coord = 2-(bump >> 1); + //int coord = (bump >> 1); + int dir = (bump & 1); + int subbump; + + for(subbump = 0; ; ++subbump) + { + VectorCopy(stuckorigin, testorigin); + if(dir) + { + // pushing maxs + testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord]; + } + else + { + // pushing mins + testorigin[coord] += stuckmins[coord] - goodmins[coord]; + } + + stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent)); + if (stucktrace.bmodelstartsolid) + { + // BAD BAD, can't fix that + return false; + } + + if (stucktrace.fraction >= 1) + break; // it WORKS! + + if(subbump >= 10) + { + // BAD BAD, can't fix that + return false; + } + + // we hit something... let's move out of it + VectorSubtract(stucktrace.endpos, testorigin, move); + nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant + VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin); + } + /* + if(subbump > 0) + Con_Printf("subbump: %d\n", subbump); + */ + + if(dir) + { + // pushing maxs + goodmaxs[coord] = stuckmaxs[coord]; + } + else + { + // pushing mins + goodmins[coord] = stuckmins[coord]; + } + } + + // WE WIN + VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin)); + + return true; +} + +qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int bump, pass; + trace_t stucktrace; + vec3_t stuckorigin; + vec3_t stuckmins, stuckmaxs; + vec_t nudge; + vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value; + if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes) + separation = 0.0f; // when using hulls, it can not be enlarged + VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs); + stuckmins[0] -= separation; + stuckmins[1] -= separation; + stuckmins[2] -= separation; + stuckmaxs[0] += separation; + stuckmaxs[1] += separation; + stuckmaxs[2] += separation; + // first pass we try to get it out of brush entities + // second pass we try to get it out of world only (can't win them all) + for (pass = 0;pass < 2;pass++) + { + VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin); + for (bump = 0;bump < 10;bump++) + { + stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent)); + if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0) + { + // found a good location, use it + VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin)); + return true; + } + nudge = -stucktrace.startdepth; + VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin); + } + } + return false; +} + +/* +============ +SV_PushEntity + +Does not change the entities velocity at all +The trace struct is filled with the trace that has been done. +Returns true if the push did not result in the entity being teleported by QC code. +============ +*/ +static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean dolink) +{ + prvm_prog_t *prog = SVVM_prog; + int solid; + int movetype; + int type; + vec3_t mins, maxs; + vec3_t start; + vec3_t end; + + solid = (int)PRVM_serveredictfloat(ent, solid); + movetype = (int)PRVM_serveredictfloat(ent, movetype); + VectorCopy(PRVM_serveredictvector(ent, mins), mins); + VectorCopy(PRVM_serveredictvector(ent, maxs), maxs); + + // move start position out of solids + if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0) + { + SV_NudgeOutOfSolid(ent); + } + + VectorCopy(PRVM_serveredictvector(ent, origin), start); + VectorAdd(start, push, end); + + if (movetype == MOVETYPE_FLYMISSILE) + type = MOVE_MISSILE; + else if (movetype == MOVETYPE_FLY_WORLDONLY) + type = MOVE_WORLDONLY; + else if (solid == SOLID_TRIGGER || solid == SOLID_NOT) + type = MOVE_NOMONSTERS; // only clip against bmodels + else + type = MOVE_NORMAL; + + *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent)); + // fail the move if stuck in world + if (trace->worldstartsolid) + return true; + + VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin)); + + ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running + + SV_LinkEdict(ent); + +#if 0 + if(!trace->startsolid) + if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid) + { + Con_Printf("something eeeeevil happened\n"); + } +#endif + + if (dolink) + SV_LinkEdict_TouchAreaGrid(ent); + + if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent)))) + SV_Impact (ent, trace); + + if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT) + { + ent->priv.required->mark = 0; + return false; + } + else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN) + { + ent->priv.required->mark = 0; + return true; + } + else + { + Con_Printf("The edict mark had been overwritten! Please debug this.\n"); + return true; + } +} + + +/* +============ +SV_PushMove + +============ +*/ +static void SV_PushMove (prvm_edict_t *pusher, float movetime) +{ + prvm_prog_t *prog = SVVM_prog; + int i, e, index; + int pusherowner, pusherprog; + int checkcontents; + qboolean rotated; + float savesolid, movetime2, pushltime; + vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, pushermins, pushermaxs, checkorigin, checkmins, checkmaxs; + int num_moved; + int numcheckentities; + static prvm_edict_t *checkentities[MAX_EDICTS]; + dp_model_t *pushermodel; + trace_t trace, trace2; + matrix4x4_t pusherfinalmatrix, pusherfinalimatrix; + static unsigned short moved_edicts[MAX_EDICTS]; + vec3_t pivot; + + if (!PRVM_serveredictvector(pusher, velocity)[0] && !PRVM_serveredictvector(pusher, velocity)[1] && !PRVM_serveredictvector(pusher, velocity)[2] && !PRVM_serveredictvector(pusher, avelocity)[0] && !PRVM_serveredictvector(pusher, avelocity)[1] && !PRVM_serveredictvector(pusher, avelocity)[2]) + { + PRVM_serveredictfloat(pusher, ltime) += movetime; + return; + } + + switch ((int) PRVM_serveredictfloat(pusher, solid)) + { + // LordHavoc: valid pusher types + case SOLID_BSP: + case SOLID_BBOX: + case SOLID_SLIDEBOX: + case SOLID_CORPSE: // LordHavoc: this would be weird... + break; + // LordHavoc: no collisions + case SOLID_NOT: + case SOLID_TRIGGER: + VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin)); + VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles)); + PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0)); + PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0)); + PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0)); + PRVM_serveredictfloat(pusher, ltime) += movetime; + SV_LinkEdict(pusher); + return; + default: + Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid)); + return; + } + index = (int) PRVM_serveredictfloat(pusher, modelindex); + if (index < 1 || index >= MAX_MODELS) + { + Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex)); + return; + } + pushermodel = SV_GetModelByIndex(index); + pusherowner = PRVM_serveredictedict(pusher, owner); + pusherprog = PRVM_EDICT_TO_PROG(pusher); + + rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0; + + movetime2 = movetime; + VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1); + VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle); + if (moveangle[0] || moveangle[2]) + { + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + else + { + mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + } + } + else if (moveangle[1]) + { + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + else + { + mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + } + } + else + { + for (i = 0;i < 3;i++) + { + if (move1[i] > 0) + { + mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + else + { + mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1; + } + } + } + + VectorNegate (moveangle, a); + AngleVectorsFLU (a, forward, left, up); + + VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig); + VectorCopy (PRVM_serveredictvector(pusher, angles), pushang); + pushltime = PRVM_serveredictfloat(pusher, ltime); + +// move the pusher to its final position + + VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin)); + VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles)); + PRVM_serveredictfloat(pusher, ltime) += movetime; + SV_LinkEdict(pusher); + + pushermodel = SV_GetModelFromEdict(pusher); + Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, PRVM_serveredictvector(pusher, origin)[0], PRVM_serveredictvector(pusher, origin)[1], PRVM_serveredictvector(pusher, origin)[2], PRVM_serveredictvector(pusher, angles)[0], PRVM_serveredictvector(pusher, angles)[1], PRVM_serveredictvector(pusher, angles)[2], 1); + Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix); + + savesolid = PRVM_serveredictfloat(pusher, solid); + +// see if any solid entities are inside the final position + num_moved = 0; + + if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push... + numcheckentities = 0; + else // MOVETYPE_PUSH + numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); + for (e = 0;e < numcheckentities;e++) + { + prvm_edict_t *check = checkentities[e]; + int movetype = (int)PRVM_serveredictfloat(check, movetype); + switch(movetype) + { + case MOVETYPE_NONE: + case MOVETYPE_PUSH: + case MOVETYPE_FOLLOW: + case MOVETYPE_NOCLIP: + case MOVETYPE_FLY_WORLDONLY: + continue; + default: + break; + } + + if (PRVM_serveredictedict(check, owner) == pusherprog) + continue; + + if (pusherowner == PRVM_EDICT_TO_PROG(check)) + continue; + + //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname))); + + // tell any MOVETYPE_STEP entity that it may need to check for water transitions + check->priv.server->waterposition_forceupdate = true; + + checkcontents = SV_GenericHitSuperContentsMask(check); + + // if the entity is standing on the pusher, it will definitely be moved + // if the entity is not standing on the pusher, but is in the pusher's + // final position, move it + if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher) + { + VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins); + VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs); + VectorCopy(PRVM_serveredictvector(check, origin), checkorigin); + VectorCopy(PRVM_serveredictvector(check, mins), checkmins); + VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents); + //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents); + if (!trace.startsolid) + { + //Con_Printf("- not in solid\n"); + continue; + } + } + + VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot); + //VectorClear(pivot); + + if (rotated) + { + vec3_t org2; + VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org); + VectorAdd (org, pivot, org); + org2[0] = DotProduct (org, forward); + org2[1] = DotProduct (org, left); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move); + VectorAdd (move, move1, move); + } + else + VectorCopy (move1, move); + + //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]); + + VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from); + VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles); + moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check); + + // physics objects need better collisions than this code can do + if (movetype == MOVETYPE_PHYSICS) + { + VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin)); + SV_LinkEdict(check); + SV_LinkEdict_TouchAreaGrid(check); + continue; + } + + // try moving the contacted entity + PRVM_serveredictfloat(pusher, solid) = SOLID_NOT; + if(!SV_PushEntity (&trace, check, move, true)) + { + // entity "check" got teleported + PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1]; + PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP + continue; // pushed enough + } + // FIXME: turn players specially + PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1]; + PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP + //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid); + + // this trace.fraction < 1 check causes items to fall off of pushers + // if they pass under or through a wall + // the groundentity check causes items to fall off of ledges + if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)) + PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND; + + // if it is still inside the pusher, block + VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins); + VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs); + VectorCopy(PRVM_serveredictvector(check, origin), checkorigin); + VectorCopy(PRVM_serveredictvector(check, mins), checkmins); + VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs); + Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents); + if (trace.startsolid) + { + vec3_t move2; + if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot)) + { + // hack to invoke all necessary movement triggers + VectorClear(move2); + if(!SV_PushEntity(&trace2, check, move2, true)) + { + // entity "check" got teleported + continue; + } + // we could fix it + continue; + } + + // still inside pusher, so it's really blocked + + // fail the move + if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0]) + continue; + if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER) + { + // corpse + PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0; + VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs)); + continue; + } + + VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin)); + VectorCopy (pushang, PRVM_serveredictvector(pusher, angles)); + PRVM_serveredictfloat(pusher, ltime) = pushltime; + SV_LinkEdict(pusher); + + // move back any entities we already moved + for (i = 0;i < num_moved;i++) + { + prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]); + VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin)); + VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles)); + SV_LinkEdict(ed); + } + + // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone + if (PRVM_serveredictfunction(pusher, blocked)) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check); + prog->ExecuteProgram(prog, PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing"); + } + break; + } + } + PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0)); + PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0)); + PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0)); +} + +/* +================ +SV_Physics_Pusher + +================ +*/ +static void SV_Physics_Pusher (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + float thinktime, oldltime, movetime; + + oldltime = PRVM_serveredictfloat(ent, ltime); + + thinktime = PRVM_serveredictfloat(ent, nextthink); + if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime) + { + movetime = thinktime - PRVM_serveredictfloat(ent, ltime); + if (movetime < 0) + movetime = 0; + } + else + movetime = sv.frametime; + + if (movetime) + // advances PRVM_serveredictfloat(ent, ltime) if not blocked + SV_PushMove (ent, movetime); + + if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime)) + { + PRVM_serveredictfloat(ent, nextthink) = 0; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts); + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing"); + } +} + + +/* +=============================================================================== + +CLIENT MOVEMENT + +=============================================================================== +*/ + +static float unstickoffsets[] = +{ + // poutting -/+z changes first as they are least weird + 0, 0, -1, + 0, 0, 1, + // x or y changes + -1, 0, 0, + 1, 0, 0, + 0, -1, 0, + 0, 1, 0, + // x and y changes + -1, -1, 0, + 1, -1, 0, + -1, 1, 0, + 1, 1, 0, +}; + +typedef enum unstickresult_e +{ + UNSTICK_STUCK = 0, + UNSTICK_GOOD = 1, + UNSTICK_UNSTUCK = 2 +} +unstickresult_t; + +static unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset) +{ + prvm_prog_t *prog = SVVM_prog; + int i, maxunstick; + + // if not stuck in a bmodel, just return + if (!SV_TestEntityPosition(ent, vec3_origin)) + return UNSTICK_GOOD; + + for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3) + { + if (!SV_TestEntityPosition(ent, unstickoffsets + i)) + { + VectorCopy(unstickoffsets + i, offset); + SV_LinkEdict(ent); + //SV_LinkEdict_TouchAreaGrid(ent); + return UNSTICK_UNSTUCK; + } + } + + maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36); + // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox + + for(i = 2; i <= maxunstick; ++i) + { + VectorClear(offset); + offset[2] = -i; + if (!SV_TestEntityPosition(ent, offset)) + { + SV_LinkEdict(ent); + //SV_LinkEdict_TouchAreaGrid(ent); + return UNSTICK_UNSTUCK; + } + offset[2] = i; + if (!SV_TestEntityPosition(ent, offset)) + { + SV_LinkEdict(ent); + //SV_LinkEdict_TouchAreaGrid(ent); + return UNSTICK_UNSTUCK; + } + } + + return UNSTICK_STUCK; +} + +qboolean SV_UnstickEntity (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t offset; + switch(SV_UnstickEntityReturnOffset(ent, offset)) + { + case UNSTICK_GOOD: + return true; + case UNSTICK_UNSTUCK: + Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]); + return true; + case UNSTICK_STUCK: + if (developer_extra.integer) + Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname))); + return false; + default: + Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n"); + return false; + } +} + +/* +============= +SV_CheckStuck + +This is a big hack to try and fix the rare case of getting stuck in the world +clipping hull. +============= +*/ +static void SV_CheckStuck (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t offset; + + switch(SV_UnstickEntityReturnOffset(ent, offset)) + { + case UNSTICK_GOOD: + VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin)); + break; + case UNSTICK_UNSTUCK: + Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]); + break; + case UNSTICK_STUCK: + VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset); + if (!SV_TestEntityPosition(ent, offset)) + { + Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname))); + SV_LinkEdict(ent); + //SV_LinkEdict_TouchAreaGrid(ent); + } + else + Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname))); + break; + default: + Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n"); + } +} + + +/* +============= +SV_CheckWater +============= +*/ +static qboolean SV_CheckWater (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int cont; + int nNativeContents; + vec3_t point; + + point[0] = PRVM_serveredictvector(ent, origin)[0]; + point[1] = PRVM_serveredictvector(ent, origin)[1]; + point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1; + + // DRESK - Support for Entity Contents Transition Event + // NOTE: Some logic needed to be slightly re-ordered + // to not affect performance and allow for the feature. + + // Acquire Super Contents Prior to Resets + cont = SV_PointSuperContents(point); + // Acquire Native Contents Here + nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont); + + // DRESK - Support for Entity Contents Transition Event + if(PRVM_serveredictfloat(ent, watertype)) + // Entity did NOT Spawn; Check + SV_CheckContentsTransition(ent, nNativeContents); + + + PRVM_serveredictfloat(ent, waterlevel) = 0; + PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY; + cont = SV_PointSuperContents(point); + if (cont & (SUPERCONTENTS_LIQUIDSMASK)) + { + PRVM_serveredictfloat(ent, watertype) = nNativeContents; + PRVM_serveredictfloat(ent, waterlevel) = 1; + point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5; + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) + { + PRVM_serveredictfloat(ent, waterlevel) = 2; + point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2]; + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) + PRVM_serveredictfloat(ent, waterlevel) = 3; + } + } + + return PRVM_serveredictfloat(ent, waterlevel) > 1; +} + +/* +============ +SV_WallFriction + +============ +*/ +static void SV_WallFriction (prvm_edict_t *ent, float *stepnormal) +{ + prvm_prog_t *prog = SVVM_prog; + float d, i; + vec3_t forward, into, side, v_angle; + + VectorCopy(PRVM_serveredictvector(ent, v_angle), v_angle); + AngleVectors (v_angle, forward, NULL, NULL); + if ((d = DotProduct (stepnormal, forward) + 0.5) < 0) + { + // cut the tangential velocity + i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity)); + VectorScale (stepnormal, i, into); + VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side); + PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d); + PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d); + } +} + +#if 0 +/* +===================== +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 (prvm_edict_t *ent, vec3_t oldvel) +{ + int i, clip; + vec3_t oldorg, dir; + + VectorCopy (PRVM_serveredictvector(ent, origin), oldorg); + VectorClear (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 (&trace, ent, dir, false, true); + + // retry the original move + PRVM_serveredictvector(ent, velocity)[0] = oldvel[0]; + PRVM_serveredictvector(ent, velocity)[1] = oldvel[1]; + PRVM_serveredictvector(ent, velocity)[2] = 0; + clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent)); + + if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4 + || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4) + { + Con_DPrint("TryUnstick - success.\n"); + return clip; + } + + // go back to the original pos and try again + VectorCopy (oldorg, PRVM_serveredictvector(ent, origin)); + } + + // still not moving + VectorClear (PRVM_serveredictvector(ent, velocity)); + Con_DPrint("TryUnstick - failure.\n"); + return 7; +} +#endif + +/* +===================== +SV_WalkMove + +Only used by players +====================== +*/ +static void SV_WalkMove (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int clip; + int oldonground; + //int originalmove_clip; + int originalmove_flags; + int originalmove_groundentity; + int hitsupercontentsmask; + int type; + vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity, entmins, entmaxs; + trace_t downtrace, trace; + qboolean applygravity; + + // if frametime is 0 (due to client sending the same timestamp twice), + // don't move + if (sv.frametime <= 0) + return; + + if (sv_gameplayfix_unstickplayers.integer) + SV_CheckStuck (ent); + + applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP); + + hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent); + + SV_CheckVelocity(ent); + + // do a regular slide move unless it looks like you ran into a step + oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND; + + VectorCopy (PRVM_serveredictvector(ent, origin), start_origin); + VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity); + + clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0); + + if(sv_gameplayfix_downtracesupportsongroundflag.integer) + if(!(clip & 1)) + { + // only try this if there was no floor in the way in the trace (no, + // this check seems to be not REALLY necessary, because if clip & 1, + // our trace will hit that thing too) + VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1); + VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1); + if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE) + type = MOVE_MISSILE; + else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) + type = MOVE_WORLDONLY; + else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT) + type = MOVE_NOMONSTERS; // only clip against bmodels + else + type = MOVE_NORMAL; + VectorCopy(PRVM_serveredictvector(ent, mins), entmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs); + trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent)); + if(trace.fraction < 1 && trace.plane.normal[2] > 0.7) + clip |= 1; // but we HAVE found a floor + } + + // if the move did not hit the ground at any point, we're not on ground + if(!(clip & 1)) + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND; + + SV_CheckVelocity(ent); + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + + if(clip & 8) // teleport + return; + + if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) + return; + + if (sv_nostep.integer) + return; + + VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin); + VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity); + //originalmove_clip = clip; + originalmove_flags = (int)PRVM_serveredictfloat(ent, flags); + originalmove_groundentity = PRVM_serveredictedict(ent, groundentity); + + // if move didn't block on a step, return + if (clip & 2) + { + // if move was not trying to move into the step, return + if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125) + return; + + if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY) + { + // return if gibbed by a trigger + if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK) + return; + + // only step up while jumping if that is enabled + if (sv_jumpstep.integer) + if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0) + return; + } + + // try moving up and forward to go up a step + // back to start pos + VectorCopy (start_origin, PRVM_serveredictvector(ent, origin)); + VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity)); + + // move up + VectorClear (upmove); + upmove[2] = sv_stepheight.value; + if(!SV_PushEntity(&trace, ent, upmove, true)) + { + // we got teleported when upstepping... must abort the move + return; + } + + // move forward + PRVM_serveredictvector(ent, velocity)[2] = 0; + clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0); + PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2]; + if(clip & 8) + { + // we got teleported when upstepping... must abort the move + // note that z velocity handling may not be what QC expects here, but we cannot help it + return; + } + + SV_CheckVelocity(ent); + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + + // check for stuckness, possibly due to the limited precision of floats + // in the clipping hulls + if (clip + && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125 + && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125) + { + //Con_Printf("wall\n"); + // stepping up didn't make any progress, revert to original move + VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin)); + VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity)); + //clip = originalmove_clip; + PRVM_serveredictfloat(ent, flags) = originalmove_flags; + PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity; + // now try to unstick if needed + //clip = SV_TryUnstick (ent, oldvel); + return; + } + + //Con_Printf("step - "); + + // extra friction based on view angle + if (clip & 2 && sv_wallfriction.integer) + SV_WallFriction (ent, stepnormal); + } + // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground + else if (!sv_gameplayfix_stepdown.integer || PRVM_serveredictfloat(ent, waterlevel) >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)) + return; + + // move down + VectorClear (downmove); + downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime; + if(!SV_PushEntity (&downtrace, ent, downmove, true)) + { + // we got teleported when downstepping... must abort the move + return; + } + + if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) + { + // this has been disabled so that you can't jump when you are stepping + // up while already jumping (also known as the Quake2 double jump bug) +#if 0 + // LordHavoc: disabled this check so you can walk on monsters/players + //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP) + { + //Con_Printf("onground\n"); + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent); + } +#endif + } + else + { + //Con_Printf("slope\n"); + // 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(originalmove_origin, PRVM_serveredictvector(ent, origin)); + VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity)); + //clip = originalmove_clip; + PRVM_serveredictfloat(ent, flags) = originalmove_flags; + PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity; + } + + SV_CheckVelocity(ent); + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); +} + +//============================================================================ + +/* +============= +SV_Physics_Follow + +Entities that are "stuck" to another entity +============= +*/ +static void SV_Physics_Follow (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t vf, vr, vu, angles, v; + prvm_edict_t *e; + + // regular thinking + if (!SV_RunThink (ent)) + return; + + // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects + e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment)); + if (PRVM_serveredictvector(e, angles)[0] == PRVM_serveredictvector(ent, punchangle)[0] && PRVM_serveredictvector(e, angles)[1] == PRVM_serveredictvector(ent, punchangle)[1] && PRVM_serveredictvector(e, angles)[2] == PRVM_serveredictvector(ent, punchangle)[2]) + { + // quick case for no rotation + VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin)); + } + else + { + angles[0] = -PRVM_serveredictvector(ent, punchangle)[0]; + angles[1] = PRVM_serveredictvector(ent, punchangle)[1]; + angles[2] = PRVM_serveredictvector(ent, punchangle)[2]; + AngleVectors (angles, vf, vr, vu); + v[0] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[0] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[0] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[0]; + v[1] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[1] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[1] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[1]; + v[2] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[2] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[2] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[2]; + angles[0] = -PRVM_serveredictvector(e, angles)[0]; + angles[1] = PRVM_serveredictvector(e, angles)[1]; + angles[2] = PRVM_serveredictvector(e, angles)[2]; + AngleVectors (angles, vf, vr, vu); + PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0]; + PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1]; + PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2]; + } + VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles)); + SV_LinkEdict(ent); + //SV_LinkEdict_TouchAreaGrid(ent); +} + +/* +============================================================================== + +TOSS / BOUNCE + +============================================================================== +*/ + +/* +============= +SV_CheckWaterTransition + +============= +*/ +static void SV_CheckWaterTransition (prvm_edict_t *ent) +{ + vec3_t entorigin; + prvm_prog_t *prog = SVVM_prog; + // LordHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility + int cont; + VectorCopy(PRVM_serveredictvector(ent, origin), entorigin); + cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(entorigin)); + if (!PRVM_serveredictfloat(ent, watertype)) + { + // just spawned here + if (!sv_gameplayfix_fixedcheckwatertransition.integer) + { + PRVM_serveredictfloat(ent, watertype) = cont; + PRVM_serveredictfloat(ent, waterlevel) = 1; + return; + } + } + // DRESK - Support for Entity Contents Transition Event + // NOTE: Call here BEFORE updating the watertype below, + // and suppress watersplash sound if a valid function + // call was made to allow for custom "splash" sounds. + else if( !SV_CheckContentsTransition(ent, cont) ) + { // Contents Transition Function Invalid; Potentially Play Water Sound + // check if the entity crossed into or out of water + if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))) + SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f); + } + + if (cont <= CONTENTS_WATER) + { + PRVM_serveredictfloat(ent, watertype) = cont; + PRVM_serveredictfloat(ent, waterlevel) = 1; + } + else + { + PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY; + PRVM_serveredictfloat(ent, waterlevel) = sv_gameplayfix_fixedcheckwatertransition.integer ? 0 : cont; + } +} + +/* +============= +SV_Physics_Toss + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ + +void SV_Physics_Toss (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + trace_t trace; + vec3_t move; + vec_t movetime; + int bump; + prvm_edict_t *groundentity; + float d, ent_gravity; + float bouncefactor; + float bouncestop; + +// if onground, return without moving + if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) + { + groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity)); + if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer) + { + // don't stick to ground if onground and moving upward + PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND; + } + else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer) + { + // we can trust FL_ONGROUND if groundentity is world because it never moves + return; + } + else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free) + { + // if ent was supported by a brush model on previous frame, + // and groundentity is now freed, set groundentity to 0 (world) + // which leaves it suspended in the air + PRVM_serveredictedict(ent, groundentity) = 0; + if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer) + return; + } + else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs)) + { + // don't slide if still touching the groundentity + return; + } + } + ent->priv.server->suspendedinairflag = false; + + SV_CheckVelocity (ent); + +// add gravity + if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE) + PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent); + +// move angles + VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles)); + + movetime = sv.frametime; + for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++) + { + // move origin + VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move); + if(!SV_PushEntity(&trace, ent, move, true)) + return; // teleported + if (ent->priv.server->free) + return; + if (trace.bmodelstartsolid && sv_gameplayfix_unstickentities.integer) + { + // try to unstick the entity + SV_UnstickEntity(ent); + if(!SV_PushEntity(&trace, ent, move, true)) + return; // teleported + if (ent->priv.server->free) + return; + } + if (trace.fraction == 1) + break; + movetime *= 1 - min(1, trace.fraction); + switch((int)PRVM_serveredictfloat(ent, movetype)) + { + case MOVETYPE_BOUNCEMISSILE: + bouncefactor = PRVM_serveredictfloat(ent, bouncefactor); + if (!bouncefactor) + bouncefactor = 1.0f; + + ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor); + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND; + if (!sv_gameplayfix_slidemoveprojectiles.integer) + movetime = 0; + break; + case MOVETYPE_BOUNCE: + bouncefactor = PRVM_serveredictfloat(ent, bouncefactor); + if (!bouncefactor) + bouncefactor = 0.5f; + + bouncestop = PRVM_serveredictfloat(ent, bouncestop); + if (!bouncestop) + bouncestop = 60.0f / 800.0f; + + ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor); + ent_gravity = PRVM_serveredictfloat(ent, gravity); + if (!ent_gravity) + ent_gravity = 1.0f; + // LordHavoc: fixed grenades not bouncing when fired down a slope + if (sv_gameplayfix_grenadebouncedownslopes.integer) + d = fabs(DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity))); + else + d = PRVM_serveredictvector(ent, velocity)[2]; + if (trace.plane.normal[2] > 0.7 && d < sv_gravity.value * bouncestop * ent_gravity) + { + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + VectorClear(PRVM_serveredictvector(ent, velocity)); + VectorClear(PRVM_serveredictvector(ent, avelocity)); + movetime = 0; + } + else + { + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND; + if (!sv_gameplayfix_slidemoveprojectiles.integer) + movetime = 0; + } + break; + default: + ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0); + if (trace.plane.normal[2] > 0.7) + { + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP) + ent->priv.server->suspendedinairflag = true; + VectorClear (PRVM_serveredictvector(ent, velocity)); + VectorClear (PRVM_serveredictvector(ent, avelocity)); + } + else + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND; + movetime = 0; + break; + } + } + +// 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. +============= +*/ +static void SV_Physics_Step (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + int flags = (int)PRVM_serveredictfloat(ent, flags); + + // DRESK + // Backup Velocity in the event that movetypesteplandevent is called, + // to provide a parameter with the entity's velocity at impact. + vec3_t backupVelocity; + VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity); + // don't fall at all if fly/swim + if (!(flags & (FL_FLY | FL_SWIM))) + { + if (flags & FL_ONGROUND) + { + // freefall if onground and moving upward + // freefall if not standing on a world surface (it may be a lift or trap door) + if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer) + { + PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND; + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0); + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + ent->priv.server->waterposition_forceupdate = true; + } + } + else + { + // freefall if not onground + int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1; + + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0); + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + + // just hit ground + if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) + { + // DRESK - Check for Entity Land Event Function + if(PRVM_serveredictfunction(ent, movetypesteplandevent)) + { // Valid Function; Execute + // Prepare Parameters + // Assign Velocity at Impact + PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0]; + PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1]; + PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2]; + // Assign Self + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + // Set Time + PRVM_serverglobalfloat(time) = sv.time; + // Execute VM Function + prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function"); + } + else + // Check for Engine Landing Sound + if(sv_sound_land.string) + SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f); + } + ent->priv.server->waterposition_forceupdate = true; + } + } + +// regular thinking + if (!SV_RunThink(ent)) + return; + + if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin)) + { + ent->priv.server->waterposition_forceupdate = false; + VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin); + SV_CheckWaterTransition(ent); + } +} + +//============================================================================ + +static void SV_Physics_Entity (prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + // don't run think/move on newly spawned projectiles as it messes up + // movement interpolation and rocket trails, and is inconsistent with + // respect to entities spawned in the same frame + // (if an ent spawns a higher numbered ent, it moves in the same frame, + // but if it spawns a lower numbered ent, it doesn't - this never moves + // ents in the first frame regardless) + qboolean runmove = ent->priv.server->move; + ent->priv.server->move = true; + if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0) + return; + switch ((int) PRVM_serveredictfloat(ent, movetype)) + { + case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime) + SV_RunThink (ent); + break; + case MOVETYPE_FOLLOW: + SV_Physics_Follow (ent); + break; + case MOVETYPE_NOCLIP: + if (SV_RunThink(ent)) + { + SV_CheckWater(ent); + VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin)); + VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles)); + } + SV_LinkEdict(ent); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_WALK: + if (SV_RunThink (ent)) + SV_WalkMove (ent); + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_FLY: + case MOVETYPE_FLY_WORLDONLY: + // regular thinking + if (SV_RunThink (ent)) + SV_Physics_Toss (ent); + break; + case MOVETYPE_PHYSICS: + if (SV_RunThink(ent)) + { + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + } + break; + default: + Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype)); + break; + } +} + +void SV_Physics_ClientMove(void) +{ + prvm_prog_t *prog = SVVM_prog; + prvm_edict_t *ent; + ent = host_client->edict; + + // call player physics, this needs the proper frametime + PRVM_serverglobalfloat(frametime) = sv.frametime; + SV_ClientThink(); + + // call standard client pre-think, with frametime = 0 + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobalfloat(frametime) = 0; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing"); + PRVM_serverglobalfloat(frametime) = sv.frametime; + + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + + // perform MOVETYPE_WALK behavior + SV_WalkMove (ent); + + // call standard player post-think, with frametime = 0 + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobalfloat(frametime) = 0; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing"); + PRVM_serverglobalfloat(frametime) = sv.frametime; + + if(PRVM_serveredictfloat(ent, fixangle)) + { + // angle fixing was requested by physics code... + // so store the current angles for later use + VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles); + host_client->fixangle_angles_set = TRUE; + + // and clear fixangle for the next frame + PRVM_serveredictfloat(ent, fixangle) = 0; + } +} + +static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + // don't do physics on disconnected clients, FrikBot relies on this + if (!host_client->begun) + return; + + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + + // don't run physics here if running asynchronously + if (host_client->clmovement_inputtimeout <= 0) + { + SV_ClientThink(); + //host_client->cmd.time = max(host_client->cmd.time, sv.time); + } + + // make sure the velocity is still sane (not a NaN) + SV_CheckVelocity(ent); + + // call standard client pre-think + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing"); + + // make sure the velocity is still sane (not a NaN) + SV_CheckVelocity(ent); +} + +static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + // don't do physics on disconnected clients, FrikBot relies on this + if (!host_client->begun) + return; + + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + + // call standard player post-think + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent); + prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing"); + + // make sure the velocity is still sane (not a NaN) + SV_CheckVelocity(ent); + + if(PRVM_serveredictfloat(ent, fixangle)) + { + // angle fixing was requested by physics code... + // so store the current angles for later use + VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles); + host_client->fixangle_angles_set = TRUE; + + // and clear fixangle for the next frame + PRVM_serveredictfloat(ent, fixangle) = 0; + } + + // decrement the countdown variable used to decide when to go back to + // synchronous physics + if (host_client->clmovement_inputtimeout > sv.frametime) + host_client->clmovement_inputtimeout -= sv.frametime; + else + host_client->clmovement_inputtimeout = 0; +} + +static void SV_Physics_ClientEntity(prvm_edict_t *ent) +{ + prvm_prog_t *prog = SVVM_prog; + // don't do physics on disconnected clients, FrikBot relies on this + if (!host_client->begun) + { + memset(&host_client->cmd, 0, sizeof(host_client->cmd)); + return; + } + + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + + switch ((int) PRVM_serveredictfloat(ent, movetype)) + { + case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime) + SV_RunThink (ent); + break; + case MOVETYPE_FOLLOW: + SV_Physics_Follow (ent); + break; + case MOVETYPE_NOCLIP: + SV_RunThink(ent); + SV_CheckWater(ent); + VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin)); + VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles)); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_WALK: + SV_RunThink (ent); + // don't run physics here if running asynchronously + if (host_client->clmovement_inputtimeout <= 0) + SV_WalkMove (ent); + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLYMISSILE: + // regular thinking + SV_RunThink (ent); + SV_Physics_Toss (ent); + break; + case MOVETYPE_FLY: + case MOVETYPE_FLY_WORLDONLY: + SV_RunThink (ent); + SV_WalkMove (ent); + break; + case MOVETYPE_PHYSICS: + SV_RunThink (ent); + break; + default: + Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype)); + break; + } + + SV_CheckVelocity (ent); + + SV_LinkEdict(ent); + SV_LinkEdict_TouchAreaGrid(ent); + + SV_CheckVelocity (ent); +} + +/* +================ +SV_Physics + +================ +*/ +void SV_Physics (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + prvm_edict_t *ent; + +// let the progs know that a new frame has started + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobalfloat(frametime) = sv.frametime; + prog->ExecuteProgram(prog, PRVM_serverfunction(StartFrame), "QC function StartFrame is missing"); + + // run physics engine + World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value); + +// +// treat each object in turn +// + + // if force_retouch, relink all the entities + if (PRVM_serverglobalfloat(force_retouch) > 0) + for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary + + if (sv_gameplayfix_consistentplayerprethink.integer) + { + // run physics on the client entities in 3 stages + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) + if (!ent->priv.server->free) + SV_Physics_ClientEntity_PreThink(ent); + + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) + if (!ent->priv.server->free) + SV_Physics_ClientEntity(ent); + + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) + if (!ent->priv.server->free) + SV_Physics_ClientEntity_PostThink(ent); + } + else + { + // run physics on the client entities + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) + { + if (!ent->priv.server->free) + { + SV_Physics_ClientEntity_PreThink(ent); + SV_Physics_ClientEntity(ent); + SV_Physics_ClientEntity_PostThink(ent); + } + } + } + + // run physics on all the non-client entities + if (!sv_freezenonclients.integer) + { + for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_Physics_Entity(ent); + // make a second pass to see if any ents spawned this frame and make + // sure they run their move/think + if (sv_gameplayfix_delayprojectiles.integer < 0) + for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->move && !ent->priv.server->free) + SV_Physics_Entity(ent); + } + + if (PRVM_serverglobalfloat(force_retouch) > 0) + PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1); + + // LordHavoc: endframe support + if (PRVM_serverfunction(EndFrame)) + { + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_serverglobalfloat(time) = sv.time; + prog->ExecuteProgram(prog, PRVM_serverfunction(EndFrame), "QC function EndFrame is missing"); + } + + // decrement prog->num_edicts if the highest number entities died + for (;PRVM_ED_CanAlloc(prog, PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--); + + if (!sv_freezenonclients.integer) + sv.time += sv.frametime; +} diff --git a/app/jni/sv_user.c b/app/jni/sv_user.c new file mode 100644 index 0000000..a65705f --- /dev/null +++ b/app/jni/sv_user.c @@ -0,0 +1,965 @@ +/* +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" +#include "sv_demo.h" +#define DEBUGMOVES 0 + +static usercmd_t cmd; +extern cvar_t sv_autodemo_perclient; + +/* +=============== +SV_SetIdealPitch +=============== +*/ +#define MAX_FORWARD 6 +void SV_SetIdealPitch (void) +{ + prvm_prog_t *prog = SVVM_prog; + float angleval, sinval, cosval, step, dir; + trace_t tr; + vec3_t top, bottom; + float z[MAX_FORWARD]; + int i, j; + int steps; + + if (!((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_ONGROUND)) + return; + + angleval = PRVM_serveredictvector(host_client->edict, angles)[YAW] * M_PI*2 / 360; + sinval = sin(angleval); + cosval = cos(angleval); + + for (i=0 ; iedict, origin)[0] + cosval*(i+3)*12; + top[1] = PRVM_serveredictvector(host_client->edict, origin)[1] + sinval*(i+3)*12; + top[2] = PRVM_serveredictvector(host_client->edict, origin)[2] + PRVM_serveredictvector(host_client->edict, view_ofs)[2]; + + bottom[0] = top[0]; + bottom[1] = top[1]; + bottom[2] = top[2] - 160; + + tr = SV_TraceLine(top, bottom, MOVE_NOMONSTERS, host_client->edict, SUPERCONTENTS_SOLID); + // if looking at a wall, leave ideal the way is was + if (tr.startsolid) + return; + + // near a dropoff + if (tr.fraction == 1) + return; + + z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); + } + + dir = 0; + steps = 0; + for (j=1 ; j -ON_EPSILON && step < ON_EPSILON) + continue; + + // mixed changes + if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) + return; + + steps++; + dir = step; + } + + if (!dir) + { + PRVM_serveredictfloat(host_client->edict, idealpitch) = 0; + return; + } + + if (steps < 2) + return; + PRVM_serveredictfloat(host_client->edict, idealpitch) = -dir * sv_idealpitchscale.value; +} + +static vec3_t wishdir, forward, right, up; +static float wishspeed; + +static qboolean onground; + +/* +================== +SV_UserFriction + +================== +*/ +static void SV_UserFriction (void) +{ + prvm_prog_t *prog = SVVM_prog; + float speed, newspeed, control, friction; + vec3_t start, stop; + trace_t trace; + + speed = sqrt(PRVM_serveredictvector(host_client->edict, velocity)[0]*PRVM_serveredictvector(host_client->edict, velocity)[0]+PRVM_serveredictvector(host_client->edict, velocity)[1]*PRVM_serveredictvector(host_client->edict, velocity)[1]); + if (!speed) + return; + + // if the leading edge is over a dropoff, increase friction + start[0] = stop[0] = PRVM_serveredictvector(host_client->edict, origin)[0] + PRVM_serveredictvector(host_client->edict, velocity)[0]/speed*16; + start[1] = stop[1] = PRVM_serveredictvector(host_client->edict, origin)[1] + PRVM_serveredictvector(host_client->edict, velocity)[1]/speed*16; + start[2] = PRVM_serveredictvector(host_client->edict, origin)[2] + PRVM_serveredictvector(host_client->edict, mins)[2]; + stop[2] = start[2] - 34; + + trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, host_client->edict, SV_GenericHitSuperContentsMask(host_client->edict)); + + 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 = speed - sv.frametime*control*friction; + + if (newspeed < 0) + newspeed = 0; + else + newspeed /= speed; + + VectorScale(PRVM_serveredictvector(host_client->edict, velocity), newspeed, PRVM_serveredictvector(host_client->edict, velocity)); +} + +/* +============== +SV_Accelerate +============== +*/ +static void SV_Accelerate (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct (PRVM_serveredictvector(host_client->edict, velocity), wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = sv_accelerate.value*sv.frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed*wishdir[i]; +} + +extern cvar_t sv_gameplayfix_q2airaccelerate; +static void SV_AirAccelerate (vec3_t wishveloc) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + float addspeed, wishspd, accelspeed, currentspeed; + + wishspd = VectorNormalizeLength (wishveloc); + if (wishspd > sv_maxairspeed.value) + wishspd = sv_maxairspeed.value; + currentspeed = DotProduct (PRVM_serveredictvector(host_client->edict, velocity), wishveloc); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; + accelspeed = (sv_airaccelerate.value < 0 ? sv_accelerate.value : sv_airaccelerate.value)*(sv_gameplayfix_q2airaccelerate.integer ? wishspd : wishspeed) * sv.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed*wishveloc[i]; +} + + +static void DropPunchAngle (void) +{ + prvm_prog_t *prog = SVVM_prog; + vec_t len; + vec3_t punchangle, punchvector; + + VectorCopy(PRVM_serveredictvector(host_client->edict, punchangle), punchangle); + VectorCopy(PRVM_serveredictvector(host_client->edict, punchvector), punchvector); + + len = VectorNormalizeLength(punchangle); + if (len > 0) + { + len -= 10*sv.frametime; + if (len < 0) + len = 0; + VectorScale(punchangle, len, punchangle); + } + + len = VectorNormalizeLength(punchvector); + if (len > 0) + { + len -= 20*sv.frametime; + if (len < 0) + len = 0; + VectorScale(punchvector, len, punchvector); + } + + VectorCopy(punchangle, PRVM_serveredictvector(host_client->edict, punchangle)); + VectorCopy(punchvector, PRVM_serveredictvector(host_client->edict, punchvector)); +} + +/* +=================== +SV_WaterMove + +=================== +*/ +static void SV_WaterMove (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + vec3_t wishvel, v_angle; + vec_t speed, newspeed, wishspeed, addspeed, accelspeed, temp; + + // user intentions + VectorCopy(PRVM_serveredictvector(host_client->edict, v_angle), v_angle); + AngleVectors(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 = VectorLength(wishvel); + if (wishspeed > sv_maxspeed.value) + { + temp = sv_maxspeed.value/wishspeed; + VectorScale (wishvel, temp, wishvel); + wishspeed = sv_maxspeed.value; + } + wishspeed *= 0.7; + + // water friction + speed = VectorLength(PRVM_serveredictvector(host_client->edict, velocity)); + if (speed) + { + newspeed = speed - sv.frametime * speed * (sv_waterfriction.value < 0 ? sv_friction.value : sv_waterfriction.value); + if (newspeed < 0) + newspeed = 0; + temp = newspeed/speed; + VectorScale(PRVM_serveredictvector(host_client->edict, velocity), temp, PRVM_serveredictvector(host_client->edict, velocity)); + } + else + newspeed = 0; + + // water acceleration + if (!wishspeed) + return; + + addspeed = wishspeed - newspeed; + if (addspeed <= 0) + return; + + VectorNormalize (wishvel); + accelspeed = (sv_wateraccelerate.value < 0 ? sv_accelerate.value : sv_wateraccelerate.value) * wishspeed * sv.frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + PRVM_serveredictvector(host_client->edict, velocity)[i] += accelspeed * wishvel[i]; +} + +static void SV_WaterJump (void) +{ + prvm_prog_t *prog = SVVM_prog; + if (sv.time > PRVM_serveredictfloat(host_client->edict, teleport_time) || !PRVM_serveredictfloat(host_client->edict, waterlevel)) + { + PRVM_serveredictfloat(host_client->edict, flags) = (int)PRVM_serveredictfloat(host_client->edict, flags) & ~FL_WATERJUMP; + PRVM_serveredictfloat(host_client->edict, teleport_time) = 0; + } + PRVM_serveredictvector(host_client->edict, velocity)[0] = PRVM_serveredictvector(host_client->edict, movedir)[0]; + PRVM_serveredictvector(host_client->edict, velocity)[1] = PRVM_serveredictvector(host_client->edict, movedir)[1]; +} + + +/* +=================== +SV_AirMove + +=================== +*/ +static void SV_AirMove (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + vec3_t wishvel; + float fmove, smove, temp; + + // LordHavoc: correct quake movement speed bug when looking up/down + wishvel[0] = wishvel[2] = 0; + wishvel[1] = PRVM_serveredictvector(host_client->edict, angles)[1]; + AngleVectors (wishvel, forward, right, up); + + fmove = cmd.forwardmove; + smove = cmd.sidemove; + +// hack to not let you back into teleporter + if (sv.time < PRVM_serveredictfloat(host_client->edict, teleport_time) && fmove < 0) + fmove = 0; + + for (i=0 ; i<3 ; i++) + wishvel[i] = forward[i]*fmove + right[i]*smove; + + if ((int)PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_WALK) + wishvel[2] += cmd.upmove; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalizeLength(wishdir); + if (wishspeed > sv_maxspeed.value) + { + temp = sv_maxspeed.value/wishspeed; + VectorScale (wishvel, temp, wishvel); + wishspeed = sv_maxspeed.value; + } + + if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NOCLIP) + { + // noclip + VectorCopy (wishvel, PRVM_serveredictvector(host_client->edict, 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) +{ + prvm_prog_t *prog = SVVM_prog; + vec3_t v_angle, angles, velocity; + + //Con_Printf("clientthink for %ims\n", (int) (sv.frametime * 1000)); + + SV_ApplyClientMove(); + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(host_client->edict); + + // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) + if (PRVM_serverfunction(SV_PlayerPhysics) && sv_playerphysicsqc.integer) + { + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PlayerPhysics), "QC function SV_PlayerPhysics is missing"); + SV_CheckVelocity(host_client->edict); + return; + } + + if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NONE) + return; + + onground = ((int)PRVM_serveredictfloat(host_client->edict, flags) & FL_ONGROUND) != 0; + + DropPunchAngle (); + + // if dead, behave differently + if (PRVM_serveredictfloat(host_client->edict, health) <= 0) + return; + + cmd = host_client->cmd; + + // angles + // show 1/3 the pitch angle and all the roll angle + VectorAdd (PRVM_serveredictvector(host_client->edict, v_angle), PRVM_serveredictvector(host_client->edict, punchangle), v_angle); + VectorCopy(PRVM_serveredictvector(host_client->edict, angles), angles); + VectorCopy(PRVM_serveredictvector(host_client->edict, velocity), velocity); + PRVM_serveredictvector(host_client->edict, angles)[ROLL] = V_CalcRoll (angles, velocity)*4; + if (!PRVM_serveredictfloat(host_client->edict, fixangle)) + { + PRVM_serveredictvector(host_client->edict, angles)[PITCH] = -v_angle[PITCH]/3; + PRVM_serveredictvector(host_client->edict, angles)[YAW] = v_angle[YAW]; + } + + if ( (int)PRVM_serveredictfloat(host_client->edict, flags) & FL_WATERJUMP ) + { + SV_WaterJump (); + SV_CheckVelocity(host_client->edict); + return; + } + + /* + // Player is (somehow) outside of the map, or flying, or noclipping + if (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP && (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict))) + //if (PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_NOCLIP || PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_FLY || SV_TestEntityPosition (host_client->edict)) + { + SV_FreeMove (); + return; + } + */ + + // walk + if ((PRVM_serveredictfloat(host_client->edict, waterlevel) >= 2) && (PRVM_serveredictfloat(host_client->edict, movetype) != MOVETYPE_NOCLIP)) + { + SV_WaterMove (); + SV_CheckVelocity(host_client->edict); + return; + } + + SV_AirMove (); + SV_CheckVelocity(host_client->edict); +} + +/* +=================== +SV_ReadClientMove +=================== +*/ +int sv_numreadmoves = 0; +usercmd_t sv_readmoves[CL_MAX_USERCMDS]; +static void SV_ReadClientMove (void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + usercmd_t newmove; + usercmd_t *move = &newmove; + + memset(move, 0, sizeof(*move)); + + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + + // read ping time + if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5 && sv.protocol != PROTOCOL_DARKPLACES6) + move->sequence = MSG_ReadLong(&sv_message); + move->time = move->clienttime = MSG_ReadFloat(&sv_message); + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + move->receivetime = (float)sv.time; + +#if DEBUGMOVES + Con_Printf("%s move%i #%i %ims (%ims) %i %i '%i %i %i' '%i %i %i'\n", move->time > move->receivetime ? "^3read future" : "^4read normal", sv_numreadmoves + 1, move->sequence, (int)floor((move->time - host_client->cmd.time) * 1000.0 + 0.5), (int)floor(move->time * 1000.0 + 0.5), move->impulse, move->buttons, (int)move->viewangles[0], (int)move->viewangles[1], (int)move->viewangles[2], (int)move->forwardmove, (int)move->sidemove, (int)move->upmove); +#endif + // limit reported time to current time + // (incase the client is trying to cheat) + move->time = min(move->time, move->receivetime + sv.frametime); + + // read current angles + for (i = 0;i < 3;i++) + { + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + move->viewangles[i] = MSG_ReadAngle8i(&sv_message); + else if (sv.protocol == PROTOCOL_DARKPLACES1) + move->viewangles[i] = MSG_ReadAngle16i(&sv_message); + else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3) + move->viewangles[i] = MSG_ReadAngle32f(&sv_message); + else + move->viewangles[i] = MSG_ReadAngle16i(&sv_message); + } + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + + // read movement + move->forwardmove = MSG_ReadCoord16i(&sv_message); + move->sidemove = MSG_ReadCoord16i(&sv_message); + move->upmove = MSG_ReadCoord16i(&sv_message); + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + + // read buttons + // be sure to bitwise OR them into the move->buttons because we want to + // accumulate button presses from multiple packets per actual move + if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5) + move->buttons = MSG_ReadByte(&sv_message); + else + move->buttons = MSG_ReadLong(&sv_message); + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + + // read impulse + move->impulse = MSG_ReadByte(&sv_message); + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + + // PRYDON_CLIENTCURSOR + if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3 && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5) + { + // 30 bytes + move->cursor_screen[0] = MSG_ReadShort(&sv_message) * (1.0f / 32767.0f); + move->cursor_screen[1] = MSG_ReadShort(&sv_message) * (1.0f / 32767.0f); + move->cursor_start[0] = MSG_ReadFloat(&sv_message); + move->cursor_start[1] = MSG_ReadFloat(&sv_message); + move->cursor_start[2] = MSG_ReadFloat(&sv_message); + move->cursor_impact[0] = MSG_ReadFloat(&sv_message); + move->cursor_impact[1] = MSG_ReadFloat(&sv_message); + move->cursor_impact[2] = MSG_ReadFloat(&sv_message); + move->cursor_entitynumber = (unsigned short)MSG_ReadShort(&sv_message); + if (move->cursor_entitynumber >= prog->max_edicts) + { + Con_DPrintf("SV_ReadClientMessage: client send bad cursor_entitynumber\n"); + move->cursor_entitynumber = 0; + } + // as requested by FrikaC, cursor_trace_ent is reset to world if the + // entity is free at time of receipt + if (PRVM_EDICT_NUM(move->cursor_entitynumber)->priv.server->free) + move->cursor_entitynumber = 0; + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + } + + // if the previous move has not been applied yet, we need to accumulate + // the impulse/buttons from it + if (!host_client->cmd.applied) + { + if (!move->impulse) + move->impulse = host_client->cmd.impulse; + move->buttons |= host_client->cmd.buttons; + } + + // now store this move for later execution + // (we have to buffer the moves because of old ones being repeated) + if (sv_numreadmoves < CL_MAX_USERCMDS) + sv_readmoves[sv_numreadmoves++] = *move; + + // movement packet loss tracking + if(move->sequence) + { + if(move->sequence > host_client->movement_highestsequence_seen) + { + if(host_client->movement_highestsequence_seen) + { + // mark moves in between as lost + if(move->sequence - host_client->movement_highestsequence_seen - 1 < NETGRAPH_PACKETS) + for(i = host_client->movement_highestsequence_seen + 1; i < move->sequence; ++i) + host_client->movement_count[i % NETGRAPH_PACKETS] = -1; + else + memset(host_client->movement_count, -1, sizeof(host_client->movement_count)); + } + // mark THIS move as seen for the first time + host_client->movement_count[move->sequence % NETGRAPH_PACKETS] = 1; + // update highest sequence seen + host_client->movement_highestsequence_seen = move->sequence; + } + else + if(host_client->movement_count[move->sequence % NETGRAPH_PACKETS] >= 0) + ++host_client->movement_count[move->sequence % NETGRAPH_PACKETS]; + } + else + { + host_client->movement_highestsequence_seen = 0; + memset(host_client->movement_count, 0, sizeof(host_client->movement_count)); + } +} + +static void SV_ExecuteClientMoves(void) +{ + prvm_prog_t *prog = SVVM_prog; + int moveindex; + float moveframetime; + double oldframetime; + double oldframetime2; +#ifdef NUM_PING_TIMES + double total; +#endif + if (sv_numreadmoves < 1) + return; + // only start accepting input once the player is spawned + if (!host_client->begun) + return; +#if DEBUGMOVES + Con_Printf("SV_ExecuteClientMoves: read %i moves at sv.time %f\n", sv_numreadmoves, (float)sv.time); +#endif + // disable clientside movement prediction in some cases + if (ceil(max(sv_readmoves[sv_numreadmoves-1].receivetime - sv_readmoves[sv_numreadmoves-1].time, 0) * 1000.0) < sv_clmovement_minping.integer) + host_client->clmovement_disabletimeout = realtime + sv_clmovement_minping_disabletime.value / 1000.0; + // several conditions govern whether clientside movement prediction is allowed + if (sv_readmoves[sv_numreadmoves-1].sequence && sv_clmovement_enable.integer && sv_clmovement_inputtimeout.value > 0 && host_client->clmovement_disabletimeout <= realtime && PRVM_serveredictfloat(host_client->edict, movetype) == MOVETYPE_WALK && (!PRVM_serveredictfloat(host_client->edict, disableclientprediction))) + { + // process the moves in order and ignore old ones + // but always trust the latest move + // (this deals with bogus initial move sequences after level change, + // where the client will eventually catch up with the level change + // and reset its move sequence) + for (moveindex = 0;moveindex < sv_numreadmoves;moveindex++) + { + usercmd_t *move = sv_readmoves + moveindex; + if (host_client->movesequence < move->sequence || moveindex == sv_numreadmoves - 1) + { +#if DEBUGMOVES + Con_Printf("%smove #%i %ims (%ims) %i %i '%i %i %i' '%i %i %i'\n", (move->time - host_client->cmd.time) > sv.frametime * 1.01 ? "^1" : "^2", move->sequence, (int)floor((move->time - host_client->cmd.time) * 1000.0 + 0.5), (int)floor(move->time * 1000.0 + 0.5), move->impulse, move->buttons, (int)move->viewangles[0], (int)move->viewangles[1], (int)move->viewangles[2], (int)move->forwardmove, (int)move->sidemove, (int)move->upmove); +#endif + // this is a new move + move->time = bound(sv.time - 1, move->time, sv.time); // prevent slowhack/speedhack combos + move->time = max(move->time, host_client->cmd.time); // prevent backstepping of time + moveframetime = bound(0, move->time - host_client->cmd.time, min(0.1, sv_clmovement_inputtimeout.value)); + + // discard (treat like lost) moves with too low distance from + // the previous one to prevent hacks using float inaccuracy + // clients will see this as packet loss in the netgraph + // this should also apply if a move cannot get + // executed because it came too late and + // already was performed serverside + if(moveframetime < 0.0005) + { + // count the move as LOST if we don't + // execute it but it has higher + // sequence count + if(host_client->movesequence) + if(move->sequence > host_client->movesequence) + host_client->movement_count[(move->sequence) % NETGRAPH_PACKETS] = -1; + continue; + } + + //Con_Printf("movesequence = %i (%i lost), moveframetime = %f\n", move->sequence, move->sequence ? move->sequence - host_client->movesequence - 1 : 0, moveframetime); + host_client->cmd = *move; + host_client->movesequence = move->sequence; + + // if using prediction, we need to perform moves when packets are + // received, even if multiple occur in one frame + // (they can't go beyond the current time so there is no cheat issue + // with this approach, and if they don't send input for a while they + // start moving anyway, so the longest 'lagaport' possible is + // determined by the sv_clmovement_inputtimeout cvar) + if (moveframetime <= 0) + continue; + oldframetime = PRVM_serverglobalfloat(frametime); + oldframetime2 = sv.frametime; + // update ping time for qc to see while executing this move + host_client->ping = host_client->cmd.receivetime - host_client->cmd.time; + // the server and qc frametime values must be changed temporarily + PRVM_serverglobalfloat(frametime) = sv.frametime = moveframetime; + // if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction) + if (sv.frametime > 0.05) + { + PRVM_serverglobalfloat(frametime) = sv.frametime = moveframetime * 0.5f; + SV_Physics_ClientMove(); + } + SV_Physics_ClientMove(); + sv.frametime = oldframetime2; + PRVM_serverglobalfloat(frametime) = oldframetime; + host_client->clmovement_inputtimeout = sv_clmovement_inputtimeout.value; + } + } + } + else + { + // try to gather button bits from old moves, but only if their time is + // advancing (ones with the same timestamp can't be trusted) + for (moveindex = 0;moveindex < sv_numreadmoves-1;moveindex++) + { + usercmd_t *move = sv_readmoves + moveindex; + if (host_client->cmd.time < move->time) + { + sv_readmoves[sv_numreadmoves-1].buttons |= move->buttons; + if (move->impulse) + sv_readmoves[sv_numreadmoves-1].impulse = move->impulse; + } + } + // now copy the new move + host_client->cmd = sv_readmoves[sv_numreadmoves-1]; + host_client->cmd.time = max(host_client->cmd.time, sv.time); + // physics will run up to sv.time, so allow no predicted moves + // before that otherwise, there is a speedhack by turning + // prediction on and off repeatedly on client side because the + // engine would run BOTH client and server physics for the same + // time + host_client->movesequence = 0; + // make sure that normal physics takes over immediately + host_client->clmovement_inputtimeout = 0; + } + + // calculate average ping time + host_client->ping = host_client->cmd.receivetime - host_client->cmd.clienttime; +#ifdef NUM_PING_TIMES + host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = host_client->cmd.receivetime - host_client->cmd.clienttime; + host_client->num_pings++; + for (i=0, total = 0;i < NUM_PING_TIMES;i++) + total += host_client->ping_times[i]; + host_client->ping = total / NUM_PING_TIMES; +#endif +} + +void SV_ApplyClientMove (void) +{ + prvm_prog_t *prog = SVVM_prog; + usercmd_t *move = &host_client->cmd; + int j, movementloss, packetloss; + + if (!move->receivetime) + return; + + // note: a move can be applied multiple times if the client packets are + // not coming as often as the physics is executed, and the move must be + // applied before running qc each time because the id1 qc had a bug where + // it clears self.button2 in PlayerJump, causing pogostick behavior if + // moves are not applied every time before calling qc + move->applied = true; + + // set the edict fields + PRVM_serveredictfloat(host_client->edict, button0) = move->buttons & 1; + PRVM_serveredictfloat(host_client->edict, button2) = (move->buttons & 2)>>1; + if (move->impulse) + PRVM_serveredictfloat(host_client->edict, impulse) = move->impulse; + // only send the impulse to qc once + move->impulse = 0; + + movementloss = packetloss = 0; + if(host_client->netconnection) + { + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (host_client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET) + packetloss++; + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (host_client->movement_count[j] < 0) + movementloss++; + } + + VectorCopy(move->viewangles, PRVM_serveredictvector(host_client->edict, v_angle)); + PRVM_serveredictfloat(host_client->edict, button3) = ((move->buttons >> 2) & 1); + PRVM_serveredictfloat(host_client->edict, button4) = ((move->buttons >> 3) & 1); + PRVM_serveredictfloat(host_client->edict, button5) = ((move->buttons >> 4) & 1); + PRVM_serveredictfloat(host_client->edict, button6) = ((move->buttons >> 5) & 1); + PRVM_serveredictfloat(host_client->edict, button7) = ((move->buttons >> 6) & 1); + PRVM_serveredictfloat(host_client->edict, button8) = ((move->buttons >> 7) & 1); + PRVM_serveredictfloat(host_client->edict, button9) = ((move->buttons >> 11) & 1); + PRVM_serveredictfloat(host_client->edict, button10) = ((move->buttons >> 12) & 1); + PRVM_serveredictfloat(host_client->edict, button11) = ((move->buttons >> 13) & 1); + PRVM_serveredictfloat(host_client->edict, button12) = ((move->buttons >> 14) & 1); + PRVM_serveredictfloat(host_client->edict, button13) = ((move->buttons >> 15) & 1); + PRVM_serveredictfloat(host_client->edict, button14) = ((move->buttons >> 16) & 1); + PRVM_serveredictfloat(host_client->edict, button15) = ((move->buttons >> 17) & 1); + PRVM_serveredictfloat(host_client->edict, button16) = ((move->buttons >> 18) & 1); + PRVM_serveredictfloat(host_client->edict, buttonuse) = ((move->buttons >> 8) & 1); + PRVM_serveredictfloat(host_client->edict, buttonchat) = ((move->buttons >> 9) & 1); + PRVM_serveredictfloat(host_client->edict, cursor_active) = ((move->buttons >> 10) & 1); + VectorSet(PRVM_serveredictvector(host_client->edict, movement), move->forwardmove, move->sidemove, move->upmove); + VectorCopy(move->cursor_screen, PRVM_serveredictvector(host_client->edict, cursor_screen)); + VectorCopy(move->cursor_start, PRVM_serveredictvector(host_client->edict, cursor_trace_start)); + VectorCopy(move->cursor_impact, PRVM_serveredictvector(host_client->edict, cursor_trace_endpos)); + PRVM_serveredictedict(host_client->edict, cursor_trace_ent) = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber)); + PRVM_serveredictfloat(host_client->edict, ping) = host_client->ping * 1000.0; + PRVM_serveredictfloat(host_client->edict, ping_packetloss) = packetloss / (float) NETGRAPH_PACKETS; + PRVM_serveredictfloat(host_client->edict, ping_movementloss) = movementloss / (float) NETGRAPH_PACKETS; +} + +static void SV_FrameLost(int framenum) +{ + if (host_client->entitydatabase5) + { + EntityFrame5_LostFrame(host_client->entitydatabase5, framenum); + EntityFrameCSQC_LostFrame(host_client, framenum); + } +} + +static void SV_FrameAck(int framenum) +{ + if (host_client->entitydatabase) + EntityFrame_AckFrame(host_client->entitydatabase, framenum); + else if (host_client->entitydatabase4) + EntityFrame4_AckFrame(host_client->entitydatabase4, framenum, true); + else if (host_client->entitydatabase5) + EntityFrame5_AckFrame(host_client->entitydatabase5, framenum); +} + +/* +=================== +SV_ReadClientMessage +=================== +*/ +void SV_ReadClientMessage(void) +{ + prvm_prog_t *prog = SVVM_prog; + int cmd, num, start; + char *s, *p, *q; + + if(sv_autodemo_perclient.integer >= 2) + SV_WriteDemoMessage(host_client, &(host_client->netconnection->message), true); + + //MSG_BeginReading (); + sv_numreadmoves = 0; + + for(;;) + { + if (!host_client->active) + { + // a command caused an error + SV_DropClient (false); + return; + } + + if (sv_message.badread) + { + Con_Print("SV_ReadClientMessage: badread\n"); + SV_DropClient (false); + return; + } + + cmd = MSG_ReadByte(&sv_message); + if (cmd == -1) + { + // end of message + // apply the moves that were read this frame + SV_ExecuteClientMoves(); + break; + } + + switch (cmd) + { + default: + Con_Printf("SV_ReadClientMessage: unknown command char %i (at offset 0x%x)\n", cmd, sv_message.readcount); + if (developer_networking.integer) + Com_HexDumpToConsole(sv_message.data, sv_message.cursize); + SV_DropClient (false); + return; + + case clc_nop: + break; + + case clc_stringcmd: + // allow reliable messages now as the client is done with initial loading + if (host_client->sendsignon == 2) + host_client->sendsignon = 0; + s = MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)); + q = NULL; + for(p = s; *p; ++p) switch(*p) + { + case 10: + case 13: + if(!q) + q = p; + break; + default: + if(q) + goto clc_stringcmd_invalid; // newline seen, THEN something else -> possible exploit + break; + } + if(q) + *q = 0; + if (strncasecmp(s, "spawn", 5) == 0 + || strncasecmp(s, "begin", 5) == 0 + || strncasecmp(s, "prespawn", 8) == 0) + Cmd_ExecuteString (s, src_client, true); + else if (PRVM_serverfunction(SV_ParseClientCommand)) + { + int restorevm_tempstringsbuf_cursize; + restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize; + PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ParseClientCommand), "QC function SV_ParseClientCommand is missing"); + prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize; + } + else + Cmd_ExecuteString (s, src_client, true); + break; + +clc_stringcmd_invalid: + Con_Printf("Received invalid stringcmd from %s\n", host_client->name); + if(developer.integer > 0) + Com_HexDumpToConsole((unsigned char *) s, strlen(s)); + break; + + case clc_disconnect: + SV_DropClient (false); // client wants to disconnect + return; + + case clc_move: + SV_ReadClientMove(); + break; + + case clc_ackdownloaddata: + start = MSG_ReadLong(&sv_message); + num = MSG_ReadShort(&sv_message); + if (host_client->download_file && host_client->download_started) + { + if (host_client->download_expectedposition == start) + { + int size = (int)FS_FileSize(host_client->download_file); + // a data block was successfully received by the client, + // update the expected position on the next data block + host_client->download_expectedposition = start + num; + // if this was the last data block of the file, it's done + if (host_client->download_expectedposition >= FS_FileSize(host_client->download_file)) + { + // tell the client that the download finished + // we need to calculate the crc now + // + // note: at this point the OS probably has the file + // entirely in memory, so this is a faster operation + // now than it was when the download started. + // + // it is also preferable to do this at the end of the + // download rather than the start because it reduces + // potential for Denial Of Service attacks against the + // server. + int crc; + unsigned char *temp; + FS_Seek(host_client->download_file, 0, SEEK_SET); + temp = (unsigned char *) Mem_Alloc(tempmempool, size); + FS_Read(host_client->download_file, temp, size); + crc = CRC_Block(temp, size); + Mem_Free(temp); + // calculated crc, send the file info to the client + // (so that it can verify the data) + Host_ClientCommands("\ncl_downloadfinished %i %i %s\n", size, crc, host_client->download_name); + Con_DPrintf("Download of %s by %s has finished\n", host_client->download_name, host_client->name); + FS_Close(host_client->download_file); + host_client->download_file = NULL; + host_client->download_name[0] = 0; + host_client->download_expectedposition = 0; + host_client->download_started = false; + } + } + else + { + // a data block was lost, reset to the expected position + // and resume sending from there + FS_Seek(host_client->download_file, host_client->download_expectedposition, SEEK_SET); + } + } + break; + + case clc_ackframe: + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + num = MSG_ReadLong(&sv_message); + if (sv_message.badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__); + if (developer_networkentities.integer >= 10) + Con_Printf("recv clc_ackframe %i\n", num); + // if the client hasn't progressed through signons yet, + // ignore any clc_ackframes we get (they're probably from the + // previous level) + if (host_client->begun && host_client->latestframenum < num) + { + int i; + for (i = host_client->latestframenum + 1;i < num;i++) + SV_FrameLost(i); + SV_FrameAck(num); + host_client->latestframenum = num; + } + break; + } + } +} + diff --git a/app/jni/svbsp.c b/app/jni/svbsp.c new file mode 100644 index 0000000..437d82a --- /dev/null +++ b/app/jni/svbsp.c @@ -0,0 +1,453 @@ + +// Shadow Volume BSP code written by Forest "LordHavoc" Hale on 2003-11-06 and placed into public domain. +// Modified by LordHavoc (to make it work and other nice things like that) on 2007-01-24 and 2007-01-25 +// Optimized by LordHavoc on 2009-12-24 and 2009-12-25 + +#include +#include +#include "svbsp.h" +#include "polygon.h" + +#define MAX_SVBSP_POLYGONPOINTS 64 +#define SVBSP_CLIP_EPSILON (1.0f / 1024.0f) + +#define SVBSP_DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) + +typedef struct svbsp_polygon_s +{ + float points[MAX_SVBSP_POLYGONPOINTS][3]; + //unsigned char splitflags[MAX_SVBSP_POLYGONPOINTS]; + int facesplitflag; + int numpoints; +} +svbsp_polygon_t; + +static void SVBSP_PlaneFromPoints(float *plane4f, const float *p1, const float *p2, const float *p3) +{ + float ilength; + // calculate unnormalized plane + plane4f[0] = (p1[1] - p2[1]) * (p3[2] - p2[2]) - (p1[2] - p2[2]) * (p3[1] - p2[1]); + plane4f[1] = (p1[2] - p2[2]) * (p3[0] - p2[0]) - (p1[0] - p2[0]) * (p3[2] - p2[2]); + plane4f[2] = (p1[0] - p2[0]) * (p3[1] - p2[1]) - (p1[1] - p2[1]) * (p3[0] - p2[0]); + plane4f[3] = SVBSP_DotProduct(plane4f, p1); + // normalize the plane normal and adjust distance accordingly + ilength = (float)sqrt(SVBSP_DotProduct(plane4f, plane4f)); + if (ilength) + ilength = 1.0f / ilength; + plane4f[0] *= ilength; + plane4f[1] *= ilength; + plane4f[2] *= ilength; + plane4f[3] *= ilength; +} + +static void SVBSP_DividePolygon(const svbsp_polygon_t *poly, const float *plane, svbsp_polygon_t *front, svbsp_polygon_t *back, const float *dists, const int *sides) +{ + int i, j, count = poly->numpoints, frontcount = 0, backcount = 0; + float frac, ifrac, c[3], pdist, ndist; + const float *nextpoint; + const float *points = poly->points[0]; + float *outfront = front->points[0]; + float *outback = back->points[0]; + for(i = 0;i < count;i++, points += 3) + { + j = i + 1; + if (j >= count) + j = 0; + if (!(sides[i] & 2)) + { + outfront[frontcount*3+0] = points[0]; + outfront[frontcount*3+1] = points[1]; + outfront[frontcount*3+2] = points[2]; + frontcount++; + } + if (!(sides[i] & 1)) + { + outback[backcount*3+0] = points[0]; + outback[backcount*3+1] = points[1]; + outback[backcount*3+2] = points[2]; + backcount++; + } + if ((sides[i] | sides[j]) == 3) + { + // don't allow splits if remaining points would overflow point buffer + if (frontcount + (count - i) > MAX_SVBSP_POLYGONPOINTS - 1) + continue; + if (backcount + (count - i) > MAX_SVBSP_POLYGONPOINTS - 1) + continue; + nextpoint = poly->points[j]; + pdist = dists[i]; + ndist = dists[j]; + frac = pdist / (pdist - ndist); + ifrac = 1.0f - frac; + c[0] = points[0] * ifrac + frac * nextpoint[0]; + c[1] = points[1] * ifrac + frac * nextpoint[1]; + c[2] = points[2] * ifrac + frac * nextpoint[2]; + outfront[frontcount*3+0] = c[0]; + outfront[frontcount*3+1] = c[1]; + outfront[frontcount*3+2] = c[2]; + frontcount++; + outback[backcount*3+0] = c[0]; + outback[backcount*3+1] = c[1]; + outback[backcount*3+2] = c[2]; + backcount++; + } + } + front->numpoints = frontcount; + back->numpoints = backcount; +} + +void SVBSP_Init(svbsp_t *b, const float *origin, int maxnodes, svbsp_node_t *nodes) +{ + memset(b, 0, sizeof(*b)); + b->origin[0] = origin[0]; + b->origin[1] = origin[1]; + b->origin[2] = origin[2]; + b->numnodes = 3; + b->maxnodes = maxnodes; + b->nodes = nodes; + b->ranoutofnodes = 0; + b->stat_occluders_rejected = 0; + b->stat_occluders_accepted = 0; + b->stat_occluders_fragments_accepted = 0; + b->stat_occluders_fragments_rejected = 0; + b->stat_queries_rejected = 0; + b->stat_queries_accepted = 0; + b->stat_queries_fragments_accepted = 0; + b->stat_queries_fragments_rejected = 0; + + // the bsp tree must be initialized to have two perpendicular splits axes + // through origin, otherwise the polygon insertions would affect the + // opposite side of the tree, which would be disasterous. + // + // so this code has to make 3 nodes and 4 leafs, and since the leafs are + // represented by empty/solid state numbers in this system rather than + // actual structs, we only need to make the 3 nodes. + + // root node + // this one splits the world into +X and -X sides + b->nodes[0].plane[0] = 1; + b->nodes[0].plane[1] = 0; + b->nodes[0].plane[2] = 0; + b->nodes[0].plane[3] = origin[0]; + b->nodes[0].parent = -1; + b->nodes[0].children[0] = 1; + b->nodes[0].children[1] = 2; + + // +X side node + // this one splits the +X half of the world into +Y and -Y + b->nodes[1].plane[0] = 0; + b->nodes[1].plane[1] = 1; + b->nodes[1].plane[2] = 0; + b->nodes[1].plane[3] = origin[1]; + b->nodes[1].parent = 0; + b->nodes[1].children[0] = -1; + b->nodes[1].children[1] = -1; + + // -X side node + // this one splits the -X half of the world into +Y and -Y + b->nodes[2].plane[0] = 0; + b->nodes[2].plane[1] = 1; + b->nodes[2].plane[2] = 0; + b->nodes[2].plane[3] = origin[1]; + b->nodes[2].parent = 0; + b->nodes[2].children[0] = -1; + b->nodes[2].children[1] = -1; +} + +static void SVBSP_InsertOccluderPolygonNodes(svbsp_t *b, int *parentnodenumpointer, int parentnodenum, const svbsp_polygon_t *poly, void (*fragmentcallback)(void *fragmentcallback_pointer1, int fragmentcallback_number1, svbsp_t *b, int numpoints, const float *points), void *fragmentcallback_pointer1, int fragmentcallback_number1) +{ + // now we need to create up to numpoints + 1 new nodes, forming a BSP tree + // describing the occluder polygon's shadow volume + int i, j, p; + svbsp_node_t *node; + + // points and lines are valid testers but not occluders + if (poly->numpoints < 3) + return; + + // if there aren't enough nodes remaining, skip it + if (b->numnodes + poly->numpoints + 1 >= b->maxnodes) + { + b->ranoutofnodes = 1; + return; + } + + // add one node per side, then the actual occluding face node + + // thread safety notes: + // DO NOT multithread insertion, it could be made 'safe' but the results + // would be inconsistent. + // + // it is completely safe to multithread queries in all cases. + // + // if an insertion is occurring the query will give intermediate results, + // being blocked by some volumes but not others, which is perfectly okay + // for visibility culling intended only to reduce rendering work + + // note down the first available nodenum for the *parentnodenumpointer + // line which is done last to allow multithreaded queries during an + // insertion + for (i = 0, p = poly->numpoints - 1;i < poly->numpoints;p = i, i++) + { +#if 1 + // see if a parent plane describes this side + for (j = parentnodenum;j >= 0;j = b->nodes[j].parent) + { + float *parentnodeplane = b->nodes[j].plane; + if (fabs(SVBSP_DotProduct(poly->points[p], parentnodeplane) - parentnodeplane[3]) < SVBSP_CLIP_EPSILON + && fabs(SVBSP_DotProduct(poly->points[i], parentnodeplane) - parentnodeplane[3]) < SVBSP_CLIP_EPSILON + && fabs(SVBSP_DotProduct(b->origin , parentnodeplane) - parentnodeplane[3]) < SVBSP_CLIP_EPSILON) + break; + } + if (j >= 0) + continue; // already have a matching parent plane +#endif +#if 0 + // skip any sides that were classified as belonging to a parent plane + if (poly->splitflags[i]) + continue; +#endif + // create a side plane + // anything infront of this is not inside the shadow volume + node = b->nodes + b->numnodes++; + SVBSP_PlaneFromPoints(node->plane, b->origin, poly->points[p], poly->points[i]); + // we need to flip the plane if it puts any part of the polygon on the + // wrong side + // (in this way this code treats all polygons as float sided) + // + // because speed is important this stops as soon as it finds proof + // that the orientation is right or wrong + // (we know that the plane is on one edge of the polygon, so there is + // never a case where points lie on both sides, so the first hint is + // sufficient) + for (j = 0;j < poly->numpoints;j++) + { + float d = SVBSP_DotProduct(poly->points[j], node->plane) - node->plane[3]; + if (d < -SVBSP_CLIP_EPSILON) + break; + if (d > SVBSP_CLIP_EPSILON) + { + node->plane[0] *= -1; + node->plane[1] *= -1; + node->plane[2] *= -1; + node->plane[3] *= -1; + break; + } + } + node->parent = parentnodenum; + node->children[0] = -1; // empty + node->children[1] = -1; // empty + // link this child into the tree + *parentnodenumpointer = parentnodenum = (int)(node - b->nodes); + // now point to the child pointer for the next node to update later + parentnodenumpointer = &node->children[1]; + } + +#if 1 + // skip the face plane if it lies on a parent plane + if (!poly->facesplitflag) +#endif + { + // add the face-plane node + // infront is empty, behind is shadow + node = b->nodes + b->numnodes++; + SVBSP_PlaneFromPoints(node->plane, poly->points[0], poly->points[1], poly->points[2]); + // this is a flip check similar to the one above + // this one checks if the plane faces the origin, if not, flip it + if (SVBSP_DotProduct(b->origin, node->plane) - node->plane[3] < -SVBSP_CLIP_EPSILON) + { + node->plane[0] *= -1; + node->plane[1] *= -1; + node->plane[2] *= -1; + node->plane[3] *= -1; + } + node->parent = parentnodenum; + node->children[0] = -1; // empty + node->children[1] = -2; // shadow + // link this child into the tree + // (with the addition of this node, queries will now be culled by it) + *parentnodenumpointer = (int)(node - b->nodes); + } +} + +static int SVBSP_AddPolygonNode(svbsp_t *b, int *parentnodenumpointer, int parentnodenum, const svbsp_polygon_t *poly, int insertoccluder, void (*fragmentcallback)(void *fragmentcallback_pointer1, int fragmentcallback_number1, svbsp_t *b, int numpoints, const float *points), void *fragmentcallback_pointer1, int fragmentcallback_number1) +{ + int i; + int s; + int facesplitflag = poly->facesplitflag; + int bothsides; + float plane[4]; + float d; + svbsp_polygon_t front; + svbsp_polygon_t back; + svbsp_node_t *node; + int sides[MAX_SVBSP_POLYGONPOINTS]; + float dists[MAX_SVBSP_POLYGONPOINTS]; + if (poly->numpoints < 1) + return 0; + // recurse through plane nodes + while (*parentnodenumpointer >= 0) + { + // get node info + parentnodenum = *parentnodenumpointer; + node = b->nodes + parentnodenum; + plane[0] = node->plane[0]; + plane[1] = node->plane[1]; + plane[2] = node->plane[2]; + plane[3] = node->plane[3]; + // calculate point dists for clipping + bothsides = 0; + for (i = 0;i < poly->numpoints;i++) + { + d = SVBSP_DotProduct(poly->points[i], plane) - plane[3]; + s = 0; + if (d > SVBSP_CLIP_EPSILON) + s = 1; + if (d < -SVBSP_CLIP_EPSILON) + s = 2; + bothsides |= s; + dists[i] = d; + sides[i] = s; + } + // see which side the polygon is on + switch(bothsides) + { + default: + case 0: + // no need to split, this polygon is on the plane + // this case only occurs for polygons on the face plane, usually + // the same polygon (inserted twice - once as occluder, once as + // tester) + // if this is an occluder, it is redundant + if (insertoccluder) + return 1; // occluded + // if this is a tester, test the front side, because it is + // probably the same polygon that created this node... + facesplitflag = 1; + parentnodenumpointer = &node->children[0]; + continue; + case 1: + // no need to split, just go to one side + parentnodenumpointer = &node->children[0]; + continue; + case 2: + // no need to split, just go to one side + parentnodenumpointer = &node->children[1]; + continue; + case 3: + // lies on both sides of the plane, we need to split it +#if 1 + SVBSP_DividePolygon(poly, plane, &front, &back, dists, sides); +#else + PolygonF_Divide(poly->numpoints, poly->points[0], plane[0], plane[1], plane[2], plane[3], SVBSP_CLIP_EPSILON, MAX_SVBSP_POLYGONPOINTS, front.points[0], &front.numpoints, MAX_SVBSP_POLYGONPOINTS, back.points[0], &back.numpoints, NULL); + if (front.numpoints > MAX_SVBSP_POLYGONPOINTS) + front.numpoints = MAX_SVBSP_POLYGONPOINTS; + if (back.numpoints > MAX_SVBSP_POLYGONPOINTS) + back.numpoints = MAX_SVBSP_POLYGONPOINTS; +#endif + front.facesplitflag = facesplitflag; + back.facesplitflag = facesplitflag; + // recurse the sides and return the resulting occlusion flags + i = SVBSP_AddPolygonNode(b, &node->children[0], *parentnodenumpointer, &front, insertoccluder, fragmentcallback, fragmentcallback_pointer1, fragmentcallback_number1); + i |= SVBSP_AddPolygonNode(b, &node->children[1], *parentnodenumpointer, &back , insertoccluder, fragmentcallback, fragmentcallback_pointer1, fragmentcallback_number1); + return i; + } + } + // leaf node + if (*parentnodenumpointer == -1) + { + // empty leaf node; and some geometry survived + // if inserting an occluder, replace this empty leaf with a shadow volume +#if 0 + for (i = 0;i < poly->numpoints-2;i++) + { + Debug_PolygonBegin(NULL, DRAWFLAG_ADDITIVE); + Debug_PolygonVertex(poly->points[ 0][0], poly->points[ 0][1], poly->points[ 0][2], 0.0f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f); + Debug_PolygonVertex(poly->points[i+1][0], poly->points[i+1][1], poly->points[i+1][2], 0.0f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f); + Debug_PolygonVertex(poly->points[i+2][0], poly->points[i+2][1], poly->points[i+2][2], 0.0f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f); + Debug_PolygonEnd(); + } +#endif + if (insertoccluder) + { + b->stat_occluders_fragments_accepted++; + SVBSP_InsertOccluderPolygonNodes(b, parentnodenumpointer, parentnodenum, poly, fragmentcallback, fragmentcallback_pointer1, fragmentcallback_number1); + } + else + b->stat_queries_fragments_accepted++; + if (fragmentcallback) + fragmentcallback(fragmentcallback_pointer1, fragmentcallback_number1, b, poly->numpoints, poly->points[0]); + return 2; + } + else + { + // otherwise it's a solid leaf which destroys all polygons inside it + if (insertoccluder) + b->stat_occluders_fragments_rejected++; + else + b->stat_queries_fragments_rejected++; +#if 0 + for (i = 0;i < poly->numpoints-2;i++) + { + Debug_PolygonBegin(NULL, DRAWFLAG_ADDITIVE); + Debug_PolygonVertex(poly->points[ 0][0], poly->points[ 0][1], poly->points[ 0][2], 0.0f, 0.0f, 0.0f, 0.0f, 0.25f, 1.0f); + Debug_PolygonVertex(poly->points[i+1][0], poly->points[i+1][1], poly->points[i+1][2], 0.0f, 0.0f, 0.0f, 0.0f, 0.25f, 1.0f); + Debug_PolygonVertex(poly->points[i+2][0], poly->points[i+2][1], poly->points[i+2][2], 0.0f, 0.0f, 0.0f, 0.0f, 0.25f, 1.0f); + Debug_PolygonEnd(); + } +#endif + } + return 1; +} + +int SVBSP_AddPolygon(svbsp_t *b, int numpoints, const float *points, int insertoccluder, void (*fragmentcallback)(void *fragmentcallback_pointer1, int fragmentcallback_number1, svbsp_t *b, int numpoints, const float *points), void *fragmentcallback_pointer1, int fragmentcallback_number1) +{ + int i; + int nodenum; + svbsp_polygon_t poly; + // don't even consider an empty polygon + // note we still allow points and lines to be tested... + if (numpoints < 1) + return 0; + // if the polygon has too many points, we would crash + if (numpoints > MAX_SVBSP_POLYGONPOINTS) + return 0; + poly.numpoints = numpoints; + for (i = 0;i < numpoints;i++) + { + poly.points[i][0] = points[i*3+0]; + poly.points[i][1] = points[i*3+1]; + poly.points[i][2] = points[i*3+2]; + //poly.splitflags[i] = 0; // this edge is a valid BSP splitter - clipped edges are not (because they lie on a bsp plane) + poly.facesplitflag = 0; // this face is a valid BSP Splitter - if it lies on a bsp plane it is not + } +#if 0 +//if (insertoccluder) + for (i = 0;i < poly.numpoints-2;i++) + { + Debug_PolygonBegin(NULL, DRAWFLAG_ADDITIVE); + Debug_PolygonVertex(poly.points[ 0][0], poly.points[ 0][1], poly.points[ 0][2], 0.0f, 0.0f, 0.0f, 0.25f, 0.0f, 1.0f); + Debug_PolygonVertex(poly.points[i+1][0], poly.points[i+1][1], poly.points[i+1][2], 0.0f, 0.0f, 0.0f, 0.25f, 0.0f, 1.0f); + Debug_PolygonVertex(poly.points[i+2][0], poly.points[i+2][1], poly.points[i+2][2], 0.0f, 0.0f, 0.0f, 0.25f, 0.0f, 1.0f); + Debug_PolygonEnd(); + } +#endif + nodenum = 0; + i = SVBSP_AddPolygonNode(b, &nodenum, -1, &poly, insertoccluder, fragmentcallback, fragmentcallback_pointer1, fragmentcallback_number1); + if (insertoccluder) + { + if (i & 2) + b->stat_occluders_accepted++; + else + b->stat_occluders_rejected++; + } + else + { + if (i & 2) + b->stat_queries_accepted++; + else + b->stat_queries_rejected++; + } + return i; +} + diff --git a/app/jni/svbsp.h b/app/jni/svbsp.h new file mode 100644 index 0000000..ca87f0d --- /dev/null +++ b/app/jni/svbsp.h @@ -0,0 +1,75 @@ + +// Shadow Volume BSP code written by Forest "LordHavoc" Hale on 2003-11-06 and placed into public domain. +// Modified by LordHavoc (to make it work and other nice things like that) on 2007-01-24 and 2007-01-25 + +#ifndef SVBSP_H +#define SVBSP_H + +typedef struct svbsp_node_s +{ + // notes: + // leaf nodes are not stored, these are always structural nodes + // (they always have a plane and two children) + // children[] can be -1 for empty leaf or -2 for shadow leaf, >= 0 is node + // parent can be -1 if this is the root node, >= 0 is a node + int parent, children[2], padding; + // node plane, splits space + float plane[4]; +} +svbsp_node_t; + +typedef struct svbsp_s +{ + // lightsource or view origin + float origin[3]; + // current number of nodes in the svbsp + int numnodes; + // how big the nodes array is + int maxnodes; + // first node is the root node + svbsp_node_t *nodes; + // non-zero indicates that an insertion failed because of lack of nodes + int ranoutofnodes; + // tree statistics + // note: do not use multithreading when gathering statistics! + // (the code updating these counters is not thread-safe, increments may + // sometimes fail when multithreaded) + int stat_occluders_rejected; + int stat_occluders_accepted; + int stat_occluders_fragments_rejected; + int stat_occluders_fragments_accepted; + int stat_queries_rejected; + int stat_queries_accepted; + int stat_queries_fragments_rejected; + int stat_queries_fragments_accepted; +} +svbsp_t; + +// this function initializes a tree to prepare for polygon insertions +// +// the maxnodes needed for a given polygon set can vary wildly, if there are +// not enough maxnodes then later polygons will not be inserted and the field +// svbsp_t->ranoutofnodes will be non-zero +// +// as a rule of thumb the minimum nodes needed for a polygon set is +// numpolygons * (averagepolygonvertices + 1) +void SVBSP_Init(svbsp_t *b, const float *origin, int maxnodes, svbsp_node_t *nodes); + +// this function tests if any part of a polygon is not in shadow, and returns +// non-zero if the polygon is not completely shadowed +// +// returns 0 if the polygon was rejected (not facing origin or no points) +// returns 1 if all of the polygon is in shadow +// returns 2 if all of the polygon is unshadowed +// returns 3 if some of the polygon is shadowed and some unshadowed +// +// it also can add a new shadow volume (insertoccluder parameter) +// +// additionally it calls your fragmentcallback on each unshadowed clipped +// part of the polygon +// (beware that polygons often get split heavily, even if entirely unshadowed) +// +// thread-safety notes: do not multi-thread insertions! +int SVBSP_AddPolygon(svbsp_t *b, int numpoints, const float *points, int insertoccluder, void (*fragmentcallback)(void *fragmentcallback_pointer1, int fragmentcallback_number1, svbsp_t *b, int numpoints, const float *points), void *fragmentcallback_pointer1, int fragmentcallback_number1); + +#endif diff --git a/app/jni/svvm_cmds.c b/app/jni/svvm_cmds.c new file mode 100644 index 0000000..e9d51fd --- /dev/null +++ b/app/jni/svvm_cmds.c @@ -0,0 +1,3847 @@ +#include "quakedef.h" + +#include "prvm_cmds.h" +#include "jpeg.h" + +//============================================================================ +// Server + + + +const char *vm_sv_extensions = +"BX_WAL_SUPPORT " +"DP_BUTTONCHAT " +"DP_BUTTONUSE " +"DP_CL_LOADSKY " +"DP_CON_ALIASPARAMETERS " +"DP_CON_BESTWEAPON " +"DP_CON_EXPANDCVAR " +"DP_CON_SET " +"DP_CON_SETA " +"DP_CON_STARTMAP " +"DP_CRYPTO " +"DP_CSQC_BINDMAPS " +"DP_CSQC_ENTITYWORLDOBJECT " +"DP_CSQC_ENTITYMODELLIGHT " +"DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET " +"DP_CSQC_MAINVIEW " +"DP_CSQC_MINFPS_QUALITY " +"DP_CSQC_MULTIFRAME_INTERPOLATION " +"DP_CSQC_BOXPARTICLES " +"DP_CSQC_SPAWNPARTICLE " +"DP_CSQC_QUERYRENDERENTITY " +"DP_CSQC_ROTATEMOVES " +"DP_CSQC_SETPAUSE " +"DP_CSQC_V_CALCREFDEF_WIP1 " +"DP_CSQC_V_CALCREFDEF_WIP2 " +"DP_EF_ADDITIVE " +"DP_EF_BLUE " +"DP_EF_DOUBLESIDED " +"DP_EF_DYNAMICMODELLIGHT " +"DP_EF_FLAME " +"DP_EF_FULLBRIGHT " +"DP_EF_NODEPTHTEST " +"DP_EF_NODRAW " +"DP_EF_NOGUNBOB " +"DP_EF_NOSELFSHADOW " +"DP_EF_NOSHADOW " +"DP_EF_RED " +"DP_EF_RESTARTANIM_BIT " +"DP_EF_STARDUST " +"DP_EF_TELEPORT_BIT " +"DP_ENT_ALPHA " +"DP_ENT_COLORMOD " +"DP_ENT_CUSTOMCOLORMAP " +"DP_ENT_EXTERIORMODELTOCLIENT " +"DP_ENT_GLOW " +"DP_ENT_GLOWMOD " +"DP_ENT_LOWPRECISION " +"DP_ENT_SCALE " +"DP_ENT_TRAILEFFECTNUM " +"DP_ENT_VIEWMODEL " +"DP_GFX_EXTERNALTEXTURES " +"DP_GFX_EXTERNALTEXTURES_PERMAP " +"DP_GFX_FOG " +"DP_GFX_MODEL_INTERPOLATION " +"DP_GFX_QUAKE3MODELTAGS " +"DP_GFX_SKINFILES " +"DP_GFX_SKYBOX " +"DP_GFX_FONTS " +"DP_GFX_FONTS_FREETYPE " +"DP_UTF8 " +"DP_FONT_VARIABLEWIDTH " +"DP_HALFLIFE_MAP " +"DP_HALFLIFE_MAP_CVAR " +"DP_HALFLIFE_SPRITE " +"DP_INPUTBUTTONS " +"DP_LIGHTSTYLE_STATICVALUE " +"DP_LITSPRITES " +"DP_LITSUPPORT " +"DP_MONSTERWALK " +"DP_MOVETYPEBOUNCEMISSILE " +"DP_MOVETYPEFLYWORLDONLY " +"DP_MOVETYPEFOLLOW " +"DP_NULL_MODEL " +"DP_QC_ASINACOSATANATAN2TAN " +"DP_QC_AUTOCVARS " +"DP_QC_CHANGEPITCH " +"DP_QC_CMD " +"DP_QC_COPYENTITY " +"DP_QC_CRC16 " +"DP_QC_CVAR_DEFSTRING " +"DP_QC_CVAR_DESCRIPTION " +"DP_QC_CVAR_STRING " +"DP_QC_CVAR_TYPE " +"DP_QC_DIGEST " +"DP_QC_DIGEST_SHA256 " +"DP_QC_EDICT_NUM " +"DP_QC_ENTITYDATA " +"DP_QC_ENTITYSTRING " +"DP_QC_ETOS " +"DP_QC_EXTRESPONSEPACKET " +"DP_QC_FINDCHAIN " +"DP_QC_FINDCHAINFLAGS " +"DP_QC_FINDCHAINFLOAT " +"DP_QC_FINDCHAIN_TOFIELD " +"DP_QC_FINDFLAGS " +"DP_QC_FINDFLOAT " +"DP_QC_FS_SEARCH " +"DP_QC_GETLIGHT " +"DP_QC_GETSURFACE " +"DP_QC_GETSURFACETRIANGLE " +"DP_QC_GETSURFACEPOINTATTRIBUTE " +"DP_QC_GETTAGINFO " +"DP_QC_GETTAGINFO_BONEPROPERTIES " +"DP_QC_GETTIME " +"DP_QC_GETTIME_CDTRACK " +"DP_QC_I18N " +"DP_QC_LOG " +"DP_QC_MINMAXBOUND " +"DP_QC_MULTIPLETEMPSTRINGS " +"DP_QC_NUM_FOR_EDICT " +"DP_QC_RANDOMVEC " +"DP_QC_SINCOSSQRTPOW " +"DP_QC_SPRINTF " +"DP_QC_STRFTIME " +"DP_QC_STRINGBUFFERS " +"DP_QC_STRINGBUFFERS_CVARLIST " +"DP_QC_STRINGBUFFERS_EXT_WIP " +"DP_QC_STRINGCOLORFUNCTIONS " +"DP_QC_STRING_CASE_FUNCTIONS " +"DP_QC_STRREPLACE " +"DP_QC_TOKENIZEBYSEPARATOR " +"DP_QC_TOKENIZE_CONSOLE " +"DP_QC_TRACEBOX " +"DP_QC_TRACETOSS " +"DP_QC_TRACE_MOVETYPE_HITMODEL " +"DP_QC_TRACE_MOVETYPE_WORLDONLY " +"DP_QC_UNLIMITEDTEMPSTRINGS " +"DP_QC_URI_ESCAPE " +"DP_QC_URI_GET " +"DP_QC_URI_POST " +"DP_QC_VECTOANGLES_WITH_ROLL " +"DP_QC_VECTORVECTORS " +"DP_QC_WHICHPACK " +"DP_QUAKE2_MODEL " +"DP_QUAKE2_SPRITE " +"DP_QUAKE3_MAP " +"DP_QUAKE3_MODEL " +"DP_REGISTERCVAR " +"DP_SKELETONOBJECTS " +"DP_SND_DIRECTIONLESSATTNNONE " +"DP_SND_FAKETRACKS " +"DP_SND_SOUND7_WIP1 " +"DP_SND_SOUND7_WIP2 " +"DP_SND_OGGVORBIS " +"DP_SND_SETPARAMS " +"DP_SND_STEREOWAV " +"DP_SND_GETSOUNDTIME " +"DP_VIDEO_DPV " +"DP_VIDEO_SUBTITLES " +"DP_SOLIDCORPSE " +"DP_SPRITE32 " +"DP_SV_BOTCLIENT " +"DP_SV_BOUNCEFACTOR " +"DP_SV_CLIENTCAMERA " +"DP_SV_CLIENTCOLORS " +"DP_SV_CLIENTNAME " +"DP_SV_CMD " +"DP_SV_CUSTOMIZEENTITYFORCLIENT " +"DP_SV_DISCARDABLEDEMO " +"DP_SV_DRAWONLYTOCLIENT " +"DP_SV_DROPCLIENT " +"DP_SV_EFFECT " +"DP_SV_ENTITYCONTENTSTRANSITION " +"DP_SV_MODELFLAGS_AS_EFFECTS " +"DP_SV_MOVETYPESTEP_LANDEVENT " +"DP_SV_NETADDRESS " +"DP_SV_NODRAWTOCLIENT " +"DP_SV_ONENTITYNOSPAWNFUNCTION " +"DP_SV_ONENTITYPREPOSTSPAWNFUNCTION " +"DP_SV_PING " +"DP_SV_PING_PACKETLOSS " +"DP_SV_PLAYERPHYSICS " +"DP_PHYSICS_ODE " +"DP_SV_POINTPARTICLES " +"DP_SV_POINTSOUND " +"DP_SV_PRECACHEANYTIME " +"DP_SV_PRINT " +"DP_SV_PUNCHVECTOR " +"DP_SV_QCSTATUS " +"DP_SV_ROTATINGBMODEL " +"DP_SV_SETCOLOR " +"DP_SV_SHUTDOWN " +"DP_SV_SLOWMO " +"DP_SV_SPAWNFUNC_PREFIX " +"DP_SV_WRITEPICTURE " +"DP_SV_WRITEUNTERMINATEDSTRING " +"DP_TE_BLOOD " +"DP_TE_BLOODSHOWER " +"DP_TE_CUSTOMFLASH " +"DP_TE_EXPLOSIONRGB " +"DP_TE_FLAMEJET " +"DP_TE_PARTICLECUBE " +"DP_TE_PARTICLERAIN " +"DP_TE_PARTICLESNOW " +"DP_TE_PLASMABURN " +"DP_TE_QUADEFFECTS1 " +"DP_TE_SMALLFLASH " +"DP_TE_SPARK " +"DP_TE_STANDARDEFFECTBUILTINS " +"DP_TRACE_HITCONTENTSMASK_SURFACEINFO " +"DP_VIEWZOOM " +"EXT_BITSHIFT " +"FRIK_FILE " +"FTE_CSQC_SKELETONOBJECTS " +"FTE_QC_CHECKPVS " +"FTE_STRINGS " +"KRIMZON_SV_PARSECLIENTCOMMAND " +"NEH_CMD_PLAY2 " +"NEH_RESTOREGAME " +"NEXUIZ_PLAYERMODEL " +"NXQ_GFX_LETTERBOX " +"PRYDON_CLIENTCURSOR " +"TENEBRAE_GFX_DLIGHTS " +"TW_SV_STEPCONTROL " +"ZQ_PAUSE " +//"EXT_CSQC " // not ready yet +; + +/* +================= +VM_SV_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) +================= +*/ +static void VM_SV_setorigin(prvm_prog_t *prog) +{ + prvm_edict_t *e; + + VM_SAFEPARMCOUNT(2, VM_setorigin); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setorigin: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setorigin: can not modify free entity\n"); + return; + } + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin)); + if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN) + e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT; + SV_LinkEdict(e); +} + +// TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black] +static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qboolean rotate) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (min[i] > max[i]) + prog->error_cmd("SetMinMaxSize: backwards mins/maxs"); + +// set derived values + VectorCopy (min, PRVM_serveredictvector(e, mins)); + VectorCopy (max, PRVM_serveredictvector(e, maxs)); + VectorSubtract (max, min, PRVM_serveredictvector(e, size)); + + SV_LinkEdict(e); +} + +/* +================= +VM_SV_setsize + +the size box is rotated by the current angle +LordHavoc: no it isn't... + +setsize (entity, minvector, maxvector) +================= +*/ +static void VM_SV_setsize(prvm_prog_t *prog) +{ + prvm_edict_t *e; + vec3_t mins, maxs; + + VM_SAFEPARMCOUNT(3, VM_setsize); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setsize: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setsize: can not modify free entity\n"); + return; + } + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs); + SetMinMaxSize(prog, e, mins, maxs, false); +} + + +/* +================= +VM_SV_setmodel + +setmodel(entity, model) +================= +*/ +static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16}; +static void VM_SV_setmodel(prvm_prog_t *prog) +{ + prvm_edict_t *e; + dp_model_t *mod; + int i; + + VM_SAFEPARMCOUNT(2, VM_setmodel); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setmodel: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setmodel: can not modify free entity\n"); + return; + } + i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1); + PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]); + PRVM_serveredictfloat(e, modelindex) = i; + + mod = SV_GetModelByIndex(i); + + if (mod) + { + if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer) + SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true); + else + SetMinMaxSize(prog, e, quakemins, quakemaxs, true); + } + else + SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true); +} + +/* +================= +VM_SV_sprint + +single print to a specific client + +sprint(clientent, value) +================= +*/ +static void VM_SV_sprint(prvm_prog_t *prog) +{ + client_t *client; + int entnum; + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint); + + VM_VarString(prog, 1, string, sizeof(string)); + + entnum = PRVM_G_EDICTNUM(OFS_PARM0); + // LordHavoc: div0 requested that sprintto world operate like print + if (entnum == 0) + { + Con_Print(string); + return; + } + + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + { + VM_Warning(prog, "tried to centerprint to a non-client\n"); + return; + } + + client = svs.clients + entnum-1; + if (!client->netconnection) + return; + + MSG_WriteChar(&client->netconnection->message,svc_print); + MSG_WriteString(&client->netconnection->message, string); +} + + +/* +================= +VM_SV_centerprint + +single print to a specific client + +centerprint(clientent, value) +================= +*/ +static void VM_SV_centerprint(prvm_prog_t *prog) +{ + client_t *client; + int entnum; + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_centerprint); + + entnum = PRVM_G_EDICTNUM(OFS_PARM0); + + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + { + VM_Warning(prog, "tried to centerprint to a non-client\n"); + return; + } + + client = svs.clients + entnum-1; + if (!client->netconnection) + return; + + VM_VarString(prog, 1, string, sizeof(string)); + MSG_WriteChar(&client->netconnection->message,svc_centerprint); + MSG_WriteString(&client->netconnection->message, string); +} + +/* +================= +VM_SV_particle + +particle(origin, color, count) +================= +*/ +static void VM_SV_particle(prvm_prog_t *prog) +{ + vec3_t org, dir; + int color; + int count; + + VM_SAFEPARMCOUNT(4, VM_SV_particle); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir); + color = (int)PRVM_G_FLOAT(OFS_PARM2); + count = (int)PRVM_G_FLOAT(OFS_PARM3); + SV_StartParticle (org, dir, color, count); +} + + +/* +================= +VM_SV_ambientsound + +================= +*/ +static void VM_SV_ambientsound(prvm_prog_t *prog) +{ + const char *samp; + vec3_t pos; + prvm_vec_t vol, attenuation; + int soundnum, large; + + VM_SAFEPARMCOUNT(4, VM_SV_ambientsound); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos); + samp = PRVM_G_STRING(OFS_PARM1); + vol = PRVM_G_FLOAT(OFS_PARM2); + attenuation = PRVM_G_FLOAT(OFS_PARM3); + +// check to see if samp was properly precached + soundnum = SV_SoundIndex(samp, 1); + if (!soundnum) + return; + + large = false; + if (soundnum >= 256) + large = true; + + // add an svc_spawnambient command to the level signon packet + + if (large) + MSG_WriteByte (&sv.signon, svc_spawnstaticsound2); + else + MSG_WriteByte (&sv.signon, svc_spawnstaticsound); + + MSG_WriteVector(&sv.signon, pos, sv.protocol); + + if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + MSG_WriteShort (&sv.signon, soundnum); + else + MSG_WriteByte (&sv.signon, soundnum); + + MSG_WriteByte (&sv.signon, (int)(vol*255)); + MSG_WriteByte (&sv.signon, (int)(attenuation*64)); + +} + +/* +================= +VM_SV_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 +already running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. + +================= +*/ +static void VM_SV_sound(prvm_prog_t *prog) +{ + const char *sample; + int channel; + prvm_edict_t *entity; + int volume; + int flags; + float attenuation; + float pitchchange; + + VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound); + + entity = PRVM_G_EDICT(OFS_PARM0); + channel = (int)PRVM_G_FLOAT(OFS_PARM1); + sample = PRVM_G_STRING(OFS_PARM2); + volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255); + if (prog->argc < 5) + { + Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n"); + attenuation = 1; + } + else + attenuation = PRVM_G_FLOAT(OFS_PARM4); + if (prog->argc < 6) + pitchchange = 0; + else + pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f; + + if (prog->argc < 7) + { + flags = 0; + if(channel >= 8 && channel <= 15) // weird QW feature + { + flags |= CHANNELFLAG_RELIABLE; + channel -= 8; + } + } + else + { + // LordHavoc: we only let the qc set certain flags, others are off-limits + flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED); + } + + if (volume < 0 || volume > 255) + { + VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n"); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n"); + return; + } + + channel = CHAN_USER2ENGINE(channel); + + if (!IS_CHAN(channel)) + { + VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n"); + return; + } + + SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange); +} + +/* +================= +VM_SV_pointsound + +Follows the same logic as VM_SV_sound, except instead of +an entity, an origin for the sound is provided, and channel +is omitted (since no entity is being tracked). + +================= +*/ +static void VM_SV_pointsound(prvm_prog_t *prog) +{ + const char *sample; + int volume; + float attenuation; + float pitchchange; + vec3_t org; + + VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound); + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + sample = PRVM_G_STRING(OFS_PARM1); + volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255); + attenuation = PRVM_G_FLOAT(OFS_PARM3); + pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f; + + if (volume < 0 || volume > 255) + { + VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n"); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n"); + return; + } + + SV_StartPointSound (org, sample, volume, attenuation, pitchchange); +} + +/* +================= +VM_SV_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, movetype, ignore) +================= +*/ +static void VM_SV_traceline(prvm_prog_t *prog) +{ + vec3_t v1, v2; + trace_t trace; + int move; + prvm_edict_t *ent; + + VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_traceline); // allow more parameters for future expansion + + prog->xfunction->builtinsprofile += 30; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2); + move = (int)PRVM_G_FLOAT(OFS_PARM2); + ent = PRVM_G_EDICT(OFS_PARM3); + + if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2])) + prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); + + trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent)); + + VM_SetTraceGlobals(prog, &trace); +} + + +/* +================= +VM_SV_tracebox + +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. + +tracebox (vector1, vector mins, vector maxs, vector2, tryents) +================= +*/ +// LordHavoc: added this for my own use, VERY useful, similar to traceline +static void VM_SV_tracebox(prvm_prog_t *prog) +{ + vec3_t v1, v2, m1, m2; + trace_t trace; + int move; + prvm_edict_t *ent; + + VM_SAFEPARMCOUNTRANGE(6, 8, VM_SV_tracebox); // allow more parameters for future expansion + + prog->xfunction->builtinsprofile += 30; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2); + move = (int)PRVM_G_FLOAT(OFS_PARM4); + ent = PRVM_G_EDICT(OFS_PARM5); + + if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2])) + prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); + + trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent)); + + VM_SetTraceGlobals(prog, &trace); +} + +static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore) +{ + int i; + float gravity; + vec3_t move, end, tossentorigin, tossentmins, tossentmaxs; + vec3_t original_origin; + vec3_t original_velocity; + vec3_t original_angles; + vec3_t original_avelocity; + trace_t trace; + + VectorCopy(PRVM_serveredictvector(tossent, origin) , original_origin ); + VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity ); + VectorCopy(PRVM_serveredictvector(tossent, angles) , original_angles ); + VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity); + + gravity = PRVM_serveredictfloat(tossent, gravity); + if (!gravity) + gravity = 1.0f; + gravity *= sv_gravity.value * 0.025; + + for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds + { + SV_CheckVelocity (tossent); + PRVM_serveredictvector(tossent, velocity)[2] -= gravity; + VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles)); + VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move); + VectorAdd (PRVM_serveredictvector(tossent, origin), move, end); + VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin); + VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins); + VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs); + trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent)); + VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin)); + PRVM_serveredictvector(tossent, velocity)[2] -= gravity; + + if (trace.fraction < 1) + break; + } + + VectorCopy(original_origin , PRVM_serveredictvector(tossent, origin) ); + VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) ); + VectorCopy(original_angles , PRVM_serveredictvector(tossent, angles) ); + VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity)); + + return trace; +} + +static void VM_SV_tracetoss(prvm_prog_t *prog) +{ + trace_t trace; + prvm_edict_t *ent; + prvm_edict_t *ignore; + + VM_SAFEPARMCOUNT(2, VM_SV_tracetoss); + + prog->xfunction->builtinsprofile += 600; + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning(prog, "tracetoss: can not use world entity\n"); + return; + } + ignore = PRVM_G_EDICT(OFS_PARM1); + + trace = SV_Trace_Toss(prog, ent, ignore); + + VM_SetTraceGlobals(prog, &trace); +} + +//============================================================================ + +static int checkpvsbytes; +static unsigned char checkpvs[MAX_MAP_LEAFS/8]; + +static int VM_SV_newcheckclient(prvm_prog_t *prog, int check) +{ + int i; + prvm_edict_t *ent; + vec3_t org; + +// cycle to the next one + + check = bound(1, check, svs.maxclients); + if (check == svs.maxclients) + i = 1; + else + i = check + 1; + + for ( ; ; i++) + { + // count the cost + prog->xfunction->builtinsprofile++; + // wrap around + if (i == svs.maxclients+1) + i = 1; + // look up the client's edict + ent = PRVM_EDICT_NUM(i); + // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop) + if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET))) + continue; + // found a valid client (possibly the same one again) + break; + } + +// get the PVS for the entity + VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org); + checkpvsbytes = 0; + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false); + + return i; +} + +/* +================= +VM_SV_checkclient + +Returns a client (or object that has a client enemy) that would be a +valid target. + +If there is more than one valid option, 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 () +================= +*/ +int c_invis, c_notvis; +static void VM_SV_checkclient(prvm_prog_t *prog) +{ + prvm_edict_t *ent, *self; + vec3_t view; + + VM_SAFEPARMCOUNT(0, VM_SV_checkclient); + + // find a new check if on a new frame + if (sv.time - sv.lastchecktime >= 0.1) + { + sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck); + sv.lastchecktime = sv.time; + } + + // return check if it might be visible + ent = PRVM_EDICT_NUM(sv.lastcheck); + if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0) + { + VM_RETURN_EDICT(prog->edicts); + return; + } + + // if current entity can't possibly see the check entity, return 0 + self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self)); + VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view); + if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view)) + { + c_notvis++; + VM_RETURN_EDICT(prog->edicts); + return; + } + + // might be able to see it + c_invis++; + VM_RETURN_EDICT(ent); +} + +//============================================================================ + +/* +================= +VM_SV_checkpvs + +Checks if an entity is in a point's PVS. +Should be fast but can be inexact. + +float checkpvs(vector viewpos, entity viewee) = #240; +================= +*/ +static void VM_SV_checkpvs(prvm_prog_t *prog) +{ + vec3_t viewpos, absmin, absmax; + prvm_edict_t *viewee; +#if 1 + unsigned char *pvs; +#else + int fatpvsbytes; + unsigned char fatpvs[MAX_MAP_LEAFS/8]; +#endif + + VM_SAFEPARMCOUNT(2, VM_SV_checkpvs); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos); + viewee = PRVM_G_EDICT(OFS_PARM1); + + if(viewee->priv.server->free) + { + VM_Warning(prog, "checkpvs: can not check free entity\n"); + PRVM_G_FLOAT(OFS_RETURN) = 4; + return; + } + +#if 1 + if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS) + { + // no PVS support on this worldmodel... darn + PRVM_G_FLOAT(OFS_RETURN) = 3; + return; + } + pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos); + if(!pvs) + { + // viewpos isn't in any PVS... darn + PRVM_G_FLOAT(OFS_RETURN) = 2; + return; + } + VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin); + VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax); + PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax); +#else + // using fat PVS like FTEQW does (slow) + if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS) + { + // no PVS support on this worldmodel... darn + PRVM_G_FLOAT(OFS_RETURN) = 3; + return; + } + fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false); + if(!fatpvsbytes) + { + // viewpos isn't in any PVS... darn + PRVM_G_FLOAT(OFS_RETURN) = 2; + return; + } + VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin); + VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax); + PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax); +#endif +} + + +/* +================= +VM_SV_stuffcmd + +Sends text over to the client's execution buffer + +stuffcmd (clientent, value, ...) +================= +*/ +static void VM_SV_stuffcmd(prvm_prog_t *prog) +{ + int entnum; + client_t *old; + char string[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_stuffcmd); + + entnum = PRVM_G_EDICTNUM(OFS_PARM0); + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + { + VM_Warning(prog, "Can't stuffcmd to a non-client\n"); + return; + } + + VM_VarString(prog, 1, string, sizeof(string)); + + old = host_client; + host_client = svs.clients + entnum-1; + Host_ClientCommands ("%s", string); + host_client = old; +} + +/* +================= +VM_SV_findradius + +Returns a chain of entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +static void VM_SV_findradius(prvm_prog_t *prog) +{ + prvm_edict_t *ent, *chain; + vec_t radius, radius2; + vec3_t org, eorg, mins, maxs; + int i; + int numtouchedicts; + static prvm_edict_t *touchedicts[MAX_EDICTS]; + int chainfield; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius); + + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name); + + chain = (prvm_edict_t *)prog->edicts; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + radius = PRVM_G_FLOAT(OFS_PARM1); + radius2 = radius * radius; + + mins[0] = org[0] - (radius + 1); + mins[1] = org[1] - (radius + 1); + mins[2] = org[2] - (radius + 1); + maxs[0] = org[0] + (radius + 1); + maxs[1] = org[1] + (radius + 1); + maxs[2] = org[2] + (radius + 1); + numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts); + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0;i < numtouchedicts;i++) + { + ent = touchedicts[i]; + prog->xfunction->builtinsprofile++; + // Quake did not return non-solid entities but darkplaces does + // (note: this is the reason you can't blow up fallen zombies) + if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer) + continue; + // LordHavoc: compare against bounding box rather than center so it + // doesn't miss large objects, and use DotProduct instead of Length + // for a major speedup + VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg); + if (sv_gameplayfix_findradiusdistancetobox.integer) + { + eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]); + eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]); + eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]); + } + else + VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg); + if (DotProduct(eorg, eorg) < radius2) + { + PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + } + + VM_RETURN_EDICT(chain); +} + +static void VM_SV_precache_sound(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_precache_sound); + PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2); +} + +static void VM_SV_precache_model(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_precache_model); + SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +/* +=============== +VM_SV_walkmove + +float(float yaw, float dist[, settrace]) walkmove +=============== +*/ +static void VM_SV_walkmove(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + float yaw, dist; + vec3_t move; + mfunction_t *oldf; + int oldself; + qboolean settrace; + + VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_walkmove); + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "walkmove: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "walkmove: can not modify free entity\n"); + return; + } + yaw = PRVM_G_FLOAT(OFS_PARM0); + dist = PRVM_G_FLOAT(OFS_PARM1); + settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2); + + if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + return; + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + +// save program state, because SV_movestep may call other progs + oldf = prog->xfunction; + oldself = PRVM_serverglobaledict(self); + + PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace); + + +// restore program state + prog->xfunction = oldf; + PRVM_serverglobaledict(self) = oldself; +} + +/* +=============== +VM_SV_droptofloor + +void() droptofloor +=============== +*/ + +static void VM_SV_droptofloor(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + vec3_t end, entorigin, entmins, entmaxs; + trace_t trace; + + VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "droptofloor: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "droptofloor: can not modify free entity\n"); + return; + } + + VectorCopy (PRVM_serveredictvector(ent, origin), end); + end[2] -= 256; + + if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer) + SV_NudgeOutOfSolid(ent); + + VectorCopy(PRVM_serveredictvector(ent, origin), entorigin); + VectorCopy(PRVM_serveredictvector(ent, mins), entmins); + VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs); + trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); + if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer) + { + vec3_t offset, org; + VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]); + VectorAdd(PRVM_serveredictvector(ent, origin), offset, org); + trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent)); + VectorSubtract(trace.endpos, offset, trace.endpos); + if (trace.startsolid) + { + Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + SV_LinkEdict(ent); + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = 0; + PRVM_G_FLOAT(OFS_RETURN) = 1; + } + else if (trace.fraction < 1) + { + Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]); + VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin)); + if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer) + SV_NudgeOutOfSolid(ent); + SV_LinkEdict(ent); + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_G_FLOAT(OFS_RETURN) = 1; + // if support is destroyed, keep suspended (gross hack for floating items in various maps) + ent->priv.server->suspendedinairflag = true; + } + } + else + { + if (!trace.allsolid && trace.fraction < 1) + { + VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin)); + SV_LinkEdict(ent); + PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND; + PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_G_FLOAT(OFS_RETURN) = 1; + // if support is destroyed, keep suspended (gross hack for floating items in various maps) + ent->priv.server->suspendedinairflag = true; + } + } +} + +/* +=============== +VM_SV_lightstyle + +void(float style, string value) lightstyle +=============== +*/ +static void VM_SV_lightstyle(prvm_prog_t *prog) +{ + int style; + const char *val; + client_t *client; + int j; + + VM_SAFEPARMCOUNT(2, VM_SV_lightstyle); + + style = (int)PRVM_G_FLOAT(OFS_PARM0); + val = PRVM_G_STRING(OFS_PARM1); + + if( (unsigned) style >= MAX_LIGHTSTYLES ) { + prog->error_cmd( "PF_lightstyle: style: %i >= 64", style ); + } + +// change the string in sv + strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style])); + +// send message to all clients on this server + if (sv.state != ss_active) + return; + + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) + { + if (client->active && client->netconnection) + { + MSG_WriteChar (&client->netconnection->message, svc_lightstyle); + MSG_WriteChar (&client->netconnection->message,style); + MSG_WriteString (&client->netconnection->message, val); + } + } +} + +/* +============= +VM_SV_checkbottom +============= +*/ +static void VM_SV_checkbottom(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_checkbottom); + PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0)); +} + +/* +============= +VM_SV_pointcontents +============= +*/ +static void VM_SV_pointcontents(prvm_prog_t *prog) +{ + vec3_t point; + VM_SAFEPARMCOUNT(1, VM_SV_pointcontents); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point); + PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(point)); +} + +/* +============= +VM_SV_aim + +Pick a vector for the player to shoot along +vector aim(entity, missilespeed) +============= +*/ +static void VM_SV_aim(prvm_prog_t *prog) +{ + prvm_edict_t *ent, *check, *bestent; + vec3_t start, dir, end, bestdir; + int i, j; + trace_t tr; + float dist, bestdist; + //float speed; + + VM_SAFEPARMCOUNT(2, VM_SV_aim); + + // assume failure if it returns early + VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN)); + // if sv_aim is so high it can't possibly accept anything, skip out early + if (sv_aim.value >= 1) + return; + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning(prog, "aim: can not use world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "aim: can not use free entity\n"); + return; + } + //speed = PRVM_G_FLOAT(OFS_PARM1); + + VectorCopy (PRVM_serveredictvector(ent, origin), start); + start[2] += 20; + +// try sending a trace straight + VectorCopy (PRVM_serverglobalvector(v_forward), dir); + VectorMA (start, 2048, dir, end); + tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM + && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) ) + { + VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN)); + return; + } + + +// try all possible entities + VectorCopy (dir, bestdir); + bestdist = sv_aim.value; + bestent = NULL; + + check = PRVM_NEXT_EDICT(prog->edicts); + for (i=1 ; inum_edicts ; i++, check = PRVM_NEXT_EDICT(check) ) + { + prog->xfunction->builtinsprofile++; + if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM) + continue; + if (check == ent) + continue; + if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team)) + continue; // don't aim at teammate + for (j=0 ; j<3 ; j++) + end[j] = PRVM_serveredictvector(check, origin)[j] + + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]); + VectorSubtract (end, start, dir); + VectorNormalize (dir); + dist = DotProduct (dir, PRVM_serverglobalvector(v_forward)); + if (dist < bestdist) + continue; // to far to turn + tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY); + if (tr.ent == check) + { // can shoot at this one + bestdist = dist; + bestent = check; + } + } + + if (bestent) + { + VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir); + dist = DotProduct (dir, PRVM_serverglobalvector(v_forward)); + VectorScale (PRVM_serverglobalvector(v_forward), dist, end); + end[2] = dir[2]; + VectorNormalize (end); + VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN)); + } + else + { + VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN)); + } +} + +/* +=============================================================================== + +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 +#define MSG_ENTITY 5 + +static sizebuf_t *WriteDest(prvm_prog_t *prog) +{ + int entnum; + int dest; + prvm_edict_t *ent; + + dest = (int)PRVM_G_FLOAT(OFS_PARM0); + switch (dest) + { + case MSG_BROADCAST: + return &sv.datagram; + + case MSG_ONE: + ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity)); + entnum = PRVM_NUM_FOR_EDICT(ent); + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection) + { + VM_Warning(prog, "WriteDest: tried to write to non-client\n"); + return &sv.reliable_datagram; + } + else + return &svs.clients[entnum-1].netconnection->message; + + default: + VM_Warning(prog, "WriteDest: bad destination\n"); + case MSG_ALL: + return &sv.reliable_datagram; + + case MSG_INIT: + return &sv.signon; + + case MSG_ENTITY: + return sv.writeentitiestoclient_msg; + } + + //return NULL; +} + +static void VM_SV_WriteByte(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteByte); + MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1)); +} + +static void VM_SV_WriteChar(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteChar); + MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1)); +} + +static void VM_SV_WriteShort(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteShort); + MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1)); +} + +static void VM_SV_WriteLong(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteLong); + MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1)); +} + +static void VM_SV_WriteAngle(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle); + MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol); +} + +static void VM_SV_WriteCoord(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord); + MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol); +} + +static void VM_SV_WriteString(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteString); + MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1)); +} + +static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString); + MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1)); +} + + +static void VM_SV_WriteEntity(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity); + MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1)); +} + +// writes a picture as at most size bytes of data +// message: +// IMGNAME \0 SIZE(short) IMGDATA +// if failed to read/compress: +// IMGNAME \0 \0 \0 +//#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE)) +static void VM_SV_WritePicture(prvm_prog_t *prog) +{ + const char *imgname; + void *buf; + size_t size; + + VM_SAFEPARMCOUNT(3, VM_SV_WritePicture); + + imgname = PRVM_G_STRING(OFS_PARM1); + size = (size_t) PRVM_G_FLOAT(OFS_PARM2); + if(size > 65535) + size = 65535; + + MSG_WriteString(WriteDest(prog), imgname); + if(Image_Compress(imgname, size, &buf, &size)) + { + // actual picture + MSG_WriteShort(WriteDest(prog), size); + SZ_Write(WriteDest(prog), (unsigned char *) buf, size); + } + else + { + // placeholder + MSG_WriteShort(WriteDest(prog), 0); + } +} + +////////////////////////////////////////////////////////// + +static void VM_SV_makestatic(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + int i, large; + + // allow 0 parameters due to an id1 qc bug in which this function is used + // with no parameters (but directly after setmodel with self in OFS_PARM0) + VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic); + + if (prog->argc >= 1) + ent = PRVM_G_EDICT(OFS_PARM0); + else + ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self)); + if (ent == prog->edicts) + { + VM_Warning(prog, "makestatic: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "makestatic: can not modify free entity\n"); + return; + } + + large = false; + if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256) + large = true; + + if (large) + { + MSG_WriteByte (&sv.signon,svc_spawnstatic2); + MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex)); + MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame)); + } + else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) + { + MSG_WriteByte (&sv.signon,svc_spawnstatic); + MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex)); + MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame)); + } + else + { + MSG_WriteByte (&sv.signon,svc_spawnstatic); + MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex)); + MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame)); + } + + MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap)); + MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin)); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol); + MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol); + } + +// throw the entity away now + PRVM_ED_Free(prog, ent); +} + +//============================================================================= + +/* +============== +VM_SV_setspawnparms +============== +*/ +static void VM_SV_setspawnparms(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + int i; + client_t *client; + + VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms); + + ent = PRVM_G_EDICT(OFS_PARM0); + i = PRVM_NUM_FOR_EDICT(ent); + if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active) + { + Con_Print("tried to setspawnparms on a non-client\n"); + return; + } + + // copy spawn parms out of the client_t + client = svs.clients + i-1; + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i]; +} + +/* +================= +VM_SV_getlight + +Returns a color vector indicating the lighting at the requested point. + +(Internal Operation note: actually measures the light beneath the point, just like + the model lighting on the client) + +getlight(vector) +================= +*/ +static void VM_SV_getlight(prvm_prog_t *prog) +{ + vec3_t ambientcolor, diffusecolor, diffusenormal; + vec3_t p; + VM_SAFEPARMCOUNT(1, VM_SV_getlight); + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p); + VectorClear(ambientcolor); + VectorClear(diffusecolor); + VectorClear(diffusenormal); + if (sv.worldmodel && sv.worldmodel->brush.LightPoint) + sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal); + VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN)); +} + +typedef struct +{ + unsigned char type; // 1/2/8 or other value if isn't used + int fieldoffset; +}customstat_t; + +static customstat_t *vm_customstats = NULL; //[515]: it starts from 0, not 32 +static int vm_customstats_last; + +void VM_CustomStats_Clear (void) +{ + if(vm_customstats) + { + Z_Free(vm_customstats); + vm_customstats = NULL; + vm_customstats_last = -1; + } +} + +void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + char s[17]; + + if(!vm_customstats) + return; + + for(i=0; i= (MAX_CL_STATS-32)) + { + VM_Warning(prog, "PF_SV_AddStat: index >= MAX_CL_STATS\n"); + return; + } + if(i > (MAX_CL_STATS-32-4) && type == 1) + { + VM_Warning(prog, "PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n"); + return; + } + vm_customstats[i].type = type; + vm_customstats[i].fieldoffset = off; + if(vm_customstats_last < i) + vm_customstats_last = i; +} + +/* +================= +VM_SV_copyentity + +copies data from one entity to another + +copyentity(src, dst) +================= +*/ +static void VM_SV_copyentity(prvm_prog_t *prog) +{ + prvm_edict_t *in, *out; + VM_SAFEPARMCOUNT(2, VM_SV_copyentity); + in = PRVM_G_EDICT(OFS_PARM0); + if (in == prog->edicts) + { + VM_Warning(prog, "copyentity: can not read world entity\n"); + return; + } + if (in->priv.server->free) + { + VM_Warning(prog, "copyentity: can not read free entity\n"); + return; + } + out = PRVM_G_EDICT(OFS_PARM1); + if (out == prog->edicts) + { + VM_Warning(prog, "copyentity: can not modify world entity\n"); + return; + } + if (out->priv.server->free) + { + VM_Warning(prog, "copyentity: can not modify free entity\n"); + return; + } + memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t)); + SV_LinkEdict(out); +} + + +/* +================= +VM_SV_setcolor + +sets the color of a client and broadcasts the update to all connected clients + +setcolor(clientent, value) +================= +*/ +static void VM_SV_setcolor(prvm_prog_t *prog) +{ + client_t *client; + int entnum, i; + + VM_SAFEPARMCOUNT(2, VM_SV_setcolor); + entnum = PRVM_G_EDICTNUM(OFS_PARM0); + i = (int)PRVM_G_FLOAT(OFS_PARM1); + + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + { + Con_Print("tried to setcolor a non-client\n"); + return; + } + + client = svs.clients + entnum-1; + if (client->edict) + { + PRVM_serveredictfloat(client->edict, clientcolors) = i; + PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1; + } + client->colors = i; + if (client->old_colors != client->colors) + { + client->old_colors = client->colors; + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, client - svs.clients); + MSG_WriteByte (&sv.reliable_datagram, client->colors); + } +} + +/* +================= +VM_SV_effect + +effect(origin, modelname, startframe, framecount, framerate) +================= +*/ +static void VM_SV_effect(prvm_prog_t *prog) +{ + int i; + const char *s; + vec3_t org; + VM_SAFEPARMCOUNT(5, VM_SV_effect); + s = PRVM_G_STRING(OFS_PARM1); + if (!s[0]) + { + VM_Warning(prog, "effect: no model specified\n"); + return; + } + + i = SV_ModelIndex(s, 1); + if (!i) + { + VM_Warning(prog, "effect: model not precached\n"); + return; + } + + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + { + VM_Warning(prog, "effect: framecount < 1\n"); + return; + } + + if (PRVM_G_FLOAT(OFS_PARM4) < 1) + { + VM_Warning(prog, "effect: framerate < 1\n"); + return; + } + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4)); +} + +static void VM_SV_te_blood(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_blood); + if (PRVM_G_FLOAT(OFS_PARM2) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_BLOOD); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // velocity + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127)); + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127)); + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127)); + // count + MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_bloodshower(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower); + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER); + // min + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // max + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // speed + MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol); + // count + MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_explosionrgb(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // color + MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255)); + MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255)); + MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_particlecube(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube); + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE); + // min + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // max + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // velocity + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + // count + MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535)); + // color + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4)); + // gravity true/false + MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0); + // randomvel + MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_particlerain(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain); + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN); + // min + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // max + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // velocity + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + // count + MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535)); + // color + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_particlesnow(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow); + if (PRVM_G_FLOAT(OFS_PARM3) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW); + // min + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // max + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // velocity + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + // count + MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535)); + // color + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_spark(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_spark); + if (PRVM_G_FLOAT(OFS_PARM2) < 1) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SPARK); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // velocity + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127)); + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127)); + MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127)); + // count + MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_gunshotquad(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_spikequad(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_superspikequad(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_explosionquad(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_smallflash(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SMALLFLASH); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_customflash(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(4, VM_SV_te_customflash); + if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0)) + return; + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // radius + MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255)); + // lifetime + MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255)); + // color + MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255)); + MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255)); + MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_gunshot(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_GUNSHOT); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_spike(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_spike); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SPIKE); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_superspike(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_superspike); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_explosion(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_explosion); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_EXPLOSION); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_tarexplosion(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_wizspike(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_WIZSPIKE); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_knightspike(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_lavasplash(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_LAVASPLASH); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_teleport(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_teleport); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_TELEPORT); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_explosion2(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_EXPLOSION2); + // origin + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // color + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1)); + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2)); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_lightning1(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_LIGHTNING1); + // owner entity + MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0)); + // start + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // end + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_lightning2(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_LIGHTNING2); + // owner entity + MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0)); + // start + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // end + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_lightning3(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_LIGHTNING3); + // owner entity + MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0)); + // start + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // end + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_beam(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_beam); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_BEAM); + // owner entity + MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0)); + // start + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // end + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_plasmaburn(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_PLASMABURN); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + SV_FlushBroadcastMessages(); +} + +static void VM_SV_te_flamejet(prvm_prog_t *prog) +{ + VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet); + MSG_WriteByte(&sv.datagram, svc_temp_entity); + MSG_WriteByte(&sv.datagram, TE_FLAMEJET); + // org + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol); + // vel + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol); + MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol); + // count + MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2)); + SV_FlushBroadcastMessages(); +} + +//void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client +//this function originally written by KrimZon, made shorter by LordHavoc +static void VM_SV_clientcommand(prvm_prog_t *prog) +{ + client_t *temp_client; + int i; + VM_SAFEPARMCOUNT(2, VM_SV_clientcommand); + + //find client for this entity + i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1); + if (i < 0 || i >= svs.maxclients || !svs.clients[i].active) + { + Con_Print("PF_clientcommand: entity is not a client\n"); + return; + } + + temp_client = host_client; + host_client = svs.clients + i; + Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true); + host_client = temp_client; +} + +//void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag) +static void VM_SV_setattachment(prvm_prog_t *prog) +{ + prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0); + prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1); + const char *tagname = PRVM_G_STRING(OFS_PARM2); + dp_model_t *model; + int tagindex; + VM_SAFEPARMCOUNT(3, VM_SV_setattachment); + + if (e == prog->edicts) + { + VM_Warning(prog, "setattachment: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setattachment: can not modify free entity\n"); + return; + } + + if (tagentity == NULL) + tagentity = prog->edicts; + + tagindex = 0; + + if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) + { + model = SV_GetModelFromEdict(tagentity); + if (model) + { + tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname); + if (tagindex == 0) + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name); + } + else + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); + } + + PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity); + PRVM_serveredictfloat(e, tag_index) = tagindex; +} + +///////////////////////////////////////// +// DP_MD3_TAGINFO extension coded by VorteX + +static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname) +{ + int i; + + i = (int)PRVM_serveredictfloat(e, modelindex); + if (i < 1 || i >= MAX_MODELS) + return -1; + + return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname); +} + +static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix) +{ + int r; + dp_model_t *model; + + *tagname = NULL; + *parentindex = 0; + Matrix4x4_CreateIdentity(tag_localmatrix); + + if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones) + { + r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix); + + if(!r) // success? + *parentindex += 1; + + return r; + } + + return 1; +} + +void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix) +{ + float scale; + float pitchsign = 1; + + scale = PRVM_serveredictfloat(ent, scale); + if (!scale) + scale = 1.0f; + + if (viewmatrix) + Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2], PRVM_serveredictvector(ent, v_angle)[0], PRVM_serveredictvector(ent, v_angle)[1], PRVM_serveredictvector(ent, v_angle)[2], scale * cl_viewmodel_scale.value); + else + { + pitchsign = SV_GetPitchSign(prog, ent); + Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], pitchsign * PRVM_serveredictvector(ent, angles)[0], PRVM_serveredictvector(ent, angles)[1], PRVM_serveredictvector(ent, angles)[2], scale); + } +} + +static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out) +{ + dp_model_t *model; + if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes) + { + VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent); + VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend); + return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out); + } + *out = identitymatrix; + return 0; +} + +// Warnings/errors code: +// 0 - normal (everything all-right) +// 1 - world entity +// 2 - free entity +// 3 - null or non-precached model +// 4 - no tags with requested index +// 5 - runaway loop at attachment chain +extern cvar_t cl_bob; +extern cvar_t cl_bobcycle; +extern cvar_t cl_bobup; +static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex) +{ + int ret; + int modelindex, attachloop; + matrix4x4_t entitymatrix, tagmatrix, attachmatrix; + dp_model_t *model; + + *out = identitymatrix; // warnings and errors return identical matrix + + if (ent == prog->edicts) + return 1; + if (ent->priv.server->free) + return 2; + + modelindex = (int)PRVM_serveredictfloat(ent, modelindex); + if (modelindex <= 0 || modelindex >= MAX_MODELS) + return 3; + + model = SV_GetModelByIndex(modelindex); + + VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent); + VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend); + + tagmatrix = identitymatrix; + // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity + attachloop = 0; + for (;;) + { + if (attachloop >= 256) // prevent runaway looping + return 5; + // apply transformation by child's tagindex on parent entity and then + // by parent entity itself + ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix); + if (ret && attachloop == 0) + return ret; + SV_GetEntityMatrix(prog, ent, &entitymatrix, false); + Matrix4x4_Concat(&tagmatrix, &attachmatrix, out); + Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); + // next iteration we process the parent entity + if (PRVM_serveredictedict(ent, tag_entity)) + { + tagindex = (int)PRVM_serveredictfloat(ent, tag_index); + ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity)); + } + else + break; + attachloop++; + } + + // RENDER_VIEWMODEL magic + if (PRVM_serveredictedict(ent, viewmodelforclient)) + { + Matrix4x4_Copy(&tagmatrix, out); + ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient)); + + SV_GetEntityMatrix(prog, ent, &entitymatrix, true); + Matrix4x4_Concat(out, &entitymatrix, &tagmatrix); + + /* + // Cl_bob, ported from rendering code + if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value) + { + double bob, cycle; + // LordHavoc: this code is *weird*, but not replacable (I think it + // should be done in QC on the server, but oh well, quake is quake) + // LordHavoc: figured out bobup: the time at which the sin is at 180 + // degrees (which allows lengthening or squishing the peak or valley) + cycle = sv.time/cl_bobcycle.value; + cycle -= (int)cycle; + if (cycle < cl_bobup.value) + cycle = sin(M_PI * cycle / cl_bobup.value); + else + cycle = sin(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 = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value; + bob = bob*0.3 + bob*0.7*cycle; + Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4)); + } + */ + } + return 0; +} + +//float(entity ent, string tagname) gettagindex; + +static void VM_SV_gettagindex(prvm_prog_t *prog) +{ + prvm_edict_t *ent; + const char *tag_name; + int tag_index; + + VM_SAFEPARMCOUNT(2, VM_SV_gettagindex); + + ent = PRVM_G_EDICT(OFS_PARM0); + tag_name = PRVM_G_STRING(OFS_PARM1); + + if (ent == prog->edicts) + { + VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent)); + return; + } + if (ent->priv.server->free) + { + VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent)); + return; + } + + tag_index = 0; + if (!SV_GetModelFromEdict(ent)) + Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent)); + else + { + tag_index = SV_GetTagIndex(prog, ent, tag_name); + if (tag_index == 0) + if(developer_extra.integer) + Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name); + } + PRVM_G_FLOAT(OFS_RETURN) = tag_index; +} + +//vector(entity ent, float tagindex) gettaginfo; +static void VM_SV_gettaginfo(prvm_prog_t *prog) +{ + prvm_edict_t *e; + int tagindex; + matrix4x4_t tag_matrix; + matrix4x4_t tag_localmatrix; + int parentindex; + const char *tagname; + int returncode; + vec3_t forward, left, up, origin; + const dp_model_t *model; + + VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo); + + e = PRVM_G_EDICT(OFS_PARM0); + tagindex = (int)PRVM_G_FLOAT(OFS_PARM1); + + returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex); + Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_serverglobalvector(v_forward)); + VectorNegate(left, PRVM_serverglobalvector(v_right)); + VectorCopy(up, PRVM_serverglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); + model = SV_GetModelFromEdict(e); + VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e); + VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time); + VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend); + SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix); + Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin); + + PRVM_serverglobalfloat(gettaginfo_parent) = parentindex; + PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0; + VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward)); + VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right)); + VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up)); + VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset)); + + switch(returncode) + { + case 1: + VM_Warning(prog, "gettagindex: can't affect world entity\n"); + break; + case 2: + VM_Warning(prog, "gettagindex: can't affect free entity\n"); + break; + case 3: + Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e)); + break; + case 4: + Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex); + break; + case 5: + Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e)); + break; + } +} + +//void(entity clent) dropclient (DP_SV_DROPCLIENT) +static void VM_SV_dropclient(prvm_prog_t *prog) +{ + int clientnum; + client_t *oldhostclient; + VM_SAFEPARMCOUNT(1, VM_SV_dropclient); + clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1; + if (clientnum < 0 || clientnum >= svs.maxclients) + { + VM_Warning(prog, "dropclient: not a client\n"); + return; + } + if (!svs.clients[clientnum].active) + { + VM_Warning(prog, "dropclient: that client slot is not connected\n"); + return; + } + oldhostclient = host_client; + host_client = svs.clients + clientnum; + SV_DropClient(false); + host_client = oldhostclient; +} + +//entity() spawnclient (DP_SV_BOTCLIENT) +static void VM_SV_spawnclient(prvm_prog_t *prog) +{ + int i; + prvm_edict_t *ed; + VM_SAFEPARMCOUNT(0, VM_SV_spawnclient); + prog->xfunction->builtinsprofile += 2; + ed = prog->edicts; + for (i = 0;i < svs.maxclients;i++) + { + if (!svs.clients[i].active) + { + prog->xfunction->builtinsprofile += 100; + SV_ConnectClient (i, NULL); + // this has to be set or else ClientDisconnect won't be called + // we assume the qc will call ClientConnect... + svs.clients[i].clientconnectcalled = true; + ed = PRVM_EDICT_NUM(i + 1); + break; + } + } + VM_RETURN_EDICT(ed); +} + +//float(entity clent) clienttype (DP_SV_BOTCLIENT) +static void VM_SV_clienttype(prvm_prog_t *prog) +{ + int clientnum; + VM_SAFEPARMCOUNT(1, VM_SV_clienttype); + clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1; + if (clientnum < 0 || clientnum >= svs.maxclients) + PRVM_G_FLOAT(OFS_RETURN) = 3; + else if (!svs.clients[clientnum].active) + PRVM_G_FLOAT(OFS_RETURN) = 0; + else if (svs.clients[clientnum].netconnection) + PRVM_G_FLOAT(OFS_RETURN) = 1; + else + PRVM_G_FLOAT(OFS_RETURN) = 2; +} + +/* +=============== +VM_SV_serverkey + +string(string key) serverkey +=============== +*/ +static void VM_SV_serverkey(prvm_prog_t *prog) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNT(1, VM_SV_serverkey); + InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string); +} + +//#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) +static void VM_SV_setmodelindex(prvm_prog_t *prog) +{ + prvm_edict_t *e; + dp_model_t *mod; + int i; + VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex); + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning(prog, "setmodelindex: can not modify world entity\n"); + return; + } + if (e->priv.server->free) + { + VM_Warning(prog, "setmodelindex: can not modify free entity\n"); + return; + } + i = (int)PRVM_G_FLOAT(OFS_PARM1); + if (i <= 0 || i >= MAX_MODELS) + { + VM_Warning(prog, "setmodelindex: invalid modelindex\n"); + return; + } + if (!sv.model_precache[i][0]) + { + VM_Warning(prog, "setmodelindex: model not precached\n"); + return; + } + + PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]); + PRVM_serveredictfloat(e, modelindex) = i; + + mod = SV_GetModelByIndex(i); + + if (mod) + { + if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer) + SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true); + else + SetMinMaxSize(prog, e, quakemins, quakemaxs, true); + } + else + SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true); +} + +//#334 string(float mdlindex) modelnameforindex (EXT_CSQC) +static void VM_SV_modelnameforindex(prvm_prog_t *prog) +{ + int i; + VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex); + + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + + i = (int)PRVM_G_FLOAT(OFS_PARM0); + if (i <= 0 || i >= MAX_MODELS) + { + VM_Warning(prog, "modelnameforindex: invalid modelindex\n"); + return; + } + if (!sv.model_precache[i][0]) + { + VM_Warning(prog, "modelnameforindex: model not precached\n"); + return; + } + + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]); +} + +//#335 float(string effectname) particleeffectnum (EXT_CSQC) +static void VM_SV_particleeffectnum(prvm_prog_t *prog) +{ + int i; + VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum); + i = SV_ParticleEffectIndex(PRVM_G_STRING(OFS_PARM0)); + if (i == 0) + i = -1; + PRVM_G_FLOAT(OFS_RETURN) = i; +} + +// #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC) +static void VM_SV_trailparticles(prvm_prog_t *prog) +{ + vec3_t start, end; + VM_SAFEPARMCOUNT(4, VM_SV_trailparticles); + + if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0) + return; + + MSG_WriteByte(&sv.datagram, svc_trailparticles); + MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0)); + MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1)); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start); + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end); + MSG_WriteVector(&sv.datagram, start, sv.protocol); + MSG_WriteVector(&sv.datagram, end, sv.protocol); + SV_FlushBroadcastMessages(); +} + +//#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC) +static void VM_SV_pointparticles(prvm_prog_t *prog) +{ + int effectnum, count; + vec3_t org, vel; + VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles); + + if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0) + return; + + effectnum = (int)PRVM_G_FLOAT(OFS_PARM0); + VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel); + count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535); + if (count == 1 && !VectorLength2(vel)) + { + // 1+2+12=15 bytes + MSG_WriteByte(&sv.datagram, svc_pointparticles1); + MSG_WriteShort(&sv.datagram, effectnum); + MSG_WriteVector(&sv.datagram, org, sv.protocol); + } + else + { + // 1+2+12+12+2=29 bytes + MSG_WriteByte(&sv.datagram, svc_pointparticles); + MSG_WriteShort(&sv.datagram, effectnum); + MSG_WriteVector(&sv.datagram, org, sv.protocol); + MSG_WriteVector(&sv.datagram, vel, sv.protocol); + MSG_WriteShort(&sv.datagram, count); + } + + SV_FlushBroadcastMessages(); +} + +//PF_setpause, // void(float pause) setpause = #531; +static void VM_SV_setpause(prvm_prog_t *prog) { + int pauseValue; + pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0); + if (pauseValue != 0) { //pause the game + sv.paused = 1; + sv.pausedstart = realtime; + } else { //disable pause, in case it was enabled + if (sv.paused != 0) { + sv.paused = 0; + sv.pausedstart = 0; + } + } + // send notification to all clients + MSG_WriteByte(&sv.reliable_datagram, svc_setpause); + MSG_WriteByte(&sv.reliable_datagram, sv.paused); +} + +// #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex. +static void VM_SV_skel_create(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = SV_GetModelByIndex(modelindex); + skeleton_t *skeleton; + int i; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (!model || !model->num_bones) + return; + for (i = 0;i < MAX_EDICTS;i++) + if (!prog->skeletons[i]) + break; + if (i == MAX_EDICTS) + return; + prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t)); + PRVM_G_FLOAT(OFS_RETURN) = i + 1; + skeleton->model = model; + skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1); + // initialize to identity matrices + for (i = 0;i < skeleton->model->num_bones;i++) + skeleton->relativetransforms[i] = identitymatrix; +} + +// #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure +static void VM_SV_skel_build(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1); + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2); + float retainfrac = PRVM_G_FLOAT(OFS_PARM3); + int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1; + dp_model_t *model = SV_GetModelByIndex(modelindex); + int numblends; + int bonenum; + int blendindex; + framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS]; + frameblend_t frameblend[MAX_FRAMEBLENDS]; + matrix4x4_t bonematrix; + matrix4x4_t matrix; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + firstbone = max(0, firstbone); + lastbone = min(lastbone, model->num_bones - 1); + lastbone = min(lastbone, skeleton->model->num_bones - 1); + VM_GenerateFrameGroupBlend(prog, framegroupblend, ed); + VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time); + for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++) + ; + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + { + memset(&bonematrix, 0, sizeof(bonematrix)); + for (blendindex = 0;blendindex < numblends;blendindex++) + { + Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum)); + Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp); + } + Matrix4x4_Normalize3(&bonematrix, &bonematrix); + Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac); + } + PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1; +} + +// #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton +static void VM_SV_skel_get_numbones(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones; +} + +// #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring) +static void VM_SV_skel_get_bonename(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + PRVM_G_INT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name); +} + +// #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +static void VM_SV_skel_get_boneparent(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1; +} + +// #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex +static void VM_SV_skel_find_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + const char *tagname = PRVM_G_STRING(OFS_PARM1); + skeleton_t *skeleton; + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1; +} + +// #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) +static void VM_SV_skel_get_bonerel(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + matrix4x4_t matrix; + vec3_t forward, left, up, origin; + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + VectorClear(PRVM_clientglobalvector(v_forward)); + VectorClear(PRVM_clientglobalvector(v_right)); + VectorClear(PRVM_clientglobalvector(v_up)); + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + matrix = skeleton->relativetransforms[bonenum]; + Matrix4x4_ToVectors(&matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorNegate(left, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); +} + +// #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) +static void VM_SV_skel_get_boneabs(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + vec3_t forward, left, up, origin; + VectorClear(PRVM_G_VECTOR(OFS_RETURN)); + VectorClear(PRVM_clientglobalvector(v_forward)); + VectorClear(PRVM_clientglobalvector(v_right)); + VectorClear(PRVM_clientglobalvector(v_up)); + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + matrix = skeleton->relativetransforms[bonenum]; + // convert to absolute + while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0) + { + temp = matrix; + Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp); + } + Matrix4x4_ToVectors(&matrix, forward, left, up, origin); + VectorCopy(forward, PRVM_clientglobalvector(v_forward)); + VectorNegate(left, PRVM_clientglobalvector(v_right)); + VectorCopy(up, PRVM_clientglobalvector(v_up)); + VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN)); +} + +// #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +static void VM_SV_skel_set_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + skeleton->relativetransforms[bonenum] = matrix; +} + +// #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +static void VM_SV_skel_mul_bone(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + if (bonenum < 0 || bonenum >= skeleton->model->num_bones) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin); + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + temp = skeleton->relativetransforms[bonenum]; + Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp); +} + +// #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) +static void VM_SV_skel_mul_bones(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1; + int bonenum; + vec3_t forward, left, up, origin; + skeleton_t *skeleton; + matrix4x4_t matrix; + matrix4x4_t temp; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin); + VectorCopy(PRVM_clientglobalvector(v_forward), forward); + VectorNegate(PRVM_clientglobalvector(v_right), left); + VectorCopy(PRVM_clientglobalvector(v_up), up); + Matrix4x4_FromVectors(&matrix, forward, left, up, origin); + firstbone = max(0, firstbone); + lastbone = min(lastbone, skeleton->model->num_bones - 1); + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + { + temp = skeleton->relativetransforms[bonenum]; + Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp); + } +} + +// #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse +static void VM_SV_skel_copybones(prvm_prog_t *prog) +{ + int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1; + int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1; + int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1; + int bonenum; + skeleton_t *skeletondst; + skeleton_t *skeletonsrc; + if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst])) + return; + if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc])) + return; + firstbone = max(0, firstbone); + lastbone = min(lastbone, skeletondst->model->num_bones - 1); + lastbone = min(lastbone, skeletonsrc->model->num_bones - 1); + for (bonenum = firstbone;bonenum <= lastbone;bonenum++) + skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum]; +} + +// #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) +static void VM_SV_skel_delete(prvm_prog_t *prog) +{ + int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1; + skeleton_t *skeleton; + if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex])) + return; + Mem_Free(skeleton); + prog->skeletons[skeletonindex] = NULL; +} + +// #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found +static void VM_SV_frameforname(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = SV_GetModelByIndex(modelindex); + const char *name = PRVM_G_STRING(OFS_PARM1); + int i; + PRVM_G_FLOAT(OFS_RETURN) = -1; + if (!model || !model->animscenes) + return; + for (i = 0;i < model->numframes;i++) + { + if (!strcasecmp(model->animscenes[i].name, name)) + { + PRVM_G_FLOAT(OFS_RETURN) = i; + break; + } + } +} + +// #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. +static void VM_SV_frameduration(prvm_prog_t *prog) +{ + int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0); + dp_model_t *model = SV_GetModelByIndex(modelindex); + int framenum = (int)PRVM_G_FLOAT(OFS_PARM1); + PRVM_G_FLOAT(OFS_RETURN) = 0; + if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes) + return; + if (model->animscenes[framenum].framerate) + PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate; +} + + +prvm_builtin_t vm_sv_builtins[] = { +NULL, // #0 NULL function (not callable) (QUAKE) +VM_makevectors, // #1 void(vector ang) makevectors (QUAKE) +VM_SV_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE) +VM_SV_setmodel, // #3 void(entity e, string m) setmodel (QUAKE) +VM_SV_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE) +NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE) +VM_break, // #6 void() break (QUAKE) +VM_random, // #7 float() random (QUAKE) +VM_SV_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE) +VM_normalize, // #9 vector(vector v) normalize (QUAKE) +VM_error, // #10 void(string e) error (QUAKE) +VM_objerror, // #11 void(string e) objerror (QUAKE) +VM_vlen, // #12 float(vector v) vlen (QUAKE) +VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE) +VM_spawn, // #14 entity() spawn (QUAKE) +VM_remove, // #15 void(entity e) remove (QUAKE) +VM_SV_traceline, // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE) +VM_SV_checkclient, // #17 entity() checkclient (QUAKE) +VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE) +VM_SV_precache_sound, // #19 void(string s) precache_sound (QUAKE) +VM_SV_precache_model, // #20 void(string s) precache_model (QUAKE) +VM_SV_stuffcmd, // #21 void(entity client, string s, ...) stuffcmd (QUAKE) +VM_SV_findradius, // #22 entity(vector org, float rad) findradius (QUAKE) +VM_bprint, // #23 void(string s, ...) bprint (QUAKE) +VM_SV_sprint, // #24 void(entity client, string s, ...) sprint (QUAKE) +VM_dprint, // #25 void(string s, ...) dprint (QUAKE) +VM_ftos, // #26 string(float f) ftos (QUAKE) +VM_vtos, // #27 string(vector v) vtos (QUAKE) +VM_coredump, // #28 void() coredump (QUAKE) +VM_traceon, // #29 void() traceon (QUAKE) +VM_traceoff, // #30 void() traceoff (QUAKE) +VM_eprint, // #31 void(entity e) eprint (QUAKE) +VM_SV_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE) +NULL, // #33 (QUAKE) +VM_SV_droptofloor, // #34 float() droptofloor (QUAKE) +VM_SV_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE) +VM_rint, // #36 float(float v) rint (QUAKE) +VM_floor, // #37 float(float v) floor (QUAKE) +VM_ceil, // #38 float(float v) ceil (QUAKE) +NULL, // #39 (QUAKE) +VM_SV_checkbottom, // #40 float(entity e) checkbottom (QUAKE) +VM_SV_pointcontents, // #41 float(vector v) pointcontents (QUAKE) +NULL, // #42 (QUAKE) +VM_fabs, // #43 float(float f) fabs (QUAKE) +VM_SV_aim, // #44 vector(entity e, float speed) aim (QUAKE) +VM_cvar, // #45 float(string s) cvar (QUAKE) +VM_localcmd, // #46 void(string s) localcmd (QUAKE) +VM_nextent, // #47 entity(entity e) nextent (QUAKE) +VM_SV_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE) +VM_changeyaw, // #49 void() ChangeYaw (QUAKE) +NULL, // #50 (QUAKE) +VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE) +VM_SV_WriteByte, // #52 void(float to, float f) WriteByte (QUAKE) +VM_SV_WriteChar, // #53 void(float to, float f) WriteChar (QUAKE) +VM_SV_WriteShort, // #54 void(float to, float f) WriteShort (QUAKE) +VM_SV_WriteLong, // #55 void(float to, float f) WriteLong (QUAKE) +VM_SV_WriteCoord, // #56 void(float to, float f) WriteCoord (QUAKE) +VM_SV_WriteAngle, // #57 void(float to, float f) WriteAngle (QUAKE) +VM_SV_WriteString, // #58 void(float to, string s) WriteString (QUAKE) +VM_SV_WriteEntity, // #59 void(float to, entity e) WriteEntity (QUAKE) +VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW) (QUAKE) +VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW) (QUAKE) +VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) (QUAKE) +VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUAKE) +VM_SV_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE) +VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE) +NULL, // #66 (QUAKE) +VM_SV_MoveToGoal, // #67 void(float step) movetogoal (QUAKE) +VM_precache_file, // #68 string(string s) precache_file (QUAKE) +VM_SV_makestatic, // #69 void(entity e) makestatic (QUAKE) +VM_changelevel, // #70 void(string s) changelevel (QUAKE) +NULL, // #71 (QUAKE) +VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE) +VM_SV_centerprint, // #73 void(entity client, strings) centerprint (QUAKE) +VM_SV_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE) +VM_SV_precache_model, // #75 string(string s) precache_model2 (QUAKE) +VM_SV_precache_sound, // #76 string(string s) precache_sound2 (QUAKE) +VM_precache_file, // #77 string(string s) precache_file2 (QUAKE) +VM_SV_setspawnparms, // #78 void(entity e) setspawnparms (QUAKE) +NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD) +NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD) +VM_stof, // #81 float(string s) stof (FRIK_FILE) +NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD) +NULL, // #83 (QUAKE) +NULL, // #84 (QUAKE) +NULL, // #85 (QUAKE) +NULL, // #86 (QUAKE) +NULL, // #87 (QUAKE) +NULL, // #88 (QUAKE) +NULL, // #89 (QUAKE) +VM_SV_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX) +VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC) +VM_SV_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT) +VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR) +VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND) +VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND) +VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND) +VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW) +VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT) +VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system) +// FrikaC and Telejano range #100-#199 +NULL, // #100 +NULL, // #101 +NULL, // #102 +NULL, // #103 +NULL, // #104 +NULL, // #105 +NULL, // #106 +NULL, // #107 +NULL, // #108 +NULL, // #109 +VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE) +VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE) +VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE) +VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE) +VM_strlen, // #114 float(string s) strlen (FRIK_FILE) +VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE) +VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE) +VM_stov, // #117 vector(string) stov (FRIK_FILE) +VM_strzone, // #118 string(string s) strzone (FRIK_FILE) +VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE) +NULL, // #120 +NULL, // #121 +NULL, // #122 +NULL, // #123 +NULL, // #124 +NULL, // #125 +NULL, // #126 +NULL, // #127 +NULL, // #128 +NULL, // #129 +NULL, // #130 +NULL, // #131 +NULL, // #132 +NULL, // #133 +NULL, // #134 +NULL, // #135 +NULL, // #136 +NULL, // #137 +NULL, // #138 +NULL, // #139 +NULL, // #140 +NULL, // #141 +NULL, // #142 +NULL, // #143 +NULL, // #144 +NULL, // #145 +NULL, // #146 +NULL, // #147 +NULL, // #148 +NULL, // #149 +NULL, // #150 +NULL, // #151 +NULL, // #152 +NULL, // #153 +NULL, // #154 +NULL, // #155 +NULL, // #156 +NULL, // #157 +NULL, // #158 +NULL, // #159 +NULL, // #160 +NULL, // #161 +NULL, // #162 +NULL, // #163 +NULL, // #164 +NULL, // #165 +NULL, // #166 +NULL, // #167 +NULL, // #168 +NULL, // #169 +NULL, // #170 +NULL, // #171 +NULL, // #172 +NULL, // #173 +NULL, // #174 +NULL, // #175 +NULL, // #176 +NULL, // #177 +NULL, // #178 +NULL, // #179 +NULL, // #180 +NULL, // #181 +NULL, // #182 +NULL, // #183 +NULL, // #184 +NULL, // #185 +NULL, // #186 +NULL, // #187 +NULL, // #188 +NULL, // #189 +NULL, // #190 +NULL, // #191 +NULL, // #192 +NULL, // #193 +NULL, // #194 +NULL, // #195 +NULL, // #196 +NULL, // #197 +NULL, // #198 +NULL, // #199 +// FTEQW range #200-#299 +NULL, // #200 +NULL, // #201 +NULL, // #202 +NULL, // #203 +NULL, // #204 +NULL, // #205 +NULL, // #206 +NULL, // #207 +NULL, // #208 +NULL, // #209 +NULL, // #210 +NULL, // #211 +NULL, // #212 +NULL, // #213 +NULL, // #214 +NULL, // #215 +NULL, // #216 +NULL, // #217 +VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT) +NULL, // #219 +NULL, // #220 +VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS) +VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS) +VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS) +VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS) +VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS) +VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS) +VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS) +VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) +VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +NULL, // #231 +VM_SV_AddStat, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC) +NULL, // #233 +NULL, // #234 +NULL, // #235 +NULL, // #236 +NULL, // #237 +NULL, // #238 +NULL, // #239 +VM_SV_checkpvs, // #240 float(vector viewpos, entity viewee) checkpvs; +NULL, // #241 +NULL, // #242 +NULL, // #243 +NULL, // #244 +NULL, // #245 +NULL, // #246 +NULL, // #247 +NULL, // #248 +NULL, // #249 +NULL, // #250 +NULL, // #251 +NULL, // #252 +NULL, // #253 +NULL, // #254 +NULL, // #255 +NULL, // #256 +NULL, // #257 +NULL, // #258 +NULL, // #259 +NULL, // #260 +NULL, // #261 +NULL, // #262 +VM_SV_skel_create, // #263 float(float modlindex) skel_create = #263; // (DP_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex. +VM_SV_skel_build, // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (DP_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure +VM_SV_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton +VM_SV_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring) +VM_SV_skel_get_boneparent, // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (DP_SKELETONOBJECTS) returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +VM_SV_skel_find_bone, // #268 float(float skel, string tagname) skel_find_bone = #268; // (DP_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex +VM_SV_skel_get_bonerel, // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (DP_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) +VM_SV_skel_get_boneabs, // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (DP_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) +VM_SV_skel_set_bone, // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (DP_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +VM_SV_skel_mul_bone, // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (DP_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) +VM_SV_skel_mul_bones, // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (DP_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) +VM_SV_skel_copybones, // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (DP_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse +VM_SV_skel_delete, // #275 void(float skel) skel_delete = #275; // (DP_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) +VM_SV_frameforname, // #276 float(float modlindex, string framename) frameforname = #276; // (DP_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found +VM_SV_frameduration, // #277 float(float modlindex, float framenum) frameduration = #277; // (DP_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. +NULL, // #278 +NULL, // #279 +NULL, // #280 +NULL, // #281 +NULL, // #282 +NULL, // #283 +NULL, // #284 +NULL, // #285 +NULL, // #286 +NULL, // #287 +NULL, // #288 +NULL, // #289 +NULL, // #290 +NULL, // #291 +NULL, // #292 +NULL, // #293 +NULL, // #294 +NULL, // #295 +NULL, // #296 +NULL, // #297 +NULL, // #298 +NULL, // #299 +// CSQC range #300-#399 +NULL, // #300 void() clearscene (EXT_CSQC) +NULL, // #301 void(float mask) addentities (EXT_CSQC) +NULL, // #302 void(entity ent) addentity (EXT_CSQC) +NULL, // #303 float(float property, ...) setproperty (EXT_CSQC) +NULL, // #304 void() renderscene (EXT_CSQC) +NULL, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC) +NULL, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon +NULL, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex +NULL, // #308 void() R_EndPolygon +NULL, // #309 +NULL, // #310 vector (vector v) cs_unproject (EXT_CSQC) +NULL, // #311 vector (vector v) cs_project (EXT_CSQC) +NULL, // #312 +NULL, // #313 +NULL, // #314 +NULL, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC) +NULL, // #316 float(string name) iscachedpic (EXT_CSQC) +NULL, // #317 string(string name, float trywad) precache_pic (EXT_CSQC) +NULL, // #318 vector(string picname) draw_getimagesize (EXT_CSQC) +NULL, // #319 void(string name) freepic (EXT_CSQC) +NULL, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC) +NULL, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC) +NULL, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC) +NULL, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC) +NULL, // #324 void(float x, float y, float width, float height) drawsetcliparea +NULL, // #325 void(void) drawresetcliparea +NULL, // #326 +NULL, // #327 +NULL, // #328 +NULL, // #329 +NULL, // #330 float(float stnum) getstatf (EXT_CSQC) +NULL, // #331 float(float stnum) getstati (EXT_CSQC) +NULL, // #332 string(float firststnum) getstats (EXT_CSQC) +VM_SV_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC) +VM_SV_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC) +VM_SV_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC) +VM_SV_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC) +VM_SV_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC) +NULL, // #338 void(string s, ...) centerprint (EXT_CSQC) +VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT) +NULL, // #340 string(float keynum) keynumtostring (EXT_CSQC) +NULL, // #341 float(string keyname) stringtokeynum (EXT_CSQC) +NULL, // #342 string(float keynum) getkeybind (EXT_CSQC) +NULL, // #343 void(float usecursor) setcursormode (EXT_CSQC) +NULL, // #344 vector() getmousepos (EXT_CSQC) +NULL, // #345 float(float framenum) getinputstate (EXT_CSQC) +NULL, // #346 void(float sens) setsensitivityscaler (EXT_CSQC) +NULL, // #347 void() runstandardplayerphysics (EXT_CSQC) +NULL, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC) +NULL, // #349 float() isdemo (EXT_CSQC) +VM_isserver, // #350 float() isserver (EXT_CSQC) +NULL, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC) +NULL, // #352 void(string cmdname) registercommand (EXT_CSQC) +VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too) +VM_SV_serverkey, // #354 string(string key) serverkey (EXT_CSQC) +NULL, // #355 +NULL, // #356 +NULL, // #357 +NULL, // #358 +NULL, // #359 +NULL, // #360 float() readbyte (EXT_CSQC) +NULL, // #361 float() readchar (EXT_CSQC) +NULL, // #362 float() readshort (EXT_CSQC) +NULL, // #363 float() readlong (EXT_CSQC) +NULL, // #364 float() readcoord (EXT_CSQC) +NULL, // #365 float() readangle (EXT_CSQC) +NULL, // #366 string() readstring (EXT_CSQC) +NULL, // #367 float() readfloat (EXT_CSQC) +NULL, // #368 +NULL, // #369 +NULL, // #370 +NULL, // #371 +NULL, // #372 +NULL, // #373 +NULL, // #374 +NULL, // #375 +NULL, // #376 +NULL, // #377 +NULL, // #378 +NULL, // #379 +NULL, // #380 +NULL, // #381 +NULL, // #382 +NULL, // #383 +NULL, // #384 +NULL, // #385 +NULL, // #386 +NULL, // #387 +NULL, // #388 +NULL, // #389 +NULL, // #390 +NULL, // #391 +NULL, // #392 +NULL, // #393 +NULL, // #394 +NULL, // #395 +NULL, // #396 +NULL, // #397 +NULL, // #398 +NULL, // #399 +// LordHavoc's range #400-#499 +VM_SV_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) +VM_SV_setcolor, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR) +VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN) +VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT) +VM_SV_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT) +VM_SV_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD) +VM_SV_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER) +VM_SV_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB) +VM_SV_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE) +VM_SV_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN) +VM_SV_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW) +VM_SV_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK) +VM_SV_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1) +VM_SV_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1) +VM_SV_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1) +VM_SV_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1) +VM_SV_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH) +VM_SV_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH) +VM_SV_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS) +VM_SV_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) +VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS) +VM_SV_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) +VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) +VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) +VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) +VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) +VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) +VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) +VM_SV_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_SV_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) +VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH) +VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH) +VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH) +VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH) +VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING) +VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS) +VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS) +VM_SV_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO) +VM_SV_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO) +VM_SV_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT) +VM_SV_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT) +VM_SV_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT) +VM_SV_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING) +VM_SV_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET) +NULL, // #458 +VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM) +VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS) +VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS) +VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS) +VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS) +VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS) +VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS) +VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS) +VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS) +VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS) +VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS) +NULL, // #470 +VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN) +VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN) +VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN) +VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN) +VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN) +VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS) +VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS) +VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME) +VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR) +VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS) +VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS) +VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING) +VM_SV_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND) +VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE) +VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE) +VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +NULL, // #487 +NULL, // #488 +NULL, // #489 +NULL, // #490 +NULL, // #491 +NULL, // #492 +NULL, // #493 +VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16) +VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE) +VM_numentityfields, // #496 float() numentityfields = #496; (DP_QC_ENTITYDATA) +VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA) +VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA) +VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA) +VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA) +VM_SV_WritePicture, // #501 +NULL, // #502 +VM_whichpack, // #503 string(string) whichpack = #503; +NULL, // #504 +NULL, // #505 +NULL, // #506 +NULL, // #507 +NULL, // #508 +NULL, // #509 +VM_uri_escape, // #510 string(string in) uri_escape = #510; +VM_uri_unescape, // #511 string(string in) uri_unescape = #511; +VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT) +VM_uri_get, // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST) +VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE) +VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE) +VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST) +VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION) +VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME) +NULL, // #520 +NULL, // #521 +NULL, // #522 +NULL, // #523 +NULL, // #524 +NULL, // #525 +NULL, // #526 +NULL, // #527 +NULL, // #528 +VM_loadfromdata, // #529 +VM_loadfromfile, // #530 +VM_SV_setpause, // #531 void(float pause) setpause = #531; +VM_log, // #532 +VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME) +VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME) +VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP) +VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP) +NULL, // #539 +VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE) +VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE) +VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE) +NULL, // #543 +NULL, // #544 +NULL, // #545 +NULL, // #546 +NULL, // #547 +NULL, // #548 +NULL, // #549 +NULL, // #550 +NULL, // #551 +NULL, // #552 +NULL, // #553 +NULL, // #554 +NULL, // #555 +NULL, // #556 +NULL, // #557 +NULL, // #558 +NULL, // #559 +NULL, // #560 +NULL, // #561 +NULL, // #562 +NULL, // #563 +NULL, // #564 +NULL, // #565 +NULL, // #566 +NULL, // #567 +NULL, // #568 +NULL, // #569 +NULL, // #570 +NULL, // #571 +NULL, // #572 +NULL, // #573 +NULL, // #574 +NULL, // #575 +NULL, // #576 +NULL, // #577 +NULL, // #578 +NULL, // #579 +NULL, // #580 +NULL, // #581 +NULL, // #582 +NULL, // #583 +NULL, // #584 +NULL, // #585 +NULL, // #586 +NULL, // #587 +NULL, // #588 +NULL, // #589 +NULL, // #590 +NULL, // #591 +NULL, // #592 +NULL, // #593 +NULL, // #594 +NULL, // #595 +NULL, // #596 +NULL, // #597 +NULL, // #598 +NULL, // #599 +NULL, // #600 +NULL, // #601 +NULL, // #602 +NULL, // #603 +NULL, // #604 +VM_callfunction, // #605 +VM_writetofile, // #606 +VM_isfunction, // #607 +NULL, // #608 +NULL, // #609 +NULL, // #610 +NULL, // #611 +NULL, // #612 +VM_parseentitydata, // #613 +NULL, // #614 +NULL, // #615 +NULL, // #616 +NULL, // #617 +NULL, // #618 +NULL, // #619 +NULL, // #620 +NULL, // #621 +NULL, // #622 +NULL, // #623 +VM_SV_getextresponse, // #624 string getextresponse(void) +NULL, // #625 +NULL, // #626 +VM_sprintf, // #627 string sprintf(string format, ...) +VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE) +VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE) +NULL, // #630 +NULL, // #631 +NULL, // #632 +NULL, // #633 +NULL, // #634 +NULL, // #635 +NULL, // #636 +NULL, // #637 +NULL, // #638 +VM_digest_hex, // #639 +NULL, // #640 +}; + +const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t); + +void SVVM_init_cmd(prvm_prog_t *prog) +{ + VM_Cmd_Init(prog); +} + +void SVVM_reset_cmd(prvm_prog_t *prog) +{ + World_End(&sv.world); + if(PRVM_serverfunction(SV_Shutdown)) + { + func_t s = PRVM_serverfunction(SV_Shutdown); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again + prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); + } + + VM_Cmd_Reset(prog); +} diff --git a/app/jni/sys.h b/app/jni/sys.h new file mode 100644 index 0000000..e5247d3 --- /dev/null +++ b/app/jni/sys.h @@ -0,0 +1,119 @@ +/* +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 + +#ifndef SYS_H +#define SYS_H + +extern cvar_t sys_usenoclockbutbenchmark; + +// +// DLL management +// + +// Win32 specific +#ifdef WIN32 +# include +typedef HMODULE dllhandle_t; + +// Other platforms +#else + typedef void* dllhandle_t; +#endif + +typedef struct dllfunction_s +{ + const char *name; + void **funcvariable; +} +dllfunction_t; + +/*! Loads a library. + * \param dllnames a NULL terminated array of possible names for the DLL you want to load. + * \param handle + * \param fcts + */ +qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts); +void Sys_UnloadLibrary (dllhandle_t* handle); +void* Sys_GetProcAddress (dllhandle_t handle, const char* name); + +/// called early in Host_Init +void Sys_InitConsole (void); +/// called after command system is initialized but before first Con_Print +void Sys_Init_Commands (void); + + +/// \returns current timestamp +char *Sys_TimeString(const char *timeformat); + +// +// system IO interface (these are the sys functions that need to be implemented in a new driver atm) +// + +/// an error will cause the entire program to exit +void Sys_Error (const char *error, ...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN; + +/// (may) output text to terminal which launched program +void Sys_PrintToTerminal(const char *text); +void Sys_PrintfToTerminal(const char *fmt, ...); + +/// INFO: This is only called by Host_Shutdown so we dont need testing for recursion +void Sys_Shutdown (void); +void Sys_Quit (int returnvalue); + +/*! on some build/platform combinations (such as Linux gcc with the -pg + * profiling option) this can turn on/off profiling, used primarily to limit + * profiling to certain areas of the code, such as ingame performance without + * regard for loading/shutdown performance (-profilegameonly on commandline) + */ +void Sys_AllowProfiling (qboolean enable); + +typedef struct sys_cleantime_s +{ + double dirtytime; // last value gotten from Sys_DirtyTime() + double cleantime; // sanitized linearly increasing time since app start +} +sys_cleantime_t; + +double Sys_DirtyTime(void); + +void Sys_ProvideSelfFD (void); + +char *Sys_ConsoleInput (void); + +/// called to yield for a little bit so as not to hog cpu when paused or debugging +void Sys_Sleep(int microseconds); + +/// Perform Key_Event () callbacks until the input que is empty +void Sys_SendKeyEvents (void); + +char *Sys_GetClipboardData (void); + +extern qboolean sys_supportsdlgetticks; +unsigned int Sys_SDL_GetTicks (void); // wrapper to call SDL_GetTicks +void Sys_SDL_Delay (unsigned int milliseconds); // wrapper to call SDL_Delay + +/// called to set process priority for dedicated servers +void Sys_InitProcessNice (void); +void Sys_MakeProcessNice (void); +void Sys_MakeProcessMean (void); + +#endif + diff --git a/app/jni/sys_linux.c b/app/jni/sys_linux.c new file mode 100644 index 0000000..63c5f90 --- /dev/null +++ b/app/jni/sys_linux.c @@ -0,0 +1,200 @@ + +#ifdef WIN32 +#include +#include +#include +#include "conio.h" +#else +#include +#include +#include +#endif + +#include + +#include "quakedef.h" + +// ======================================================================= +// General routines +// ======================================================================= +void Sys_Shutdown (void) +{ +#ifdef FNDELAY + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); +#endif + fflush(stdout); + exit(0); +} + +void Sys_Error (const char *error, ...) +{ + va_list argptr; + char string[MAX_INPUTLINE]; + +// change stdin to non blocking +#ifdef FNDELAY + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); +#endif + + va_start (argptr,error); + dpvsnprintf (string, sizeof (string), error, argptr); + va_end (argptr); + + Con_Printf ("Quake Error: %s\n", string); + + Host_Shutdown (); + exit (1); +} + +static int outfd = 1; +void Sys_PrintToTerminal(const char *text) +{ + if(outfd < 0) + return; +#ifdef FNDELAY + // BUG: for some reason, NDELAY also affects stdout (1) when used on stdin (0). + // this is because both go to /dev/tty by default! + { + int origflags = fcntl (outfd, F_GETFL, 0); + fcntl (outfd, F_SETFL, origflags & ~FNDELAY); +#endif +#ifdef WIN32 +#define write _write +#endif + while(*text) + { + fs_offset_t written = (fs_offset_t)write(outfd, text, strlen(text)); + if(written <= 0) + break; // sorry, I cannot do anything about this error - without an output + text += written; + } +#ifdef FNDELAY + fcntl (outfd, F_SETFL, origflags); + } +#endif + //fprintf(stdout, "%s", text); +} + +char *Sys_ConsoleInput(void) +{ + //if (cls.state == ca_dedicated) + { + static char text[MAX_INPUTLINE]; + static unsigned int len = 0; +#ifdef WIN32 + int c; + + // read a line out + while (_kbhit ()) + { + c = _getch (); + if (c == '\r') + { + text[len] = '\0'; + _putch ('\n'); + len = 0; + return text; + } + if (c == '\b') + { + if (len) + { + _putch (c); + _putch (' '); + _putch (c); + len--; + } + continue; + } + if (len < sizeof (text) - 1) + { + _putch (c); + text[len] = c; + len++; + } + } +#else + fd_set fdset; + struct timeval timeout; + FD_ZERO(&fdset); + FD_SET(0, &fdset); // stdin + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (select (1, &fdset, NULL, NULL, &timeout) != -1 && FD_ISSET(0, &fdset)) + { + len = read (0, text, sizeof(text) - 1); + if (len >= 1) + { + // rip off the \n and terminate + // div0: WHY? console code can deal with \n just fine + // this caused problems with pasting stuff into a terminal window + // so, not ripping off the \n, but STILL keeping a NUL terminator + text[len] = 0; + return text; + } + } +#endif + } + return NULL; +} + +char *Sys_GetClipboardData (void) +{ + return NULL; +} + +void Sys_InitConsole (void) +{ +} + +int main (int argc, char **argv) +{ + signal(SIGFPE, SIG_IGN); + + com_argc = argc; + int argvsize=0; + int i; + for (i=0; i +# include // timeGetTime +# include // localtime +#ifdef _MSC_VER +#pragma comment(lib, "winmm.lib") +#endif +#else +# include +# include +# include +# include +# ifdef SUPPORTDLL +# include +# endif +#endif + +static char sys_timestring[128]; +char *Sys_TimeString(const char *timeformat) +{ + time_t mytime = time(NULL); +#if _MSC_VER >= 1400 + struct tm mytm; + localtime_s(&mytm, &mytime); + strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm); +#else + strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime)); +#endif + return sys_timestring; +} + +extern void QC_exit(int exitCode); + +extern qboolean host_shuttingdown; +void Sys_Quit (int returnvalue) +{ + if (COM_CheckParm("-profilegameonly")) + Sys_AllowProfiling(false); + + //Inform the main rendering loop we are exiting the game + QC_exit(1); + //host_shuttingdown = true; + //Host_Shutdown(); +} + +#if defined(__linux__) || defined(__FreeBSD__) +#ifdef __cplusplus +extern "C" +#endif +int moncontrol(int); +#endif + +void Sys_AllowProfiling(qboolean enable) +{ +#if defined(__linux__) || defined(__FreeBSD__) + //moncontrol(enable); +#endif +} + + +/* +=============================================================================== + +DLL MANAGEMENT + +=============================================================================== +*/ + +static qboolean Sys_LoadLibraryFunctions(dllhandle_t dllhandle, const dllfunction_t *fcts, qboolean complain, qboolean has_next) +{ + const dllfunction_t *func; + if(dllhandle) + { + for (func = fcts; func && func->name != NULL; func++) + if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name))) + { + if(complain) + { + Con_DPrintf (" - missing function \"%s\" - broken library!", func->name); + if(has_next) + Con_DPrintf("\nContinuing with"); + } + goto notfound; + } + return true; + + notfound: + for (func = fcts; func && func->name != NULL; func++) + *func->funcvariable = NULL; + } + return false; +} + +qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts) +{ +#ifdef SUPPORTDLL + const dllfunction_t *func; + dllhandle_t dllhandle = 0; + unsigned int i; + + if (handle == NULL) + return false; + +#ifndef WIN32 +#ifdef PREFER_PRELOAD + dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); + if(Sys_LoadLibraryFunctions(dllhandle, fcts, false, false)) + { + Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]); + *handle = dllhandle; + return true; + } + else + Sys_UnloadLibrary(&dllhandle); +notfound: +#endif +#endif + + // Initializations + for (func = fcts; func && func->name != NULL; func++) + *func->funcvariable = NULL; + + // Try every possible name + Con_DPrintf ("Trying to load library..."); + for (i = 0; dllnames[i] != NULL; i++) + { + Con_DPrintf (" \"%s\"", dllnames[i]); +#ifdef WIN32 +# ifndef DONT_USE_SETDLLDIRECTORY +# ifdef _WIN64 + SetDllDirectory("bin64"); +# else + SetDllDirectory("bin32"); +# endif +# endif + dllhandle = LoadLibrary (dllnames[i]); + // no need to unset this - we want ALL dlls to be loaded from there, anyway +#else + dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL); +#endif + if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, (dllnames[i+1] != NULL) || (strrchr(com_argv[0], '/')))) + break; + else + Sys_UnloadLibrary (&dllhandle); + } + + // see if the names can be loaded relative to the executable path + // (this is for Mac OSX which does not check next to the executable) + if (!dllhandle && strrchr(com_argv[0], '/')) + { + char path[MAX_OSPATH]; + strlcpy(path, com_argv[0], sizeof(path)); + strrchr(path, '/')[1] = 0; + for (i = 0; dllnames[i] != NULL; i++) + { + char temp[MAX_OSPATH]; + strlcpy(temp, path, sizeof(temp)); + strlcat(temp, dllnames[i], sizeof(temp)); + Con_DPrintf (" \"%s\"", temp); +#ifdef WIN32 + dllhandle = LoadLibrary (temp); +#else + dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL); +#endif + if (Sys_LoadLibraryFunctions(dllhandle, fcts, true, dllnames[i+1] != NULL)) + break; + else + Sys_UnloadLibrary (&dllhandle); + } + } + + // No DLL found + if (! dllhandle) + { + Con_DPrintf(" - failed.\n"); + return false; + } + + Con_DPrintf(" - loaded.\n"); + + *handle = dllhandle; + return true; +#else + return false; +#endif +} + +void Sys_UnloadLibrary (dllhandle_t* handle) +{ +#ifdef SUPPORTDLL + if (handle == NULL || *handle == NULL) + return; + +#ifdef WIN32 + FreeLibrary (*handle); +#else + dlclose (*handle); +#endif + + *handle = NULL; +#endif +} + +void* Sys_GetProcAddress (dllhandle_t handle, const char* name) +{ +#ifdef SUPPORTDLL +#ifdef WIN32 + return (void *)GetProcAddress (handle, name); +#else + return (void *)dlsym (handle, name); +#endif +#else + return NULL; +#endif +} + +#ifdef WIN32 +# define HAVE_TIMEGETTIME 1 +# define HAVE_QUERYPERFORMANCECOUNTER 1 +# define HAVE_Sleep 1 +#endif + +#if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES) +# define HAVE_CLOCKGETTIME 1 +#endif + +#ifndef WIN32 +// FIXME improve this check, manpage hints to DST_NONE +# define HAVE_GETTIMEOFDAY 1 +#endif + +#ifndef WIN32 +// on Win32, select() cannot be used with all three FD list args being NULL according to MSDN +// (so much for POSIX...) +# ifdef FD_SET +# define HAVE_SELECT 1 +# endif +#endif + +#ifndef WIN32 +// FIXME improve this check +# define HAVE_USLEEP 1 +#endif + +// this one is referenced elsewhere +cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."}; + +// these are not +static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"}; +static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"}; +static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"}; +#if HAVE_QUERYPERFORMANCECOUNTER +static cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "0", "use windows QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power) for timing rather than timeGetTime function (which has issues on some motherboards)"}; +#endif +#if HAVE_CLOCKGETTIME +static cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"}; +#endif + +static double benchmark_time; // actually always contains an integer amount of milliseconds, will eventually "overflow" + +void Sys_Init_Commands (void) +{ + Cvar_RegisterVariable(&sys_debugsleep); + Cvar_RegisterVariable(&sys_usenoclockbutbenchmark); +#if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY + if(sys_supportsdlgetticks) + { + Cvar_RegisterVariable(&sys_usesdlgetticks); + Cvar_RegisterVariable(&sys_usesdldelay); + } +#endif +#if HAVE_QUERYPERFORMANCECOUNTER + Cvar_RegisterVariable(&sys_usequeryperformancecounter); +#endif +#if HAVE_CLOCKGETTIME + Cvar_RegisterVariable(&sys_useclockgettime); +#endif +} + +double Sys_DirtyTime(void) +{ + // first all the OPTIONAL timers + + // benchmark timer (fake clock) + if(sys_usenoclockbutbenchmark.integer) + { + double old_benchmark_time = benchmark_time; + benchmark_time += 1; + if(benchmark_time == old_benchmark_time) + Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry"); + return benchmark_time * 0.000001; + } +#if HAVE_QUERYPERFORMANCECOUNTER + if (sys_usequeryperformancecounter.integer) + { + // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine. + // QueryPerformanceCounter + // platform: + // Windows 95/98/ME/NT/2000/XP + // features: + // very accurate (CPU cycles) + // known issues: + // does not necessarily match realtime too well (tends to get faster and faster in win98) + // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors) + double timescale; + LARGE_INTEGER PerformanceFreq; + LARGE_INTEGER PerformanceCount; + + if (QueryPerformanceFrequency (&PerformanceFreq)) + { + QueryPerformanceCounter (&PerformanceCount); + + #ifdef __BORLANDC__ + timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0); + return ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale; + #else + timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0); + return ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale; + #endif + } + else + { + Con_Printf("No hardware timer available\n"); + // fall back to other clock sources + Cvar_SetValueQuick(&sys_usequeryperformancecounter, false); + } + } +#endif + +#if HAVE_CLOCKGETTIME + if (sys_useclockgettime.integer) + { + struct timespec ts; +# ifdef CLOCK_MONOTONIC + // linux + clock_gettime(CLOCK_MONOTONIC, &ts); +# else + // sunos + clock_gettime(CLOCK_HIGHRES, &ts); +# endif + return (double) ts.tv_sec + ts.tv_nsec / 1000000000.0; + } +#endif + + // now all the FALLBACK timers + if(sys_supportsdlgetticks && sys_usesdlgetticks.integer) + return (double) Sys_SDL_GetTicks() / 1000.0; +#if HAVE_GETTIMEOFDAY + { + struct timeval tp; + gettimeofday(&tp, NULL); + return (double) tp.tv_sec + tp.tv_usec / 1000000.0; + } +#elif HAVE_TIMEGETTIME + { + static int firsttimegettime = true; + // timeGetTime + // platform: + // Windows 95/98/ME/NT/2000/XP + // features: + // reasonable accuracy (millisecond) + // issues: + // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter) + + // make sure the timer is high precision, otherwise different versions of windows have varying accuracy + if (firsttimegettime) + { + timeBeginPeriod(1); + firsttimegettime = false; + } + + return (double) timeGetTime() / 1000.0; + } +#else + // fallback for using the SDL timer if no other timer is available + // this calls Sys_Error() if not linking against SDL + return (double) Sys_SDL_GetTicks() / 1000.0; +#endif +} + +void Sys_Sleep(int microseconds) +{ + double t = 0; + if(sys_usenoclockbutbenchmark.integer) + { + if(microseconds) + { + double old_benchmark_time = benchmark_time; + benchmark_time += microseconds; + if(benchmark_time == old_benchmark_time) + Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry"); + } + return; + } + if(sys_debugsleep.integer) + { + t = Sys_DirtyTime(); + } + if(sys_supportsdlgetticks && sys_usesdldelay.integer) + { + Sys_SDL_Delay(microseconds / 1000); + } +#if HAVE_SELECT + else + { + struct timeval tv; + tv.tv_sec = microseconds / 1000000; + tv.tv_usec = microseconds % 1000000; + select(0, NULL, NULL, NULL, &tv); + } +#elif HAVE_USLEEP + else + { + usleep(microseconds); + } +#elif HAVE_Sleep + else + { + Sleep(microseconds / 1000); + } +#else + else + { + Sys_SDL_Delay(microseconds / 1000); + } +#endif + if(sys_debugsleep.integer) + { + t = Sys_DirtyTime() - t; + Sys_PrintfToTerminal("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000)); + } +} + +void Sys_PrintfToTerminal(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr,fmt); + dpvsnprintf(msg,sizeof(msg),fmt,argptr); + va_end(argptr); + + Sys_PrintToTerminal(msg); +} + +#ifndef WIN32 +static const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize) +{ + const char *p = PATH; + const char *q; + if(p && name) + { + while((q = strchr(p, ':'))) + { + dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name); + if(FS_SysFileExists(buf)) + return buf; + p = q + 1; + } + if(!q) // none found - try the last item + { + dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name); + if(FS_SysFileExists(buf)) + return buf; + } + } + return name; +} +#endif + +static const char *Sys_FindExecutableName(void) +{ +#if defined(WIN32) + return com_argv[0]; +#else + static char exenamebuf[MAX_OSPATH+1]; + ssize_t n = -1; +#if defined(__FreeBSD__) + n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1); +#elif defined(__linux__) + n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1); +#endif + if(n > 0 && (size_t)(n) < sizeof(exenamebuf)) + { + exenamebuf[n] = 0; + return exenamebuf; + } + if(strchr(com_argv[0], '/')) + return com_argv[0]; // possibly a relative path + else + return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf)); +#endif +} + +void Sys_ProvideSelfFD(void) +{ + if(com_selffd != -1) + return; + com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false); +} + +// for x86 cpus only... (x64 has SSE2_PRESENT) +#if defined(SSE_POSSIBLE) && !defined(SSE2_PRESENT) +// code from SDL, shortened as we can expect CPUID to work +static int CPUID_Features(void) +{ + int features = 0; +# if defined(__GNUC__) && defined(__i386__) + __asm__ ( +" movl %%ebx,%%edi\n" +" xorl %%eax,%%eax \n" +" incl %%eax \n" +" cpuid # Get family/model/stepping/features\n" +" movl %%edx,%0 \n" +" movl %%edi,%%ebx\n" + : "=m" (features) + : + : "%eax", "%ecx", "%edx", "%edi" + ); +# elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + __asm { + xor eax, eax + inc eax + cpuid ; Get family/model/stepping/features + mov features, edx + } +# else +# error SSE_POSSIBLE set but no CPUID implementation +# endif + return features; +} +#endif + +#ifdef SSE_POSSIBLE +qboolean Sys_HaveSSE(void) +{ + // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection + if(COM_CheckParm("-nosse")) + return false; +#ifdef SSE_PRESENT + return true; +#else + // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection + if(COM_CheckParm("-forcesse") || COM_CheckParm("-forcesse2")) + return true; + if(CPUID_Features() & (1 << 25)) + return true; + return false; +#endif +} + +qboolean Sys_HaveSSE2(void) +{ + // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection + if(COM_CheckParm("-nosse") || COM_CheckParm("-nosse2")) + return false; +#ifdef SSE2_PRESENT + return true; +#else + // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection + if(COM_CheckParm("-forcesse2")) + return true; + if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26 + return true; + return false; +#endif +} +#endif + +/// called to set process priority for dedicated servers +#if defined(__linux__) +#include +#include +static int nicelevel; +static qboolean nicepossible; +static qboolean isnice; +void Sys_InitProcessNice (void) +{ + struct rlimit lim; + nicepossible = false; + if(COM_CheckParm("-nonice")) + return; + errno = 0; + nicelevel = getpriority(PRIO_PROCESS, 0); + if(errno) + { + Con_Printf("Kernel does not support reading process priority - cannot use niceness\n"); + return; + } + if(getrlimit(RLIMIT_NICE, &lim)) + { + Con_Printf("Kernel does not support lowering nice level again - cannot use niceness\n"); + return; + } + if(lim.rlim_cur != RLIM_INFINITY && nicelevel < (int) (20 - lim.rlim_cur)) + { + Con_Printf("Current nice level is below the soft limit - cannot use niceness\n"); + return; + } + nicepossible = true; + isnice = false; +} +void Sys_MakeProcessNice (void) +{ + if(!nicepossible) + return; + if(isnice) + return; + Con_DPrintf("Process is becoming 'nice'...\n"); + if(setpriority(PRIO_PROCESS, 0, 19)) + Con_Printf("Failed to raise nice level to %d\n", 19); + isnice = true; +} +void Sys_MakeProcessMean (void) +{ + if(!nicepossible) + return; + if(!isnice) + return; + Con_DPrintf("Process is becoming 'mean'...\n"); + if(setpriority(PRIO_PROCESS, 0, nicelevel)) + Con_Printf("Failed to lower nice level to %d\n", nicelevel); + isnice = false; +} +#else +void Sys_InitProcessNice (void) +{ +} +void Sys_MakeProcessNice (void) +{ +} +void Sys_MakeProcessMean (void) +{ +} +#endif diff --git a/app/jni/thread.h b/app/jni/thread.h new file mode 100644 index 0000000..7f590a4 --- /dev/null +++ b/app/jni/thread.h @@ -0,0 +1,42 @@ +#ifndef THREAD_H + +// enable Sys_PrintfToTerminal calls on nearly every threading call +//#define THREADDEBUG +//#define THREADDISABLE +// use recursive mutex (non-posix) extensions in thread_pthread +#define THREADRECURSIVE + +#define Thread_CreateMutex() (_Thread_CreateMutex(__FILE__, __LINE__)) +#define Thread_DestroyMutex(m) (_Thread_DestroyMutex(m, __FILE__, __LINE__)) +#define Thread_LockMutex(m) (_Thread_LockMutex(m, __FILE__, __LINE__)) +#define Thread_UnlockMutex(m) (_Thread_UnlockMutex(m, __FILE__, __LINE__)) +#define Thread_CreateCond() (_Thread_CreateCond(__FILE__, __LINE__)) +#define Thread_DestroyCond(cond) (_Thread_DestroyCond(cond, __FILE__, __LINE__)) +#define Thread_CondSignal(cond) (_Thread_CondSignal(cond, __FILE__, __LINE__)) +#define Thread_CondBroadcast(cond) (_Thread_CondBroadcast(cond, __FILE__, __LINE__)) +#define Thread_CondWait(cond, mutex) (_Thread_CondWait(cond, mutex, __FILE__, __LINE__)) +#define Thread_CreateThread(fn, data) (_Thread_CreateThread(fn, data, __FILE__, __LINE__)) +#define Thread_WaitThread(thread, retval) (_Thread_WaitThread(thread, retval, __FILE__, __LINE__)) +#define Thread_CreateBarrier(count) (_Thread_CreateBarrier(count, __FILE__, __LINE__)) +#define Thread_DestroyBarrier(barrier) (_Thread_DestroyBarrier(barrier, __FILE__, __LINE__)) +#define Thread_WaitBarrier(barrier) (_Thread_WaitBarrier(barrier, __FILE__, __LINE__)) + +int Thread_Init(void); +void Thread_Shutdown(void); +qboolean Thread_HasThreads(void); +void *_Thread_CreateMutex(const char *filename, int fileline); +void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline); +int _Thread_LockMutex(void *mutex, const char *filename, int fileline); +int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline); +void *_Thread_CreateCond(const char *filename, int fileline); +void _Thread_DestroyCond(void *cond, const char *filename, int fileline); +int _Thread_CondSignal(void *cond, const char *filename, int fileline); +int _Thread_CondBroadcast(void *cond, const char *filename, int fileline); +int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline); +void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline); +int _Thread_WaitThread(void *thread, int retval, const char *filename, int fileline); +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline); +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline); +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline); + +#endif diff --git a/app/jni/thread_pthread.c b/app/jni/thread_pthread.c new file mode 100644 index 0000000..7bded93 --- /dev/null +++ b/app/jni/thread_pthread.c @@ -0,0 +1,226 @@ +#include "quakedef.h" +#include "thread.h" +#ifdef THREADRECURSIVE +#define __USE_UNIX98 +#include +#endif +#include + + +int Thread_Init(void) +{ + return 0; +} + +void Thread_Shutdown(void) +{ +} + +qboolean Thread_HasThreads(void) +{ + return true; +} + +void *_Thread_CreateMutex(const char *filename, int fileline) +{ +#ifdef THREADRECURSIVE + pthread_mutexattr_t attr; +#endif + pthread_mutex_t *mutexp = (pthread_mutex_t *) Z_Malloc(sizeof(pthread_mutex_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p mutex create %s:%i\n" , mutexp, filename, fileline); +#endif +#ifdef THREADRECURSIVE + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(mutexp, &attr); + pthread_mutexattr_destroy(&attr); +#else + pthread_mutex_init(mutexp, NULL); +#endif + return mutexp; +} + +void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline) +{ + pthread_mutex_t *mutexp = (pthread_mutex_t *) mutex; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p mutex destroy %s:%i\n", mutex, filename, fileline); +#endif + pthread_mutex_destroy(mutexp); + Z_Free(mutexp); +} + +int _Thread_LockMutex(void *mutex, const char *filename, int fileline) +{ + pthread_mutex_t *mutexp = (pthread_mutex_t *) mutex; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p mutex lock %s:%i\n" , mutex, filename, fileline); +#endif + return pthread_mutex_lock(mutexp); +} + +int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline) +{ + pthread_mutex_t *mutexp = (pthread_mutex_t *) mutex; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p mutex unlock %s:%i\n" , mutex, filename, fileline); +#endif + return pthread_mutex_unlock(mutexp); +} + +void *_Thread_CreateCond(const char *filename, int fileline) +{ + pthread_cond_t *condp = (pthread_cond_t *) Z_Malloc(sizeof(pthread_cond_t)); + pthread_cond_init(condp, NULL); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p cond create %s:%i\n" , condp, filename, fileline); +#endif + return condp; +} + +void _Thread_DestroyCond(void *cond, const char *filename, int fileline) +{ + pthread_cond_t *condp = (pthread_cond_t *) cond; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p cond destroy %s:%i\n" , cond, filename, fileline); +#endif + pthread_cond_destroy(condp); + Z_Free(condp); +} + +int _Thread_CondSignal(void *cond, const char *filename, int fileline) +{ + pthread_cond_t *condp = (pthread_cond_t *) cond; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p cond signal %s:%i\n" , cond, filename, fileline); +#endif + return pthread_cond_signal(condp); +} + +int _Thread_CondBroadcast(void *cond, const char *filename, int fileline) +{ + pthread_cond_t *condp = (pthread_cond_t *) cond; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p cond broadcast %s:%i\n" , cond, filename, fileline); +#endif + return pthread_cond_broadcast(condp); +} + +int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline) +{ + pthread_cond_t *condp = (pthread_cond_t *) cond; + pthread_mutex_t *mutexp = (pthread_mutex_t *) mutex; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p cond wait %s:%i\n" , cond, filename, fileline); +#endif + return pthread_cond_wait(condp, mutexp); +} + +void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline) +{ + pthread_t *threadp = (pthread_t *) Z_Malloc(sizeof(pthread_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p thread create %s:%i\n" , threadp, filename, fileline); +#endif + int r = pthread_create(threadp, NULL, (void * (*) (void *)) fn, data); + if(r) + { + Z_Free(threadp); + return NULL; + } + return threadp; +} + +int _Thread_WaitThread(void *thread, int retval, const char *filename, int fileline) +{ + pthread_t *threadp = (pthread_t *) thread; + void *status = (void *) (intptr_t) retval; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p thread wait %s:%i\n" , thread, filename, fileline); +#endif + pthread_join(*threadp, &status); + Z_Free(threadp); + return (int) (intptr_t) status; +} + +#ifdef PTHREAD_BARRIER_SERIAL_THREAD +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) Z_Malloc(sizeof(pthread_barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + pthread_barrier_init(b, NULL, count); + return (void *) b; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + pthread_barrier_destroy(b); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + pthread_barrier_t *b = (pthread_barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + pthread_barrier_wait(b); +} +#else +// standard barrier implementation using conds and mutexes +// see: http://www.howforge.com/implementing-barrier-in-pthreads +typedef struct { + unsigned int needed; + unsigned int called; + void *mutex; + void *cond; +} barrier_t; + +void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) Z_Malloc(sizeof(barrier_t)); +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier create(%d) %s:%i\n", b, count, filename, fileline); +#endif + b->needed = count; + b->called = 0; + b->mutex = Thread_CreateMutex(); + b->cond = Thread_CreateCond(); + return (void *) b; +} + +void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier destroy %s:%i\n", b, filename, fileline); +#endif + Thread_DestroyMutex(b->mutex); + Thread_DestroyCond(b->cond); +} + +void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline) +{ + volatile barrier_t *b = (volatile barrier_t *) barrier; +#ifdef THREADDEBUG + Sys_PrintfToTerminal("%p barrier wait %s:%i\n", b, filename, fileline); +#endif + Thread_LockMutex(b->mutex); + b->called++; + if (b->called == b->needed) { + b->called = 0; + Thread_CondBroadcast(b->cond); + } else { + do { + Thread_CondWait(b->cond, b->mutex); + } while(b->called); + } + Thread_UnlockMutex(b->mutex); +} +#endif diff --git a/app/jni/timing.h b/app/jni/timing.h new file mode 100644 index 0000000..33da858 --- /dev/null +++ b/app/jni/timing.h @@ -0,0 +1,58 @@ +/* +Simple helper macros to time blocks or statements. + +Copyright (C) 2007 Frank Richter + +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 __TIMING_H__ +#define __TIMING_H__ + +#if defined(DO_TIMING) + +#define TIMING_BEGIN double _timing_end_, _timing_start_ = Sys_DirtyTime(); +#define TIMING_END_STR(S) \ + _timing_end_ = Sys_DirtyTime(); \ + Con_Printf ("%s: %.3g s\n", S, _timing_end_ - _timing_start_); +#define TIMING_END TIMING_END_STR(__FUNCTION__) + +#define TIMING_INTERMEDIATE(S) \ + { \ + double currentTime = Sys_DirtyTime(); \ + Con_Printf ("%s: %.3g s\n", S, currentTime - _timing_start_); \ + } + +#define TIMING_TIMESTATEMENT(Stmt) \ + { \ + TIMING_BEGIN \ + Stmt; \ + TIMING_END_STR(#Stmt); \ + } + +#else + +#define TIMING_BEGIN +#define TIMING_END_STR(S) +#define TIMING_END +#define TIMING_INTERMEDIATE(S) +#define TIMING_TIMESTATEMENT(Stmt) Stmt + +#endif + +#endif // __TIMING_H__ + diff --git a/app/jni/utf8lib.c b/app/jni/utf8lib.c new file mode 100644 index 0000000..76cc813 --- /dev/null +++ b/app/jni/utf8lib.c @@ -0,0 +1,3055 @@ +#include "quakedef.h" +#include "utf8lib.h" + +/* +================================================================================ +Initialization of UTF-8 support and new cvars. +================================================================================ +*/ +// for compatibility this defaults to 0 +cvar_t utf8_enable = {CVAR_SAVE, "utf8_enable", "0", "Enable UTF-8 support. For compatibility, this is disabled by default in most games."}; + +void u8_Init(void) +{ + Cvar_RegisterVariable(&utf8_enable); +} + +/* +================================================================================ +UTF-8 encoding and decoding functions follow. +================================================================================ +*/ + +unsigned char utf8_lengths[256] = { // 0 = invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // ascii characters + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0xBF are within multibyte sequences + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // they could be interpreted as 2-byte starts but + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // the codepoint would be < 127 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0 and C1 would also result in overlong encodings + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + // with F5 the codepoint is above 0x10FFFF, + // F8-FB would start 5-byte sequences + // FC-FD would start 6-byte sequences + // ... +}; +Uchar utf8_range[5] = { + 1, // invalid - let's not allow the creation of 0-bytes :P + 1, // ascii minimum + 0x80, // 2-byte minimum + 0x800, // 3-byte minimum + 0x10000, // 4-byte minimum +}; + +/** Analyze the next character and return various information if requested. + * @param _s An utf-8 string. + * @param _start Filled with the start byte-offset of the next valid character + * @param _len Fileed with the length of the next valid character + * @param _ch Filled with the unicode value of the next character + * @param _maxlen Maximum number of bytes to read from _s + * @return Whether or not another valid character is in the string + */ +#define U8_ANALYZE_INFINITY 7 +static qboolean u8_analyze(const char *_s, size_t *_start, size_t *_len, Uchar *_ch, size_t _maxlen) +{ + const unsigned char *s = (const unsigned char*)_s; + size_t i, j; + size_t bits = 0; + Uchar ch; + + i = 0; +findchar: + while (i < _maxlen && s[i] && (bits = utf8_lengths[s[i]]) == 0) + ++i; + + if (i >= _maxlen || !s[i]) { + if (_start) *_start = i; + if (_len) *_len = 0; + return false; + } + + if (bits == 1) { // ascii + if (_start) *_start = i; + if (_len) *_len = 1; + if (_ch) *_ch = (Uchar)s[i]; + return true; + } + + ch = (s[i] & (0xFF >> bits)); + for (j = 1; j < bits; ++j) + { + if ( (s[i+j] & 0xC0) != 0x80 ) + { + i += j; + goto findchar; + } + ch = (ch << 6) | (s[i+j] & 0x3F); + } + if (ch < utf8_range[bits] || ch >= 0x10FFFF) + { + i += bits; + goto findchar; + } +#if 0 + // <0xC2 is always an overlong encoding, they're invalid, thus skipped + while (i < _maxlen && s[i] && s[i] >= 0x80 && s[i] < 0xC2) { + //fprintf(stderr, "skipping\n"); + ++i; + } + + // If we hit the end, well, we're out and invalid + if(i >= _maxlen || !s[i]) { + if (_start) *_start = i; + if (_len) *_len = 0; + return false; + } + + // I'll leave that in - if you remove it, also change the part below + // to support 1-byte chars correctly + if (s[i] < 0x80) + { + if (_start) *_start = i; + if (_len) *_len = 1; + if (_ch) *_ch = (Uchar)s[i]; + //fprintf(stderr, "valid ascii\n"); + return true; + } + + // Figure out the next char's length + bc = s[i]; + bits = 1; + // count the 1 bits, they're the # of bytes + for (bt = 0x40; bt && (bc & bt); bt >>= 1, ++bits); + if (!bt) + { + //fprintf(stderr, "superlong\n"); + ++i; + goto findchar; + } + if(i + bits > _maxlen) { + /* + if (_start) *_start = i; + if (_len) *_len = 0; + return false; + */ + ++i; + goto findchar; + } + // turn bt into a mask and give ch a starting value + --bt; + ch = (s[i] & bt); + // check the byte sequence for invalid bytes + for (j = 1; j < bits; ++j) + { + // valid bit value: 10xx xxxx + //if (s[i+j] < 0x80 || s[i+j] >= 0xC0) + if ( (s[i+j] & 0xC0) != 0x80 ) + { + //fprintf(stderr, "sequence of %i f'd at %i by %x\n", bits, j, (unsigned int)s[i+j]); + // this byte sequence is invalid, skip it + i += j; + // find a character after it + goto findchar; + } + // at the same time, decode the character + ch = (ch << 6) | (s[i+j] & 0x3F); + } + + // Now check the decoded byte for an overlong encoding + if ( (bits >= 2 && ch < 0x80) || + (bits >= 3 && ch < 0x800) || + (bits >= 4 && ch < 0x10000) || + ch >= 0x10FFFF // RFC 3629 + ) + { + i += bits; + //fprintf(stderr, "overlong: %i bytes for %x\n", bits, ch); + goto findchar; + } +#endif + + if (_start) + *_start = i; + if (_len) + *_len = bits; + if (_ch) + *_ch = ch; + //fprintf(stderr, "valid utf8\n"); + return true; +} + +/** Get the number of characters in an UTF-8 string. + * @param _s An utf-8 encoded null-terminated string. + * @return The number of unicode characters in the string. + */ +size_t u8_strlen(const char *_s) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + if (!utf8_enable.integer) + return strlen(_s); + + while (*s) + { + // ascii char, skip u8_analyze + if (*s < 0x80) + { + ++len; + ++s; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + break; + // valid character, skip after it + s += st + ln; + ++len; + } + return len; +} + +static int colorcode_skipwidth(const unsigned char *s) +{ + if(*s == STRING_COLOR_TAG) + { + if(s[1] <= '9' && s[1] >= '0') // ^[0-9] found + { + return 2; + } + else if(s[1] == STRING_COLOR_RGB_TAG_CHAR && + ((s[2] >= '0' && s[2] <= '9') || (s[2] >= 'a' && s[2] <= 'f') || (s[2] >= 'A' && s[2] <= 'F')) && + ((s[3] >= '0' && s[3] <= '9') || (s[3] >= 'a' && s[3] <= 'f') || (s[3] >= 'A' && s[3] <= 'F')) && + ((s[4] >= '0' && s[4] <= '9') || (s[4] >= 'a' && s[4] <= 'f') || (s[4] >= 'A' && s[4] <= 'F'))) + { + return 5; + } + else if(s[1] == STRING_COLOR_TAG) + { + return 1; // special case, do NOT call colorcode_skipwidth for next char + } + } + return 0; +} + +/** Get the number of characters in a part of an UTF-8 string. + * @param _s An utf-8 encoded null-terminated string. + * @param n The maximum number of bytes. + * @return The number of unicode characters in the string. + */ +size_t u8_strnlen(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + if (!utf8_enable.integer) + { + len = strlen(_s); + return (len < n) ? len : n; + } + + while (*s && n) + { + // ascii char, skip u8_analyze + if (*s < 0x80) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + --n; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, n)) + break; + // valid character, see if it's still inside the range specified by n: + if (n < st + ln) + return len; + ++len; + n -= st + ln; + s += st + ln; + } + return len; +} + +static size_t u8_strnlen_colorcodes(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + while (*s && n) + { + int w = colorcode_skipwidth(s); + n -= w; + s += w; + if(w > 1) // == 1 means single caret + continue; + + // ascii char, skip u8_analyze + if (*s < 0x80 || !utf8_enable.integer) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + --n; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, n)) + break; + // valid character, see if it's still inside the range specified by n: + if (n < st + ln) + return len; + ++len; + n -= st + ln; + s += st + ln; + } + return len; +} + +/** Get the number of bytes used in a string to represent an amount of characters. + * @param _s An utf-8 encoded null-terminated string. + * @param n The number of characters we want to know the byte-size for. + * @return The number of bytes used to represent n characters. + */ +size_t u8_bytelen(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + if (!utf8_enable.integer) { + len = strlen(_s); + return (len < n) ? len : n; + } + + while (*s && n) + { + // ascii char, skip u8_analyze + if (*s < 0x80) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + ++len; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + break; + --n; + s += st + ln; + len += st + ln; + } + return len; +} + +static size_t u8_bytelen_colorcodes(const char *_s, size_t n) +{ + size_t st, ln; + size_t len = 0; + const unsigned char *s = (const unsigned char*)_s; + + while (*s && n) + { + int w = colorcode_skipwidth(s); + len += w; + s += w; + if(w > 1) // == 1 means single caret + continue; + + // ascii char, skip u8_analyze + if (*s < 0x80 || !utf8_enable.integer) + { + ++len; + ++s; + --n; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + ++len; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + break; + --n; + s += st + ln; + len += st + ln; + } + return len; +} + +/** Get the byte-index for a character-index. + * @param _s An utf-8 encoded string. + * @param i The character-index for which you want the byte offset. + * @param len If not null, character's length will be stored in there. + * @return The byte-index at which the character begins, or -1 if the string is too short. + */ +int u8_byteofs(const char *_s, size_t i, size_t *len) +{ + size_t st, ln; + size_t ofs = 0; + const unsigned char *s = (const unsigned char*)_s; + + if (!utf8_enable.integer) + { + if (strlen(_s) < i) + { + if (len) *len = 0; + return -1; + } + + if (len) *len = 1; + return i; + } + + st = ln = 0; + do + { + ofs += ln; + if (!u8_analyze((const char*)s + ofs, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + return -1; + ofs += st; + } while(i-- > 0); + if (len) + *len = ln; + return ofs; +} + +/** Get the char-index for a byte-index. + * @param _s An utf-8 encoded string. + * @param i The byte offset for which you want the character index. + * @param len If not null, the offset within the character is stored here. + * @return The character-index, or -1 if the string is too short. + */ +int u8_charidx(const char *_s, size_t i, size_t *len) +{ + size_t st, ln; + size_t ofs = 0; + size_t pofs = 0; + int idx = 0; + const unsigned char *s = (const unsigned char*)_s; + + if (!utf8_enable.integer) + { + if (len) *len = 0; + return i; + } + + while (ofs < i && s[ofs]) + { + // ascii character, skip u8_analyze + if (s[ofs] < 0x80) + { + pofs = ofs; + ++idx; + ++ofs; + continue; + } + + // invalid, skip u8_analyze + if (s[ofs] < 0xC2) + { + ++ofs; + continue; + } + + if (!u8_analyze((const char*)s+ofs, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + return -1; + // see if next char is after the bytemark + if (ofs + st > i) + { + if (len) + *len = i - pofs; + return idx; + } + ++idx; + pofs = ofs + st; + ofs += st + ln; + // see if bytemark is within the char + if (ofs > i) + { + if (len) + *len = i - pofs; + return idx; + } + } + if (len) *len = 0; + return idx; +} + +/** Get the byte offset of the previous byte. + * The result equals: + * prevchar_pos = u8_byteofs(text, u8_charidx(text, thischar_pos, NULL) - 1, NULL) + * @param _s An utf-8 encoded string. + * @param i The current byte offset. + * @return The byte offset of the previous character + */ +size_t u8_prevbyte(const char *_s, size_t i) +{ + size_t st, ln; + const unsigned char *s = (const unsigned char*)_s; + size_t lastofs = 0; + size_t ofs = 0; + + if (!utf8_enable.integer) + { + if (i > 0) + return i-1; + return 0; + } + + while (ofs < i && s[ofs]) + { + // ascii character, skip u8_analyze + if (s[ofs] < 0x80) + { + lastofs = ofs++; + continue; + } + + // invalid, skip u8_analyze + if (s[ofs] < 0xC2) + { + ++ofs; + continue; + } + + if (!u8_analyze((const char*)s+ofs, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + return lastofs; + if (ofs + st > i) + return lastofs; + if (ofs + st + ln >= i) + return ofs + st; + + lastofs = ofs; + ofs += st + ln; + } + return lastofs; +} + +Uchar u8_quake2utf8map[256] = { + 0xE000, 0xE001, 0xE002, 0xE003, 0xE004, 0xE005, 0xE006, 0xE007, 0xE008, 0xE009, 0xE00A, 0xE00B, 0xE00C, 0xE00D, 0xE00E, 0xE00F, // specials + 0xE010, 0xE011, 0xE012, 0xE013, 0xE014, 0xE015, 0xE016, 0xE017, 0xE018, 0xE019, 0xE01A, 0xE01B, 0xE01C, 0xE01D, 0xE01E, 0xE01F, // specials + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, // shift+digit line + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, // digits + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // caps + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, // caps + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // small + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, // small + 0xE080, 0xE081, 0xE082, 0xE083, 0xE084, 0xE085, 0xE086, 0xE087, 0xE088, 0xE089, 0xE08A, 0xE08B, 0xE08C, 0xE08D, 0xE08E, 0xE08F, // specials + 0xE090, 0xE091, 0xE092, 0xE093, 0xE094, 0xE095, 0xE096, 0xE097, 0xE098, 0xE099, 0xE09A, 0xE09B, 0xE09C, 0xE09D, 0xE09E, 0xE09F, // faces + 0xE0A0, 0xE0A1, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7, 0xE0A8, 0xE0A9, 0xE0AA, 0xE0AB, 0xE0AC, 0xE0AD, 0xE0AE, 0xE0AF, + 0xE0B0, 0xE0B1, 0xE0B2, 0xE0B3, 0xE0B4, 0xE0B5, 0xE0B6, 0xE0B7, 0xE0B8, 0xE0B9, 0xE0BA, 0xE0BB, 0xE0BC, 0xE0BD, 0xE0BE, 0xE0BF, + 0xE0C0, 0xE0C1, 0xE0C2, 0xE0C3, 0xE0C4, 0xE0C5, 0xE0C6, 0xE0C7, 0xE0C8, 0xE0C9, 0xE0CA, 0xE0CB, 0xE0CC, 0xE0CD, 0xE0CE, 0xE0CF, + 0xE0D0, 0xE0D1, 0xE0D2, 0xE0D3, 0xE0D4, 0xE0D5, 0xE0D6, 0xE0D7, 0xE0D8, 0xE0D9, 0xE0DA, 0xE0DB, 0xE0DC, 0xE0DD, 0xE0DE, 0xE0DF, + 0xE0E0, 0xE0E1, 0xE0E2, 0xE0E3, 0xE0E4, 0xE0E5, 0xE0E6, 0xE0E7, 0xE0E8, 0xE0E9, 0xE0EA, 0xE0EB, 0xE0EC, 0xE0ED, 0xE0EE, 0xE0EF, + 0xE0F0, 0xE0F1, 0xE0F2, 0xE0F3, 0xE0F4, 0xE0F5, 0xE0F6, 0xE0F7, 0xE0F8, 0xE0F9, 0xE0FA, 0xE0FB, 0xE0FC, 0xE0FD, 0xE0FE, 0xE0FF, +}; + +/** Fetch a character from an utf-8 encoded string. + * @param _s The start of an utf-8 encoded multi-byte character. + * @param _end Will point to after the first multi-byte character. + * @return The 32-bit integer representation of the first multi-byte character or 0 for invalid characters. + */ +Uchar u8_getchar_utf8_enabled(const char *_s, const char **_end) +{ + size_t st, ln; + Uchar ch; + + if (!u8_analyze(_s, &st, &ln, &ch, U8_ANALYZE_INFINITY)) + ch = 0; + if (_end) + *_end = _s + st + ln; + return ch; +} + +/** Fetch a character from an utf-8 encoded string. + * @param _s The start of an utf-8 encoded multi-byte character. + * @param _end Will point to after the first multi-byte character. + * @return The 32-bit integer representation of the first multi-byte character or 0 for invalid characters. + */ +Uchar u8_getnchar_utf8_enabled(const char *_s, const char **_end, size_t _maxlen) +{ + size_t st, ln; + Uchar ch; + + if (!u8_analyze(_s, &st, &ln, &ch, _maxlen)) + ch = 0; + if (_end) + *_end = _s + st + ln; + return ch; +} + +/** Encode a wide-character into utf-8. + * @param w The wide character to encode. + * @param to The target buffer the utf-8 encoded string is stored to. + * @param maxlen The maximum number of bytes that fit into the target buffer. + * @return Number of bytes written to the buffer not including the terminating null. + * Less or equal to 0 if the buffer is too small. + */ +int u8_fromchar(Uchar w, char *to, size_t maxlen) +{ + if (maxlen < 1) + return 0; + + if (!w) + return 0; + + if (w >= 0xE000 && !utf8_enable.integer) + w -= 0xE000; + + if (w < 0x80 || !utf8_enable.integer) + { + to[0] = (char)w; + if (maxlen < 2) + return -1; + to[1] = 0; + return 1; + } + // for a little speedup + if (w < 0x800) + { + if (maxlen < 3) + { + to[0] = 0; + return -1; + } + to[2] = 0; + to[1] = 0x80 | (w & 0x3F); w >>= 6; + to[0] = 0xC0 | w; + return 2; + } + if (w < 0x10000) + { + if (maxlen < 4) + { + to[0] = 0; + return -1; + } + to[3] = 0; + to[2] = 0x80 | (w & 0x3F); w >>= 6; + to[1] = 0x80 | (w & 0x3F); w >>= 6; + to[0] = 0xE0 | w; + return 3; + } + + // RFC 3629 + if (w <= 0x10FFFF) + { + if (maxlen < 5) + { + to[0] = 0; + return -1; + } + to[4] = 0; + to[3] = 0x80 | (w & 0x3F); w >>= 6; + to[2] = 0x80 | (w & 0x3F); w >>= 6; + to[1] = 0x80 | (w & 0x3F); w >>= 6; + to[0] = 0xF0 | w; + return 4; + } + return 0; +} + +/** uses u8_fromchar on a static buffer + * @param ch The unicode character to convert to encode + * @param l The number of bytes without the terminating null. + * @return A statically allocated buffer containing the character's utf8 representation, or NULL if it fails. + */ +char *u8_encodech(Uchar ch, size_t *l, char *buf16) +{ + size_t len; + len = u8_fromchar(ch, buf16, 16); + if (len > 0) + { + if (l) *l = len; + return buf16; + } + return NULL; +} + +/** Convert a utf-8 multibyte string to a wide character string. + * @param wcs The target wide-character buffer. + * @param mb The utf-8 encoded multibyte string to convert. + * @param maxlen The maximum number of wide-characters that fit into the target buffer. + * @return The number of characters written to the target buffer. + */ +size_t u8_mbstowcs(Uchar *wcs, const char *mb, size_t maxlen) +{ + size_t i; + Uchar ch; + if (maxlen < 1) + return 0; + for (i = 0; *mb && i < maxlen-1; ++i) + { + ch = u8_getchar(mb, &mb); + if (!ch) + break; + wcs[i] = ch; + } + wcs[i] = 0; + return i; +} + +/** Convert a wide-character string to a utf-8 multibyte string. + * @param mb The target buffer the utf-8 string is written to. + * @param wcs The wide-character string to convert. + * @param maxlen The number bytes that fit into the multibyte target buffer. + * @return The number of bytes written, not including the terminating \0 + */ +size_t u8_wcstombs(char *mb, const Uchar *wcs, size_t maxlen) +{ + size_t i; + const char *start = mb; + if (maxlen < 2) + return 0; + for (i = 0; wcs[i] && i < maxlen-1; ++i) + { + /* + int len; + if ( (len = u8_fromchar(wcs[i], mb, maxlen - i)) < 0) + return (mb - start); + mb += len; + */ + mb += u8_fromchar(wcs[i], mb, maxlen - i); + } + *mb = 0; + return (mb - start); +} + +/* +============ +UTF-8 aware COM_StringLengthNoColors + +calculates the visible width of a color coded string. + +*valid is filled with TRUE if the string is a valid colored string (that is, if +it does not end with an unfinished color code). If it gets filled with FALSE, a +fix would be adding a STRING_COLOR_TAG at the end of the string. + +valid can be set to NULL if the caller doesn't care. + +For size_s, specify the maximum number of characters from s to use, or 0 to use +all characters until the zero terminator. +============ +*/ +size_t +COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid); +size_t +u8_COM_StringLengthNoColors(const char *_s, size_t size_s, qboolean *valid) +{ + const unsigned char *s = (const unsigned char*)_s; + const unsigned char *end; + size_t len = 0; + size_t st, ln; + + if (!utf8_enable.integer) + return COM_StringLengthNoColors(_s, size_s, valid); + + end = size_s ? (s + size_s) : NULL; + + for(;;) + { + switch((s == end) ? 0 : *s) + { + case 0: + if(valid) + *valid = TRUE; + return len; + case STRING_COLOR_TAG: + ++s; + switch((s == end) ? 0 : *s) + { + case STRING_COLOR_RGB_TAG_CHAR: + if (s+1 != end && isxdigit(s[1]) && + s+2 != end && isxdigit(s[2]) && + s+3 != end && isxdigit(s[3]) ) + { + s+=3; + break; + } + ++len; // STRING_COLOR_TAG + ++len; // STRING_COLOR_RGB_TAG_CHAR + break; + case 0: // ends with unfinished color code! + ++len; + if(valid) + *valid = FALSE; + return len; + case STRING_COLOR_TAG: // escaped ^ + ++len; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': // color code + break; + default: // not a color code + ++len; // STRING_COLOR_TAG + ++len; // the character + break; + } + ++s; + continue; + default: + break; + } + + // ascii char, skip u8_analyze + if (*s < 0x80) + { + ++len; + ++s; + continue; + } + + // invalid, skip u8_analyze + if (*s < 0xC2) + { + ++s; + continue; + } + + if (!u8_analyze((const char*)s, &st, &ln, NULL, U8_ANALYZE_INFINITY)) + { + // we CAN end up here, if an invalid char is between this one and the end of the string + if(valid) + *valid = TRUE; + return len; + } + + if(end && s + st + ln > end) + { + // string length exceeded by new character + if(valid) + *valid = TRUE; + return len; + } + + // valid character, skip after it + s += st + ln; + ++len; + } + // never get here +} + +/** Pads a utf-8 string + * @param out The target buffer the utf-8 string is written to. + * @param outsize The size of the target buffer, including the final NUL + * @param in The input utf-8 buffer + * @param leftalign Left align the output string (by default right alignment is done) + * @param minwidth The minimum output width + * @param maxwidth The maximum output width + * @return The number of bytes written, not including the terminating \0 + */ +size_t u8_strpad(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth) +{ + if(!utf8_enable.integer) + { + return dpsnprintf(out, outsize, "%*.*s", leftalign ? -(int) minwidth : (int) minwidth, (int) maxwidth, in); + } + else + { + size_t l = u8_bytelen(in, maxwidth); + size_t actual_width = u8_strnlen(in, l); + int pad = (actual_width >= minwidth) ? 0 : (minwidth - actual_width); + int prec = l; + int lpad = leftalign ? 0 : pad; + int rpad = leftalign ? pad : 0; + return dpsnprintf(out, outsize, "%*s%.*s%*s", lpad, "", prec, in, rpad, ""); + } +} + +size_t u8_strpad_colorcodes(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth) +{ + size_t l = u8_bytelen_colorcodes(in, maxwidth); + size_t actual_width = u8_strnlen_colorcodes(in, l); + int pad = (actual_width >= minwidth) ? 0 : (minwidth - actual_width); + int prec = l; + int lpad = leftalign ? 0 : pad; + int rpad = leftalign ? pad : 0; + return dpsnprintf(out, outsize, "%*s%.*s%*s", lpad, "", prec, in, rpad, ""); +} + + +/* +The two following functions (u8_toupper, u8_tolower) are derived from +ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt and the following license +holds for these: + +Copyright © 1991-2011 Unicode, Inc. All rights reserved. Distributed under the +Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +the Unicode data files and any associated documentation (the "Data Files") or +Unicode software and any associated documentation (the "Software") to deal in +the Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell copies +of the Data Files or Software, and to permit persons to whom the Data Files or +Software are furnished to do so, provided that (a) the above copyright +notice(s) and this permission notice appear with all copies of the Data Files +or Software, (b) both the above copyright notice(s) and this permission notice +appear in associated documentation, and (c) there is clear notice in each +modified Data File or in the Software as well as in the documentation +associated with the Data File(s) or Software that the data or software has been +modified. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN +THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING +OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR +SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +these Data Files or Software without prior written authorization of the +copyright holder. +*/ + +Uchar u8_toupper(Uchar ch) +{ + switch(ch) + { + case 0x0061: return 0x0041; + case 0x0062: return 0x0042; + case 0x0063: return 0x0043; + case 0x0064: return 0x0044; + case 0x0065: return 0x0045; + case 0x0066: return 0x0046; + case 0x0067: return 0x0047; + case 0x0068: return 0x0048; + case 0x0069: return 0x0049; + case 0x006A: return 0x004A; + case 0x006B: return 0x004B; + case 0x006C: return 0x004C; + case 0x006D: return 0x004D; + case 0x006E: return 0x004E; + case 0x006F: return 0x004F; + case 0x0070: return 0x0050; + case 0x0071: return 0x0051; + case 0x0072: return 0x0052; + case 0x0073: return 0x0053; + case 0x0074: return 0x0054; + case 0x0075: return 0x0055; + case 0x0076: return 0x0056; + case 0x0077: return 0x0057; + case 0x0078: return 0x0058; + case 0x0079: return 0x0059; + case 0x007A: return 0x005A; + case 0x00B5: return 0x039C; + case 0x00E0: return 0x00C0; + case 0x00E1: return 0x00C1; + case 0x00E2: return 0x00C2; + case 0x00E3: return 0x00C3; + case 0x00E4: return 0x00C4; + case 0x00E5: return 0x00C5; + case 0x00E6: return 0x00C6; + case 0x00E7: return 0x00C7; + case 0x00E8: return 0x00C8; + case 0x00E9: return 0x00C9; + case 0x00EA: return 0x00CA; + case 0x00EB: return 0x00CB; + case 0x00EC: return 0x00CC; + case 0x00ED: return 0x00CD; + case 0x00EE: return 0x00CE; + case 0x00EF: return 0x00CF; + case 0x00F0: return 0x00D0; + case 0x00F1: return 0x00D1; + case 0x00F2: return 0x00D2; + case 0x00F3: return 0x00D3; + case 0x00F4: return 0x00D4; + case 0x00F5: return 0x00D5; + case 0x00F6: return 0x00D6; + case 0x00F8: return 0x00D8; + case 0x00F9: return 0x00D9; + case 0x00FA: return 0x00DA; + case 0x00FB: return 0x00DB; + case 0x00FC: return 0x00DC; + case 0x00FD: return 0x00DD; + case 0x00FE: return 0x00DE; + case 0x00FF: return 0x0178; + case 0x0101: return 0x0100; + case 0x0103: return 0x0102; + case 0x0105: return 0x0104; + case 0x0107: return 0x0106; + case 0x0109: return 0x0108; + case 0x010B: return 0x010A; + case 0x010D: return 0x010C; + case 0x010F: return 0x010E; + case 0x0111: return 0x0110; + case 0x0113: return 0x0112; + case 0x0115: return 0x0114; + case 0x0117: return 0x0116; + case 0x0119: return 0x0118; + case 0x011B: return 0x011A; + case 0x011D: return 0x011C; + case 0x011F: return 0x011E; + case 0x0121: return 0x0120; + case 0x0123: return 0x0122; + case 0x0125: return 0x0124; + case 0x0127: return 0x0126; + case 0x0129: return 0x0128; + case 0x012B: return 0x012A; + case 0x012D: return 0x012C; + case 0x012F: return 0x012E; + case 0x0131: return 0x0049; + case 0x0133: return 0x0132; + case 0x0135: return 0x0134; + case 0x0137: return 0x0136; + case 0x013A: return 0x0139; + case 0x013C: return 0x013B; + case 0x013E: return 0x013D; + case 0x0140: return 0x013F; + case 0x0142: return 0x0141; + case 0x0144: return 0x0143; + case 0x0146: return 0x0145; + case 0x0148: return 0x0147; + case 0x014B: return 0x014A; + case 0x014D: return 0x014C; + case 0x014F: return 0x014E; + case 0x0151: return 0x0150; + case 0x0153: return 0x0152; + case 0x0155: return 0x0154; + case 0x0157: return 0x0156; + case 0x0159: return 0x0158; + case 0x015B: return 0x015A; + case 0x015D: return 0x015C; + case 0x015F: return 0x015E; + case 0x0161: return 0x0160; + case 0x0163: return 0x0162; + case 0x0165: return 0x0164; + case 0x0167: return 0x0166; + case 0x0169: return 0x0168; + case 0x016B: return 0x016A; + case 0x016D: return 0x016C; + case 0x016F: return 0x016E; + case 0x0171: return 0x0170; + case 0x0173: return 0x0172; + case 0x0175: return 0x0174; + case 0x0177: return 0x0176; + case 0x017A: return 0x0179; + case 0x017C: return 0x017B; + case 0x017E: return 0x017D; + case 0x017F: return 0x0053; + case 0x0180: return 0x0243; + case 0x0183: return 0x0182; + case 0x0185: return 0x0184; + case 0x0188: return 0x0187; + case 0x018C: return 0x018B; + case 0x0192: return 0x0191; + case 0x0195: return 0x01F6; + case 0x0199: return 0x0198; + case 0x019A: return 0x023D; + case 0x019E: return 0x0220; + case 0x01A1: return 0x01A0; + case 0x01A3: return 0x01A2; + case 0x01A5: return 0x01A4; + case 0x01A8: return 0x01A7; + case 0x01AD: return 0x01AC; + case 0x01B0: return 0x01AF; + case 0x01B4: return 0x01B3; + case 0x01B6: return 0x01B5; + case 0x01B9: return 0x01B8; + case 0x01BD: return 0x01BC; + case 0x01BF: return 0x01F7; + case 0x01C5: return 0x01C4; + case 0x01C6: return 0x01C4; + case 0x01C8: return 0x01C7; + case 0x01C9: return 0x01C7; + case 0x01CB: return 0x01CA; + case 0x01CC: return 0x01CA; + case 0x01CE: return 0x01CD; + case 0x01D0: return 0x01CF; + case 0x01D2: return 0x01D1; + case 0x01D4: return 0x01D3; + case 0x01D6: return 0x01D5; + case 0x01D8: return 0x01D7; + case 0x01DA: return 0x01D9; + case 0x01DC: return 0x01DB; + case 0x01DD: return 0x018E; + case 0x01DF: return 0x01DE; + case 0x01E1: return 0x01E0; + case 0x01E3: return 0x01E2; + case 0x01E5: return 0x01E4; + case 0x01E7: return 0x01E6; + case 0x01E9: return 0x01E8; + case 0x01EB: return 0x01EA; + case 0x01ED: return 0x01EC; + case 0x01EF: return 0x01EE; + case 0x01F2: return 0x01F1; + case 0x01F3: return 0x01F1; + case 0x01F5: return 0x01F4; + case 0x01F9: return 0x01F8; + case 0x01FB: return 0x01FA; + case 0x01FD: return 0x01FC; + case 0x01FF: return 0x01FE; + case 0x0201: return 0x0200; + case 0x0203: return 0x0202; + case 0x0205: return 0x0204; + case 0x0207: return 0x0206; + case 0x0209: return 0x0208; + case 0x020B: return 0x020A; + case 0x020D: return 0x020C; + case 0x020F: return 0x020E; + case 0x0211: return 0x0210; + case 0x0213: return 0x0212; + case 0x0215: return 0x0214; + case 0x0217: return 0x0216; + case 0x0219: return 0x0218; + case 0x021B: return 0x021A; + case 0x021D: return 0x021C; + case 0x021F: return 0x021E; + case 0x0223: return 0x0222; + case 0x0225: return 0x0224; + case 0x0227: return 0x0226; + case 0x0229: return 0x0228; + case 0x022B: return 0x022A; + case 0x022D: return 0x022C; + case 0x022F: return 0x022E; + case 0x0231: return 0x0230; + case 0x0233: return 0x0232; + case 0x023C: return 0x023B; + case 0x023F: return 0x2C7E; + case 0x0240: return 0x2C7F; + case 0x0242: return 0x0241; + case 0x0247: return 0x0246; + case 0x0249: return 0x0248; + case 0x024B: return 0x024A; + case 0x024D: return 0x024C; + case 0x024F: return 0x024E; + case 0x0250: return 0x2C6F; + case 0x0251: return 0x2C6D; + case 0x0252: return 0x2C70; + case 0x0253: return 0x0181; + case 0x0254: return 0x0186; + case 0x0256: return 0x0189; + case 0x0257: return 0x018A; + case 0x0259: return 0x018F; + case 0x025B: return 0x0190; + case 0x0260: return 0x0193; + case 0x0263: return 0x0194; + case 0x0265: return 0xA78D; + case 0x0268: return 0x0197; + case 0x0269: return 0x0196; + case 0x026B: return 0x2C62; + case 0x026F: return 0x019C; + case 0x0271: return 0x2C6E; + case 0x0272: return 0x019D; + case 0x0275: return 0x019F; + case 0x027D: return 0x2C64; + case 0x0280: return 0x01A6; + case 0x0283: return 0x01A9; + case 0x0288: return 0x01AE; + case 0x0289: return 0x0244; + case 0x028A: return 0x01B1; + case 0x028B: return 0x01B2; + case 0x028C: return 0x0245; + case 0x0292: return 0x01B7; + case 0x0345: return 0x0399; + case 0x0371: return 0x0370; + case 0x0373: return 0x0372; + case 0x0377: return 0x0376; + case 0x037B: return 0x03FD; + case 0x037C: return 0x03FE; + case 0x037D: return 0x03FF; + case 0x03AC: return 0x0386; + case 0x03AD: return 0x0388; + case 0x03AE: return 0x0389; + case 0x03AF: return 0x038A; + case 0x03B1: return 0x0391; + case 0x03B2: return 0x0392; + case 0x03B3: return 0x0393; + case 0x03B4: return 0x0394; + case 0x03B5: return 0x0395; + case 0x03B6: return 0x0396; + case 0x03B7: return 0x0397; + case 0x03B8: return 0x0398; + case 0x03B9: return 0x0399; + case 0x03BA: return 0x039A; + case 0x03BB: return 0x039B; + case 0x03BC: return 0x039C; + case 0x03BD: return 0x039D; + case 0x03BE: return 0x039E; + case 0x03BF: return 0x039F; + case 0x03C0: return 0x03A0; + case 0x03C1: return 0x03A1; + case 0x03C2: return 0x03A3; + case 0x03C3: return 0x03A3; + case 0x03C4: return 0x03A4; + case 0x03C5: return 0x03A5; + case 0x03C6: return 0x03A6; + case 0x03C7: return 0x03A7; + case 0x03C8: return 0x03A8; + case 0x03C9: return 0x03A9; + case 0x03CA: return 0x03AA; + case 0x03CB: return 0x03AB; + case 0x03CC: return 0x038C; + case 0x03CD: return 0x038E; + case 0x03CE: return 0x038F; + case 0x03D0: return 0x0392; + case 0x03D1: return 0x0398; + case 0x03D5: return 0x03A6; + case 0x03D6: return 0x03A0; + case 0x03D7: return 0x03CF; + case 0x03D9: return 0x03D8; + case 0x03DB: return 0x03DA; + case 0x03DD: return 0x03DC; + case 0x03DF: return 0x03DE; + case 0x03E1: return 0x03E0; + case 0x03E3: return 0x03E2; + case 0x03E5: return 0x03E4; + case 0x03E7: return 0x03E6; + case 0x03E9: return 0x03E8; + case 0x03EB: return 0x03EA; + case 0x03ED: return 0x03EC; + case 0x03EF: return 0x03EE; + case 0x03F0: return 0x039A; + case 0x03F1: return 0x03A1; + case 0x03F2: return 0x03F9; + case 0x03F5: return 0x0395; + case 0x03F8: return 0x03F7; + case 0x03FB: return 0x03FA; + case 0x0430: return 0x0410; + case 0x0431: return 0x0411; + case 0x0432: return 0x0412; + case 0x0433: return 0x0413; + case 0x0434: return 0x0414; + case 0x0435: return 0x0415; + case 0x0436: return 0x0416; + case 0x0437: return 0x0417; + case 0x0438: return 0x0418; + case 0x0439: return 0x0419; + case 0x043A: return 0x041A; + case 0x043B: return 0x041B; + case 0x043C: return 0x041C; + case 0x043D: return 0x041D; + case 0x043E: return 0x041E; + case 0x043F: return 0x041F; + case 0x0440: return 0x0420; + case 0x0441: return 0x0421; + case 0x0442: return 0x0422; + case 0x0443: return 0x0423; + case 0x0444: return 0x0424; + case 0x0445: return 0x0425; + case 0x0446: return 0x0426; + case 0x0447: return 0x0427; + case 0x0448: return 0x0428; + case 0x0449: return 0x0429; + case 0x044A: return 0x042A; + case 0x044B: return 0x042B; + case 0x044C: return 0x042C; + case 0x044D: return 0x042D; + case 0x044E: return 0x042E; + case 0x044F: return 0x042F; + case 0x0450: return 0x0400; + case 0x0451: return 0x0401; + case 0x0452: return 0x0402; + case 0x0453: return 0x0403; + case 0x0454: return 0x0404; + case 0x0455: return 0x0405; + case 0x0456: return 0x0406; + case 0x0457: return 0x0407; + case 0x0458: return 0x0408; + case 0x0459: return 0x0409; + case 0x045A: return 0x040A; + case 0x045B: return 0x040B; + case 0x045C: return 0x040C; + case 0x045D: return 0x040D; + case 0x045E: return 0x040E; + case 0x045F: return 0x040F; + case 0x0461: return 0x0460; + case 0x0463: return 0x0462; + case 0x0465: return 0x0464; + case 0x0467: return 0x0466; + case 0x0469: return 0x0468; + case 0x046B: return 0x046A; + case 0x046D: return 0x046C; + case 0x046F: return 0x046E; + case 0x0471: return 0x0470; + case 0x0473: return 0x0472; + case 0x0475: return 0x0474; + case 0x0477: return 0x0476; + case 0x0479: return 0x0478; + case 0x047B: return 0x047A; + case 0x047D: return 0x047C; + case 0x047F: return 0x047E; + case 0x0481: return 0x0480; + case 0x048B: return 0x048A; + case 0x048D: return 0x048C; + case 0x048F: return 0x048E; + case 0x0491: return 0x0490; + case 0x0493: return 0x0492; + case 0x0495: return 0x0494; + case 0x0497: return 0x0496; + case 0x0499: return 0x0498; + case 0x049B: return 0x049A; + case 0x049D: return 0x049C; + case 0x049F: return 0x049E; + case 0x04A1: return 0x04A0; + case 0x04A3: return 0x04A2; + case 0x04A5: return 0x04A4; + case 0x04A7: return 0x04A6; + case 0x04A9: return 0x04A8; + case 0x04AB: return 0x04AA; + case 0x04AD: return 0x04AC; + case 0x04AF: return 0x04AE; + case 0x04B1: return 0x04B0; + case 0x04B3: return 0x04B2; + case 0x04B5: return 0x04B4; + case 0x04B7: return 0x04B6; + case 0x04B9: return 0x04B8; + case 0x04BB: return 0x04BA; + case 0x04BD: return 0x04BC; + case 0x04BF: return 0x04BE; + case 0x04C2: return 0x04C1; + case 0x04C4: return 0x04C3; + case 0x04C6: return 0x04C5; + case 0x04C8: return 0x04C7; + case 0x04CA: return 0x04C9; + case 0x04CC: return 0x04CB; + case 0x04CE: return 0x04CD; + case 0x04CF: return 0x04C0; + case 0x04D1: return 0x04D0; + case 0x04D3: return 0x04D2; + case 0x04D5: return 0x04D4; + case 0x04D7: return 0x04D6; + case 0x04D9: return 0x04D8; + case 0x04DB: return 0x04DA; + case 0x04DD: return 0x04DC; + case 0x04DF: return 0x04DE; + case 0x04E1: return 0x04E0; + case 0x04E3: return 0x04E2; + case 0x04E5: return 0x04E4; + case 0x04E7: return 0x04E6; + case 0x04E9: return 0x04E8; + case 0x04EB: return 0x04EA; + case 0x04ED: return 0x04EC; + case 0x04EF: return 0x04EE; + case 0x04F1: return 0x04F0; + case 0x04F3: return 0x04F2; + case 0x04F5: return 0x04F4; + case 0x04F7: return 0x04F6; + case 0x04F9: return 0x04F8; + case 0x04FB: return 0x04FA; + case 0x04FD: return 0x04FC; + case 0x04FF: return 0x04FE; + case 0x0501: return 0x0500; + case 0x0503: return 0x0502; + case 0x0505: return 0x0504; + case 0x0507: return 0x0506; + case 0x0509: return 0x0508; + case 0x050B: return 0x050A; + case 0x050D: return 0x050C; + case 0x050F: return 0x050E; + case 0x0511: return 0x0510; + case 0x0513: return 0x0512; + case 0x0515: return 0x0514; + case 0x0517: return 0x0516; + case 0x0519: return 0x0518; + case 0x051B: return 0x051A; + case 0x051D: return 0x051C; + case 0x051F: return 0x051E; + case 0x0521: return 0x0520; + case 0x0523: return 0x0522; + case 0x0525: return 0x0524; + case 0x0527: return 0x0526; + case 0x0561: return 0x0531; + case 0x0562: return 0x0532; + case 0x0563: return 0x0533; + case 0x0564: return 0x0534; + case 0x0565: return 0x0535; + case 0x0566: return 0x0536; + case 0x0567: return 0x0537; + case 0x0568: return 0x0538; + case 0x0569: return 0x0539; + case 0x056A: return 0x053A; + case 0x056B: return 0x053B; + case 0x056C: return 0x053C; + case 0x056D: return 0x053D; + case 0x056E: return 0x053E; + case 0x056F: return 0x053F; + case 0x0570: return 0x0540; + case 0x0571: return 0x0541; + case 0x0572: return 0x0542; + case 0x0573: return 0x0543; + case 0x0574: return 0x0544; + case 0x0575: return 0x0545; + case 0x0576: return 0x0546; + case 0x0577: return 0x0547; + case 0x0578: return 0x0548; + case 0x0579: return 0x0549; + case 0x057A: return 0x054A; + case 0x057B: return 0x054B; + case 0x057C: return 0x054C; + case 0x057D: return 0x054D; + case 0x057E: return 0x054E; + case 0x057F: return 0x054F; + case 0x0580: return 0x0550; + case 0x0581: return 0x0551; + case 0x0582: return 0x0552; + case 0x0583: return 0x0553; + case 0x0584: return 0x0554; + case 0x0585: return 0x0555; + case 0x0586: return 0x0556; + case 0x1D79: return 0xA77D; + case 0x1D7D: return 0x2C63; + case 0x1E01: return 0x1E00; + case 0x1E03: return 0x1E02; + case 0x1E05: return 0x1E04; + case 0x1E07: return 0x1E06; + case 0x1E09: return 0x1E08; + case 0x1E0B: return 0x1E0A; + case 0x1E0D: return 0x1E0C; + case 0x1E0F: return 0x1E0E; + case 0x1E11: return 0x1E10; + case 0x1E13: return 0x1E12; + case 0x1E15: return 0x1E14; + case 0x1E17: return 0x1E16; + case 0x1E19: return 0x1E18; + case 0x1E1B: return 0x1E1A; + case 0x1E1D: return 0x1E1C; + case 0x1E1F: return 0x1E1E; + case 0x1E21: return 0x1E20; + case 0x1E23: return 0x1E22; + case 0x1E25: return 0x1E24; + case 0x1E27: return 0x1E26; + case 0x1E29: return 0x1E28; + case 0x1E2B: return 0x1E2A; + case 0x1E2D: return 0x1E2C; + case 0x1E2F: return 0x1E2E; + case 0x1E31: return 0x1E30; + case 0x1E33: return 0x1E32; + case 0x1E35: return 0x1E34; + case 0x1E37: return 0x1E36; + case 0x1E39: return 0x1E38; + case 0x1E3B: return 0x1E3A; + case 0x1E3D: return 0x1E3C; + case 0x1E3F: return 0x1E3E; + case 0x1E41: return 0x1E40; + case 0x1E43: return 0x1E42; + case 0x1E45: return 0x1E44; + case 0x1E47: return 0x1E46; + case 0x1E49: return 0x1E48; + case 0x1E4B: return 0x1E4A; + case 0x1E4D: return 0x1E4C; + case 0x1E4F: return 0x1E4E; + case 0x1E51: return 0x1E50; + case 0x1E53: return 0x1E52; + case 0x1E55: return 0x1E54; + case 0x1E57: return 0x1E56; + case 0x1E59: return 0x1E58; + case 0x1E5B: return 0x1E5A; + case 0x1E5D: return 0x1E5C; + case 0x1E5F: return 0x1E5E; + case 0x1E61: return 0x1E60; + case 0x1E63: return 0x1E62; + case 0x1E65: return 0x1E64; + case 0x1E67: return 0x1E66; + case 0x1E69: return 0x1E68; + case 0x1E6B: return 0x1E6A; + case 0x1E6D: return 0x1E6C; + case 0x1E6F: return 0x1E6E; + case 0x1E71: return 0x1E70; + case 0x1E73: return 0x1E72; + case 0x1E75: return 0x1E74; + case 0x1E77: return 0x1E76; + case 0x1E79: return 0x1E78; + case 0x1E7B: return 0x1E7A; + case 0x1E7D: return 0x1E7C; + case 0x1E7F: return 0x1E7E; + case 0x1E81: return 0x1E80; + case 0x1E83: return 0x1E82; + case 0x1E85: return 0x1E84; + case 0x1E87: return 0x1E86; + case 0x1E89: return 0x1E88; + case 0x1E8B: return 0x1E8A; + case 0x1E8D: return 0x1E8C; + case 0x1E8F: return 0x1E8E; + case 0x1E91: return 0x1E90; + case 0x1E93: return 0x1E92; + case 0x1E95: return 0x1E94; + case 0x1E9B: return 0x1E60; + case 0x1EA1: return 0x1EA0; + case 0x1EA3: return 0x1EA2; + case 0x1EA5: return 0x1EA4; + case 0x1EA7: return 0x1EA6; + case 0x1EA9: return 0x1EA8; + case 0x1EAB: return 0x1EAA; + case 0x1EAD: return 0x1EAC; + case 0x1EAF: return 0x1EAE; + case 0x1EB1: return 0x1EB0; + case 0x1EB3: return 0x1EB2; + case 0x1EB5: return 0x1EB4; + case 0x1EB7: return 0x1EB6; + case 0x1EB9: return 0x1EB8; + case 0x1EBB: return 0x1EBA; + case 0x1EBD: return 0x1EBC; + case 0x1EBF: return 0x1EBE; + case 0x1EC1: return 0x1EC0; + case 0x1EC3: return 0x1EC2; + case 0x1EC5: return 0x1EC4; + case 0x1EC7: return 0x1EC6; + case 0x1EC9: return 0x1EC8; + case 0x1ECB: return 0x1ECA; + case 0x1ECD: return 0x1ECC; + case 0x1ECF: return 0x1ECE; + case 0x1ED1: return 0x1ED0; + case 0x1ED3: return 0x1ED2; + case 0x1ED5: return 0x1ED4; + case 0x1ED7: return 0x1ED6; + case 0x1ED9: return 0x1ED8; + case 0x1EDB: return 0x1EDA; + case 0x1EDD: return 0x1EDC; + case 0x1EDF: return 0x1EDE; + case 0x1EE1: return 0x1EE0; + case 0x1EE3: return 0x1EE2; + case 0x1EE5: return 0x1EE4; + case 0x1EE7: return 0x1EE6; + case 0x1EE9: return 0x1EE8; + case 0x1EEB: return 0x1EEA; + case 0x1EED: return 0x1EEC; + case 0x1EEF: return 0x1EEE; + case 0x1EF1: return 0x1EF0; + case 0x1EF3: return 0x1EF2; + case 0x1EF5: return 0x1EF4; + case 0x1EF7: return 0x1EF6; + case 0x1EF9: return 0x1EF8; + case 0x1EFB: return 0x1EFA; + case 0x1EFD: return 0x1EFC; + case 0x1EFF: return 0x1EFE; + case 0x1F00: return 0x1F08; + case 0x1F01: return 0x1F09; + case 0x1F02: return 0x1F0A; + case 0x1F03: return 0x1F0B; + case 0x1F04: return 0x1F0C; + case 0x1F05: return 0x1F0D; + case 0x1F06: return 0x1F0E; + case 0x1F07: return 0x1F0F; + case 0x1F10: return 0x1F18; + case 0x1F11: return 0x1F19; + case 0x1F12: return 0x1F1A; + case 0x1F13: return 0x1F1B; + case 0x1F14: return 0x1F1C; + case 0x1F15: return 0x1F1D; + case 0x1F20: return 0x1F28; + case 0x1F21: return 0x1F29; + case 0x1F22: return 0x1F2A; + case 0x1F23: return 0x1F2B; + case 0x1F24: return 0x1F2C; + case 0x1F25: return 0x1F2D; + case 0x1F26: return 0x1F2E; + case 0x1F27: return 0x1F2F; + case 0x1F30: return 0x1F38; + case 0x1F31: return 0x1F39; + case 0x1F32: return 0x1F3A; + case 0x1F33: return 0x1F3B; + case 0x1F34: return 0x1F3C; + case 0x1F35: return 0x1F3D; + case 0x1F36: return 0x1F3E; + case 0x1F37: return 0x1F3F; + case 0x1F40: return 0x1F48; + case 0x1F41: return 0x1F49; + case 0x1F42: return 0x1F4A; + case 0x1F43: return 0x1F4B; + case 0x1F44: return 0x1F4C; + case 0x1F45: return 0x1F4D; + case 0x1F51: return 0x1F59; + case 0x1F53: return 0x1F5B; + case 0x1F55: return 0x1F5D; + case 0x1F57: return 0x1F5F; + case 0x1F60: return 0x1F68; + case 0x1F61: return 0x1F69; + case 0x1F62: return 0x1F6A; + case 0x1F63: return 0x1F6B; + case 0x1F64: return 0x1F6C; + case 0x1F65: return 0x1F6D; + case 0x1F66: return 0x1F6E; + case 0x1F67: return 0x1F6F; + case 0x1F70: return 0x1FBA; + case 0x1F71: return 0x1FBB; + case 0x1F72: return 0x1FC8; + case 0x1F73: return 0x1FC9; + case 0x1F74: return 0x1FCA; + case 0x1F75: return 0x1FCB; + case 0x1F76: return 0x1FDA; + case 0x1F77: return 0x1FDB; + case 0x1F78: return 0x1FF8; + case 0x1F79: return 0x1FF9; + case 0x1F7A: return 0x1FEA; + case 0x1F7B: return 0x1FEB; + case 0x1F7C: return 0x1FFA; + case 0x1F7D: return 0x1FFB; + case 0x1F80: return 0x1F88; + case 0x1F81: return 0x1F89; + case 0x1F82: return 0x1F8A; + case 0x1F83: return 0x1F8B; + case 0x1F84: return 0x1F8C; + case 0x1F85: return 0x1F8D; + case 0x1F86: return 0x1F8E; + case 0x1F87: return 0x1F8F; + case 0x1F90: return 0x1F98; + case 0x1F91: return 0x1F99; + case 0x1F92: return 0x1F9A; + case 0x1F93: return 0x1F9B; + case 0x1F94: return 0x1F9C; + case 0x1F95: return 0x1F9D; + case 0x1F96: return 0x1F9E; + case 0x1F97: return 0x1F9F; + case 0x1FA0: return 0x1FA8; + case 0x1FA1: return 0x1FA9; + case 0x1FA2: return 0x1FAA; + case 0x1FA3: return 0x1FAB; + case 0x1FA4: return 0x1FAC; + case 0x1FA5: return 0x1FAD; + case 0x1FA6: return 0x1FAE; + case 0x1FA7: return 0x1FAF; + case 0x1FB0: return 0x1FB8; + case 0x1FB1: return 0x1FB9; + case 0x1FB3: return 0x1FBC; + case 0x1FBE: return 0x0399; + case 0x1FC3: return 0x1FCC; + case 0x1FD0: return 0x1FD8; + case 0x1FD1: return 0x1FD9; + case 0x1FE0: return 0x1FE8; + case 0x1FE1: return 0x1FE9; + case 0x1FE5: return 0x1FEC; + case 0x1FF3: return 0x1FFC; + case 0x214E: return 0x2132; + case 0x2170: return 0x2160; + case 0x2171: return 0x2161; + case 0x2172: return 0x2162; + case 0x2173: return 0x2163; + case 0x2174: return 0x2164; + case 0x2175: return 0x2165; + case 0x2176: return 0x2166; + case 0x2177: return 0x2167; + case 0x2178: return 0x2168; + case 0x2179: return 0x2169; + case 0x217A: return 0x216A; + case 0x217B: return 0x216B; + case 0x217C: return 0x216C; + case 0x217D: return 0x216D; + case 0x217E: return 0x216E; + case 0x217F: return 0x216F; + case 0x2184: return 0x2183; + case 0x24D0: return 0x24B6; + case 0x24D1: return 0x24B7; + case 0x24D2: return 0x24B8; + case 0x24D3: return 0x24B9; + case 0x24D4: return 0x24BA; + case 0x24D5: return 0x24BB; + case 0x24D6: return 0x24BC; + case 0x24D7: return 0x24BD; + case 0x24D8: return 0x24BE; + case 0x24D9: return 0x24BF; + case 0x24DA: return 0x24C0; + case 0x24DB: return 0x24C1; + case 0x24DC: return 0x24C2; + case 0x24DD: return 0x24C3; + case 0x24DE: return 0x24C4; + case 0x24DF: return 0x24C5; + case 0x24E0: return 0x24C6; + case 0x24E1: return 0x24C7; + case 0x24E2: return 0x24C8; + case 0x24E3: return 0x24C9; + case 0x24E4: return 0x24CA; + case 0x24E5: return 0x24CB; + case 0x24E6: return 0x24CC; + case 0x24E7: return 0x24CD; + case 0x24E8: return 0x24CE; + case 0x24E9: return 0x24CF; + case 0x2C30: return 0x2C00; + case 0x2C31: return 0x2C01; + case 0x2C32: return 0x2C02; + case 0x2C33: return 0x2C03; + case 0x2C34: return 0x2C04; + case 0x2C35: return 0x2C05; + case 0x2C36: return 0x2C06; + case 0x2C37: return 0x2C07; + case 0x2C38: return 0x2C08; + case 0x2C39: return 0x2C09; + case 0x2C3A: return 0x2C0A; + case 0x2C3B: return 0x2C0B; + case 0x2C3C: return 0x2C0C; + case 0x2C3D: return 0x2C0D; + case 0x2C3E: return 0x2C0E; + case 0x2C3F: return 0x2C0F; + case 0x2C40: return 0x2C10; + case 0x2C41: return 0x2C11; + case 0x2C42: return 0x2C12; + case 0x2C43: return 0x2C13; + case 0x2C44: return 0x2C14; + case 0x2C45: return 0x2C15; + case 0x2C46: return 0x2C16; + case 0x2C47: return 0x2C17; + case 0x2C48: return 0x2C18; + case 0x2C49: return 0x2C19; + case 0x2C4A: return 0x2C1A; + case 0x2C4B: return 0x2C1B; + case 0x2C4C: return 0x2C1C; + case 0x2C4D: return 0x2C1D; + case 0x2C4E: return 0x2C1E; + case 0x2C4F: return 0x2C1F; + case 0x2C50: return 0x2C20; + case 0x2C51: return 0x2C21; + case 0x2C52: return 0x2C22; + case 0x2C53: return 0x2C23; + case 0x2C54: return 0x2C24; + case 0x2C55: return 0x2C25; + case 0x2C56: return 0x2C26; + case 0x2C57: return 0x2C27; + case 0x2C58: return 0x2C28; + case 0x2C59: return 0x2C29; + case 0x2C5A: return 0x2C2A; + case 0x2C5B: return 0x2C2B; + case 0x2C5C: return 0x2C2C; + case 0x2C5D: return 0x2C2D; + case 0x2C5E: return 0x2C2E; + case 0x2C61: return 0x2C60; + case 0x2C65: return 0x023A; + case 0x2C66: return 0x023E; + case 0x2C68: return 0x2C67; + case 0x2C6A: return 0x2C69; + case 0x2C6C: return 0x2C6B; + case 0x2C73: return 0x2C72; + case 0x2C76: return 0x2C75; + case 0x2C81: return 0x2C80; + case 0x2C83: return 0x2C82; + case 0x2C85: return 0x2C84; + case 0x2C87: return 0x2C86; + case 0x2C89: return 0x2C88; + case 0x2C8B: return 0x2C8A; + case 0x2C8D: return 0x2C8C; + case 0x2C8F: return 0x2C8E; + case 0x2C91: return 0x2C90; + case 0x2C93: return 0x2C92; + case 0x2C95: return 0x2C94; + case 0x2C97: return 0x2C96; + case 0x2C99: return 0x2C98; + case 0x2C9B: return 0x2C9A; + case 0x2C9D: return 0x2C9C; + case 0x2C9F: return 0x2C9E; + case 0x2CA1: return 0x2CA0; + case 0x2CA3: return 0x2CA2; + case 0x2CA5: return 0x2CA4; + case 0x2CA7: return 0x2CA6; + case 0x2CA9: return 0x2CA8; + case 0x2CAB: return 0x2CAA; + case 0x2CAD: return 0x2CAC; + case 0x2CAF: return 0x2CAE; + case 0x2CB1: return 0x2CB0; + case 0x2CB3: return 0x2CB2; + case 0x2CB5: return 0x2CB4; + case 0x2CB7: return 0x2CB6; + case 0x2CB9: return 0x2CB8; + case 0x2CBB: return 0x2CBA; + case 0x2CBD: return 0x2CBC; + case 0x2CBF: return 0x2CBE; + case 0x2CC1: return 0x2CC0; + case 0x2CC3: return 0x2CC2; + case 0x2CC5: return 0x2CC4; + case 0x2CC7: return 0x2CC6; + case 0x2CC9: return 0x2CC8; + case 0x2CCB: return 0x2CCA; + case 0x2CCD: return 0x2CCC; + case 0x2CCF: return 0x2CCE; + case 0x2CD1: return 0x2CD0; + case 0x2CD3: return 0x2CD2; + case 0x2CD5: return 0x2CD4; + case 0x2CD7: return 0x2CD6; + case 0x2CD9: return 0x2CD8; + case 0x2CDB: return 0x2CDA; + case 0x2CDD: return 0x2CDC; + case 0x2CDF: return 0x2CDE; + case 0x2CE1: return 0x2CE0; + case 0x2CE3: return 0x2CE2; + case 0x2CEC: return 0x2CEB; + case 0x2CEE: return 0x2CED; + case 0x2D00: return 0x10A0; + case 0x2D01: return 0x10A1; + case 0x2D02: return 0x10A2; + case 0x2D03: return 0x10A3; + case 0x2D04: return 0x10A4; + case 0x2D05: return 0x10A5; + case 0x2D06: return 0x10A6; + case 0x2D07: return 0x10A7; + case 0x2D08: return 0x10A8; + case 0x2D09: return 0x10A9; + case 0x2D0A: return 0x10AA; + case 0x2D0B: return 0x10AB; + case 0x2D0C: return 0x10AC; + case 0x2D0D: return 0x10AD; + case 0x2D0E: return 0x10AE; + case 0x2D0F: return 0x10AF; + case 0x2D10: return 0x10B0; + case 0x2D11: return 0x10B1; + case 0x2D12: return 0x10B2; + case 0x2D13: return 0x10B3; + case 0x2D14: return 0x10B4; + case 0x2D15: return 0x10B5; + case 0x2D16: return 0x10B6; + case 0x2D17: return 0x10B7; + case 0x2D18: return 0x10B8; + case 0x2D19: return 0x10B9; + case 0x2D1A: return 0x10BA; + case 0x2D1B: return 0x10BB; + case 0x2D1C: return 0x10BC; + case 0x2D1D: return 0x10BD; + case 0x2D1E: return 0x10BE; + case 0x2D1F: return 0x10BF; + case 0x2D20: return 0x10C0; + case 0x2D21: return 0x10C1; + case 0x2D22: return 0x10C2; + case 0x2D23: return 0x10C3; + case 0x2D24: return 0x10C4; + case 0x2D25: return 0x10C5; + case 0xA641: return 0xA640; + case 0xA643: return 0xA642; + case 0xA645: return 0xA644; + case 0xA647: return 0xA646; + case 0xA649: return 0xA648; + case 0xA64B: return 0xA64A; + case 0xA64D: return 0xA64C; + case 0xA64F: return 0xA64E; + case 0xA651: return 0xA650; + case 0xA653: return 0xA652; + case 0xA655: return 0xA654; + case 0xA657: return 0xA656; + case 0xA659: return 0xA658; + case 0xA65B: return 0xA65A; + case 0xA65D: return 0xA65C; + case 0xA65F: return 0xA65E; + case 0xA661: return 0xA660; + case 0xA663: return 0xA662; + case 0xA665: return 0xA664; + case 0xA667: return 0xA666; + case 0xA669: return 0xA668; + case 0xA66B: return 0xA66A; + case 0xA66D: return 0xA66C; + case 0xA681: return 0xA680; + case 0xA683: return 0xA682; + case 0xA685: return 0xA684; + case 0xA687: return 0xA686; + case 0xA689: return 0xA688; + case 0xA68B: return 0xA68A; + case 0xA68D: return 0xA68C; + case 0xA68F: return 0xA68E; + case 0xA691: return 0xA690; + case 0xA693: return 0xA692; + case 0xA695: return 0xA694; + case 0xA697: return 0xA696; + case 0xA723: return 0xA722; + case 0xA725: return 0xA724; + case 0xA727: return 0xA726; + case 0xA729: return 0xA728; + case 0xA72B: return 0xA72A; + case 0xA72D: return 0xA72C; + case 0xA72F: return 0xA72E; + case 0xA733: return 0xA732; + case 0xA735: return 0xA734; + case 0xA737: return 0xA736; + case 0xA739: return 0xA738; + case 0xA73B: return 0xA73A; + case 0xA73D: return 0xA73C; + case 0xA73F: return 0xA73E; + case 0xA741: return 0xA740; + case 0xA743: return 0xA742; + case 0xA745: return 0xA744; + case 0xA747: return 0xA746; + case 0xA749: return 0xA748; + case 0xA74B: return 0xA74A; + case 0xA74D: return 0xA74C; + case 0xA74F: return 0xA74E; + case 0xA751: return 0xA750; + case 0xA753: return 0xA752; + case 0xA755: return 0xA754; + case 0xA757: return 0xA756; + case 0xA759: return 0xA758; + case 0xA75B: return 0xA75A; + case 0xA75D: return 0xA75C; + case 0xA75F: return 0xA75E; + case 0xA761: return 0xA760; + case 0xA763: return 0xA762; + case 0xA765: return 0xA764; + case 0xA767: return 0xA766; + case 0xA769: return 0xA768; + case 0xA76B: return 0xA76A; + case 0xA76D: return 0xA76C; + case 0xA76F: return 0xA76E; + case 0xA77A: return 0xA779; + case 0xA77C: return 0xA77B; + case 0xA77F: return 0xA77E; + case 0xA781: return 0xA780; + case 0xA783: return 0xA782; + case 0xA785: return 0xA784; + case 0xA787: return 0xA786; + case 0xA78C: return 0xA78B; + case 0xA791: return 0xA790; + case 0xA7A1: return 0xA7A0; + case 0xA7A3: return 0xA7A2; + case 0xA7A5: return 0xA7A4; + case 0xA7A7: return 0xA7A6; + case 0xA7A9: return 0xA7A8; + case 0xFF41: return 0xFF21; + case 0xFF42: return 0xFF22; + case 0xFF43: return 0xFF23; + case 0xFF44: return 0xFF24; + case 0xFF45: return 0xFF25; + case 0xFF46: return 0xFF26; + case 0xFF47: return 0xFF27; + case 0xFF48: return 0xFF28; + case 0xFF49: return 0xFF29; + case 0xFF4A: return 0xFF2A; + case 0xFF4B: return 0xFF2B; + case 0xFF4C: return 0xFF2C; + case 0xFF4D: return 0xFF2D; + case 0xFF4E: return 0xFF2E; + case 0xFF4F: return 0xFF2F; + case 0xFF50: return 0xFF30; + case 0xFF51: return 0xFF31; + case 0xFF52: return 0xFF32; + case 0xFF53: return 0xFF33; + case 0xFF54: return 0xFF34; + case 0xFF55: return 0xFF35; + case 0xFF56: return 0xFF36; + case 0xFF57: return 0xFF37; + case 0xFF58: return 0xFF38; + case 0xFF59: return 0xFF39; + case 0xFF5A: return 0xFF3A; + case 0x10428: return 0x10400; + case 0x10429: return 0x10401; + case 0x1042A: return 0x10402; + case 0x1042B: return 0x10403; + case 0x1042C: return 0x10404; + case 0x1042D: return 0x10405; + case 0x1042E: return 0x10406; + case 0x1042F: return 0x10407; + case 0x10430: return 0x10408; + case 0x10431: return 0x10409; + case 0x10432: return 0x1040A; + case 0x10433: return 0x1040B; + case 0x10434: return 0x1040C; + case 0x10435: return 0x1040D; + case 0x10436: return 0x1040E; + case 0x10437: return 0x1040F; + case 0x10438: return 0x10410; + case 0x10439: return 0x10411; + case 0x1043A: return 0x10412; + case 0x1043B: return 0x10413; + case 0x1043C: return 0x10414; + case 0x1043D: return 0x10415; + case 0x1043E: return 0x10416; + case 0x1043F: return 0x10417; + case 0x10440: return 0x10418; + case 0x10441: return 0x10419; + case 0x10442: return 0x1041A; + case 0x10443: return 0x1041B; + case 0x10444: return 0x1041C; + case 0x10445: return 0x1041D; + case 0x10446: return 0x1041E; + case 0x10447: return 0x1041F; + case 0x10448: return 0x10420; + case 0x10449: return 0x10421; + case 0x1044A: return 0x10422; + case 0x1044B: return 0x10423; + case 0x1044C: return 0x10424; + case 0x1044D: return 0x10425; + case 0x1044E: return 0x10426; + case 0x1044F: return 0x10427; + default: return ch; + } +} + +Uchar u8_tolower(Uchar ch) +{ + switch(ch) + { + case 0x0041: return 0x0061; + case 0x0042: return 0x0062; + case 0x0043: return 0x0063; + case 0x0044: return 0x0064; + case 0x0045: return 0x0065; + case 0x0046: return 0x0066; + case 0x0047: return 0x0067; + case 0x0048: return 0x0068; + case 0x0049: return 0x0069; + case 0x004A: return 0x006A; + case 0x004B: return 0x006B; + case 0x004C: return 0x006C; + case 0x004D: return 0x006D; + case 0x004E: return 0x006E; + case 0x004F: return 0x006F; + case 0x0050: return 0x0070; + case 0x0051: return 0x0071; + case 0x0052: return 0x0072; + case 0x0053: return 0x0073; + case 0x0054: return 0x0074; + case 0x0055: return 0x0075; + case 0x0056: return 0x0076; + case 0x0057: return 0x0077; + case 0x0058: return 0x0078; + case 0x0059: return 0x0079; + case 0x005A: return 0x007A; + case 0x00C0: return 0x00E0; + case 0x00C1: return 0x00E1; + case 0x00C2: return 0x00E2; + case 0x00C3: return 0x00E3; + case 0x00C4: return 0x00E4; + case 0x00C5: return 0x00E5; + case 0x00C6: return 0x00E6; + case 0x00C7: return 0x00E7; + case 0x00C8: return 0x00E8; + case 0x00C9: return 0x00E9; + case 0x00CA: return 0x00EA; + case 0x00CB: return 0x00EB; + case 0x00CC: return 0x00EC; + case 0x00CD: return 0x00ED; + case 0x00CE: return 0x00EE; + case 0x00CF: return 0x00EF; + case 0x00D0: return 0x00F0; + case 0x00D1: return 0x00F1; + case 0x00D2: return 0x00F2; + case 0x00D3: return 0x00F3; + case 0x00D4: return 0x00F4; + case 0x00D5: return 0x00F5; + case 0x00D6: return 0x00F6; + case 0x00D8: return 0x00F8; + case 0x00D9: return 0x00F9; + case 0x00DA: return 0x00FA; + case 0x00DB: return 0x00FB; + case 0x00DC: return 0x00FC; + case 0x00DD: return 0x00FD; + case 0x00DE: return 0x00FE; + case 0x0100: return 0x0101; + case 0x0102: return 0x0103; + case 0x0104: return 0x0105; + case 0x0106: return 0x0107; + case 0x0108: return 0x0109; + case 0x010A: return 0x010B; + case 0x010C: return 0x010D; + case 0x010E: return 0x010F; + case 0x0110: return 0x0111; + case 0x0112: return 0x0113; + case 0x0114: return 0x0115; + case 0x0116: return 0x0117; + case 0x0118: return 0x0119; + case 0x011A: return 0x011B; + case 0x011C: return 0x011D; + case 0x011E: return 0x011F; + case 0x0120: return 0x0121; + case 0x0122: return 0x0123; + case 0x0124: return 0x0125; + case 0x0126: return 0x0127; + case 0x0128: return 0x0129; + case 0x012A: return 0x012B; + case 0x012C: return 0x012D; + case 0x012E: return 0x012F; + case 0x0130: return 0x0069; + case 0x0132: return 0x0133; + case 0x0134: return 0x0135; + case 0x0136: return 0x0137; + case 0x0139: return 0x013A; + case 0x013B: return 0x013C; + case 0x013D: return 0x013E; + case 0x013F: return 0x0140; + case 0x0141: return 0x0142; + case 0x0143: return 0x0144; + case 0x0145: return 0x0146; + case 0x0147: return 0x0148; + case 0x014A: return 0x014B; + case 0x014C: return 0x014D; + case 0x014E: return 0x014F; + case 0x0150: return 0x0151; + case 0x0152: return 0x0153; + case 0x0154: return 0x0155; + case 0x0156: return 0x0157; + case 0x0158: return 0x0159; + case 0x015A: return 0x015B; + case 0x015C: return 0x015D; + case 0x015E: return 0x015F; + case 0x0160: return 0x0161; + case 0x0162: return 0x0163; + case 0x0164: return 0x0165; + case 0x0166: return 0x0167; + case 0x0168: return 0x0169; + case 0x016A: return 0x016B; + case 0x016C: return 0x016D; + case 0x016E: return 0x016F; + case 0x0170: return 0x0171; + case 0x0172: return 0x0173; + case 0x0174: return 0x0175; + case 0x0176: return 0x0177; + case 0x0178: return 0x00FF; + case 0x0179: return 0x017A; + case 0x017B: return 0x017C; + case 0x017D: return 0x017E; + case 0x0181: return 0x0253; + case 0x0182: return 0x0183; + case 0x0184: return 0x0185; + case 0x0186: return 0x0254; + case 0x0187: return 0x0188; + case 0x0189: return 0x0256; + case 0x018A: return 0x0257; + case 0x018B: return 0x018C; + case 0x018E: return 0x01DD; + case 0x018F: return 0x0259; + case 0x0190: return 0x025B; + case 0x0191: return 0x0192; + case 0x0193: return 0x0260; + case 0x0194: return 0x0263; + case 0x0196: return 0x0269; + case 0x0197: return 0x0268; + case 0x0198: return 0x0199; + case 0x019C: return 0x026F; + case 0x019D: return 0x0272; + case 0x019F: return 0x0275; + case 0x01A0: return 0x01A1; + case 0x01A2: return 0x01A3; + case 0x01A4: return 0x01A5; + case 0x01A6: return 0x0280; + case 0x01A7: return 0x01A8; + case 0x01A9: return 0x0283; + case 0x01AC: return 0x01AD; + case 0x01AE: return 0x0288; + case 0x01AF: return 0x01B0; + case 0x01B1: return 0x028A; + case 0x01B2: return 0x028B; + case 0x01B3: return 0x01B4; + case 0x01B5: return 0x01B6; + case 0x01B7: return 0x0292; + case 0x01B8: return 0x01B9; + case 0x01BC: return 0x01BD; + case 0x01C4: return 0x01C6; + case 0x01C5: return 0x01C6; + case 0x01C7: return 0x01C9; + case 0x01C8: return 0x01C9; + case 0x01CA: return 0x01CC; + case 0x01CB: return 0x01CC; + case 0x01CD: return 0x01CE; + case 0x01CF: return 0x01D0; + case 0x01D1: return 0x01D2; + case 0x01D3: return 0x01D4; + case 0x01D5: return 0x01D6; + case 0x01D7: return 0x01D8; + case 0x01D9: return 0x01DA; + case 0x01DB: return 0x01DC; + case 0x01DE: return 0x01DF; + case 0x01E0: return 0x01E1; + case 0x01E2: return 0x01E3; + case 0x01E4: return 0x01E5; + case 0x01E6: return 0x01E7; + case 0x01E8: return 0x01E9; + case 0x01EA: return 0x01EB; + case 0x01EC: return 0x01ED; + case 0x01EE: return 0x01EF; + case 0x01F1: return 0x01F3; + case 0x01F2: return 0x01F3; + case 0x01F4: return 0x01F5; + case 0x01F6: return 0x0195; + case 0x01F7: return 0x01BF; + case 0x01F8: return 0x01F9; + case 0x01FA: return 0x01FB; + case 0x01FC: return 0x01FD; + case 0x01FE: return 0x01FF; + case 0x0200: return 0x0201; + case 0x0202: return 0x0203; + case 0x0204: return 0x0205; + case 0x0206: return 0x0207; + case 0x0208: return 0x0209; + case 0x020A: return 0x020B; + case 0x020C: return 0x020D; + case 0x020E: return 0x020F; + case 0x0210: return 0x0211; + case 0x0212: return 0x0213; + case 0x0214: return 0x0215; + case 0x0216: return 0x0217; + case 0x0218: return 0x0219; + case 0x021A: return 0x021B; + case 0x021C: return 0x021D; + case 0x021E: return 0x021F; + case 0x0220: return 0x019E; + case 0x0222: return 0x0223; + case 0x0224: return 0x0225; + case 0x0226: return 0x0227; + case 0x0228: return 0x0229; + case 0x022A: return 0x022B; + case 0x022C: return 0x022D; + case 0x022E: return 0x022F; + case 0x0230: return 0x0231; + case 0x0232: return 0x0233; + case 0x023A: return 0x2C65; + case 0x023B: return 0x023C; + case 0x023D: return 0x019A; + case 0x023E: return 0x2C66; + case 0x0241: return 0x0242; + case 0x0243: return 0x0180; + case 0x0244: return 0x0289; + case 0x0245: return 0x028C; + case 0x0246: return 0x0247; + case 0x0248: return 0x0249; + case 0x024A: return 0x024B; + case 0x024C: return 0x024D; + case 0x024E: return 0x024F; + case 0x0370: return 0x0371; + case 0x0372: return 0x0373; + case 0x0376: return 0x0377; + case 0x0386: return 0x03AC; + case 0x0388: return 0x03AD; + case 0x0389: return 0x03AE; + case 0x038A: return 0x03AF; + case 0x038C: return 0x03CC; + case 0x038E: return 0x03CD; + case 0x038F: return 0x03CE; + case 0x0391: return 0x03B1; + case 0x0392: return 0x03B2; + case 0x0393: return 0x03B3; + case 0x0394: return 0x03B4; + case 0x0395: return 0x03B5; + case 0x0396: return 0x03B6; + case 0x0397: return 0x03B7; + case 0x0398: return 0x03B8; + case 0x0399: return 0x03B9; + case 0x039A: return 0x03BA; + case 0x039B: return 0x03BB; + case 0x039C: return 0x03BC; + case 0x039D: return 0x03BD; + case 0x039E: return 0x03BE; + case 0x039F: return 0x03BF; + case 0x03A0: return 0x03C0; + case 0x03A1: return 0x03C1; + case 0x03A3: return 0x03C3; + case 0x03A4: return 0x03C4; + case 0x03A5: return 0x03C5; + case 0x03A6: return 0x03C6; + case 0x03A7: return 0x03C7; + case 0x03A8: return 0x03C8; + case 0x03A9: return 0x03C9; + case 0x03AA: return 0x03CA; + case 0x03AB: return 0x03CB; + case 0x03CF: return 0x03D7; + case 0x03D8: return 0x03D9; + case 0x03DA: return 0x03DB; + case 0x03DC: return 0x03DD; + case 0x03DE: return 0x03DF; + case 0x03E0: return 0x03E1; + case 0x03E2: return 0x03E3; + case 0x03E4: return 0x03E5; + case 0x03E6: return 0x03E7; + case 0x03E8: return 0x03E9; + case 0x03EA: return 0x03EB; + case 0x03EC: return 0x03ED; + case 0x03EE: return 0x03EF; + case 0x03F4: return 0x03B8; + case 0x03F7: return 0x03F8; + case 0x03F9: return 0x03F2; + case 0x03FA: return 0x03FB; + case 0x03FD: return 0x037B; + case 0x03FE: return 0x037C; + case 0x03FF: return 0x037D; + case 0x0400: return 0x0450; + case 0x0401: return 0x0451; + case 0x0402: return 0x0452; + case 0x0403: return 0x0453; + case 0x0404: return 0x0454; + case 0x0405: return 0x0455; + case 0x0406: return 0x0456; + case 0x0407: return 0x0457; + case 0x0408: return 0x0458; + case 0x0409: return 0x0459; + case 0x040A: return 0x045A; + case 0x040B: return 0x045B; + case 0x040C: return 0x045C; + case 0x040D: return 0x045D; + case 0x040E: return 0x045E; + case 0x040F: return 0x045F; + case 0x0410: return 0x0430; + case 0x0411: return 0x0431; + case 0x0412: return 0x0432; + case 0x0413: return 0x0433; + case 0x0414: return 0x0434; + case 0x0415: return 0x0435; + case 0x0416: return 0x0436; + case 0x0417: return 0x0437; + case 0x0418: return 0x0438; + case 0x0419: return 0x0439; + case 0x041A: return 0x043A; + case 0x041B: return 0x043B; + case 0x041C: return 0x043C; + case 0x041D: return 0x043D; + case 0x041E: return 0x043E; + case 0x041F: return 0x043F; + case 0x0420: return 0x0440; + case 0x0421: return 0x0441; + case 0x0422: return 0x0442; + case 0x0423: return 0x0443; + case 0x0424: return 0x0444; + case 0x0425: return 0x0445; + case 0x0426: return 0x0446; + case 0x0427: return 0x0447; + case 0x0428: return 0x0448; + case 0x0429: return 0x0449; + case 0x042A: return 0x044A; + case 0x042B: return 0x044B; + case 0x042C: return 0x044C; + case 0x042D: return 0x044D; + case 0x042E: return 0x044E; + case 0x042F: return 0x044F; + case 0x0460: return 0x0461; + case 0x0462: return 0x0463; + case 0x0464: return 0x0465; + case 0x0466: return 0x0467; + case 0x0468: return 0x0469; + case 0x046A: return 0x046B; + case 0x046C: return 0x046D; + case 0x046E: return 0x046F; + case 0x0470: return 0x0471; + case 0x0472: return 0x0473; + case 0x0474: return 0x0475; + case 0x0476: return 0x0477; + case 0x0478: return 0x0479; + case 0x047A: return 0x047B; + case 0x047C: return 0x047D; + case 0x047E: return 0x047F; + case 0x0480: return 0x0481; + case 0x048A: return 0x048B; + case 0x048C: return 0x048D; + case 0x048E: return 0x048F; + case 0x0490: return 0x0491; + case 0x0492: return 0x0493; + case 0x0494: return 0x0495; + case 0x0496: return 0x0497; + case 0x0498: return 0x0499; + case 0x049A: return 0x049B; + case 0x049C: return 0x049D; + case 0x049E: return 0x049F; + case 0x04A0: return 0x04A1; + case 0x04A2: return 0x04A3; + case 0x04A4: return 0x04A5; + case 0x04A6: return 0x04A7; + case 0x04A8: return 0x04A9; + case 0x04AA: return 0x04AB; + case 0x04AC: return 0x04AD; + case 0x04AE: return 0x04AF; + case 0x04B0: return 0x04B1; + case 0x04B2: return 0x04B3; + case 0x04B4: return 0x04B5; + case 0x04B6: return 0x04B7; + case 0x04B8: return 0x04B9; + case 0x04BA: return 0x04BB; + case 0x04BC: return 0x04BD; + case 0x04BE: return 0x04BF; + case 0x04C0: return 0x04CF; + case 0x04C1: return 0x04C2; + case 0x04C3: return 0x04C4; + case 0x04C5: return 0x04C6; + case 0x04C7: return 0x04C8; + case 0x04C9: return 0x04CA; + case 0x04CB: return 0x04CC; + case 0x04CD: return 0x04CE; + case 0x04D0: return 0x04D1; + case 0x04D2: return 0x04D3; + case 0x04D4: return 0x04D5; + case 0x04D6: return 0x04D7; + case 0x04D8: return 0x04D9; + case 0x04DA: return 0x04DB; + case 0x04DC: return 0x04DD; + case 0x04DE: return 0x04DF; + case 0x04E0: return 0x04E1; + case 0x04E2: return 0x04E3; + case 0x04E4: return 0x04E5; + case 0x04E6: return 0x04E7; + case 0x04E8: return 0x04E9; + case 0x04EA: return 0x04EB; + case 0x04EC: return 0x04ED; + case 0x04EE: return 0x04EF; + case 0x04F0: return 0x04F1; + case 0x04F2: return 0x04F3; + case 0x04F4: return 0x04F5; + case 0x04F6: return 0x04F7; + case 0x04F8: return 0x04F9; + case 0x04FA: return 0x04FB; + case 0x04FC: return 0x04FD; + case 0x04FE: return 0x04FF; + case 0x0500: return 0x0501; + case 0x0502: return 0x0503; + case 0x0504: return 0x0505; + case 0x0506: return 0x0507; + case 0x0508: return 0x0509; + case 0x050A: return 0x050B; + case 0x050C: return 0x050D; + case 0x050E: return 0x050F; + case 0x0510: return 0x0511; + case 0x0512: return 0x0513; + case 0x0514: return 0x0515; + case 0x0516: return 0x0517; + case 0x0518: return 0x0519; + case 0x051A: return 0x051B; + case 0x051C: return 0x051D; + case 0x051E: return 0x051F; + case 0x0520: return 0x0521; + case 0x0522: return 0x0523; + case 0x0524: return 0x0525; + case 0x0526: return 0x0527; + case 0x0531: return 0x0561; + case 0x0532: return 0x0562; + case 0x0533: return 0x0563; + case 0x0534: return 0x0564; + case 0x0535: return 0x0565; + case 0x0536: return 0x0566; + case 0x0537: return 0x0567; + case 0x0538: return 0x0568; + case 0x0539: return 0x0569; + case 0x053A: return 0x056A; + case 0x053B: return 0x056B; + case 0x053C: return 0x056C; + case 0x053D: return 0x056D; + case 0x053E: return 0x056E; + case 0x053F: return 0x056F; + case 0x0540: return 0x0570; + case 0x0541: return 0x0571; + case 0x0542: return 0x0572; + case 0x0543: return 0x0573; + case 0x0544: return 0x0574; + case 0x0545: return 0x0575; + case 0x0546: return 0x0576; + case 0x0547: return 0x0577; + case 0x0548: return 0x0578; + case 0x0549: return 0x0579; + case 0x054A: return 0x057A; + case 0x054B: return 0x057B; + case 0x054C: return 0x057C; + case 0x054D: return 0x057D; + case 0x054E: return 0x057E; + case 0x054F: return 0x057F; + case 0x0550: return 0x0580; + case 0x0551: return 0x0581; + case 0x0552: return 0x0582; + case 0x0553: return 0x0583; + case 0x0554: return 0x0584; + case 0x0555: return 0x0585; + case 0x0556: return 0x0586; + case 0x10A0: return 0x2D00; + case 0x10A1: return 0x2D01; + case 0x10A2: return 0x2D02; + case 0x10A3: return 0x2D03; + case 0x10A4: return 0x2D04; + case 0x10A5: return 0x2D05; + case 0x10A6: return 0x2D06; + case 0x10A7: return 0x2D07; + case 0x10A8: return 0x2D08; + case 0x10A9: return 0x2D09; + case 0x10AA: return 0x2D0A; + case 0x10AB: return 0x2D0B; + case 0x10AC: return 0x2D0C; + case 0x10AD: return 0x2D0D; + case 0x10AE: return 0x2D0E; + case 0x10AF: return 0x2D0F; + case 0x10B0: return 0x2D10; + case 0x10B1: return 0x2D11; + case 0x10B2: return 0x2D12; + case 0x10B3: return 0x2D13; + case 0x10B4: return 0x2D14; + case 0x10B5: return 0x2D15; + case 0x10B6: return 0x2D16; + case 0x10B7: return 0x2D17; + case 0x10B8: return 0x2D18; + case 0x10B9: return 0x2D19; + case 0x10BA: return 0x2D1A; + case 0x10BB: return 0x2D1B; + case 0x10BC: return 0x2D1C; + case 0x10BD: return 0x2D1D; + case 0x10BE: return 0x2D1E; + case 0x10BF: return 0x2D1F; + case 0x10C0: return 0x2D20; + case 0x10C1: return 0x2D21; + case 0x10C2: return 0x2D22; + case 0x10C3: return 0x2D23; + case 0x10C4: return 0x2D24; + case 0x10C5: return 0x2D25; + case 0x1E00: return 0x1E01; + case 0x1E02: return 0x1E03; + case 0x1E04: return 0x1E05; + case 0x1E06: return 0x1E07; + case 0x1E08: return 0x1E09; + case 0x1E0A: return 0x1E0B; + case 0x1E0C: return 0x1E0D; + case 0x1E0E: return 0x1E0F; + case 0x1E10: return 0x1E11; + case 0x1E12: return 0x1E13; + case 0x1E14: return 0x1E15; + case 0x1E16: return 0x1E17; + case 0x1E18: return 0x1E19; + case 0x1E1A: return 0x1E1B; + case 0x1E1C: return 0x1E1D; + case 0x1E1E: return 0x1E1F; + case 0x1E20: return 0x1E21; + case 0x1E22: return 0x1E23; + case 0x1E24: return 0x1E25; + case 0x1E26: return 0x1E27; + case 0x1E28: return 0x1E29; + case 0x1E2A: return 0x1E2B; + case 0x1E2C: return 0x1E2D; + case 0x1E2E: return 0x1E2F; + case 0x1E30: return 0x1E31; + case 0x1E32: return 0x1E33; + case 0x1E34: return 0x1E35; + case 0x1E36: return 0x1E37; + case 0x1E38: return 0x1E39; + case 0x1E3A: return 0x1E3B; + case 0x1E3C: return 0x1E3D; + case 0x1E3E: return 0x1E3F; + case 0x1E40: return 0x1E41; + case 0x1E42: return 0x1E43; + case 0x1E44: return 0x1E45; + case 0x1E46: return 0x1E47; + case 0x1E48: return 0x1E49; + case 0x1E4A: return 0x1E4B; + case 0x1E4C: return 0x1E4D; + case 0x1E4E: return 0x1E4F; + case 0x1E50: return 0x1E51; + case 0x1E52: return 0x1E53; + case 0x1E54: return 0x1E55; + case 0x1E56: return 0x1E57; + case 0x1E58: return 0x1E59; + case 0x1E5A: return 0x1E5B; + case 0x1E5C: return 0x1E5D; + case 0x1E5E: return 0x1E5F; + case 0x1E60: return 0x1E61; + case 0x1E62: return 0x1E63; + case 0x1E64: return 0x1E65; + case 0x1E66: return 0x1E67; + case 0x1E68: return 0x1E69; + case 0x1E6A: return 0x1E6B; + case 0x1E6C: return 0x1E6D; + case 0x1E6E: return 0x1E6F; + case 0x1E70: return 0x1E71; + case 0x1E72: return 0x1E73; + case 0x1E74: return 0x1E75; + case 0x1E76: return 0x1E77; + case 0x1E78: return 0x1E79; + case 0x1E7A: return 0x1E7B; + case 0x1E7C: return 0x1E7D; + case 0x1E7E: return 0x1E7F; + case 0x1E80: return 0x1E81; + case 0x1E82: return 0x1E83; + case 0x1E84: return 0x1E85; + case 0x1E86: return 0x1E87; + case 0x1E88: return 0x1E89; + case 0x1E8A: return 0x1E8B; + case 0x1E8C: return 0x1E8D; + case 0x1E8E: return 0x1E8F; + case 0x1E90: return 0x1E91; + case 0x1E92: return 0x1E93; + case 0x1E94: return 0x1E95; + case 0x1E9E: return 0x00DF; + case 0x1EA0: return 0x1EA1; + case 0x1EA2: return 0x1EA3; + case 0x1EA4: return 0x1EA5; + case 0x1EA6: return 0x1EA7; + case 0x1EA8: return 0x1EA9; + case 0x1EAA: return 0x1EAB; + case 0x1EAC: return 0x1EAD; + case 0x1EAE: return 0x1EAF; + case 0x1EB0: return 0x1EB1; + case 0x1EB2: return 0x1EB3; + case 0x1EB4: return 0x1EB5; + case 0x1EB6: return 0x1EB7; + case 0x1EB8: return 0x1EB9; + case 0x1EBA: return 0x1EBB; + case 0x1EBC: return 0x1EBD; + case 0x1EBE: return 0x1EBF; + case 0x1EC0: return 0x1EC1; + case 0x1EC2: return 0x1EC3; + case 0x1EC4: return 0x1EC5; + case 0x1EC6: return 0x1EC7; + case 0x1EC8: return 0x1EC9; + case 0x1ECA: return 0x1ECB; + case 0x1ECC: return 0x1ECD; + case 0x1ECE: return 0x1ECF; + case 0x1ED0: return 0x1ED1; + case 0x1ED2: return 0x1ED3; + case 0x1ED4: return 0x1ED5; + case 0x1ED6: return 0x1ED7; + case 0x1ED8: return 0x1ED9; + case 0x1EDA: return 0x1EDB; + case 0x1EDC: return 0x1EDD; + case 0x1EDE: return 0x1EDF; + case 0x1EE0: return 0x1EE1; + case 0x1EE2: return 0x1EE3; + case 0x1EE4: return 0x1EE5; + case 0x1EE6: return 0x1EE7; + case 0x1EE8: return 0x1EE9; + case 0x1EEA: return 0x1EEB; + case 0x1EEC: return 0x1EED; + case 0x1EEE: return 0x1EEF; + case 0x1EF0: return 0x1EF1; + case 0x1EF2: return 0x1EF3; + case 0x1EF4: return 0x1EF5; + case 0x1EF6: return 0x1EF7; + case 0x1EF8: return 0x1EF9; + case 0x1EFA: return 0x1EFB; + case 0x1EFC: return 0x1EFD; + case 0x1EFE: return 0x1EFF; + case 0x1F08: return 0x1F00; + case 0x1F09: return 0x1F01; + case 0x1F0A: return 0x1F02; + case 0x1F0B: return 0x1F03; + case 0x1F0C: return 0x1F04; + case 0x1F0D: return 0x1F05; + case 0x1F0E: return 0x1F06; + case 0x1F0F: return 0x1F07; + case 0x1F18: return 0x1F10; + case 0x1F19: return 0x1F11; + case 0x1F1A: return 0x1F12; + case 0x1F1B: return 0x1F13; + case 0x1F1C: return 0x1F14; + case 0x1F1D: return 0x1F15; + case 0x1F28: return 0x1F20; + case 0x1F29: return 0x1F21; + case 0x1F2A: return 0x1F22; + case 0x1F2B: return 0x1F23; + case 0x1F2C: return 0x1F24; + case 0x1F2D: return 0x1F25; + case 0x1F2E: return 0x1F26; + case 0x1F2F: return 0x1F27; + case 0x1F38: return 0x1F30; + case 0x1F39: return 0x1F31; + case 0x1F3A: return 0x1F32; + case 0x1F3B: return 0x1F33; + case 0x1F3C: return 0x1F34; + case 0x1F3D: return 0x1F35; + case 0x1F3E: return 0x1F36; + case 0x1F3F: return 0x1F37; + case 0x1F48: return 0x1F40; + case 0x1F49: return 0x1F41; + case 0x1F4A: return 0x1F42; + case 0x1F4B: return 0x1F43; + case 0x1F4C: return 0x1F44; + case 0x1F4D: return 0x1F45; + case 0x1F59: return 0x1F51; + case 0x1F5B: return 0x1F53; + case 0x1F5D: return 0x1F55; + case 0x1F5F: return 0x1F57; + case 0x1F68: return 0x1F60; + case 0x1F69: return 0x1F61; + case 0x1F6A: return 0x1F62; + case 0x1F6B: return 0x1F63; + case 0x1F6C: return 0x1F64; + case 0x1F6D: return 0x1F65; + case 0x1F6E: return 0x1F66; + case 0x1F6F: return 0x1F67; + case 0x1F88: return 0x1F80; + case 0x1F89: return 0x1F81; + case 0x1F8A: return 0x1F82; + case 0x1F8B: return 0x1F83; + case 0x1F8C: return 0x1F84; + case 0x1F8D: return 0x1F85; + case 0x1F8E: return 0x1F86; + case 0x1F8F: return 0x1F87; + case 0x1F98: return 0x1F90; + case 0x1F99: return 0x1F91; + case 0x1F9A: return 0x1F92; + case 0x1F9B: return 0x1F93; + case 0x1F9C: return 0x1F94; + case 0x1F9D: return 0x1F95; + case 0x1F9E: return 0x1F96; + case 0x1F9F: return 0x1F97; + case 0x1FA8: return 0x1FA0; + case 0x1FA9: return 0x1FA1; + case 0x1FAA: return 0x1FA2; + case 0x1FAB: return 0x1FA3; + case 0x1FAC: return 0x1FA4; + case 0x1FAD: return 0x1FA5; + case 0x1FAE: return 0x1FA6; + case 0x1FAF: return 0x1FA7; + case 0x1FB8: return 0x1FB0; + case 0x1FB9: return 0x1FB1; + case 0x1FBA: return 0x1F70; + case 0x1FBB: return 0x1F71; + case 0x1FBC: return 0x1FB3; + case 0x1FC8: return 0x1F72; + case 0x1FC9: return 0x1F73; + case 0x1FCA: return 0x1F74; + case 0x1FCB: return 0x1F75; + case 0x1FCC: return 0x1FC3; + case 0x1FD8: return 0x1FD0; + case 0x1FD9: return 0x1FD1; + case 0x1FDA: return 0x1F76; + case 0x1FDB: return 0x1F77; + case 0x1FE8: return 0x1FE0; + case 0x1FE9: return 0x1FE1; + case 0x1FEA: return 0x1F7A; + case 0x1FEB: return 0x1F7B; + case 0x1FEC: return 0x1FE5; + case 0x1FF8: return 0x1F78; + case 0x1FF9: return 0x1F79; + case 0x1FFA: return 0x1F7C; + case 0x1FFB: return 0x1F7D; + case 0x1FFC: return 0x1FF3; + case 0x2126: return 0x03C9; + case 0x212A: return 0x006B; + case 0x212B: return 0x00E5; + case 0x2132: return 0x214E; + case 0x2160: return 0x2170; + case 0x2161: return 0x2171; + case 0x2162: return 0x2172; + case 0x2163: return 0x2173; + case 0x2164: return 0x2174; + case 0x2165: return 0x2175; + case 0x2166: return 0x2176; + case 0x2167: return 0x2177; + case 0x2168: return 0x2178; + case 0x2169: return 0x2179; + case 0x216A: return 0x217A; + case 0x216B: return 0x217B; + case 0x216C: return 0x217C; + case 0x216D: return 0x217D; + case 0x216E: return 0x217E; + case 0x216F: return 0x217F; + case 0x2183: return 0x2184; + case 0x24B6: return 0x24D0; + case 0x24B7: return 0x24D1; + case 0x24B8: return 0x24D2; + case 0x24B9: return 0x24D3; + case 0x24BA: return 0x24D4; + case 0x24BB: return 0x24D5; + case 0x24BC: return 0x24D6; + case 0x24BD: return 0x24D7; + case 0x24BE: return 0x24D8; + case 0x24BF: return 0x24D9; + case 0x24C0: return 0x24DA; + case 0x24C1: return 0x24DB; + case 0x24C2: return 0x24DC; + case 0x24C3: return 0x24DD; + case 0x24C4: return 0x24DE; + case 0x24C5: return 0x24DF; + case 0x24C6: return 0x24E0; + case 0x24C7: return 0x24E1; + case 0x24C8: return 0x24E2; + case 0x24C9: return 0x24E3; + case 0x24CA: return 0x24E4; + case 0x24CB: return 0x24E5; + case 0x24CC: return 0x24E6; + case 0x24CD: return 0x24E7; + case 0x24CE: return 0x24E8; + case 0x24CF: return 0x24E9; + case 0x2C00: return 0x2C30; + case 0x2C01: return 0x2C31; + case 0x2C02: return 0x2C32; + case 0x2C03: return 0x2C33; + case 0x2C04: return 0x2C34; + case 0x2C05: return 0x2C35; + case 0x2C06: return 0x2C36; + case 0x2C07: return 0x2C37; + case 0x2C08: return 0x2C38; + case 0x2C09: return 0x2C39; + case 0x2C0A: return 0x2C3A; + case 0x2C0B: return 0x2C3B; + case 0x2C0C: return 0x2C3C; + case 0x2C0D: return 0x2C3D; + case 0x2C0E: return 0x2C3E; + case 0x2C0F: return 0x2C3F; + case 0x2C10: return 0x2C40; + case 0x2C11: return 0x2C41; + case 0x2C12: return 0x2C42; + case 0x2C13: return 0x2C43; + case 0x2C14: return 0x2C44; + case 0x2C15: return 0x2C45; + case 0x2C16: return 0x2C46; + case 0x2C17: return 0x2C47; + case 0x2C18: return 0x2C48; + case 0x2C19: return 0x2C49; + case 0x2C1A: return 0x2C4A; + case 0x2C1B: return 0x2C4B; + case 0x2C1C: return 0x2C4C; + case 0x2C1D: return 0x2C4D; + case 0x2C1E: return 0x2C4E; + case 0x2C1F: return 0x2C4F; + case 0x2C20: return 0x2C50; + case 0x2C21: return 0x2C51; + case 0x2C22: return 0x2C52; + case 0x2C23: return 0x2C53; + case 0x2C24: return 0x2C54; + case 0x2C25: return 0x2C55; + case 0x2C26: return 0x2C56; + case 0x2C27: return 0x2C57; + case 0x2C28: return 0x2C58; + case 0x2C29: return 0x2C59; + case 0x2C2A: return 0x2C5A; + case 0x2C2B: return 0x2C5B; + case 0x2C2C: return 0x2C5C; + case 0x2C2D: return 0x2C5D; + case 0x2C2E: return 0x2C5E; + case 0x2C60: return 0x2C61; + case 0x2C62: return 0x026B; + case 0x2C63: return 0x1D7D; + case 0x2C64: return 0x027D; + case 0x2C67: return 0x2C68; + case 0x2C69: return 0x2C6A; + case 0x2C6B: return 0x2C6C; + case 0x2C6D: return 0x0251; + case 0x2C6E: return 0x0271; + case 0x2C6F: return 0x0250; + case 0x2C70: return 0x0252; + case 0x2C72: return 0x2C73; + case 0x2C75: return 0x2C76; + case 0x2C7E: return 0x023F; + case 0x2C7F: return 0x0240; + case 0x2C80: return 0x2C81; + case 0x2C82: return 0x2C83; + case 0x2C84: return 0x2C85; + case 0x2C86: return 0x2C87; + case 0x2C88: return 0x2C89; + case 0x2C8A: return 0x2C8B; + case 0x2C8C: return 0x2C8D; + case 0x2C8E: return 0x2C8F; + case 0x2C90: return 0x2C91; + case 0x2C92: return 0x2C93; + case 0x2C94: return 0x2C95; + case 0x2C96: return 0x2C97; + case 0x2C98: return 0x2C99; + case 0x2C9A: return 0x2C9B; + case 0x2C9C: return 0x2C9D; + case 0x2C9E: return 0x2C9F; + case 0x2CA0: return 0x2CA1; + case 0x2CA2: return 0x2CA3; + case 0x2CA4: return 0x2CA5; + case 0x2CA6: return 0x2CA7; + case 0x2CA8: return 0x2CA9; + case 0x2CAA: return 0x2CAB; + case 0x2CAC: return 0x2CAD; + case 0x2CAE: return 0x2CAF; + case 0x2CB0: return 0x2CB1; + case 0x2CB2: return 0x2CB3; + case 0x2CB4: return 0x2CB5; + case 0x2CB6: return 0x2CB7; + case 0x2CB8: return 0x2CB9; + case 0x2CBA: return 0x2CBB; + case 0x2CBC: return 0x2CBD; + case 0x2CBE: return 0x2CBF; + case 0x2CC0: return 0x2CC1; + case 0x2CC2: return 0x2CC3; + case 0x2CC4: return 0x2CC5; + case 0x2CC6: return 0x2CC7; + case 0x2CC8: return 0x2CC9; + case 0x2CCA: return 0x2CCB; + case 0x2CCC: return 0x2CCD; + case 0x2CCE: return 0x2CCF; + case 0x2CD0: return 0x2CD1; + case 0x2CD2: return 0x2CD3; + case 0x2CD4: return 0x2CD5; + case 0x2CD6: return 0x2CD7; + case 0x2CD8: return 0x2CD9; + case 0x2CDA: return 0x2CDB; + case 0x2CDC: return 0x2CDD; + case 0x2CDE: return 0x2CDF; + case 0x2CE0: return 0x2CE1; + case 0x2CE2: return 0x2CE3; + case 0x2CEB: return 0x2CEC; + case 0x2CED: return 0x2CEE; + case 0xA640: return 0xA641; + case 0xA642: return 0xA643; + case 0xA644: return 0xA645; + case 0xA646: return 0xA647; + case 0xA648: return 0xA649; + case 0xA64A: return 0xA64B; + case 0xA64C: return 0xA64D; + case 0xA64E: return 0xA64F; + case 0xA650: return 0xA651; + case 0xA652: return 0xA653; + case 0xA654: return 0xA655; + case 0xA656: return 0xA657; + case 0xA658: return 0xA659; + case 0xA65A: return 0xA65B; + case 0xA65C: return 0xA65D; + case 0xA65E: return 0xA65F; + case 0xA660: return 0xA661; + case 0xA662: return 0xA663; + case 0xA664: return 0xA665; + case 0xA666: return 0xA667; + case 0xA668: return 0xA669; + case 0xA66A: return 0xA66B; + case 0xA66C: return 0xA66D; + case 0xA680: return 0xA681; + case 0xA682: return 0xA683; + case 0xA684: return 0xA685; + case 0xA686: return 0xA687; + case 0xA688: return 0xA689; + case 0xA68A: return 0xA68B; + case 0xA68C: return 0xA68D; + case 0xA68E: return 0xA68F; + case 0xA690: return 0xA691; + case 0xA692: return 0xA693; + case 0xA694: return 0xA695; + case 0xA696: return 0xA697; + case 0xA722: return 0xA723; + case 0xA724: return 0xA725; + case 0xA726: return 0xA727; + case 0xA728: return 0xA729; + case 0xA72A: return 0xA72B; + case 0xA72C: return 0xA72D; + case 0xA72E: return 0xA72F; + case 0xA732: return 0xA733; + case 0xA734: return 0xA735; + case 0xA736: return 0xA737; + case 0xA738: return 0xA739; + case 0xA73A: return 0xA73B; + case 0xA73C: return 0xA73D; + case 0xA73E: return 0xA73F; + case 0xA740: return 0xA741; + case 0xA742: return 0xA743; + case 0xA744: return 0xA745; + case 0xA746: return 0xA747; + case 0xA748: return 0xA749; + case 0xA74A: return 0xA74B; + case 0xA74C: return 0xA74D; + case 0xA74E: return 0xA74F; + case 0xA750: return 0xA751; + case 0xA752: return 0xA753; + case 0xA754: return 0xA755; + case 0xA756: return 0xA757; + case 0xA758: return 0xA759; + case 0xA75A: return 0xA75B; + case 0xA75C: return 0xA75D; + case 0xA75E: return 0xA75F; + case 0xA760: return 0xA761; + case 0xA762: return 0xA763; + case 0xA764: return 0xA765; + case 0xA766: return 0xA767; + case 0xA768: return 0xA769; + case 0xA76A: return 0xA76B; + case 0xA76C: return 0xA76D; + case 0xA76E: return 0xA76F; + case 0xA779: return 0xA77A; + case 0xA77B: return 0xA77C; + case 0xA77D: return 0x1D79; + case 0xA77E: return 0xA77F; + case 0xA780: return 0xA781; + case 0xA782: return 0xA783; + case 0xA784: return 0xA785; + case 0xA786: return 0xA787; + case 0xA78B: return 0xA78C; + case 0xA78D: return 0x0265; + case 0xA790: return 0xA791; + case 0xA7A0: return 0xA7A1; + case 0xA7A2: return 0xA7A3; + case 0xA7A4: return 0xA7A5; + case 0xA7A6: return 0xA7A7; + case 0xA7A8: return 0xA7A9; + case 0xFF21: return 0xFF41; + case 0xFF22: return 0xFF42; + case 0xFF23: return 0xFF43; + case 0xFF24: return 0xFF44; + case 0xFF25: return 0xFF45; + case 0xFF26: return 0xFF46; + case 0xFF27: return 0xFF47; + case 0xFF28: return 0xFF48; + case 0xFF29: return 0xFF49; + case 0xFF2A: return 0xFF4A; + case 0xFF2B: return 0xFF4B; + case 0xFF2C: return 0xFF4C; + case 0xFF2D: return 0xFF4D; + case 0xFF2E: return 0xFF4E; + case 0xFF2F: return 0xFF4F; + case 0xFF30: return 0xFF50; + case 0xFF31: return 0xFF51; + case 0xFF32: return 0xFF52; + case 0xFF33: return 0xFF53; + case 0xFF34: return 0xFF54; + case 0xFF35: return 0xFF55; + case 0xFF36: return 0xFF56; + case 0xFF37: return 0xFF57; + case 0xFF38: return 0xFF58; + case 0xFF39: return 0xFF59; + case 0xFF3A: return 0xFF5A; + case 0x10400: return 0x10428; + case 0x10401: return 0x10429; + case 0x10402: return 0x1042A; + case 0x10403: return 0x1042B; + case 0x10404: return 0x1042C; + case 0x10405: return 0x1042D; + case 0x10406: return 0x1042E; + case 0x10407: return 0x1042F; + case 0x10408: return 0x10430; + case 0x10409: return 0x10431; + case 0x1040A: return 0x10432; + case 0x1040B: return 0x10433; + case 0x1040C: return 0x10434; + case 0x1040D: return 0x10435; + case 0x1040E: return 0x10436; + case 0x1040F: return 0x10437; + case 0x10410: return 0x10438; + case 0x10411: return 0x10439; + case 0x10412: return 0x1043A; + case 0x10413: return 0x1043B; + case 0x10414: return 0x1043C; + case 0x10415: return 0x1043D; + case 0x10416: return 0x1043E; + case 0x10417: return 0x1043F; + case 0x10418: return 0x10440; + case 0x10419: return 0x10441; + case 0x1041A: return 0x10442; + case 0x1041B: return 0x10443; + case 0x1041C: return 0x10444; + case 0x1041D: return 0x10445; + case 0x1041E: return 0x10446; + case 0x1041F: return 0x10447; + case 0x10420: return 0x10448; + case 0x10421: return 0x10449; + case 0x10422: return 0x1044A; + case 0x10423: return 0x1044B; + case 0x10424: return 0x1044C; + case 0x10425: return 0x1044D; + case 0x10426: return 0x1044E; + case 0x10427: return 0x1044F; + default: return ch; + } +} diff --git a/app/jni/utf8lib.h b/app/jni/utf8lib.h new file mode 100644 index 0000000..543fbfc --- /dev/null +++ b/app/jni/utf8lib.h @@ -0,0 +1,67 @@ +/* + * UTF-8 utility functions for DarkPlaces + */ +#ifndef UTF8LIB_H__ +#define UTF8LIB_H__ + +#include "qtypes.h" + +// types for unicode strings +// let them be 32 bit for now +// normally, whcar_t is 16 or 32 bit, 16 on linux I think, 32 on haiku and maybe windows +#ifdef _MSC_VER +typedef __int32 U_int32; +#else +#include +#include +typedef int32_t U_int32; +#endif + +// Uchar, a wide character +typedef U_int32 Uchar; + +// Initialize UTF8, this registers cvars which allows for UTF8 to be disabled +// completely. +// When UTF8 is disabled, every u8_ function will work exactly as you'd expect +// a non-utf8 version to work: u8_strlen() will wrap to strlen() +// u8_byteofs() and u8_charidx() will simply return whatever is passed as index parameter +// u8_getchar() will will just return the next byte, u8_fromchar will write one byte, ... +extern cvar_t utf8_enable; +void u8_Init(void); + +size_t u8_strlen(const char*); +size_t u8_strnlen(const char*, size_t); +int u8_byteofs(const char*, size_t, size_t*); +int u8_charidx(const char*, size_t, size_t*); +size_t u8_bytelen(const char*, size_t); +size_t u8_prevbyte(const char*, size_t); +Uchar u8_getchar_utf8_enabled(const char*, const char**); +Uchar u8_getnchar_utf8_enabled(const char*, const char**, size_t); +int u8_fromchar(Uchar, char*, size_t); +size_t u8_mbstowcs(Uchar *, const char *, size_t); +size_t u8_wcstombs(char*, const Uchar*, size_t); +size_t u8_COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid); + +// returns a static buffer, use this for inlining +char *u8_encodech(Uchar ch, size_t*, char*buf16); + +size_t u8_strpad(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth); +size_t u8_strpad_colorcodes(char *out, size_t outsize, const char *in, qboolean leftalign, size_t minwidth, size_t maxwidth); + +/* Careful: if we disable utf8 but not freetype, we wish to see freetype chars + * for normal letters. So use E000+x for special chars, but leave the freetype stuff for the + * rest: + */ +extern Uchar u8_quake2utf8map[256]; +// these defines get a bit tricky, as c and e may be aliased to the same variable +#define u8_getchar(c,e) (utf8_enable.integer ? u8_getchar_utf8_enabled(c,e) : (u8_quake2utf8map[(unsigned char)(*(e) = (c) + 1)[-1]])) +#define u8_getchar_noendptr(c) (utf8_enable.integer ? u8_getchar_utf8_enabled(c,NULL) : (u8_quake2utf8map[(unsigned char)*(c)])) +#define u8_getchar_check(c,e) ((e) ? u8_getchar((c),(e)) : u8_getchar_noendptr((c))) +#define u8_getnchar(c,e,n) (utf8_enable.integer ? u8_getnchar_utf8_enabled(c,e,n) : ((n) <= 0 ? ((*(e) = c), 0) : (u8_quake2utf8map[(unsigned char)(*(e) = (c) + 1)[-1]]))) +#define u8_getnchar_noendptr(c,n) (utf8_enable.integer ? u8_getnchar_utf8_enabled(c,NULL,n) : ((n) <= 0 ? 0 : (u8_quake2utf8map[(unsigned char)*(c)]))) +#define u8_getnchar_check(c,e,n) ((e) ? u8_getchar((c),(e),(n)) : u8_getchar_noendptr((c),(n))) + +Uchar u8_toupper(Uchar ch); +Uchar u8_tolower(Uchar ch); + +#endif // UTF8LIB_H__ diff --git a/app/jni/vid.h b/app/jni/vid.h new file mode 100644 index 0000000..1b960d4 --- /dev/null +++ b/app/jni/vid.h @@ -0,0 +1,296 @@ +/* +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 + +#ifndef VID_H +#define VID_H + +#define ENGINE_ICON ( (gamemode == GAME_NEXUIZ) ? nexuiz_xpm : darkplaces_xpm ) + +extern int cl_available; + +#define MAX_TEXTUREUNITS 16 + +typedef enum renderpath_e +{ + RENDERPATH_GL11, + RENDERPATH_GL13, + RENDERPATH_GL20, + RENDERPATH_D3D9, + RENDERPATH_D3D10, + RENDERPATH_D3D11, + RENDERPATH_SOFT, + RENDERPATH_GLES1, + RENDERPATH_GLES2 +} +renderpath_t; + +typedef struct viddef_support_s +{ + qboolean gl20shaders; + qboolean gl20shaders130; // indicates glBindFragDataLocation is available + int glshaderversion; // typical values: 100 110 120 130 140 ... + qboolean amd_texture_texture4; + qboolean arb_depth_texture; + qboolean arb_draw_buffers; + qboolean arb_framebuffer_object; + qboolean arb_multitexture; + qboolean arb_occlusion_query; + qboolean arb_shadow; + qboolean arb_texture_compression; + qboolean arb_texture_cube_map; + qboolean arb_texture_env_combine; + qboolean arb_texture_gather; + qboolean arb_texture_non_power_of_two; + qboolean arb_vertex_buffer_object; + qboolean arb_uniform_buffer_object; + qboolean ati_separate_stencil; + qboolean ext_blend_minmax; + qboolean ext_blend_subtract; + qboolean ext_draw_range_elements; + qboolean ext_framebuffer_object; + qboolean ext_packed_depth_stencil; + qboolean ext_stencil_two_side; + qboolean ext_texture_3d; + qboolean ext_texture_compression_s3tc; + qboolean ext_texture_edge_clamp; + qboolean ext_texture_filter_anisotropic; + qboolean ext_texture_srgb; + qboolean arb_multisample; +} +viddef_support_t; + +typedef struct viddef_mode_s +{ + int width; + int height; + int bitsperpixel; + qboolean fullscreen; + float refreshrate; + qboolean userefreshrate; + qboolean stereobuffer; + int samples; +} +viddef_mode_t; + +typedef struct viddef_s +{ + // these are set by VID_Mode + viddef_mode_t mode; + // used in many locations in the renderer + int width; + int height; + int bitsperpixel; + qboolean fullscreen; + float refreshrate; + qboolean userefreshrate; + qboolean stereobuffer; + int samples; + qboolean stencil; + qboolean sRGB2D; // whether 2D rendering is sRGB corrected (based on sRGBcapable2D) + qboolean sRGB3D; // whether 3D rendering is sRGB corrected (based on sRGBcapable3D) + qboolean sRGBcapable2D; // whether 2D rendering can be sRGB corrected (renderpath, v_hwgamma) + qboolean sRGBcapable3D; // whether 3D rendering can be sRGB corrected (renderpath, v_hwgamma) + + renderpath_t renderpath; + qboolean forcevbo; // some renderpaths can not operate without it + qboolean useinterleavedarrays; // required by some renderpaths + qboolean allowalphatocoverage; // indicates the GL_AlphaToCoverage function works on this renderpath and framebuffer + + unsigned int texunits; + unsigned int teximageunits; + unsigned int texarrayunits; + unsigned int drawrangeelements_maxvertices; + unsigned int drawrangeelements_maxindices; + + unsigned int maxtexturesize_2d; + unsigned int maxtexturesize_3d; + unsigned int maxtexturesize_cubemap; + unsigned int max_anisotropy; + unsigned int maxdrawbuffers; + + viddef_support_t support; + + // in RENDERPATH_SOFT this is a 32bpp native-endian ARGB framebuffer + // (native-endian ARGB meaning that in little endian it is BGRA bytes, + // in big endian it is ARGB byte order, the format is converted during + // blit to the window) + unsigned int *softpixels; + unsigned int *softdepthpixels; + + int forcetextype; // always use GL_BGRA for D3D, always use GL_RGBA for GLES, etc +} viddef_t; + +// global video state +extern viddef_t vid; +extern void (*vid_menudrawfn)(void); +extern void (*vid_menukeyfn)(int key); + +#define MAXJOYAXIS 16 +// if this is changed, the corresponding code in vid_shared.c must be updated +#define MAXJOYBUTTON 36 +typedef struct vid_joystate_s +{ + float axis[MAXJOYAXIS]; // -1 to +1 + unsigned char button[MAXJOYBUTTON]; // 0 or 1 + qboolean is360; // indicates this joystick is a Microsoft Xbox 360 Controller For Windows +} +vid_joystate_t; + +extern vid_joystate_t vid_joystate; + +extern cvar_t joy_index; +extern cvar_t joy_enable; +extern cvar_t joy_detected; +extern cvar_t joy_active; + +float VID_JoyState_GetAxis(const vid_joystate_t *joystate, int axis, float sensitivity, float deadzone); +void VID_ApplyJoyState(vid_joystate_t *joystate); +void VID_BuildJoyState(vid_joystate_t *joystate); +void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate); +void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate); +int VID_Shared_SetJoystick(int index); +qboolean VID_JoyBlockEmulatedKeys(int keycode); +void VID_EnableJoystick(qboolean enable); + +extern qboolean vid_hidden; +extern qboolean vid_activewindow; +extern cvar_t vid_hardwaregammasupported; +extern qboolean vid_usinghwgamma; +extern qboolean vid_supportrefreshrate; + +extern cvar_t vid_soft; +extern cvar_t vid_soft_threads; +extern cvar_t vid_soft_interlace; + +extern cvar_t vid_fullscreen; +extern cvar_t vid_width; +extern cvar_t vid_height; +extern cvar_t vid_bitsperpixel; +extern cvar_t vid_samples; +extern cvar_t vid_refreshrate; +extern cvar_t vid_userefreshrate; +extern cvar_t vid_vsync; +extern cvar_t vid_mouse; +extern cvar_t vid_grabkeyboard; +extern cvar_t vid_touchscreen; +extern cvar_t vid_stick_mouse; +extern cvar_t vid_resizable; +extern cvar_t vid_minwidth; +extern cvar_t vid_minheight; +extern cvar_t vid_sRGB; +extern cvar_t vid_sRGB_fallback; + +extern cvar_t gl_finish; + +extern cvar_t v_gamma; +extern cvar_t v_contrast; +extern cvar_t v_brightness; +extern cvar_t v_color_enable; +extern cvar_t v_color_black_r; +extern cvar_t v_color_black_g; +extern cvar_t v_color_black_b; +extern cvar_t v_color_grey_r; +extern cvar_t v_color_grey_g; +extern cvar_t v_color_grey_b; +extern cvar_t v_color_white_r; +extern cvar_t v_color_white_g; +extern cvar_t v_color_white_b; +extern cvar_t v_hwgamma; + +// brand of graphics chip +extern const char *gl_vendor; +// graphics chip model and other information +extern const char *gl_renderer; +// begins with 1.0.0, 1.1.0, 1.2.0, 1.2.1, 1.3.0, 1.3.1, or 1.4.0 +extern const char *gl_version; +// extensions list, space separated +extern const char *gl_extensions; +// WGL, GLX, or AGL +extern const char *gl_platform; +// another extensions list, containing platform-specific extensions that are +// not in the main list +extern const char *gl_platformextensions; +// name of driver library (opengl32.dll, libGL.so.1, or whatever) +extern char gl_driver[256]; + +void *GL_GetProcAddress(const char *name); +qboolean GL_CheckExtension(const char *minglver_or_ext, const dllfunction_t *funcs, const char *disableparm, int silent); + +void VID_Shared_Init(void); + +void GL_Init (void); + +void VID_ClearExtensions(void); +void VID_CheckExtensions(void); + +void VID_Init (void); +// Called at startup + +void VID_Shutdown (void); +// Called at shutdown + +int VID_SetMode (int modenum); +// sets the mode; only used by the Quake engine for resetting to mode 0 (the +// base mode) on memory allocation failures + +qboolean VID_InitMode(viddef_mode_t *mode); +// allocates and opens an appropriate OpenGL context (and its window) + + +// sets hardware gamma correction, returns false if the device does not +// support gamma control +// (ONLY called by VID_UpdateGamma and VID_RestoreSystemGamma) +int VID_SetGamma(unsigned short *ramps, int rampsize); +// gets hardware gamma correction, returns false if the device does not +// support gamma control +// (ONLY called by VID_UpdateGamma and VID_RestoreSystemGamma) +int VID_GetGamma(unsigned short *ramps, int rampsize); +// makes sure ramp arrays are big enough and calls VID_GetGamma/VID_SetGamma +// (ONLY to be called from VID_Finish!) +void VID_UpdateGamma(qboolean force, int rampsize); +// turns off hardware gamma ramps immediately +// (called from various shutdown/deactivation functions) +void VID_RestoreSystemGamma(void); + +void VID_SetMouse (qboolean fullscreengrab, qboolean relative, qboolean hidecursor); +void VID_Finish (void); + +void VID_Restart_f(void); + +void VID_Start(void); +void VID_Stop(void); + +extern unsigned int vid_gammatables_serial; // so other subsystems can poll if gamma parameters have changed; this starts with 0 and gets increased by 1 each time the gamma parameters get changed and VID_BuildGammaTables should be called again +extern qboolean vid_gammatables_trivial; // this is set to true if all color control values are at default setting, and it therefore would make no sense to use the gamma table +void VID_BuildGammaTables(unsigned short *ramps, int rampsize); // builds the current gamma tables into an array (needs 3*rampsize items) + +typedef struct +{ + int width, height, bpp, refreshrate; + int pixelheight_num, pixelheight_denom; +} +vid_mode_t; +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount); +size_t VID_SortModes(vid_mode_t *modes, size_t count, qboolean usebpp, qboolean userefreshrate, qboolean useaspect); +void VID_Soft_SharedSetup(void); + +#endif + diff --git a/app/jni/vid_android.c b/app/jni/vid_android.c new file mode 100644 index 0000000..57e6e45 --- /dev/null +++ b/app/jni/vid_android.c @@ -0,0 +1,592 @@ +/* +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 +//#include +#include + +int cl_available = true; + +static long oldtime=0; + +qboolean vid_supportrefreshrate = false; +extern int vrMode; + + +void VID_Shutdown(void) +{ +} + +static void signal_handler(int sig) +{ + Con_Printf("Received signal %d, exiting...\n", sig); + Sys_Quit(1); +} + +static void InitSig(void) +{ + //Nope, I want a logcat backtrace. + /*signal(SIGHUP, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGTRAP, signal_handler); + signal(SIGIOT, signal_handler); + signal(SIGBUS, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler);*/ +} + +void qglBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +{ +//Nope.avi +} + +void qglUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +{ +//Nope.avi +} + +GLuint qglGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) +{ +//Nope.avi +return 0; +} + +void glLoadMatrixf(const GLfloat *m) +{ +//Nope.avi +} + +void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ +//Nope.avi +} + +void glClientActiveTexture(GLenum target) +{ +//Nope.avi +} + +void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) +{ +//Nope.avi +} + +void qglBindFramebuffer(GLenum target, GLuint framebuffer) +{ +glBindFramebuffer(target, framebuffer); +} + +void qglBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ +glBindRenderbuffer(target, renderbuffer); +} + +void qglDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) +{ +glDeleteRenderbuffers(n, renderbuffers); +} + +void qglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ +glDeleteFramebuffers(n, framebuffers); +} + +void qglGenFramebuffers(GLsizei n, GLuint *framebuffers) +{ +glGenFramebuffers(n, framebuffers); +} + +GLenum qglCheckFramebufferStatus(GLenum target) +{ +return glCheckFramebufferStatus(target); +} + +void qglGenRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ +glGenRenderbuffers(n, renderbuffers); +} + +void qglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ +glRenderbufferStorage(target, internalformat, width, height); +} + +void VID_SetMouse (qboolean fullscreengrab, qboolean relative, qboolean hidecursor) +{ +} + +bool scndswp=0; +void VID_Finish (void) +{ +//if (scndswp) eglSwapBuffers(eglGetCurrentDisplay(), eglGetCurrentSurface(EGL_DRAW)); +scndswp=1; +} + +int VID_SetGamma(unsigned short *ramps, int rampsize) +{ + return FALSE; +} + +int VID_GetGamma(unsigned short *ramps, int rampsize) +{ + return FALSE; +} + +void VID_Init(void) +{ + InitSig(); // trap evil signals +} + +#define SDL_GL_ExtensionSupported(x) (strstr(gl_extensions, x) || strstr(gl_platformextensions, x)) + +int is32bit=0; + +void GLES_Init(void) +{ + gl_renderer = (const char *)qglGetString(GL_RENDERER); + gl_vendor = (const char *)qglGetString(GL_VENDOR); + gl_version = (const char *)qglGetString(GL_VERSION); + gl_extensions = (const char *)qglGetString(GL_EXTENSIONS); + + if (!gl_extensions) + gl_extensions = ""; + if (!gl_platformextensions) + gl_platformextensions = ""; + + Con_Printf("GL_VENDOR: %s\n", gl_vendor); + Con_Printf("GL_RENDERER: %s\n", gl_renderer); + Con_Printf("GL_VERSION: %s\n", gl_version); + Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions); + Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); + + // LordHavoc: report supported extensions + Con_Printf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); + + // GLES devices in general do not like GL_BGRA, so use GL_RGBA + vid.forcetextype = TEXTYPE_RGBA; + + vid.support.gl20shaders = true; + vid.support.amd_texture_texture4 = false; + vid.support.arb_depth_texture = false; + vid.support.arb_draw_buffers = false; + vid.support.arb_multitexture = false; + vid.support.arb_occlusion_query = false; + vid.support.arb_shadow = false; + vid.support.arb_texture_compression = SDL_GL_ExtensionSupported("GL_EXT_texture_compression_s3tc"); + vid.support.arb_texture_cube_map = true; + vid.support.arb_texture_env_combine = false; + vid.support.arb_texture_gather = false; + vid.support.arb_texture_non_power_of_two = strstr(gl_extensions, "GL_OES_texture_npot") != NULL; + vid.support.arb_vertex_buffer_object = true; + vid.support.arb_uniform_buffer_object = false; + vid.support.ati_separate_stencil = false; + vid.support.ext_blend_minmax = false; + vid.support.ext_blend_subtract = true; + vid.support.ext_draw_range_elements = true; + vid.support.ext_framebuffer_object = false; + vid.support.ext_packed_depth_stencil = false; + vid.support.ext_stencil_two_side = false; + vid.support.ext_texture_3d = SDL_GL_ExtensionSupported("GL_OES_texture_3D"); + vid.support.ext_texture_compression_s3tc = SDL_GL_ExtensionSupported("GL_EXT_texture_compression_s3tc"); + vid.support.ext_texture_edge_clamp = true; + vid.support.ext_texture_filter_anisotropic = false; // probably don't want to use it... + vid.support.ext_texture_srgb = false; + + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d); + if (vid.support.ext_texture_filter_anisotropic) + qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint*)&vid.max_anisotropy); + if (vid.support.arb_texture_cube_map) + qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap); + Con_Printf("GL_MAX_CUBE_MAP_TEXTURE_SIZE = %i\n", vid.maxtexturesize_cubemap); + Con_Printf("GL_MAX_3D_TEXTURE_SIZE = %i\n", vid.maxtexturesize_3d); + { +#define GL_ALPHA_BITS 0x0D55 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 + int fb_r = -1, fb_g = -1, fb_b = -1, fb_a = -1, fb_d = -1, fb_s = -1; + qglGetIntegerv(GL_RED_BITS , &fb_r); + qglGetIntegerv(GL_GREEN_BITS , &fb_g); + qglGetIntegerv(GL_BLUE_BITS , &fb_b); + qglGetIntegerv(GL_ALPHA_BITS , &fb_a); + qglGetIntegerv(GL_DEPTH_BITS , &fb_d); + qglGetIntegerv(GL_STENCIL_BITS, &fb_s); + if ((fb_r+fb_g+fb_b+fb_a)>=24) is32bit=1; + Con_Printf("Framebuffer depth is R%iG%iB%iA%iD%iS%i\n", fb_r, fb_g, fb_b, fb_a, fb_d, fb_s); + } + + // verify that cubemap textures are really supported + if (vid.support.arb_texture_cube_map && vid.maxtexturesize_cubemap < 256) + vid.support.arb_texture_cube_map = false; + + // verify that 3d textures are really supported + if (vid.support.ext_texture_3d && vid.maxtexturesize_3d < 32) + { + vid.support.ext_texture_3d = false; + Con_Printf("GL_OES_texture_3d reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n"); + } + + vid.texunits = 4; + vid.teximageunits = 8; + vid.texarrayunits = 5; + vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS); + vid.teximageunits = bound(1, vid.teximageunits, MAX_TEXTUREUNITS); + vid.texarrayunits = bound(1, vid.texarrayunits, MAX_TEXTUREUNITS); + Con_DPrintf("Using GLES2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : ""); + vid.renderpath = RENDERPATH_GLES2; + vid.useinterleavedarrays = false; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = false; + + // VorteX: set other info (maybe place them in VID_InitMode?) + extern cvar_t gl_info_vendor; + extern cvar_t gl_info_renderer; + extern cvar_t gl_info_version; + extern cvar_t gl_info_platform; + extern cvar_t gl_info_driver; + Cvar_SetQuick(&gl_info_vendor, gl_vendor); + Cvar_SetQuick(&gl_info_renderer, gl_renderer); + Cvar_SetQuick(&gl_info_version, gl_version); + Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : ""); + Cvar_SetQuick(&gl_info_driver, gl_driver); +} + +int andrw=640; +int andrh=480; + +qboolean VID_InitMode(viddef_mode_t *mode) +{ + mode->width = andrw; + mode->height = andrh; + mode->fullscreen = true; + mode->refreshrate=60.0f; + vid.softpixels = NULL; + vid_hidden=false; + gl_platform = "Android"; + gl_platformextensions = ""; + GLES_Init(); + if (is32bit) + mode->bitsperpixel=32;else mode->bitsperpixel=16; + return true; +} + +void *GL_GetProcAddress(const char *name) +{ + return NULL; +} + +void Sys_SendKeyEvents(void) +{ +} + +void VID_BuildJoyState(vid_joystate_t *joystate) +{ +} + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + return 0; +} + +typedef struct r_glsl_permutation_s +{ + /// hash lookup data + struct r_glsl_permutation_s *hashnext; + unsigned int mode; + unsigned int permutation; + + /// indicates if we have tried compiling this permutation already + qboolean compiled; + /// 0 if compilation failed + int program; + // texture units assigned to each detected uniform + int tex_Texture_First; + int tex_Texture_Second; + int tex_Texture_GammaRamps; + int tex_Texture_Normal; + int tex_Texture_Color; + int tex_Texture_Gloss; + int tex_Texture_Glow; + int tex_Texture_SecondaryNormal; + int tex_Texture_SecondaryColor; + int tex_Texture_SecondaryGloss; + int tex_Texture_SecondaryGlow; + int tex_Texture_Pants; + int tex_Texture_Shirt; + int tex_Texture_FogHeightTexture; + int tex_Texture_FogMask; + int tex_Texture_Lightmap; + int tex_Texture_Deluxemap; + int tex_Texture_Attenuation; + int tex_Texture_Cube; + int tex_Texture_Refraction; + int tex_Texture_Reflection; + int tex_Texture_ShadowMap2D; + int tex_Texture_CubeProjection; + int tex_Texture_ScreenNormalMap; + int tex_Texture_ScreenDiffuse; + int tex_Texture_ScreenSpecular; + int tex_Texture_ReflectMask; + int tex_Texture_ReflectCube; + int tex_Texture_BounceGrid; + /// locations of detected uniforms in program object, or -1 if not found + int loc_Texture_First; + int loc_Texture_Second; + int loc_Texture_GammaRamps; + int loc_Texture_Normal; + int loc_Texture_Color; + int loc_Texture_Gloss; + int loc_Texture_Glow; + int loc_Texture_SecondaryNormal; + int loc_Texture_SecondaryColor; + int loc_Texture_SecondaryGloss; + int loc_Texture_SecondaryGlow; + int loc_Texture_Pants; + int loc_Texture_Shirt; + int loc_Texture_FogHeightTexture; + int loc_Texture_FogMask; + int loc_Texture_Lightmap; + int loc_Texture_Deluxemap; + int loc_Texture_Attenuation; + int loc_Texture_Cube; + int loc_Texture_Refraction; + int loc_Texture_Reflection; + int loc_Texture_ShadowMap2D; + int loc_Texture_CubeProjection; + int loc_Texture_ScreenNormalMap; + int loc_Texture_ScreenDiffuse; + int loc_Texture_ScreenSpecular; + int loc_Texture_ReflectMask; + int loc_Texture_ReflectCube; + int loc_Texture_BounceGrid; + int loc_Alpha; + int loc_BloomBlur_Parameters; + int loc_ClientTime; + int loc_Color_Ambient; + int loc_Color_Diffuse; + int loc_Color_Specular; + int loc_Color_Glow; + int loc_Color_Pants; + int loc_Color_Shirt; + int loc_DeferredColor_Ambient; + int loc_DeferredColor_Diffuse; + int loc_DeferredColor_Specular; + int loc_DeferredMod_Diffuse; + int loc_DeferredMod_Specular; + int loc_DistortScaleRefractReflect; + int loc_EyePosition; + int loc_FogColor; + int loc_FogHeightFade; + int loc_FogPlane; + int loc_FogPlaneViewDist; + int loc_FogRangeRecip; + int loc_LightColor; + int loc_LightDir; + int loc_LightPosition; + int loc_OffsetMapping_ScaleSteps; + int loc_OffsetMapping_LodDistance; + int loc_OffsetMapping_Bias; + int loc_PixelSize; + int loc_ReflectColor; + int loc_ReflectFactor; + int loc_ReflectOffset; + int loc_RefractColor; + int loc_Saturation; + int loc_ScreenCenterRefractReflect; + int loc_ScreenScaleRefractReflect; + int loc_ScreenToDepth; + int loc_ShadowMap_Parameters; + int loc_ShadowMap_TextureScale; + int loc_SpecularPower; + int loc_UserVec1; + int loc_UserVec2; + int loc_UserVec3; + int loc_UserVec4; + int loc_ViewTintColor; + int loc_ViewToLight; + int loc_ModelToLight; + int loc_TexMatrix; + int loc_BackgroundTexMatrix; + int loc_ModelViewProjectionMatrix; + int loc_ModelViewMatrix; + int loc_PixelToScreenTexCoord; + int loc_ModelToReflectCube; + int loc_ShadowMapMatrix; + int loc_BloomColorSubtract; + int loc_NormalmapScrollBlend; + int loc_BounceGridMatrix; + int loc_BounceGridIntensity; +} +r_glsl_permutation_t; + +extern r_glsl_permutation_t *r_glsl_permutation; +extern void android_kostyl(); + +void QC_BeginFrame() +{ + scndswp=0; + if (r_glsl_permutation!=0) + { +// glUseProgram(r_glsl_permutation->program); +// R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First,0); +// android_kostyl();//from ЯUSSIAИ "КоÑ�тыль" - "A dirty hack" + } + Host_BeginFrame(); +} + +void QC_DrawFrame(int eye, int x, int y) +{ + Host_Frame(eye, x, y); +} + +void QC_EndFrame() +{ + Host_EndFrame(); +} + +void QC_KeyEvent(int state,int key,int character) +{ + Key_Event(key, character, state); +} + +float analogx=0.0f; +float analogy=0.0f; +int analogenabled=0; +void QC_Analog(int enable,float x,float y) +{ + analogenabled=enable; + analogx=x; + analogy=y; +} + +void QC_MotionEvent(float delta, float dx, float dy) +{ + static bool canAdjust = true; + + //Pitch lock? + if (cl_pitchmode.integer != 0 || vrMode == 0) { + + float dir = 1.0f; + if (cl_pitchmode.integer == 1) + dir = -1.0f; + + in_mouse_y += (dy * delta * dir); + in_windowmouse_y += (dy * delta * dir); + if (in_windowmouse_y < 0) in_windowmouse_y = 0; + if (in_windowmouse_y > andrh - 1) in_windowmouse_y = andrh - 1; + } + + //If not in vr mode, then always use yaw stick control + if (cl_yawmode.integer == 2) + { + in_mouse_x+=(dx*delta); + in_windowmouse_x += (dx*delta); + if (in_windowmouse_x<0) in_windowmouse_x=0; + if (in_windowmouse_x>andrw-1) in_windowmouse_x=andrw-1; + } + else if (cl_yawmode.integer == 1) { + if (fabs(dx) > 0.4 && canAdjust && delta != -1.0f) { + if (dx > 0.0) + cl.comfortInc--; + else + cl.comfortInc++; + + int max = (360.f / cl_comfort.value); + + if (cl.comfortInc >= max) + cl.comfortInc = 0; + if (cl.comfortInc < 0) + cl.comfortInc = max - 1; + + canAdjust = false; + } + + if (fabs(dx) < 0.3) + canAdjust = true; + } +} + +static struct { + float pitch, previous_pitch, yaw, previous_yaw, roll; +} move_event; + + +void IN_Move(void) +{ + if (cl_pitchmode.integer != 0) { + cl.viewangles[PITCH] -= move_event.previous_pitch; + cl.viewangles[PITCH] += move_event.pitch; + } + else { + cl.viewangles[PITCH] = move_event.pitch; + } + + if (cl_yawmode.integer != 1) + cl.viewangles[YAW] -= move_event.previous_yaw; + cl.viewangles[YAW] += move_event.yaw ; + cl.viewangles[ROLL] = move_event.roll ; +} + +void QC_MoveEvent(float yaw, float pitch, float roll) +{ + move_event.previous_yaw = move_event.yaw; + move_event.previous_pitch = move_event.pitch; + move_event.yaw = yaw * cl_yawmult.value; + move_event.pitch = pitch * cl_pitchmult.value; + move_event.roll = roll; + + if (cl_yawmode.integer == 3) + { + long t=Sys_Milliseconds(); + long delta=t-oldtime; + oldtime=t; + if (delta>1000) + delta=1000; + + float engage_angle = 45.0f; + + float dx = yaw; + if (yaw > engage_angle || yaw < -engage_angle) { + dx = (yaw > engage_angle) ? dx-engage_angle : dx+engage_angle; + dx /= -10.0f; + } + else { + dx = 0.0f; + } + + in_mouse_x+=(dx*delta); + in_windowmouse_x += (dx*delta); + if (in_windowmouse_x<0) in_windowmouse_x=0; + if (in_windowmouse_x>andrw-1) in_windowmouse_x=andrw-1; + } +} + +void QC_SetResolution(int width, int height) +{ + andrw=width; + andrh=height; + VID_Restart_f(); +} diff --git a/app/jni/vid_shared.c b/app/jni/vid_shared.c new file mode 100644 index 0000000..4b4b1e1 --- /dev/null +++ b/app/jni/vid_shared.c @@ -0,0 +1,2125 @@ + +#include "quakedef.h" +#include "cdaudio.h" +#include "image.h" + +#ifdef SUPPORTD3D +#include +#ifdef _MSC_VER +#pragma comment(lib, "d3d9.lib") +#endif + +LPDIRECT3DDEVICE9 vid_d3d9dev; +#endif + +#ifdef WIN32 +//#include +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 +#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 +#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 +#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 +#define XUSER_INDEX_ANY 0x000000FF + +typedef struct xinput_gamepad_s +{ + WORD wButtons; + BYTE bLeftTrigger; + BYTE bRightTrigger; + SHORT sThumbLX; + SHORT sThumbLY; + SHORT sThumbRX; + SHORT sThumbRY; +} +xinput_gamepad_t; + +typedef struct xinput_state_s +{ + DWORD dwPacketNumber; + xinput_gamepad_t Gamepad; +} +xinput_state_t; + +typedef struct xinput_keystroke_s +{ + WORD VirtualKey; + WCHAR Unicode; + WORD Flags; + BYTE UserIndex; + BYTE HidCode; +} +xinput_keystroke_t; + +DWORD (WINAPI *qXInputGetState)(DWORD index, xinput_state_t *state); +DWORD (WINAPI *qXInputGetKeystroke)(DWORD index, DWORD reserved, xinput_keystroke_t *keystroke); + +qboolean vid_xinputinitialized = false; +int vid_xinputindex = -1; +#endif + +// global video state +viddef_t vid; + +// AK FIXME -> input_dest +qboolean in_client_mouse = true; + +// AK where should it be placed ? +float in_mouse_x, in_mouse_y; +float in_windowmouse_x, in_windowmouse_y; + +// LordHavoc: if window is hidden, don't update screen +qboolean vid_hidden = true; +// LordHavoc: if window is not the active window, don't hog as much CPU time, +// let go of the mouse, turn off sound, and restore system gamma ramps... +qboolean vid_activewindow = true; + +vid_joystate_t vid_joystate; + +#ifdef WIN32 +cvar_t joy_xinputavailable = {CVAR_READONLY, "joy_xinputavailable", "0", "indicates which devices are being reported by the Windows XInput API (first controller = 1, second = 2, third = 4, fourth = 8, added together)"}; +#endif +cvar_t joy_active = {CVAR_READONLY, "joy_active", "0", "indicates that a joystick is active (detected and enabled)"}; +cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"}; +cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"}; +cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple (0 uses the first controller, 1 uses the second, ...)"}; +cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"}; +cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"}; +cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"}; +cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"}; +cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"}; +cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"}; +cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"}; +cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"}; +cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"}; +cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"}; +cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"}; +cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"}; +cvar_t joy_axiskeyevents = {CVAR_SAVE, "joy_axiskeyevents", "0", "generate uparrow/leftarrow etc. keyevents for joystick axes, use if your joystick driver is not generating them"}; +cvar_t joy_axiskeyevents_deadzone = {CVAR_SAVE, "joy_axiskeyevents_deadzone", "0.5", "deadzone value for axes"}; +cvar_t joy_x360_axisforward = {0, "joy_x360_axisforward", "1", "which joystick axis to query for forward/backward movement"}; +cvar_t joy_x360_axisside = {0, "joy_x360_axisside", "0", "which joystick axis to query for right/left movement"}; +cvar_t joy_x360_axisup = {0, "joy_x360_axisup", "-1", "which joystick axis to query for up/down movement"}; +cvar_t joy_x360_axispitch = {0, "joy_x360_axispitch", "3", "which joystick axis to query for looking up/down"}; +cvar_t joy_x360_axisyaw = {0, "joy_x360_axisyaw", "2", "which joystick axis to query for looking right/left"}; +cvar_t joy_x360_axisroll = {0, "joy_x360_axisroll", "-1", "which joystick axis to query for tilting head right/left"}; +cvar_t joy_x360_deadzoneforward = {0, "joy_x360_deadzoneforward", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_deadzoneside = {0, "joy_x360_deadzoneside", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_deadzoneup = {0, "joy_x360_deadzoneup", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_deadzonepitch = {0, "joy_x360_deadzonepitch", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_deadzoneyaw = {0, "joy_x360_deadzoneyaw", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_deadzoneroll = {0, "joy_x360_deadzoneroll", "0.266", "deadzone tolerance, suggested values are in the range 0 to 0.01"}; +cvar_t joy_x360_sensitivityforward = {0, "joy_x360_sensitivityforward", "1", "movement multiplier"}; +cvar_t joy_x360_sensitivityside = {0, "joy_x360_sensitivityside", "1", "movement multiplier"}; +cvar_t joy_x360_sensitivityup = {0, "joy_x360_sensitivityup", "1", "movement multiplier"}; +cvar_t joy_x360_sensitivitypitch = {0, "joy_x360_sensitivitypitch", "-1", "movement multiplier"}; +cvar_t joy_x360_sensitivityyaw = {0, "joy_x360_sensitivityyaw", "-1", "movement multiplier"}; +cvar_t joy_x360_sensitivityroll = {0, "joy_x360_sensitivityroll", "1", "movement multiplier"}; + +// cvars for DPSOFTRAST +cvar_t vid_soft = {CVAR_SAVE, "vid_soft", "0", "enables use of the DarkPlaces Software Rasterizer rather than OpenGL or Direct3D"}; +cvar_t vid_soft_threads = {CVAR_SAVE, "vid_soft_threads", "8", "the number of threads the DarkPlaces Software Rasterizer should use"}; +cvar_t vid_soft_interlace = {CVAR_SAVE, "vid_soft_interlace", "1", "whether the DarkPlaces Software Rasterizer should interlace the screen bands occupied by each thread"}; + +// we don't know until we try it! +cvar_t vid_hardwaregammasupported = {CVAR_READONLY,"vid_hardwaregammasupported","1", "indicates whether hardware gamma is supported (updated by attempts to set hardware gamma ramps)"}; + +// VorteX: more info cvars, mostly set in VID_CheckExtensions +cvar_t gl_info_vendor = {CVAR_READONLY, "gl_info_vendor", "", "indicates brand of graphics chip"}; +cvar_t gl_info_renderer = {CVAR_READONLY, "gl_info_renderer", "", "indicates graphics chip model and other information"}; +cvar_t gl_info_version = {CVAR_READONLY, "gl_info_version", "", "indicates version of current renderer. begins with 1.0.0, 1.1.0, 1.2.0, 1.3.1 etc."}; +cvar_t gl_info_extensions = {CVAR_READONLY, "gl_info_extensions", "", "indicates extension list found by engine, space separated."}; +cvar_t gl_info_platform = {CVAR_READONLY, "gl_info_platform", "", "indicates GL platform: WGL, GLX, or AGL."}; +cvar_t gl_info_driver = {CVAR_READONLY, "gl_info_driver", "", "name of driver library (opengl32.dll, libGL.so.1, or whatever)."}; + +// whether hardware gamma ramps are currently in effect +qboolean vid_usinghwgamma = false; + +int vid_gammarampsize = 0; +unsigned short *vid_gammaramps = NULL; +unsigned short *vid_systemgammaramps = NULL; + +cvar_t vid_fullscreen = {CVAR_SAVE, "vid_fullscreen", "1", "use fullscreen (1) or windowed (0)"}; +cvar_t vid_width = {CVAR_SAVE, "vid_width", "640", "resolution"}; +cvar_t vid_height = {CVAR_SAVE, "vid_height", "480", "resolution"}; +cvar_t vid_bitsperpixel = {CVAR_SAVE, "vid_bitsperpixel", "32", "how many bits per pixel to render at (32 or 16, 32 is recommended)"}; +cvar_t vid_samples = {CVAR_SAVE, "vid_samples", "1", "how many anti-aliasing samples per pixel to request from the graphics driver (4 is recommended, 1 is faster)"}; +cvar_t vid_refreshrate = {CVAR_SAVE, "vid_refreshrate", "60", "refresh rate to use, in hz (higher values flicker less, if supported by your monitor)"}; +cvar_t vid_userefreshrate = {CVAR_SAVE, "vid_userefreshrate", "0", "set this to 1 to make vid_refreshrate used, or to 0 to let the engine choose a sane default"}; +cvar_t vid_stereobuffer = {CVAR_SAVE, "vid_stereobuffer", "0", "enables 'quad-buffered' stereo rendering for stereo shutterglasses, HMD (head mounted display) devices, or polarized stereo LCDs, if supported by your drivers"}; + +cvar_t vid_vsync = {CVAR_SAVE, "vid_vsync", "0", "sync to vertical blank, prevents 'tearing' (seeing part of one frame and part of another on the screen at the same time), automatically disabled when doing timedemo benchmarks"}; +cvar_t vid_mouse = {CVAR_SAVE, "vid_mouse", "1", "whether to use the mouse in windowed mode (fullscreen always does)"}; +cvar_t vid_grabkeyboard = {CVAR_SAVE, "vid_grabkeyboard", "0", "whether to grab the keyboard when mouse is active (prevents use of volume control keys, music player keys, etc on some keyboards)"}; +cvar_t vid_minwidth = {0, "vid_minwidth", "0", "minimum vid_width that is acceptable (to be set in default.cfg in mods)"}; +cvar_t vid_minheight = {0, "vid_minheight", "0", "minimum vid_height that is acceptable (to be set in default.cfg in mods)"}; +cvar_t vid_gl13 = {0, "vid_gl13", "1", "enables faster rendering using OpenGL 1.3 features (such as GL_ARB_texture_env_combine extension)"}; +cvar_t vid_gl20 = {0, "vid_gl20", "1", "enables faster rendering using OpenGL 2.0 features (such as GL_ARB_fragment_shader extension)"}; +cvar_t gl_finish = {0, "gl_finish", "0", "make the cpu wait for the graphics processor at the end of each rendered frame (can help with strange input or video lag problems on some machines)"}; +cvar_t vid_sRGB = {CVAR_SAVE, "vid_sRGB", "0", "if hardware is capable, modify rendering to be gamma corrected for the sRGB color standard (computer monitors, TVs), recommended"}; +cvar_t vid_sRGB_fallback = {CVAR_SAVE, "vid_sRGB_fallback", "0", "do an approximate sRGB fallback if not properly supported by hardware (2: also use the fallback if framebuffer is 8bit, 3: always use the fallback even if sRGB is supported)"}; + +cvar_t vid_touchscreen = {0, "vid_touchscreen", "0", "Use touchscreen-style input (no mouse grab, track mouse motion only while button is down, screen areas for mimicing joystick axes and buttons"}; +cvar_t vid_stick_mouse = {CVAR_SAVE, "vid_stick_mouse", "0", "have the mouse stuck in the center of the screen" }; +cvar_t vid_resizable = {CVAR_SAVE, "vid_resizable", "0", "0: window not resizable, 1: resizable, 2: window can be resized but the framebuffer isn't adjusted" }; + +cvar_t v_gamma = {CVAR_SAVE, "v_gamma", "1", "inverse gamma correction value, a brightness effect that does not affect white or black, and tends to make the image grey and dull"}; +cvar_t v_contrast = {CVAR_SAVE, "v_contrast", "1", "brightness of white (values above 1 give a brighter image with increased color saturation, unlike v_gamma)"}; +cvar_t v_brightness = {CVAR_SAVE, "v_brightness", "0", "brightness of black, useful for monitors that are too dark"}; +cvar_t v_contrastboost = {CVAR_SAVE, "v_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"}; +cvar_t v_color_enable = {CVAR_SAVE, "v_color_enable", "0", "enables black-grey-white color correction curve controls"}; +cvar_t v_color_black_r = {CVAR_SAVE, "v_color_black_r", "0", "desired color of black"}; +cvar_t v_color_black_g = {CVAR_SAVE, "v_color_black_g", "0", "desired color of black"}; +cvar_t v_color_black_b = {CVAR_SAVE, "v_color_black_b", "0", "desired color of black"}; +cvar_t v_color_grey_r = {CVAR_SAVE, "v_color_grey_r", "0.5", "desired color of grey"}; +cvar_t v_color_grey_g = {CVAR_SAVE, "v_color_grey_g", "0.5", "desired color of grey"}; +cvar_t v_color_grey_b = {CVAR_SAVE, "v_color_grey_b", "0.5", "desired color of grey"}; +cvar_t v_color_white_r = {CVAR_SAVE, "v_color_white_r", "1", "desired color of white"}; +cvar_t v_color_white_g = {CVAR_SAVE, "v_color_white_g", "1", "desired color of white"}; +cvar_t v_color_white_b = {CVAR_SAVE, "v_color_white_b", "1", "desired color of white"}; +cvar_t v_hwgamma = {CVAR_SAVE, "v_hwgamma", "0", "enables use of hardware gamma correction ramps if available (note: does not work very well on Windows2000 and above), values are 0 = off, 1 = attempt to use hardware gamma, 2 = use hardware gamma whether it works or not"}; +cvar_t v_glslgamma = {CVAR_SAVE, "v_glslgamma", "1", "enables use of GLSL to apply gamma correction ramps if available (note: overrides v_hwgamma)"}; +cvar_t v_glslgamma_2d = {CVAR_SAVE, "v_glslgamma_2d", "0", "applies GLSL gamma to 2d pictures (HUD, fonts)"}; +cvar_t v_psycho = {0, "v_psycho", "0", "easter egg"}; + +// brand of graphics chip +const char *gl_vendor; +// graphics chip model and other information +const char *gl_renderer; +// begins with 1.0.0, 1.1.0, 1.2.0, 1.2.1, 1.3.0, 1.3.1, or 1.4.0 +const char *gl_version; +// extensions list, space separated +const char *gl_extensions; +// WGL, GLX, or AGL +const char *gl_platform; +// another extensions list, containing platform-specific extensions that are +// not in the main list +const char *gl_platformextensions; +// name of driver library (opengl32.dll, libGL.so.1, or whatever) +char gl_driver[256]; + +#ifndef USE_GLES2 +// GL_ARB_multitexture +void (GLAPIENTRY *qglMultiTexCoord1f) (GLenum, GLfloat); +void (GLAPIENTRY *qglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); +void (GLAPIENTRY *qglMultiTexCoord3f) (GLenum, GLfloat, GLfloat, GLfloat); +void (GLAPIENTRY *qglMultiTexCoord4f) (GLenum, GLfloat, GLfloat, GLfloat, GLfloat); +void (GLAPIENTRY *qglActiveTexture) (GLenum); +void (GLAPIENTRY *qglClientActiveTexture) (GLenum); + +// general GL functions + +void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + +void (GLAPIENTRY *qglClear)(GLbitfield mask); + +void (GLAPIENTRY *qglAlphaFunc)(GLenum func, GLclampf ref); +void (GLAPIENTRY *qglBlendFunc)(GLenum sfactor, GLenum dfactor); +void (GLAPIENTRY *qglCullFace)(GLenum mode); + +void (GLAPIENTRY *qglDrawBuffer)(GLenum mode); +void (GLAPIENTRY *qglReadBuffer)(GLenum mode); +void (GLAPIENTRY *qglEnable)(GLenum cap); +void (GLAPIENTRY *qglDisable)(GLenum cap); +GLboolean (GLAPIENTRY *qglIsEnabled)(GLenum cap); + +void (GLAPIENTRY *qglEnableClientState)(GLenum cap); +void (GLAPIENTRY *qglDisableClientState)(GLenum cap); + +void (GLAPIENTRY *qglGetBooleanv)(GLenum pname, GLboolean *params); +void (GLAPIENTRY *qglGetDoublev)(GLenum pname, GLdouble *params); +void (GLAPIENTRY *qglGetFloatv)(GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetIntegerv)(GLenum pname, GLint *params); + +GLenum (GLAPIENTRY *qglGetError)(void); +const GLubyte* (GLAPIENTRY *qglGetString)(GLenum name); +void (GLAPIENTRY *qglFinish)(void); +void (GLAPIENTRY *qglFlush)(void); + +void (GLAPIENTRY *qglClearDepth)(GLclampd depth); +void (GLAPIENTRY *qglDepthFunc)(GLenum func); +void (GLAPIENTRY *qglDepthMask)(GLboolean flag); +void (GLAPIENTRY *qglDepthRange)(GLclampd near_val, GLclampd far_val); +void (GLAPIENTRY *qglDepthRangef)(GLclampf near_val, GLclampf far_val); +void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + +void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count); +void (GLAPIENTRY *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +void (GLAPIENTRY *qglNormalPointer)(GLenum type, GLsizei stride, const GLvoid *ptr); +void (GLAPIENTRY *qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +void (GLAPIENTRY *qglArrayElement)(GLint i); + +void (GLAPIENTRY *qglColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void (GLAPIENTRY *qglTexCoord1f)(GLfloat s); +void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t); +void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r); +void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y); +void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z); +void (GLAPIENTRY *qglVertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void (GLAPIENTRY *qglBegin)(GLenum mode); +void (GLAPIENTRY *qglEnd)(void); + +void (GLAPIENTRY *qglMatrixMode)(GLenum mode); +//void (GLAPIENTRY *qglOrtho)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +//void (GLAPIENTRY *qglFrustum)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val); +void (GLAPIENTRY *qglViewport)(GLint x, GLint y, GLsizei width, GLsizei height); +//void (GLAPIENTRY *qglPushMatrix)(void); +//void (GLAPIENTRY *qglPopMatrix)(void); +void (GLAPIENTRY *qglLoadIdentity)(void); +//void (GLAPIENTRY *qglLoadMatrixd)(const GLdouble *m); +void (GLAPIENTRY *qglLoadMatrixf)(const GLfloat *m); +//void (GLAPIENTRY *qglMultMatrixd)(const GLdouble *m); +//void (GLAPIENTRY *qglMultMatrixf)(const GLfloat *m); +//void (GLAPIENTRY *qglRotated)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +//void (GLAPIENTRY *qglRotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +//void (GLAPIENTRY *qglScaled)(GLdouble x, GLdouble y, GLdouble z); +//void (GLAPIENTRY *qglScalef)(GLfloat x, GLfloat y, GLfloat z); +//void (GLAPIENTRY *qglTranslated)(GLdouble x, GLdouble y, GLdouble z); +//void (GLAPIENTRY *qglTranslatef)(GLfloat x, GLfloat y, GLfloat z); + +void (GLAPIENTRY *qglReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); + +void (GLAPIENTRY *qglStencilFunc)(GLenum func, GLint ref, GLuint mask); +void (GLAPIENTRY *qglStencilMask)(GLuint mask); +void (GLAPIENTRY *qglStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); +void (GLAPIENTRY *qglClearStencil)(GLint s); + +void (GLAPIENTRY *qglTexEnvf)(GLenum target, GLenum pname, GLfloat param); +void (GLAPIENTRY *qglTexEnvfv)(GLenum target, GLenum pname, const GLfloat *params); +void (GLAPIENTRY *qglTexEnvi)(GLenum target, GLenum pname, GLint param); +void (GLAPIENTRY *qglTexParameterf)(GLenum target, GLenum pname, GLfloat param); +void (GLAPIENTRY *qglTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglTexParameteri)(GLenum target, GLenum pname, GLint param); +void (GLAPIENTRY *qglGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetTexParameteriv)(GLenum target, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void (GLAPIENTRY *qglHint)(GLenum target, GLenum mode); + +void (GLAPIENTRY *qglGenTextures)(GLsizei n, GLuint *textures); +void (GLAPIENTRY *qglDeleteTextures)(GLsizei n, const GLuint *textures); +void (GLAPIENTRY *qglBindTexture)(GLenum target, GLuint texture); +//void (GLAPIENTRY *qglPrioritizeTextures)(GLsizei n, const GLuint *textures, const GLclampf *priorities); +//GLboolean (GLAPIENTRY *qglAreTexturesResident)(GLsizei n, const GLuint *textures, GLboolean *residences); +//GLboolean (GLAPIENTRY *qglIsTexture)(GLuint texture); +//void (GLAPIENTRY *qglPixelStoref)(GLenum pname, GLfloat param); +void (GLAPIENTRY *qglPixelStorei)(GLenum pname, GLint param); + +//void (GLAPIENTRY *qglTexImage1D)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void (GLAPIENTRY *qglTexImage2D)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +//void (GLAPIENTRY *qglTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void (GLAPIENTRY *qglTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +//void (GLAPIENTRY *qglCopyTexImage1D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +void (GLAPIENTRY *qglCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +//void (GLAPIENTRY *qglCopyTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void (GLAPIENTRY *qglCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + + +void (GLAPIENTRY *qglDrawRangeElementsEXT)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + +//void (GLAPIENTRY *qglColorTableEXT)(int, int, int, int, int, const void *); + +void (GLAPIENTRY *qglTexImage3D)(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void (GLAPIENTRY *qglTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +void (GLAPIENTRY *qglCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + +void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + +void (GLAPIENTRY *qglPolygonOffset)(GLfloat factor, GLfloat units); +void (GLAPIENTRY *qglPolygonMode)(GLenum face, GLenum mode); +void (GLAPIENTRY *qglPolygonStipple)(const GLubyte *mask); + +//void (GLAPIENTRY *qglClipPlane)(GLenum plane, const GLdouble *equation); +//void (GLAPIENTRY *qglGetClipPlane)(GLenum plane, GLdouble *equation); + +//[515]: added on 29.07.2005 +void (GLAPIENTRY *qglLineWidth)(GLfloat width); +void (GLAPIENTRY *qglPointSize)(GLfloat size); + +void (GLAPIENTRY *qglBlendEquationEXT)(GLenum); + +void (GLAPIENTRY *qglStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum); +void (GLAPIENTRY *qglStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint); +void (GLAPIENTRY *qglActiveStencilFaceEXT)(GLenum); + +void (GLAPIENTRY *qglDeleteShader)(GLuint obj); +void (GLAPIENTRY *qglDeleteProgram)(GLuint obj); +//GLuint (GLAPIENTRY *qglGetHandle)(GLenum pname); +void (GLAPIENTRY *qglDetachShader)(GLuint containerObj, GLuint attachedObj); +GLuint (GLAPIENTRY *qglCreateShader)(GLenum shaderType); +void (GLAPIENTRY *qglShaderSource)(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length); +void (GLAPIENTRY *qglCompileShader)(GLuint shaderObj); +GLuint (GLAPIENTRY *qglCreateProgram)(void); +void (GLAPIENTRY *qglAttachShader)(GLuint containerObj, GLuint obj); +void (GLAPIENTRY *qglLinkProgram)(GLuint programObj); +void (GLAPIENTRY *qglUseProgram)(GLuint programObj); +void (GLAPIENTRY *qglValidateProgram)(GLuint programObj); +void (GLAPIENTRY *qglUniform1f)(GLint location, GLfloat v0); +void (GLAPIENTRY *qglUniform2f)(GLint location, GLfloat v0, GLfloat v1); +void (GLAPIENTRY *qglUniform3f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +void (GLAPIENTRY *qglUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +void (GLAPIENTRY *qglUniform1i)(GLint location, GLint v0); +void (GLAPIENTRY *qglUniform2i)(GLint location, GLint v0, GLint v1); +void (GLAPIENTRY *qglUniform3i)(GLint location, GLint v0, GLint v1, GLint v2); +void (GLAPIENTRY *qglUniform4i)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +void (GLAPIENTRY *qglUniform1fv)(GLint location, GLsizei count, const GLfloat *value); +void (GLAPIENTRY *qglUniform2fv)(GLint location, GLsizei count, const GLfloat *value); +void (GLAPIENTRY *qglUniform3fv)(GLint location, GLsizei count, const GLfloat *value); +void (GLAPIENTRY *qglUniform4fv)(GLint location, GLsizei count, const GLfloat *value); +void (GLAPIENTRY *qglUniform1iv)(GLint location, GLsizei count, const GLint *value); +void (GLAPIENTRY *qglUniform2iv)(GLint location, GLsizei count, const GLint *value); +void (GLAPIENTRY *qglUniform3iv)(GLint location, GLsizei count, const GLint *value); +void (GLAPIENTRY *qglUniform4iv)(GLint location, GLsizei count, const GLint *value); +void (GLAPIENTRY *qglUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void (GLAPIENTRY *qglUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void (GLAPIENTRY *qglUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +void (GLAPIENTRY *qglGetShaderiv)(GLuint obj, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetProgramiv)(GLuint obj, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetShaderInfoLog)(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog); +void (GLAPIENTRY *qglGetProgramInfoLog)(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog); +void (GLAPIENTRY *qglGetAttachedShaders)(GLuint containerObj, GLsizei maxCount, GLsizei *count, GLuint *obj); +GLint (GLAPIENTRY *qglGetUniformLocation)(GLuint programObj, const GLchar *name); +void (GLAPIENTRY *qglGetActiveUniform)(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +void (GLAPIENTRY *qglGetUniformfv)(GLuint programObj, GLint location, GLfloat *params); +void (GLAPIENTRY *qglGetUniformiv)(GLuint programObj, GLint location, GLint *params); +void (GLAPIENTRY *qglGetShaderSource)(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *source); + +void (GLAPIENTRY *qglVertexAttrib1f)(GLuint index, GLfloat v0); +void (GLAPIENTRY *qglVertexAttrib1s)(GLuint index, GLshort v0); +void (GLAPIENTRY *qglVertexAttrib1d)(GLuint index, GLdouble v0); +void (GLAPIENTRY *qglVertexAttrib2f)(GLuint index, GLfloat v0, GLfloat v1); +void (GLAPIENTRY *qglVertexAttrib2s)(GLuint index, GLshort v0, GLshort v1); +void (GLAPIENTRY *qglVertexAttrib2d)(GLuint index, GLdouble v0, GLdouble v1); +void (GLAPIENTRY *qglVertexAttrib3f)(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2); +void (GLAPIENTRY *qglVertexAttrib3s)(GLuint index, GLshort v0, GLshort v1, GLshort v2); +void (GLAPIENTRY *qglVertexAttrib3d)(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2); +void (GLAPIENTRY *qglVertexAttrib4f)(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +void (GLAPIENTRY *qglVertexAttrib4s)(GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3); +void (GLAPIENTRY *qglVertexAttrib4d)(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +void (GLAPIENTRY *qglVertexAttrib4Nub)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +void (GLAPIENTRY *qglVertexAttrib1fv)(GLuint index, const GLfloat *v); +void (GLAPIENTRY *qglVertexAttrib1sv)(GLuint index, const GLshort *v); +void (GLAPIENTRY *qglVertexAttrib1dv)(GLuint index, const GLdouble *v); +void (GLAPIENTRY *qglVertexAttrib2fv)(GLuint index, const GLfloat *v); +void (GLAPIENTRY *qglVertexAttrib2sv)(GLuint index, const GLshort *v); +void (GLAPIENTRY *qglVertexAttrib2dv)(GLuint index, const GLdouble *v); +void (GLAPIENTRY *qglVertexAttrib3fv)(GLuint index, const GLfloat *v); +void (GLAPIENTRY *qglVertexAttrib3sv)(GLuint index, const GLshort *v); +void (GLAPIENTRY *qglVertexAttrib3dv)(GLuint index, const GLdouble *v); +void (GLAPIENTRY *qglVertexAttrib4fv)(GLuint index, const GLfloat *v); +void (GLAPIENTRY *qglVertexAttrib4sv)(GLuint index, const GLshort *v); +void (GLAPIENTRY *qglVertexAttrib4dv)(GLuint index, const GLdouble *v); +void (GLAPIENTRY *qglVertexAttrib4iv)(GLuint index, const GLint *v); +void (GLAPIENTRY *qglVertexAttrib4bv)(GLuint index, const GLbyte *v); +void (GLAPIENTRY *qglVertexAttrib4ubv)(GLuint index, const GLubyte *v); +void (GLAPIENTRY *qglVertexAttrib4usv)(GLuint index, const GLushort *v); +void (GLAPIENTRY *qglVertexAttrib4uiv)(GLuint index, const GLuint *v); +void (GLAPIENTRY *qglVertexAttrib4Nbv)(GLuint index, const GLbyte *v); +void (GLAPIENTRY *qglVertexAttrib4Nsv)(GLuint index, const GLshort *v); +void (GLAPIENTRY *qglVertexAttrib4Niv)(GLuint index, const GLint *v); +void (GLAPIENTRY *qglVertexAttrib4Nubv)(GLuint index, const GLubyte *v); +void (GLAPIENTRY *qglVertexAttrib4Nusv)(GLuint index, const GLushort *v); +void (GLAPIENTRY *qglVertexAttrib4Nuiv)(GLuint index, const GLuint *v); +void (GLAPIENTRY *qglVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +void (GLAPIENTRY *qglEnableVertexAttribArray)(GLuint index); +void (GLAPIENTRY *qglDisableVertexAttribArray)(GLuint index); +void (GLAPIENTRY *qglBindAttribLocation)(GLuint programObj, GLuint index, const GLchar *name); +void (GLAPIENTRY *qglBindFragDataLocation)(GLuint programObj, GLuint index, const GLchar *name); +void (GLAPIENTRY *qglGetActiveAttrib)(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLint (GLAPIENTRY *qglGetAttribLocation)(GLuint programObj, const GLchar *name); +void (GLAPIENTRY *qglGetVertexAttribdv)(GLuint index, GLenum pname, GLdouble *params); +void (GLAPIENTRY *qglGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat *params); +void (GLAPIENTRY *qglGetVertexAttribiv)(GLuint index, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid **pointer); + +//GL_ARB_vertex_buffer_object +void (GLAPIENTRY *qglBindBufferARB) (GLenum target, GLuint buffer); +void (GLAPIENTRY *qglDeleteBuffersARB) (GLsizei n, const GLuint *buffers); +void (GLAPIENTRY *qglGenBuffersARB) (GLsizei n, GLuint *buffers); +GLboolean (GLAPIENTRY *qglIsBufferARB) (GLuint buffer); +GLvoid* (GLAPIENTRY *qglMapBufferARB) (GLenum target, GLenum access); +GLboolean (GLAPIENTRY *qglUnmapBufferARB) (GLenum target); +void (GLAPIENTRY *qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +void (GLAPIENTRY *qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + +//GL_ARB_framebuffer_object +GLboolean (GLAPIENTRY *qglIsRenderbuffer)(GLuint renderbuffer); +GLvoid (GLAPIENTRY *qglBindRenderbuffer)(GLenum target, GLuint renderbuffer); +GLvoid (GLAPIENTRY *qglDeleteRenderbuffers)(GLsizei n, const GLuint *renderbuffers); +GLvoid (GLAPIENTRY *qglGenRenderbuffers)(GLsizei n, GLuint *renderbuffers); +GLvoid (GLAPIENTRY *qglRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLvoid (GLAPIENTRY *qglRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLvoid (GLAPIENTRY *qglGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params); +GLboolean (GLAPIENTRY *qglIsFramebuffer)(GLuint framebuffer); +GLvoid (GLAPIENTRY *qglBindFramebuffer)(GLenum target, GLuint framebuffer); +GLvoid (GLAPIENTRY *qglDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers); +GLvoid (GLAPIENTRY *qglGenFramebuffers)(GLsizei n, GLuint *framebuffers); +GLenum (GLAPIENTRY *qglCheckFramebufferStatus)(GLenum target); +GLvoid (GLAPIENTRY *qglFramebufferTexture1D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLvoid (GLAPIENTRY *qglFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLvoid (GLAPIENTRY *qglFramebufferTexture3D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer); +GLvoid (GLAPIENTRY *qglFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLvoid (GLAPIENTRY *qglFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLvoid (GLAPIENTRY *qglGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLvoid (GLAPIENTRY *qglBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLvoid (GLAPIENTRY *qglGenerateMipmap)(GLenum target); + +void (GLAPIENTRY *qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); + +void (GLAPIENTRY *qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +void (GLAPIENTRY *qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +//void (GLAPIENTRY *qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +void (GLAPIENTRY *qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +void (GLAPIENTRY *qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +//void (GLAPIENTRY *qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +void (GLAPIENTRY *qglGetCompressedTexImageARB)(GLenum target, GLint lod, void *img); + +void (GLAPIENTRY *qglGenQueriesARB)(GLsizei n, GLuint *ids); +void (GLAPIENTRY *qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); +GLboolean (GLAPIENTRY *qglIsQueryARB)(GLuint qid); +void (GLAPIENTRY *qglBeginQueryARB)(GLenum target, GLuint qid); +void (GLAPIENTRY *qglEndQueryARB)(GLenum target); +void (GLAPIENTRY *qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetQueryObjectivARB)(GLuint qid, GLenum pname, GLint *params); +void (GLAPIENTRY *qglGetQueryObjectuivARB)(GLuint qid, GLenum pname, GLuint *params); + +void (GLAPIENTRY *qglSampleCoverageARB)(GLclampf value, GLboolean invert); + +void (GLAPIENTRY *qglGetUniformIndices)(GLuint program, GLsizei uniformCount, const GLchar** uniformNames, GLuint* uniformIndices); +void (GLAPIENTRY *qglGetActiveUniformsiv)(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +void (GLAPIENTRY *qglGetActiveUniformName)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName); +GLuint (GLAPIENTRY *qglGetUniformBlockIndex)(GLuint program, const GLchar* uniformBlockName); +void (GLAPIENTRY *qglGetActiveUniformBlockiv)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +void (GLAPIENTRY *qglGetActiveUniformBlockName)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); +void (GLAPIENTRY *qglBindBufferRange)(GLenum target, GLuint index, GLuint buffer, GLintptrARB offset, GLsizeiptrARB size); +void (GLAPIENTRY *qglBindBufferBase)(GLenum target, GLuint index, GLuint buffer); +void (GLAPIENTRY *qglGetIntegeri_v)(GLenum target, GLuint index, GLint* data); +void (GLAPIENTRY *qglUniformBlockBinding)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif + +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + +qboolean GL_CheckExtension(const char *minglver_or_ext, const dllfunction_t *funcs, const char *disableparm, int silent) +{ + int failed = false; + const dllfunction_t *func; + struct { int major, minor; } min_version, curr_version; + char extstr[MAX_INPUTLINE]; + int ext; + + if(sscanf(minglver_or_ext, "%d.%d", &min_version.major, &min_version.minor) == 2) + ext = 0; // opengl version + else if(minglver_or_ext[0] != toupper(minglver_or_ext[0])) + ext = -1; // pseudo name + else + ext = 1; // extension name + + if (ext) + Con_DPrintf("checking for %s... ", minglver_or_ext); + else + Con_DPrintf("checking for OpenGL %s core features... ", minglver_or_ext); + + for (func = funcs;func && func->name;func++) + *func->funcvariable = NULL; + + if (disableparm && (COM_CheckParm(disableparm) || COM_CheckParm("-safe"))) + { + Con_DPrint("disabled by commandline\n"); + return false; + } + + if (ext == 1) // opengl extension + { + if (!strstr(gl_extensions ? gl_extensions : "", minglver_or_ext) && !strstr(gl_platformextensions ? gl_platformextensions : "", minglver_or_ext)) + { + Con_DPrint("not detected\n"); + return false; + } + } + + if(ext == 0) // opengl version + { + if (sscanf(gl_version, "%d.%d", &curr_version.major, &curr_version.minor) < 2) + curr_version.major = curr_version.minor = 1; + + if (curr_version.major < min_version.major || (curr_version.major == min_version.major && curr_version.minor < min_version.minor)) + { + Con_DPrintf("not detected (OpenGL %d.%d loaded)\n", curr_version.major, curr_version.minor); + return false; + } + } + + for (func = funcs;func && func->name != NULL;func++) + { + // Con_DPrintf("\n %s... ", func->name); + + // functions are cleared before all the extensions are evaluated + if (!(*func->funcvariable = (void *) GL_GetProcAddress(func->name))) + { + if (ext && !silent) + Con_DPrintf("%s is missing function \"%s\" - broken driver!\n", minglver_or_ext, func->name); + if (!ext) + Con_Printf("OpenGL %s core features are missing function \"%s\" - broken driver!\n", minglver_or_ext, func->name); + failed = true; + } + } + // delay the return so it prints all missing functions + if (failed) + return false; + // VorteX: add to found extension list + dpsnprintf(extstr, sizeof(extstr), "%s %s ", gl_info_extensions.string, minglver_or_ext); + Cvar_SetQuick(&gl_info_extensions, extstr); + + Con_DPrint("enabled\n"); + return true; +} + +#ifndef USE_GLES2 +static dllfunction_t opengl110funcs[] = +{ + {"glClearColor", (void **) &qglClearColor}, + {"glClear", (void **) &qglClear}, + {"glAlphaFunc", (void **) &qglAlphaFunc}, + {"glBlendFunc", (void **) &qglBlendFunc}, + {"glCullFace", (void **) &qglCullFace}, + {"glDrawBuffer", (void **) &qglDrawBuffer}, + {"glReadBuffer", (void **) &qglReadBuffer}, + {"glEnable", (void **) &qglEnable}, + {"glDisable", (void **) &qglDisable}, + {"glIsEnabled", (void **) &qglIsEnabled}, + {"glEnableClientState", (void **) &qglEnableClientState}, + {"glDisableClientState", (void **) &qglDisableClientState}, + {"glGetBooleanv", (void **) &qglGetBooleanv}, + {"glGetDoublev", (void **) &qglGetDoublev}, + {"glGetFloatv", (void **) &qglGetFloatv}, + {"glGetIntegerv", (void **) &qglGetIntegerv}, + {"glGetError", (void **) &qglGetError}, + {"glGetString", (void **) &qglGetString}, + {"glFinish", (void **) &qglFinish}, + {"glFlush", (void **) &qglFlush}, + {"glClearDepth", (void **) &qglClearDepth}, + {"glDepthFunc", (void **) &qglDepthFunc}, + {"glDepthMask", (void **) &qglDepthMask}, + {"glDepthRange", (void **) &qglDepthRange}, + {"glDrawElements", (void **) &qglDrawElements}, + {"glDrawArrays", (void **) &qglDrawArrays}, + {"glColorMask", (void **) &qglColorMask}, + {"glVertexPointer", (void **) &qglVertexPointer}, + {"glNormalPointer", (void **) &qglNormalPointer}, + {"glColorPointer", (void **) &qglColorPointer}, + {"glTexCoordPointer", (void **) &qglTexCoordPointer}, + {"glArrayElement", (void **) &qglArrayElement}, + {"glColor4ub", (void **) &qglColor4ub}, + {"glColor4f", (void **) &qglColor4f}, + {"glTexCoord1f", (void **) &qglTexCoord1f}, + {"glTexCoord2f", (void **) &qglTexCoord2f}, + {"glTexCoord3f", (void **) &qglTexCoord3f}, + {"glTexCoord4f", (void **) &qglTexCoord4f}, + {"glVertex2f", (void **) &qglVertex2f}, + {"glVertex3f", (void **) &qglVertex3f}, + {"glVertex4f", (void **) &qglVertex4f}, + {"glBegin", (void **) &qglBegin}, + {"glEnd", (void **) &qglEnd}, +//[515]: added on 29.07.2005 + {"glLineWidth", (void**) &qglLineWidth}, + {"glPointSize", (void**) &qglPointSize}, +// + {"glMatrixMode", (void **) &qglMatrixMode}, +// {"glOrtho", (void **) &qglOrtho}, +// {"glFrustum", (void **) &qglFrustum}, + {"glViewport", (void **) &qglViewport}, +// {"glPushMatrix", (void **) &qglPushMatrix}, +// {"glPopMatrix", (void **) &qglPopMatrix}, + {"glLoadIdentity", (void **) &qglLoadIdentity}, +// {"glLoadMatrixd", (void **) &qglLoadMatrixd}, + {"glLoadMatrixf", (void **) &qglLoadMatrixf}, +// {"glMultMatrixd", (void **) &qglMultMatrixd}, +// {"glMultMatrixf", (void **) &qglMultMatrixf}, +// {"glRotated", (void **) &qglRotated}, +// {"glRotatef", (void **) &qglRotatef}, +// {"glScaled", (void **) &qglScaled}, +// {"glScalef", (void **) &qglScalef}, +// {"glTranslated", (void **) &qglTranslated}, +// {"glTranslatef", (void **) &qglTranslatef}, + {"glReadPixels", (void **) &qglReadPixels}, + {"glStencilFunc", (void **) &qglStencilFunc}, + {"glStencilMask", (void **) &qglStencilMask}, + {"glStencilOp", (void **) &qglStencilOp}, + {"glClearStencil", (void **) &qglClearStencil}, + {"glTexEnvf", (void **) &qglTexEnvf}, + {"glTexEnvfv", (void **) &qglTexEnvfv}, + {"glTexEnvi", (void **) &qglTexEnvi}, + {"glTexParameterf", (void **) &qglTexParameterf}, + {"glTexParameterfv", (void **) &qglTexParameterfv}, + {"glTexParameteri", (void **) &qglTexParameteri}, + {"glGetTexImage", (void **) &qglGetTexImage}, + {"glGetTexParameterfv", (void **) &qglGetTexParameterfv}, + {"glGetTexParameteriv", (void **) &qglGetTexParameteriv}, + {"glGetTexLevelParameterfv", (void **) &qglGetTexLevelParameterfv}, + {"glGetTexLevelParameteriv", (void **) &qglGetTexLevelParameteriv}, + {"glHint", (void **) &qglHint}, +// {"glPixelStoref", (void **) &qglPixelStoref}, + {"glPixelStorei", (void **) &qglPixelStorei}, + {"glGenTextures", (void **) &qglGenTextures}, + {"glDeleteTextures", (void **) &qglDeleteTextures}, + {"glBindTexture", (void **) &qglBindTexture}, +// {"glPrioritizeTextures", (void **) &qglPrioritizeTextures}, +// {"glAreTexturesResident", (void **) &qglAreTexturesResident}, +// {"glIsTexture", (void **) &qglIsTexture}, +// {"glTexImage1D", (void **) &qglTexImage1D}, + {"glTexImage2D", (void **) &qglTexImage2D}, +// {"glTexSubImage1D", (void **) &qglTexSubImage1D}, + {"glTexSubImage2D", (void **) &qglTexSubImage2D}, +// {"glCopyTexImage1D", (void **) &qglCopyTexImage1D}, + {"glCopyTexImage2D", (void **) &qglCopyTexImage2D}, +// {"glCopyTexSubImage1D", (void **) &qglCopyTexSubImage1D}, + {"glCopyTexSubImage2D", (void **) &qglCopyTexSubImage2D}, + {"glScissor", (void **) &qglScissor}, + {"glPolygonOffset", (void **) &qglPolygonOffset}, + {"glPolygonMode", (void **) &qglPolygonMode}, + {"glPolygonStipple", (void **) &qglPolygonStipple}, +// {"glClipPlane", (void **) &qglClipPlane}, +// {"glGetClipPlane", (void **) &qglGetClipPlane}, + {NULL, NULL} +}; + +static dllfunction_t drawrangeelementsfuncs[] = +{ + {"glDrawRangeElements", (void **) &qglDrawRangeElements}, + {NULL, NULL} +}; + +static dllfunction_t drawrangeelementsextfuncs[] = +{ + {"glDrawRangeElementsEXT", (void **) &qglDrawRangeElementsEXT}, + {NULL, NULL} +}; + +static dllfunction_t multitexturefuncs[] = +{ + {"glMultiTexCoord1fARB", (void **) &qglMultiTexCoord1f}, + {"glMultiTexCoord2fARB", (void **) &qglMultiTexCoord2f}, + {"glMultiTexCoord3fARB", (void **) &qglMultiTexCoord3f}, + {"glMultiTexCoord4fARB", (void **) &qglMultiTexCoord4f}, + {"glActiveTextureARB", (void **) &qglActiveTexture}, + {"glClientActiveTextureARB", (void **) &qglClientActiveTexture}, + {NULL, NULL} +}; + +static dllfunction_t texture3dextfuncs[] = +{ + {"glTexImage3DEXT", (void **) &qglTexImage3D}, + {"glTexSubImage3DEXT", (void **) &qglTexSubImage3D}, + {"glCopyTexSubImage3DEXT", (void **) &qglCopyTexSubImage3D}, + {NULL, NULL} +}; + +static dllfunction_t atiseparatestencilfuncs[] = +{ + {"glStencilOpSeparateATI", (void **) &qglStencilOpSeparate}, + {"glStencilFuncSeparateATI", (void **) &qglStencilFuncSeparate}, + {NULL, NULL} +}; + +static dllfunction_t gl2separatestencilfuncs[] = +{ + {"glStencilOpSeparate", (void **) &qglStencilOpSeparate}, + {"glStencilFuncSeparate", (void **) &qglStencilFuncSeparate}, + {NULL, NULL} +}; + +static dllfunction_t stenciltwosidefuncs[] = +{ + {"glActiveStencilFaceEXT", (void **) &qglActiveStencilFaceEXT}, + {NULL, NULL} +}; + +static dllfunction_t blendequationfuncs[] = +{ + {"glBlendEquationEXT", (void **) &qglBlendEquationEXT}, + {NULL, NULL} +}; + +static dllfunction_t gl20shaderfuncs[] = +{ + {"glDeleteShader", (void **) &qglDeleteShader}, + {"glDeleteProgram", (void **) &qglDeleteProgram}, +// {"glGetHandle", (void **) &qglGetHandle}, + {"glDetachShader", (void **) &qglDetachShader}, + {"glCreateShader", (void **) &qglCreateShader}, + {"glShaderSource", (void **) &qglShaderSource}, + {"glCompileShader", (void **) &qglCompileShader}, + {"glCreateProgram", (void **) &qglCreateProgram}, + {"glAttachShader", (void **) &qglAttachShader}, + {"glLinkProgram", (void **) &qglLinkProgram}, + {"glUseProgram", (void **) &qglUseProgram}, + {"glValidateProgram", (void **) &qglValidateProgram}, + {"glUniform1f", (void **) &qglUniform1f}, + {"glUniform2f", (void **) &qglUniform2f}, + {"glUniform3f", (void **) &qglUniform3f}, + {"glUniform4f", (void **) &qglUniform4f}, + {"glUniform1i", (void **) &qglUniform1i}, + {"glUniform2i", (void **) &qglUniform2i}, + {"glUniform3i", (void **) &qglUniform3i}, + {"glUniform4i", (void **) &qglUniform4i}, + {"glUniform1fv", (void **) &qglUniform1fv}, + {"glUniform2fv", (void **) &qglUniform2fv}, + {"glUniform3fv", (void **) &qglUniform3fv}, + {"glUniform4fv", (void **) &qglUniform4fv}, + {"glUniform1iv", (void **) &qglUniform1iv}, + {"glUniform2iv", (void **) &qglUniform2iv}, + {"glUniform3iv", (void **) &qglUniform3iv}, + {"glUniform4iv", (void **) &qglUniform4iv}, + {"glUniformMatrix2fv", (void **) &qglUniformMatrix2fv}, + {"glUniformMatrix3fv", (void **) &qglUniformMatrix3fv}, + {"glUniformMatrix4fv", (void **) &qglUniformMatrix4fv}, + {"glGetShaderiv", (void **) &qglGetShaderiv}, + {"glGetProgramiv", (void **) &qglGetProgramiv}, + {"glGetShaderInfoLog", (void **) &qglGetShaderInfoLog}, + {"glGetProgramInfoLog", (void **) &qglGetProgramInfoLog}, + {"glGetAttachedShaders", (void **) &qglGetAttachedShaders}, + {"glGetUniformLocation", (void **) &qglGetUniformLocation}, + {"glGetActiveUniform", (void **) &qglGetActiveUniform}, + {"glGetUniformfv", (void **) &qglGetUniformfv}, + {"glGetUniformiv", (void **) &qglGetUniformiv}, + {"glGetShaderSource", (void **) &qglGetShaderSource}, + {"glVertexAttrib1f", (void **) &qglVertexAttrib1f}, + {"glVertexAttrib1s", (void **) &qglVertexAttrib1s}, + {"glVertexAttrib1d", (void **) &qglVertexAttrib1d}, + {"glVertexAttrib2f", (void **) &qglVertexAttrib2f}, + {"glVertexAttrib2s", (void **) &qglVertexAttrib2s}, + {"glVertexAttrib2d", (void **) &qglVertexAttrib2d}, + {"glVertexAttrib3f", (void **) &qglVertexAttrib3f}, + {"glVertexAttrib3s", (void **) &qglVertexAttrib3s}, + {"glVertexAttrib3d", (void **) &qglVertexAttrib3d}, + {"glVertexAttrib4f", (void **) &qglVertexAttrib4f}, + {"glVertexAttrib4s", (void **) &qglVertexAttrib4s}, + {"glVertexAttrib4d", (void **) &qglVertexAttrib4d}, + {"glVertexAttrib4Nub", (void **) &qglVertexAttrib4Nub}, + {"glVertexAttrib1fv", (void **) &qglVertexAttrib1fv}, + {"glVertexAttrib1sv", (void **) &qglVertexAttrib1sv}, + {"glVertexAttrib1dv", (void **) &qglVertexAttrib1dv}, + {"glVertexAttrib2fv", (void **) &qglVertexAttrib1fv}, + {"glVertexAttrib2sv", (void **) &qglVertexAttrib1sv}, + {"glVertexAttrib2dv", (void **) &qglVertexAttrib1dv}, + {"glVertexAttrib3fv", (void **) &qglVertexAttrib1fv}, + {"glVertexAttrib3sv", (void **) &qglVertexAttrib1sv}, + {"glVertexAttrib3dv", (void **) &qglVertexAttrib1dv}, + {"glVertexAttrib4fv", (void **) &qglVertexAttrib1fv}, + {"glVertexAttrib4sv", (void **) &qglVertexAttrib1sv}, + {"glVertexAttrib4dv", (void **) &qglVertexAttrib1dv}, +// {"glVertexAttrib4iv", (void **) &qglVertexAttrib1iv}, +// {"glVertexAttrib4bv", (void **) &qglVertexAttrib1bv}, +// {"glVertexAttrib4ubv", (void **) &qglVertexAttrib1ubv}, +// {"glVertexAttrib4usv", (void **) &qglVertexAttrib1usv}, +// {"glVertexAttrib4uiv", (void **) &qglVertexAttrib1uiv}, +// {"glVertexAttrib4Nbv", (void **) &qglVertexAttrib1Nbv}, +// {"glVertexAttrib4Nsv", (void **) &qglVertexAttrib1Nsv}, +// {"glVertexAttrib4Niv", (void **) &qglVertexAttrib1Niv}, +// {"glVertexAttrib4Nubv", (void **) &qglVertexAttrib1Nubv}, +// {"glVertexAttrib4Nusv", (void **) &qglVertexAttrib1Nusv}, +// {"glVertexAttrib4Nuiv", (void **) &qglVertexAttrib1Nuiv}, + {"glVertexAttribPointer", (void **) &qglVertexAttribPointer}, + {"glEnableVertexAttribArray", (void **) &qglEnableVertexAttribArray}, + {"glDisableVertexAttribArray", (void **) &qglDisableVertexAttribArray}, + {"glBindAttribLocation", (void **) &qglBindAttribLocation}, + {"glGetActiveAttrib", (void **) &qglGetActiveAttrib}, + {"glGetAttribLocation", (void **) &qglGetAttribLocation}, + {"glGetVertexAttribdv", (void **) &qglGetVertexAttribdv}, + {"glGetVertexAttribfv", (void **) &qglGetVertexAttribfv}, + {"glGetVertexAttribiv", (void **) &qglGetVertexAttribiv}, + {"glGetVertexAttribPointerv", (void **) &qglGetVertexAttribPointerv}, + {NULL, NULL} +}; + +static dllfunction_t glsl130funcs[] = +{ + {"glBindFragDataLocation", (void **) &qglBindFragDataLocation}, + {NULL, NULL} +}; + +static dllfunction_t vbofuncs[] = +{ + {"glBindBufferARB" , (void **) &qglBindBufferARB}, + {"glDeleteBuffersARB" , (void **) &qglDeleteBuffersARB}, + {"glGenBuffersARB" , (void **) &qglGenBuffersARB}, + {"glIsBufferARB" , (void **) &qglIsBufferARB}, + {"glMapBufferARB" , (void **) &qglMapBufferARB}, + {"glUnmapBufferARB" , (void **) &qglUnmapBufferARB}, + {"glBufferDataARB" , (void **) &qglBufferDataARB}, + {"glBufferSubDataARB" , (void **) &qglBufferSubDataARB}, + {NULL, NULL} +}; + +static dllfunction_t ubofuncs[] = +{ + {"glGetUniformIndices" , (void **) &qglGetUniformIndices}, + {"glGetActiveUniformsiv" , (void **) &qglGetActiveUniformsiv}, + {"glGetActiveUniformName" , (void **) &qglGetActiveUniformName}, + {"glGetUniformBlockIndex" , (void **) &qglGetUniformBlockIndex}, + {"glGetActiveUniformBlockiv" , (void **) &qglGetActiveUniformBlockiv}, + {"glGetActiveUniformBlockName", (void **) &qglGetActiveUniformBlockName}, + {"glBindBufferRange" , (void **) &qglBindBufferRange}, + {"glBindBufferBase" , (void **) &qglBindBufferBase}, + {"glGetIntegeri_v" , (void **) &qglGetIntegeri_v}, + {"glUniformBlockBinding" , (void **) &qglUniformBlockBinding}, + {NULL, NULL} +}; + +static dllfunction_t arbfbofuncs[] = +{ + {"glIsRenderbuffer" , (void **) &qglIsRenderbuffer}, + {"glBindRenderbuffer" , (void **) &qglBindRenderbuffer}, + {"glDeleteRenderbuffers" , (void **) &qglDeleteRenderbuffers}, + {"glGenRenderbuffers" , (void **) &qglGenRenderbuffers}, + {"glRenderbufferStorage" , (void **) &qglRenderbufferStorage}, + {"glRenderbufferStorageMultisample" , (void **) &qglRenderbufferStorageMultisample}, // not in GL_EXT_framebuffer_object + {"glGetRenderbufferParameteriv" , (void **) &qglGetRenderbufferParameteriv}, + {"glIsFramebuffer" , (void **) &qglIsFramebuffer}, + {"glBindFramebuffer" , (void **) &qglBindFramebuffer}, + {"glDeleteFramebuffers" , (void **) &qglDeleteFramebuffers}, + {"glGenFramebuffers" , (void **) &qglGenFramebuffers}, + {"glCheckFramebufferStatus" , (void **) &qglCheckFramebufferStatus}, + {"glFramebufferTexture1D" , (void **) &qglFramebufferTexture1D}, + {"glFramebufferTexture2D" , (void **) &qglFramebufferTexture2D}, + {"glFramebufferTexture3D" , (void **) &qglFramebufferTexture3D}, + {"glFramebufferTextureLayer" , (void **) &qglFramebufferTextureLayer}, // not in GL_EXT_framebuffer_object + {"glFramebufferRenderbuffer" , (void **) &qglFramebufferRenderbuffer}, + {"glGetFramebufferAttachmentParameteriv" , (void **) &qglGetFramebufferAttachmentParameteriv}, + {"glBlitFramebuffer" , (void **) &qglBlitFramebuffer}, // not in GL_EXT_framebuffer_object + {"glGenerateMipmap" , (void **) &qglGenerateMipmap}, + {NULL, NULL} +}; + +static dllfunction_t extfbofuncs[] = +{ + {"glIsRenderbufferEXT" , (void **) &qglIsRenderbuffer}, + {"glBindRenderbufferEXT" , (void **) &qglBindRenderbuffer}, + {"glDeleteRenderbuffersEXT" , (void **) &qglDeleteRenderbuffers}, + {"glGenRenderbuffersEXT" , (void **) &qglGenRenderbuffers}, + {"glRenderbufferStorageEXT" , (void **) &qglRenderbufferStorage}, + {"glGetRenderbufferParameterivEXT" , (void **) &qglGetRenderbufferParameteriv}, + {"glIsFramebufferEXT" , (void **) &qglIsFramebuffer}, + {"glBindFramebufferEXT" , (void **) &qglBindFramebuffer}, + {"glDeleteFramebuffersEXT" , (void **) &qglDeleteFramebuffers}, + {"glGenFramebuffersEXT" , (void **) &qglGenFramebuffers}, + {"glCheckFramebufferStatusEXT" , (void **) &qglCheckFramebufferStatus}, + {"glFramebufferTexture1DEXT" , (void **) &qglFramebufferTexture1D}, + {"glFramebufferTexture2DEXT" , (void **) &qglFramebufferTexture2D}, + {"glFramebufferTexture3DEXT" , (void **) &qglFramebufferTexture3D}, + {"glFramebufferRenderbufferEXT" , (void **) &qglFramebufferRenderbuffer}, + {"glGetFramebufferAttachmentParameterivEXT" , (void **) &qglGetFramebufferAttachmentParameteriv}, + {"glGenerateMipmapEXT" , (void **) &qglGenerateMipmap}, + {NULL, NULL} +}; + +static dllfunction_t texturecompressionfuncs[] = +{ + {"glCompressedTexImage3DARB", (void **) &qglCompressedTexImage3DARB}, + {"glCompressedTexImage2DARB", (void **) &qglCompressedTexImage2DARB}, +// {"glCompressedTexImage1DARB", (void **) &qglCompressedTexImage1DARB}, + {"glCompressedTexSubImage3DARB", (void **) &qglCompressedTexSubImage3DARB}, + {"glCompressedTexSubImage2DARB", (void **) &qglCompressedTexSubImage2DARB}, +// {"glCompressedTexSubImage1DARB", (void **) &qglCompressedTexSubImage1DARB}, + {"glGetCompressedTexImageARB", (void **) &qglGetCompressedTexImageARB}, + {NULL, NULL} +}; + +static dllfunction_t occlusionqueryfuncs[] = +{ + {"glGenQueriesARB", (void **) &qglGenQueriesARB}, + {"glDeleteQueriesARB", (void **) &qglDeleteQueriesARB}, + {"glIsQueryARB", (void **) &qglIsQueryARB}, + {"glBeginQueryARB", (void **) &qglBeginQueryARB}, + {"glEndQueryARB", (void **) &qglEndQueryARB}, + {"glGetQueryivARB", (void **) &qglGetQueryivARB}, + {"glGetQueryObjectivARB", (void **) &qglGetQueryObjectivARB}, + {"glGetQueryObjectuivARB", (void **) &qglGetQueryObjectuivARB}, + {NULL, NULL} +}; + +static dllfunction_t drawbuffersfuncs[] = +{ + {"glDrawBuffersARB", (void **) &qglDrawBuffersARB}, + {NULL, NULL} +}; + +static dllfunction_t multisamplefuncs[] = +{ + {"glSampleCoverageARB", (void **) &qglSampleCoverageARB}, + {NULL, NULL} +}; +#endif + +void VID_ClearExtensions(void) +{ + // VorteX: reset extensions info cvar, it got filled by GL_CheckExtension + Cvar_SetQuick(&gl_info_extensions, ""); + + // clear the extension flags + memset(&vid.support, 0, sizeof(vid.support)); + vid.renderpath = RENDERPATH_GL11; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = false; + vid.useinterleavedarrays = false; + vid.forcevbo = false; + vid.maxtexturesize_2d = 0; + vid.maxtexturesize_3d = 0; + vid.maxtexturesize_cubemap = 0; + vid.texunits = 1; + vid.teximageunits = 1; + vid.texarrayunits = 1; + vid.max_anisotropy = 1; + vid.maxdrawbuffers = 1; + +#ifndef USE_GLES2 + // this is a complete list of all functions that are directly checked in the renderer + qglDrawRangeElements = NULL; + qglDrawBuffer = NULL; + qglPolygonStipple = NULL; + qglFlush = NULL; + qglActiveTexture = NULL; + qglGetCompressedTexImageARB = NULL; + qglFramebufferTexture2D = NULL; + qglDrawBuffersARB = NULL; +#endif +} + +#ifndef USE_GLES2 +void VID_CheckExtensions(void) +{ + if (!GL_CheckExtension("glbase", opengl110funcs, NULL, false)) + Sys_Error("OpenGL 1.1.0 functions not found"); + vid.support.gl20shaders = GL_CheckExtension("2.0", gl20shaderfuncs, "-noshaders", true); + + CHECKGLERROR + + Con_DPrint("Checking OpenGL extensions...\n"); + + if (vid.support.gl20shaders) + { + char *s; + // detect what GLSL version is available, to enable features like r_glsl_skeletal and higher quality reliefmapping + vid.support.glshaderversion = 100; + s = (char *) qglGetString(GL_SHADING_LANGUAGE_VERSION); + if (s) + vid.support.glshaderversion = (int)(atof(s) * 100.0f + 0.5f); + if (vid.support.glshaderversion < 100) + vid.support.glshaderversion = 100; + Con_DPrintf("Detected GLSL #version %i\n", vid.support.glshaderversion); + // get the glBindFragDataLocation function + if (vid.support.glshaderversion >= 130) + vid.support.gl20shaders130 = GL_CheckExtension("glshaders130", glsl130funcs, "-noglsl130", true); + } + + // GL drivers generally prefer GL_BGRA + vid.forcetextype = GL_BGRA; + + vid.support.amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false); + vid.support.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false); + vid.support.arb_draw_buffers = GL_CheckExtension("GL_ARB_draw_buffers", drawbuffersfuncs, "-nodrawbuffers", false); + vid.support.arb_multitexture = GL_CheckExtension("GL_ARB_multitexture", multitexturefuncs, "-nomtex", false); + vid.support.arb_occlusion_query = GL_CheckExtension("GL_ARB_occlusion_query", occlusionqueryfuncs, "-noocclusionquery", false); + vid.support.arb_shadow = GL_CheckExtension("GL_ARB_shadow", NULL, "-noshadow", false); + vid.support.arb_texture_compression = GL_CheckExtension("GL_ARB_texture_compression", texturecompressionfuncs, "-notexturecompression", false); + vid.support.arb_texture_cube_map = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false); + vid.support.arb_texture_env_combine = GL_CheckExtension("GL_ARB_texture_env_combine", NULL, "-nocombine", false) || GL_CheckExtension("GL_EXT_texture_env_combine", NULL, "-nocombine", false); + vid.support.arb_texture_gather = GL_CheckExtension("GL_ARB_texture_gather", NULL, "-notexturegather", false); +#ifndef __APPLE__ + // LordHavoc: too many bugs on OSX! + vid.support.arb_texture_non_power_of_two = GL_CheckExtension("GL_ARB_texture_non_power_of_two", NULL, "-notexturenonpoweroftwo", false); +#endif + vid.support.arb_vertex_buffer_object = GL_CheckExtension("GL_ARB_vertex_buffer_object", vbofuncs, "-novbo", false); + vid.support.arb_uniform_buffer_object = GL_CheckExtension("GL_ARB_uniform_buffer_object", ubofuncs, "-noubo", false); + vid.support.ati_separate_stencil = GL_CheckExtension("separatestencil", gl2separatestencilfuncs, "-noseparatestencil", true) || GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "-noseparatestencil", false); + vid.support.ext_blend_minmax = GL_CheckExtension("GL_EXT_blend_minmax", blendequationfuncs, "-noblendminmax", false); + vid.support.ext_blend_subtract = GL_CheckExtension("GL_EXT_blend_subtract", blendequationfuncs, "-noblendsubtract", false); + vid.support.ext_draw_range_elements = GL_CheckExtension("drawrangeelements", drawrangeelementsfuncs, "-nodrawrangeelements", true) || GL_CheckExtension("GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "-nodrawrangeelements", false); + vid.support.arb_framebuffer_object = GL_CheckExtension("GL_ARB_framebuffer_object", arbfbofuncs, "-nofbo", false); + if (vid.support.arb_framebuffer_object) + vid.support.ext_framebuffer_object = true; + else + vid.support.ext_framebuffer_object = GL_CheckExtension("GL_EXT_framebuffer_object", extfbofuncs, "-nofbo", false); + + vid.support.ext_packed_depth_stencil = GL_CheckExtension("GL_EXT_packed_depth_stencil", NULL, "-nopackeddepthstencil", false); + vid.support.ext_stencil_two_side = GL_CheckExtension("GL_EXT_stencil_two_side", stenciltwosidefuncs, "-nostenciltwoside", false); + vid.support.ext_texture_3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false); + vid.support.ext_texture_compression_s3tc = GL_CheckExtension("GL_EXT_texture_compression_s3tc", NULL, "-nos3tc", false); + vid.support.ext_texture_edge_clamp = GL_CheckExtension("GL_EXT_texture_edge_clamp", NULL, "-noedgeclamp", false) || GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "-noedgeclamp", false); + vid.support.ext_texture_filter_anisotropic = GL_CheckExtension("GL_EXT_texture_filter_anisotropic", NULL, "-noanisotropy", false); + vid.support.ext_texture_srgb = GL_CheckExtension("GL_EXT_texture_sRGB", NULL, "-nosrgb", false); + vid.support.arb_multisample = GL_CheckExtension("GL_ARB_multisample", multisamplefuncs, "-nomultisample", false); + vid.allowalphatocoverage = false; + +// COMMANDLINEOPTION: GL: -noshaders disables use of OpenGL 2.0 shaders (which allow pixel shader effects, can improve per pixel lighting performance and capabilities) +// COMMANDLINEOPTION: GL: -noanisotropy disables GL_EXT_texture_filter_anisotropic (allows higher quality texturing) +// COMMANDLINEOPTION: GL: -noblendminmax disables GL_EXT_blend_minmax +// COMMANDLINEOPTION: GL: -noblendsubtract disables GL_EXT_blend_subtract +// COMMANDLINEOPTION: GL: -nocombine disables GL_ARB_texture_env_combine or GL_EXT_texture_env_combine (required for bumpmapping and faster map rendering) +// COMMANDLINEOPTION: GL: -nocubemap disables GL_ARB_texture_cube_map (required for bumpmapping) +// COMMANDLINEOPTION: GL: -nodepthtexture disables use of GL_ARB_depth_texture (required for shadowmapping) +// COMMANDLINEOPTION: GL: -nodrawbuffers disables use of GL_ARB_draw_buffers (required for r_shadow_deferredprepass) +// COMMANDLINEOPTION: GL: -nodrawrangeelements disables GL_EXT_draw_range_elements (renders faster) +// COMMANDLINEOPTION: GL: -noedgeclamp disables GL_EXT_texture_edge_clamp or GL_SGIS_texture_edge_clamp (recommended, some cards do not support the other texture clamp method) +// COMMANDLINEOPTION: GL: -nofbo disables GL_EXT_framebuffer_object (which accelerates rendering), only used if GL_ARB_fragment_shader is also available +// COMMANDLINEOPTION: GL: -nomtex disables GL_ARB_multitexture (required for faster map rendering) +// COMMANDLINEOPTION: GL: -noocclusionquery disables GL_ARB_occlusion_query (which allows coronas to fade according to visibility, and potentially used for rendering optimizations) +// COMMANDLINEOPTION: GL: -nos3tc disables GL_EXT_texture_compression_s3tc (which allows use of .dds texture caching) +// COMMANDLINEOPTION: GL: -noseparatestencil disables use of OpenGL2.0 glStencilOpSeparate and GL_ATI_separate_stencil extensions (which accelerate shadow rendering) +// COMMANDLINEOPTION: GL: -noshadow disables use of GL_ARB_shadow (required for hardware shadowmap filtering) +// COMMANDLINEOPTION: GL: -nostenciltwoside disables GL_EXT_stencil_two_side (which accelerate shadow rendering) +// COMMANDLINEOPTION: GL: -notexture3d disables GL_EXT_texture3D (required for spherical lights, otherwise they render as a column) +// COMMANDLINEOPTION: GL: -notexture4 disables GL_AMD_texture_texture4 (which provides fetch4 sampling) +// COMMANDLINEOPTION: GL: -notexturecompression disables GL_ARB_texture_compression (which saves video memory if it is supported, but can also degrade image quality, see gl_texturecompression cvar documentation for more information) +// COMMANDLINEOPTION: GL: -notexturegather disables GL_ARB_texture_gather (which provides fetch4 sampling) +// COMMANDLINEOPTION: GL: -notexturenonpoweroftwo disables GL_ARB_texture_non_power_of_two (which saves video memory if it is supported, but crashes on some buggy drivers) +// COMMANDLINEOPTION: GL: -novbo disables GL_ARB_vertex_buffer_object (which accelerates rendering) +// COMMANDLINEOPTION: GL: -nosrgb disables GL_EXT_texture_sRGB (which is used for higher quality non-linear texture gamma) +// COMMANDLINEOPTION: GL: -nomultisample disables GL_ARB_multisample + + if (vid.support.arb_draw_buffers) + qglGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, (GLint*)&vid.maxdrawbuffers); + + // disable non-power-of-two textures on Radeon X1600 and other cards that do not accelerate it with some filtering modes / repeat modes that we use + // we detect these cards by checking if the hardware supports vertex texture fetch (Geforce6 does, Radeon X1600 does not, all GL3-class hardware does) + if(vid.support.arb_texture_non_power_of_two && vid.support.gl20shaders) + { + int val = 0; + qglGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &val);CHECKGLERROR + if (val < 1) + vid.support.arb_texture_non_power_of_two = false; + } + + // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code + if (qglDrawRangeElements == NULL) + qglDrawRangeElements = qglDrawRangeElementsEXT; + + qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d); + if (vid.support.ext_texture_filter_anisotropic) + qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint*)&vid.max_anisotropy); + if (vid.support.arb_texture_cube_map) + qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap); + if (vid.support.ext_texture_3d) + qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d); + + // verify that 3d textures are really supported + if (vid.support.ext_texture_3d && vid.maxtexturesize_3d < 32) + { + vid.support.ext_texture_3d = false; + Con_Printf("GL_EXT_texture3D reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n"); + } + + vid.texunits = vid.teximageunits = vid.texarrayunits = 1; + if (vid.support.arb_multitexture) + qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits); + if (vid_gl20.integer && vid.support.gl20shaders) + { + qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits); + qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (int *)&vid.teximageunits);CHECKGLERROR + qglGetIntegerv(GL_MAX_TEXTURE_COORDS, (int *)&vid.texarrayunits);CHECKGLERROR + vid.texunits = bound(4, vid.texunits, MAX_TEXTUREUNITS); + vid.teximageunits = bound(16, vid.teximageunits, MAX_TEXTUREUNITS); + vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS); + Con_DPrintf("Using GL2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : ""); + vid.renderpath = RENDERPATH_GL20; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = true; + vid.useinterleavedarrays = false; + Con_Printf("vid.support.arb_multisample %i\n", vid.support.arb_multisample); + Con_Printf("vid.support.gl20shaders %i\n", vid.support.gl20shaders); + vid.allowalphatocoverage = true; // but see below, it may get turned to false again if GL_SAMPLES_ARB is <= 1 + } + else if (vid.support.arb_texture_env_combine && vid.texunits >= 2 && vid_gl13.integer) + { + qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits); + vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS); + vid.teximageunits = vid.texunits; + vid.texarrayunits = vid.texunits; + Con_DPrintf("Using GL1.3 rendering path - %i texture units, single pass rendering\n", vid.texunits); + vid.renderpath = RENDERPATH_GL13; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = false; + vid.useinterleavedarrays = false; + } + else + { + vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS); + vid.teximageunits = vid.texunits; + vid.texarrayunits = vid.texunits; + Con_DPrintf("Using GL1.1 rendering path - %i texture units, two pass rendering\n", vid.texunits); + vid.renderpath = RENDERPATH_GL11; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = false; + vid.useinterleavedarrays = false; + } + + // enable multisample antialiasing if possible + if(vid.support.arb_multisample) + { + int samples = 0; + qglGetIntegerv(GL_SAMPLES_ARB, &samples); + vid.samples = samples; + if (samples > 1) + qglEnable(GL_MULTISAMPLE_ARB); + else + vid.allowalphatocoverage = false; + } + else + { + vid.allowalphatocoverage = false; + vid.samples = 1; + } + + // VorteX: set other info (maybe place them in VID_InitMode?) + Cvar_SetQuick(&gl_info_vendor, gl_vendor); + Cvar_SetQuick(&gl_info_renderer, gl_renderer); + Cvar_SetQuick(&gl_info_version, gl_version); + Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : ""); + Cvar_SetQuick(&gl_info_driver, gl_driver); +} +#endif + +float VID_JoyState_GetAxis(const vid_joystate_t *joystate, int axis, float sensitivity, float deadzone) +{ + float value; + value = (axis >= 0 && axis < MAXJOYAXIS) ? joystate->axis[axis] : 0.0f; + value = value > deadzone ? (value - deadzone) : (value < -deadzone ? (value + deadzone) : 0.0f); + value *= deadzone > 0 ? (1.0f / (1.0f - deadzone)) : 1.0f; + value = bound(-1, value, 1); + return value * sensitivity; +} + +qboolean VID_JoyBlockEmulatedKeys(int keycode) +{ + int j; + vid_joystate_t joystate; + + if (!joy_axiskeyevents.integer) + return false; + if (vid_joystate.is360) + return false; + if (keycode != K_UPARROW && keycode != K_DOWNARROW && keycode != K_RIGHTARROW && keycode != K_LEFTARROW) + return false; + + // block system-generated key events for arrow keys if we're emulating the arrow keys ourselves + VID_BuildJoyState(&joystate); + for (j = 32;j < 36;j++) + if (vid_joystate.button[j] || joystate.button[j]) + return true; + + return false; +} + +void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate) +{ +#ifdef WIN32 + xinput_state_t xinputstate; +#endif + memset(joystate, 0, sizeof(*joystate)); +#ifdef WIN32 + if (vid_xinputindex >= 0 && qXInputGetState && qXInputGetState(vid_xinputindex, &xinputstate) == S_OK) + { + joystate->is360 = true; + joystate->button[ 0] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0; + joystate->button[ 1] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0; + joystate->button[ 2] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0; + joystate->button[ 3] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0; + joystate->button[ 4] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0; + joystate->button[ 5] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0; + joystate->button[ 6] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; + joystate->button[ 7] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; + joystate->button[ 8] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; + joystate->button[ 9] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; + joystate->button[10] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0; + joystate->button[11] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; + joystate->button[12] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0; + joystate->button[13] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0; + joystate->button[14] = xinputstate.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; + joystate->button[15] = xinputstate.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; + joystate->button[16] = xinputstate.Gamepad.sThumbLY < -16384; + joystate->button[17] = xinputstate.Gamepad.sThumbLY > 16384; + joystate->button[18] = xinputstate.Gamepad.sThumbLX < -16384; + joystate->button[19] = xinputstate.Gamepad.sThumbLX > 16384; + joystate->button[20] = xinputstate.Gamepad.sThumbRY < -16384; + joystate->button[21] = xinputstate.Gamepad.sThumbRY > 16384; + joystate->button[22] = xinputstate.Gamepad.sThumbRX < -16384; + joystate->button[23] = xinputstate.Gamepad.sThumbRX > 16384; + joystate->axis[ 4] = xinputstate.Gamepad.bLeftTrigger * (1.0f / 255.0f); + joystate->axis[ 5] = xinputstate.Gamepad.bRightTrigger * (1.0f / 255.0f); + joystate->axis[ 0] = xinputstate.Gamepad.sThumbLX * (1.0f / 32767.0f); + joystate->axis[ 1] = xinputstate.Gamepad.sThumbLY * (1.0f / 32767.0f); + joystate->axis[ 2] = xinputstate.Gamepad.sThumbRX * (1.0f / 32767.0f); + joystate->axis[ 3] = xinputstate.Gamepad.sThumbRY * (1.0f / 32767.0f); + } +#endif +} + +void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate) +{ + float f, r; + if (joystate->is360) + return; + // emulate key events for thumbstick + f = VID_JoyState_GetAxis(joystate, joy_axisforward.integer, 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityforward.value; + r = VID_JoyState_GetAxis(joystate, joy_axisside.integer , 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityside.value; +#if MAXJOYBUTTON != 36 +#error this code must be updated if MAXJOYBUTTON changes! +#endif + joystate->button[32] = f > 0.0f; + joystate->button[33] = f < 0.0f; + joystate->button[34] = r > 0.0f; + joystate->button[35] = r < 0.0f; +} + +static void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer) +{ + if (oldbutton) + { + if (newbutton) + { + if (realtime >= *timer) + { + Key_Event(key, 0, true); + *timer = realtime + 0.1; + } + } + else + { + Key_Event(key, 0, false); + *timer = 0; + } + } + else + { + if (newbutton) + { + Key_Event(key, 0, true); + *timer = realtime + 0.5; + } + } +} + +#if MAXJOYBUTTON != 36 +#error this code must be updated if MAXJOYBUTTON changes! +#endif +static int joybuttonkey[MAXJOYBUTTON][2] = +{ + {K_JOY1, K_ENTER}, {K_JOY2, K_ESCAPE}, {K_JOY3, 0}, {K_JOY4, 0}, {K_JOY5, 0}, {K_JOY6, 0}, {K_JOY7, 0}, {K_JOY8, 0}, {K_JOY9, 0}, {K_JOY10, 0}, {K_JOY11, 0}, {K_JOY12, 0}, {K_JOY13, 0}, {K_JOY14, 0}, {K_JOY15, 0}, {K_JOY16, 0}, + {K_AUX1, 0}, {K_AUX2, 0}, {K_AUX3, 0}, {K_AUX4, 0}, {K_AUX5, 0}, {K_AUX6, 0}, {K_AUX7, 0}, {K_AUX8, 0}, {K_AUX9, 0}, {K_AUX10, 0}, {K_AUX11, 0}, {K_AUX12, 0}, {K_AUX13, 0}, {K_AUX14, 0}, {K_AUX15, 0}, {K_AUX16, 0}, + {K_JOY_UP, K_UPARROW}, {K_JOY_DOWN, K_DOWNARROW}, {K_JOY_RIGHT, K_RIGHTARROW}, {K_JOY_LEFT, K_LEFTARROW}, +}; + +static int joybuttonkey360[][2] = +{ + {K_X360_DPAD_UP, K_UPARROW}, + {K_X360_DPAD_DOWN, K_DOWNARROW}, + {K_X360_DPAD_LEFT, K_LEFTARROW}, + {K_X360_DPAD_RIGHT, K_RIGHTARROW}, + {K_X360_START, K_ESCAPE}, + {K_X360_BACK, K_ESCAPE}, + {K_X360_LEFT_THUMB, 0}, + {K_X360_RIGHT_THUMB, 0}, + {K_X360_LEFT_SHOULDER, 0}, + {K_X360_RIGHT_SHOULDER, 0}, + {K_X360_A, K_ENTER}, + {K_X360_B, K_ESCAPE}, + {K_X360_X, 0}, + {K_X360_Y, 0}, + {K_X360_LEFT_TRIGGER, 0}, + {K_X360_RIGHT_TRIGGER, 0}, + {K_X360_LEFT_THUMB_DOWN, K_DOWNARROW}, + {K_X360_LEFT_THUMB_UP, K_UPARROW}, + {K_X360_LEFT_THUMB_LEFT, K_LEFTARROW}, + {K_X360_LEFT_THUMB_RIGHT, K_RIGHTARROW}, + {K_X360_RIGHT_THUMB_DOWN, 0}, + {K_X360_RIGHT_THUMB_UP, 0}, + {K_X360_RIGHT_THUMB_LEFT, 0}, + {K_X360_RIGHT_THUMB_RIGHT, 0}, +}; + +double vid_joybuttontimer[MAXJOYBUTTON]; +void VID_ApplyJoyState(vid_joystate_t *joystate) +{ + int j; + int c = joy_axiskeyevents.integer != 0; + if (joystate->is360) + { +#if 0 + // keystrokes (chatpad) + // DOES NOT WORK - no driver support in xinput1_3.dll :( + xinput_keystroke_t keystroke; + while (qXInputGetKeystroke && qXInputGetKeystroke(XUSER_INDEX_ANY, 0, &keystroke) == S_OK) + Con_Printf("XInput KeyStroke: VirtualKey %i, Unicode %i, Flags %x, UserIndex %i, HidCode %i\n", keystroke.VirtualKey, keystroke.Unicode, keystroke.Flags, keystroke.UserIndex, keystroke.HidCode); +#endif + + // emit key events for buttons + for (j = 0;j < (int)(sizeof(joybuttonkey360)/sizeof(joybuttonkey360[0]));j++) + VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey360[j][c], &vid_joybuttontimer[j]); + + // axes + cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_x360_axisforward.integer, joy_x360_sensitivityforward.value, joy_x360_deadzoneforward.value) * cl_forwardspeed.value; + cl.cmd.sidemove += VID_JoyState_GetAxis(joystate, joy_x360_axisside.integer, joy_x360_sensitivityside.value, joy_x360_deadzoneside.value) * cl_sidespeed.value; + cl.cmd.upmove += VID_JoyState_GetAxis(joystate, joy_x360_axisup.integer, joy_x360_sensitivityup.value, joy_x360_deadzoneup.value) * cl_upspeed.value; + cl.viewangles[0] += VID_JoyState_GetAxis(joystate, joy_x360_axispitch.integer, joy_x360_sensitivitypitch.value, joy_x360_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value; + cl.viewangles[1] += VID_JoyState_GetAxis(joystate, joy_x360_axisyaw.integer, joy_x360_sensitivityyaw.value, joy_x360_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value; + //cl.viewangles[2] += VID_JoyState_GetAxis(joystate, joy_x360_axisroll.integer, joy_x360_sensitivityroll.value, joy_x360_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value; + } + else + { + // emit key events for buttons + for (j = 0;j < MAXJOYBUTTON;j++) + VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey[j][c], &vid_joybuttontimer[j]); + + // axes + cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value; + cl.cmd.sidemove += VID_JoyState_GetAxis(joystate, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value; + cl.cmd.upmove += VID_JoyState_GetAxis(joystate, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value; + cl.viewangles[0] += VID_JoyState_GetAxis(joystate, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value; + cl.viewangles[1] += VID_JoyState_GetAxis(joystate, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value; + //cl.viewangles[2] += VID_JoyState_GetAxis(joystate, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value; + } + + vid_joystate = *joystate; +} + +int VID_Shared_SetJoystick(int index) +{ +#ifdef WIN32 + int i; + int xinputcount = 0; + int xinputindex = -1; + int xinputavailable = 0; + xinput_state_t state; + // detect available XInput controllers + for (i = 0;i < 4;i++) + { + if (qXInputGetState && qXInputGetState(i, &state) == S_OK) + { + xinputavailable |= 1<= 0) + Con_Printf("Joystick %i opened (XInput Device %i)\n", index, xinputindex); + } + return xinputcount; +#else + return 0; +#endif +} + + +static void Force_CenterView_f (void) +{ + cl.viewangles[PITCH] = 0; +} + +static int gamma_forcenextframe = false; +static float cachegamma, cachebrightness, cachecontrast, cacheblack[3], cachegrey[3], cachewhite[3], cachecontrastboost; +static int cachecolorenable, cachehwgamma; + +unsigned int vid_gammatables_serial = 0; // so other subsystems can poll if gamma parameters have changed +qboolean vid_gammatables_trivial = true; +void VID_BuildGammaTables(unsigned short *ramps, int rampsize) +{ + if (cachecolorenable) + { + BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[0]), cachewhite[0], cacheblack[0], cachecontrastboost, ramps, rampsize); + BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[1]), cachewhite[1], cacheblack[1], cachecontrastboost, ramps + rampsize, rampsize); + BuildGammaTable16(1.0f, invpow(0.5, 1 - cachegrey[2]), cachewhite[2], cacheblack[2], cachecontrastboost, ramps + rampsize*2, rampsize); + } + else + { + BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps, rampsize); + BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize, rampsize); + BuildGammaTable16(1.0f, cachegamma, cachecontrast, cachebrightness, cachecontrastboost, ramps + rampsize*2, rampsize); + } + + if(vid.sRGB2D || vid.sRGB3D) + { + int i; + for(i = 0; i < 3*rampsize; ++i) + ramps[i] = (int)floor(bound(0.0f, Image_sRGBFloatFromLinearFloat(ramps[i] / 65535.0f), 1.0f) * 65535.0f + 0.5f); + } + + // LordHavoc: this code came from Ben Winslow and Zinx Verituse, I have + // immensely butchered it to work with variable framerates and fit in with + // the rest of darkplaces. + if (v_psycho.integer) + { + int x, y; + float t; + static float n[3], nd[3], nt[3]; + static int init = true; + unsigned short *ramp; + gamma_forcenextframe = true; + if (init) + { + init = false; + for (x = 0;x < 3;x++) + { + n[x] = lhrandom(0, 1); + nd[x] = (rand()&1)?-0.25:0.25; + nt[x] = lhrandom(1, 8.2); + } + } + + for (x = 0;x < 3;x++) + { + nt[x] -= cl.realframetime; + if (nt[x] < 0) + { + nd[x] = -nd[x]; + nt[x] += lhrandom(1, 8.2); + } + n[x] += nd[x] * cl.realframetime; + n[x] -= floor(n[x]); + } + + for (x = 0, ramp = ramps;x < 3;x++) + for (y = 0, t = n[x] - 0.75f;y < rampsize;y++, t += 0.75f * (2.0f / rampsize)) + *ramp++ = (unsigned short)(cos(t*(M_PI*2.0)) * 32767.0f + 32767.0f); + } +} + +void VID_UpdateGamma(qboolean force, int rampsize) +{ + cvar_t *c; + float f; + int wantgamma; + qboolean gamma_changed = false; + + // LordHavoc: don't mess with gamma tables if running dedicated + if (cls.state == ca_dedicated) + return; + + wantgamma = v_hwgamma.integer; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + if (v_glslgamma.integer) + wantgamma = 0; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + break; + } + if(!vid_activewindow) + wantgamma = 0; +#define BOUNDCVAR(cvar, m1, m2) c = &(cvar);f = bound(m1, c->value, m2);if (c->value != f) Cvar_SetValueQuick(c, f); + BOUNDCVAR(v_gamma, 0.1, 5); + BOUNDCVAR(v_contrast, 0.2, 5); + BOUNDCVAR(v_brightness, -v_contrast.value * 0.8, 0.8); + //BOUNDCVAR(v_contrastboost, 0.0625, 16); + BOUNDCVAR(v_color_black_r, 0, 0.8); + BOUNDCVAR(v_color_black_g, 0, 0.8); + BOUNDCVAR(v_color_black_b, 0, 0.8); + BOUNDCVAR(v_color_grey_r, 0, 0.95); + BOUNDCVAR(v_color_grey_g, 0, 0.95); + BOUNDCVAR(v_color_grey_b, 0, 0.95); + BOUNDCVAR(v_color_white_r, 1, 5); + BOUNDCVAR(v_color_white_g, 1, 5); + BOUNDCVAR(v_color_white_b, 1, 5); +#undef BOUNDCVAR + + // set vid_gammatables_trivial to true if the current settings would generate the identity gamma table + vid_gammatables_trivial = false; + if(v_psycho.integer == 0) + if(v_contrastboost.value == 1) + if(!vid.sRGB2D) + if(!vid.sRGB3D) + { + if(v_color_enable.integer) + { + if(v_color_black_r.value == 0) + if(v_color_black_g.value == 0) + if(v_color_black_b.value == 0) + if(fabs(v_color_grey_r.value - 0.5) < 1e-6) + if(fabs(v_color_grey_g.value - 0.5) < 1e-6) + if(fabs(v_color_grey_b.value - 0.5) < 1e-6) + if(v_color_white_r.value == 1) + if(v_color_white_g.value == 1) + if(v_color_white_b.value == 1) + vid_gammatables_trivial = true; + } + else + { + if(v_gamma.value == 1) + if(v_contrast.value == 1) + if(v_brightness.value == 0) + vid_gammatables_trivial = true; + } + } + +#define GAMMACHECK(cache, value) if (cache != (value)) gamma_changed = true;cache = (value) + if(v_psycho.integer) + gamma_changed = true; + GAMMACHECK(cachegamma , v_gamma.value); + GAMMACHECK(cachecontrast , v_contrast.value); + GAMMACHECK(cachebrightness , v_brightness.value); + GAMMACHECK(cachecontrastboost, v_contrastboost.value); + GAMMACHECK(cachecolorenable, v_color_enable.integer); + GAMMACHECK(cacheblack[0] , v_color_black_r.value); + GAMMACHECK(cacheblack[1] , v_color_black_g.value); + GAMMACHECK(cacheblack[2] , v_color_black_b.value); + GAMMACHECK(cachegrey[0] , v_color_grey_r.value); + GAMMACHECK(cachegrey[1] , v_color_grey_g.value); + GAMMACHECK(cachegrey[2] , v_color_grey_b.value); + GAMMACHECK(cachewhite[0] , v_color_white_r.value); + GAMMACHECK(cachewhite[1] , v_color_white_g.value); + GAMMACHECK(cachewhite[2] , v_color_white_b.value); + + if(gamma_changed) + ++vid_gammatables_serial; + + GAMMACHECK(cachehwgamma , wantgamma); +#undef GAMMACHECK + + if (!force && !gamma_forcenextframe && !gamma_changed) + return; + + gamma_forcenextframe = false; + + if (cachehwgamma) + { + if (!vid_usinghwgamma) + { + vid_usinghwgamma = true; + if (vid_gammarampsize != rampsize || !vid_gammaramps) + { + vid_gammarampsize = rampsize; + if (vid_gammaramps) + Z_Free(vid_gammaramps); + vid_gammaramps = (unsigned short *)Z_Malloc(6 * vid_gammarampsize * sizeof(unsigned short)); + vid_systemgammaramps = vid_gammaramps + 3 * vid_gammarampsize; + } + VID_GetGamma(vid_systemgammaramps, vid_gammarampsize); + } + + VID_BuildGammaTables(vid_gammaramps, vid_gammarampsize); + + // set vid_hardwaregammasupported to true if VID_SetGamma succeeds, OR if vid_hwgamma is >= 2 (forced gamma - ignores driver return value) + Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_gammaramps, vid_gammarampsize) || cachehwgamma >= 2); + // if custom gamma ramps failed (Windows stupidity), restore to system gamma + if(!vid_hardwaregammasupported.integer) + { + if (vid_usinghwgamma) + { + vid_usinghwgamma = false; + VID_SetGamma(vid_systemgammaramps, vid_gammarampsize); + } + } + } + else + { + if (vid_usinghwgamma) + { + vid_usinghwgamma = false; + VID_SetGamma(vid_systemgammaramps, vid_gammarampsize); + } + } +} + +void VID_RestoreSystemGamma(void) +{ + if (vid_usinghwgamma) + { + vid_usinghwgamma = false; + Cvar_SetValueQuick(&vid_hardwaregammasupported, VID_SetGamma(vid_systemgammaramps, vid_gammarampsize)); + // force gamma situation to be reexamined next frame + gamma_forcenextframe = true; + } +} + +#ifdef WIN32 +static dllfunction_t xinputdllfuncs[] = +{ + {"XInputGetState", (void **) &qXInputGetState}, + {"XInputGetKeystroke", (void **) &qXInputGetKeystroke}, + {NULL, NULL} +}; +static const char* xinputdllnames [] = +{ + "xinput1_3.dll", + "xinput1_2.dll", + "xinput1_1.dll", + NULL +}; +static dllhandle_t xinputdll_dll = NULL; +#endif + +void VID_Shared_Init(void) +{ +#ifdef SSE_POSSIBLE + if (Sys_HaveSSE2()) + { + Con_Printf("DPSOFTRAST available (SSE2 instructions detected)\n"); + Cvar_RegisterVariable(&vid_soft); + Cvar_RegisterVariable(&vid_soft_threads); + Cvar_RegisterVariable(&vid_soft_interlace); + } + else + Con_Printf("DPSOFTRAST not available (SSE2 disabled or not detected)\n"); +#else + Con_Printf("DPSOFTRAST not available (SSE2 not compiled in)\n"); +#endif + + Cvar_RegisterVariable(&vid_hardwaregammasupported); + Cvar_RegisterVariable(&gl_info_vendor); + Cvar_RegisterVariable(&gl_info_renderer); + Cvar_RegisterVariable(&gl_info_version); + Cvar_RegisterVariable(&gl_info_extensions); + Cvar_RegisterVariable(&gl_info_platform); + Cvar_RegisterVariable(&gl_info_driver); + Cvar_RegisterVariable(&v_gamma); + Cvar_RegisterVariable(&v_brightness); + Cvar_RegisterVariable(&v_contrastboost); + Cvar_RegisterVariable(&v_contrast); + + Cvar_RegisterVariable(&v_color_enable); + Cvar_RegisterVariable(&v_color_black_r); + Cvar_RegisterVariable(&v_color_black_g); + Cvar_RegisterVariable(&v_color_black_b); + Cvar_RegisterVariable(&v_color_grey_r); + Cvar_RegisterVariable(&v_color_grey_g); + Cvar_RegisterVariable(&v_color_grey_b); + Cvar_RegisterVariable(&v_color_white_r); + Cvar_RegisterVariable(&v_color_white_g); + Cvar_RegisterVariable(&v_color_white_b); + + Cvar_RegisterVariable(&v_hwgamma); + Cvar_RegisterVariable(&v_glslgamma); + Cvar_RegisterVariable(&v_glslgamma_2d); + + Cvar_RegisterVariable(&v_psycho); + + Cvar_RegisterVariable(&vid_fullscreen); + Cvar_RegisterVariable(&vid_width); + Cvar_RegisterVariable(&vid_height); + Cvar_RegisterVariable(&vid_bitsperpixel); + Cvar_RegisterVariable(&vid_samples); + Cvar_RegisterVariable(&vid_refreshrate); + Cvar_RegisterVariable(&vid_userefreshrate); + Cvar_RegisterVariable(&vid_stereobuffer); + Cvar_RegisterVariable(&vid_vsync); + Cvar_RegisterVariable(&vid_mouse); + Cvar_RegisterVariable(&vid_grabkeyboard); + Cvar_RegisterVariable(&vid_touchscreen); + Cvar_RegisterVariable(&vid_stick_mouse); + Cvar_RegisterVariable(&vid_resizable); + Cvar_RegisterVariable(&vid_minwidth); + Cvar_RegisterVariable(&vid_minheight); + Cvar_RegisterVariable(&vid_gl13); + Cvar_RegisterVariable(&vid_gl20); + Cvar_RegisterVariable(&gl_finish); + Cvar_RegisterVariable(&vid_sRGB); + Cvar_RegisterVariable(&vid_sRGB_fallback); + + Cvar_RegisterVariable(&joy_active); +#ifdef WIN32 + Cvar_RegisterVariable(&joy_xinputavailable); +#endif + Cvar_RegisterVariable(&joy_detected); + Cvar_RegisterVariable(&joy_enable); + Cvar_RegisterVariable(&joy_index); + Cvar_RegisterVariable(&joy_axisforward); + Cvar_RegisterVariable(&joy_axisside); + Cvar_RegisterVariable(&joy_axisup); + Cvar_RegisterVariable(&joy_axispitch); + Cvar_RegisterVariable(&joy_axisyaw); + //Cvar_RegisterVariable(&joy_axisroll); + Cvar_RegisterVariable(&joy_deadzoneforward); + Cvar_RegisterVariable(&joy_deadzoneside); + Cvar_RegisterVariable(&joy_deadzoneup); + Cvar_RegisterVariable(&joy_deadzonepitch); + Cvar_RegisterVariable(&joy_deadzoneyaw); + //Cvar_RegisterVariable(&joy_deadzoneroll); + Cvar_RegisterVariable(&joy_sensitivityforward); + Cvar_RegisterVariable(&joy_sensitivityside); + Cvar_RegisterVariable(&joy_sensitivityup); + Cvar_RegisterVariable(&joy_sensitivitypitch); + Cvar_RegisterVariable(&joy_sensitivityyaw); + //Cvar_RegisterVariable(&joy_sensitivityroll); + Cvar_RegisterVariable(&joy_axiskeyevents); + Cvar_RegisterVariable(&joy_axiskeyevents_deadzone); + Cvar_RegisterVariable(&joy_x360_axisforward); + Cvar_RegisterVariable(&joy_x360_axisside); + Cvar_RegisterVariable(&joy_x360_axisup); + Cvar_RegisterVariable(&joy_x360_axispitch); + Cvar_RegisterVariable(&joy_x360_axisyaw); + //Cvar_RegisterVariable(&joy_x360_axisroll); + Cvar_RegisterVariable(&joy_x360_deadzoneforward); + Cvar_RegisterVariable(&joy_x360_deadzoneside); + Cvar_RegisterVariable(&joy_x360_deadzoneup); + Cvar_RegisterVariable(&joy_x360_deadzonepitch); + Cvar_RegisterVariable(&joy_x360_deadzoneyaw); + //Cvar_RegisterVariable(&joy_x360_deadzoneroll); + Cvar_RegisterVariable(&joy_x360_sensitivityforward); + Cvar_RegisterVariable(&joy_x360_sensitivityside); + Cvar_RegisterVariable(&joy_x360_sensitivityup); + Cvar_RegisterVariable(&joy_x360_sensitivitypitch); + Cvar_RegisterVariable(&joy_x360_sensitivityyaw); + //Cvar_RegisterVariable(&joy_x360_sensitivityroll); + +#ifdef WIN32 + Sys_LoadLibrary(xinputdllnames, &xinputdll_dll, xinputdllfuncs); +#endif + + Cmd_AddCommand("force_centerview", Force_CenterView_f, "recenters view (stops looking up/down)"); + Cmd_AddCommand("vid_restart", VID_Restart_f, "restarts video system (closes and reopens the window, restarts renderer)"); +} + +static int VID_Mode(int fullscreen, int width, int height, int bpp, float refreshrate, int stereobuffer, int samples) +{ + viddef_mode_t mode; + char vabuf[1024]; + + memset(&mode, 0, sizeof(mode)); + mode.fullscreen = fullscreen != 0; + mode.width = width; + mode.height = height; + mode.bitsperpixel = bpp; + mode.refreshrate = vid_userefreshrate.integer ? max(1, refreshrate) : 0; + mode.userefreshrate = vid_userefreshrate.integer != 0; + mode.stereobuffer = stereobuffer != 0; + mode.samples = samples; + cl_ignoremousemoves = 2; + VID_ClearExtensions(); + + vid.samples = vid.mode.samples; + if (VID_InitMode(&mode)) + { + // accept the (possibly modified) mode + vid.mode = mode; + vid.fullscreen = vid.mode.fullscreen; + vid.width = vid.mode.width; + vid.height = vid.mode.height; + vid.bitsperpixel = vid.mode.bitsperpixel; + vid.refreshrate = vid.mode.refreshrate; + vid.userefreshrate = vid.mode.userefreshrate; + vid.stereobuffer = vid.mode.stereobuffer; + vid.stencil = vid.mode.bitsperpixel >= 16; + vid.sRGB2D = vid_sRGB.integer >= 1 && vid.sRGBcapable2D; + vid.sRGB3D = vid_sRGB.integer >= 1 && vid.sRGBcapable3D; + + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + { + GLboolean stereo; + qglGetBooleanv(GL_STEREO, &stereo); + vid.stereobuffer = stereo != 0; + } + break; + default: + vid.stereobuffer = false; + break; + } + + if( + (vid_sRGB_fallback.integer >= 3) // force fallback + || + (vid_sRGB_fallback.integer >= 2 && // fallback if framebuffer is 8bit + !(r_viewfbo.integer >= 2 && vid.support.ext_framebuffer_object && vid.support.arb_texture_non_power_of_two && vid.samples < 2)) + ) + vid.sRGB2D = vid.sRGB3D = false; + + if(vid.samples != vid.mode.samples) + Con_Printf("NOTE: requested %dx AA, got %dx AA\n", vid.mode.samples, vid.samples); + + Con_Printf("Video Mode: %s %dx%dx%dx%.2fhz%s%s\n", mode.fullscreen ? "fullscreen" : "window", mode.width, mode.height, mode.bitsperpixel, mode.refreshrate, mode.stereobuffer ? " stereo" : "", mode.samples > 1 ? va(vabuf, sizeof(vabuf), " (%ix AA)", mode.samples) : ""); + + Cvar_SetValueQuick(&vid_fullscreen, vid.mode.fullscreen); + Cvar_SetValueQuick(&vid_width, vid.mode.width); + Cvar_SetValueQuick(&vid_height, vid.mode.height); + Cvar_SetValueQuick(&vid_bitsperpixel, vid.mode.bitsperpixel); + Cvar_SetValueQuick(&vid_samples, vid.mode.samples); + if(vid_userefreshrate.integer) + Cvar_SetValueQuick(&vid_refreshrate, vid.mode.refreshrate); + Cvar_SetValueQuick(&vid_stereobuffer, vid.stereobuffer ? 1 : 0); + + return true; + } + else + return false; +} + +static void VID_OpenSystems(void) +{ + R_Modules_Start(); + S_Startup(); +} + +static void VID_CloseSystems(void) +{ + S_Shutdown(); + R_Modules_Shutdown(); +} + +qboolean vid_commandlinecheck = true; +extern qboolean vid_opened; + +void VID_Restart_f(void) +{ + char vabuf[1024]; + char vabuf2[1024]; + // don't crash if video hasn't started yet + if (vid_commandlinecheck) + return; + + if (!vid_opened) + { + SCR_BeginLoadingPlaque(false); + return; + } + + Con_Printf("VID_Restart: changing from %s %dx%dx%dbpp%s%s, to %s %dx%dx%dbpp%s%s.\n", + vid.mode.fullscreen ? "fullscreen" : "window", vid.mode.width, vid.mode.height, vid.mode.bitsperpixel, vid.mode.fullscreen && vid.mode.userefreshrate ? va(vabuf, sizeof(vabuf), "x%.2fhz", vid.mode.refreshrate) : "", vid.mode.samples > 1 ? va(vabuf2, sizeof(vabuf2), " (%ix AA)", vid.mode.samples) : "", + vid_fullscreen.integer ? "fullscreen" : "window", vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_fullscreen.integer && vid_userefreshrate.integer ? va(vabuf, sizeof(vabuf), "x%.2fhz", vid_refreshrate.value) : "", vid_samples.integer > 1 ? va(vabuf2, sizeof(vabuf2), " (%ix AA)", vid_samples.integer) : ""); + VID_CloseSystems(); + VID_Shutdown(); + if (!VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.value, vid_stereobuffer.integer, vid_samples.integer)) + { + Con_Print("Video mode change failed\n"); + if (!VID_Mode(vid.mode.fullscreen, vid.mode.width, vid.mode.height, vid.mode.bitsperpixel, vid.mode.refreshrate, vid.mode.stereobuffer, vid.mode.samples)) + Sys_Error("Unable to restore to last working video mode"); + } + VID_OpenSystems(); +} + +const char *vidfallbacks[][2] = +{ + {"vid_stereobuffer", "0"}, + {"vid_samples", "1"}, + {"vid_userefreshrate", "0"}, + {"vid_width", "640"}, + {"vid_height", "480"}, + {"vid_bitsperpixel", "16"}, + {NULL, NULL} +}; + +// this is only called once by Host_StartVideo and again on each FS_GameDir_f +void VID_Start(void) +{ + int i, width, height, success; + if (vid_commandlinecheck) + { + // interpret command-line parameters + vid_commandlinecheck = false; +// COMMANDLINEOPTION: Video: -window performs +vid_fullscreen 0 + if (COM_CheckParm("-window") || COM_CheckParm("-safe")) + Cvar_SetValueQuick(&vid_fullscreen, false); +// COMMANDLINEOPTION: Video: -fullscreen performs +vid_fullscreen 1 + if (COM_CheckParm("-fullscreen")) + Cvar_SetValueQuick(&vid_fullscreen, true); + width = 0; + height = 0; +// COMMANDLINEOPTION: Video: -width performs +vid_width and also +vid_height if only -width is specified (example: -width 1024 sets 1024x768 mode) + if ((i = COM_CheckParm("-width")) != 0) + width = atoi(com_argv[i+1]); +// COMMANDLINEOPTION: Video: -height performs +vid_height and also +vid_width if only -height is specified (example: -height 768 sets 1024x768 mode) + if ((i = COM_CheckParm("-height")) != 0) + height = atoi(com_argv[i+1]); + if (width == 0) + width = height * 4 / 3; + if (height == 0) + height = width * 3 / 4; + if (width) + Cvar_SetValueQuick(&vid_width, width); + if (height) + Cvar_SetValueQuick(&vid_height, height); +// COMMANDLINEOPTION: Video: -bpp performs +vid_bitsperpixel (example -bpp 32 or -bpp 16) + if ((i = COM_CheckParm("-bpp")) != 0) + Cvar_SetQuick(&vid_bitsperpixel, com_argv[i+1]); + } + + success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.value, vid_stereobuffer.integer, vid_samples.integer); + if (!success) + { + Con_Print("Desired video mode fail, trying fallbacks...\n"); + for (i = 0;!success && vidfallbacks[i][0] != NULL;i++) + { + Cvar_Set(vidfallbacks[i][0], vidfallbacks[i][1]); + success = VID_Mode(vid_fullscreen.integer, vid_width.integer, vid_height.integer, vid_bitsperpixel.integer, vid_refreshrate.value, vid_stereobuffer.integer, vid_samples.integer); + } + if (!success) + Sys_Error("Video modes failed"); + } + VID_OpenSystems(); +} + +void VID_Stop(void) +{ + VID_CloseSystems(); + VID_Shutdown(); +} + +static int VID_SortModes_Compare(const void *a_, const void *b_) +{ + vid_mode_t *a = (vid_mode_t *) a_; + vid_mode_t *b = (vid_mode_t *) b_; + if(a->width > b->width) + return +1; + if(a->width < b->width) + return -1; + if(a->height > b->height) + return +1; + if(a->height < b->height) + return -1; + if(a->refreshrate > b->refreshrate) + return +1; + if(a->refreshrate < b->refreshrate) + return -1; + if(a->bpp > b->bpp) + return +1; + if(a->bpp < b->bpp) + return -1; + if(a->pixelheight_num * b->pixelheight_denom > a->pixelheight_denom * b->pixelheight_num) + return +1; + if(a->pixelheight_num * b->pixelheight_denom < a->pixelheight_denom * b->pixelheight_num) + return -1; + return 0; +} +size_t VID_SortModes(vid_mode_t *modes, size_t count, qboolean usebpp, qboolean userefreshrate, qboolean useaspect) +{ + size_t i; + if(count == 0) + return 0; + // 1. sort them + qsort(modes, count, sizeof(*modes), VID_SortModes_Compare); + // 2. remove duplicates + for(i = 0; i < count; ++i) + { + if(modes[i].width && modes[i].height) + { + if(i == 0) + continue; + if(modes[i].width != modes[i-1].width) + continue; + if(modes[i].height != modes[i-1].height) + continue; + if(userefreshrate) + if(modes[i].refreshrate != modes[i-1].refreshrate) + continue; + if(usebpp) + if(modes[i].bpp != modes[i-1].bpp) + continue; + if(useaspect) + if(modes[i].pixelheight_num * modes[i-1].pixelheight_denom != modes[i].pixelheight_denom * modes[i-1].pixelheight_num) + continue; + } + // a dupe, or a bogus mode! + if(i < count-1) + memmove(&modes[i], &modes[i+1], sizeof(*modes) * (count-1 - i)); + --i; // check this index again, as mode i+1 is now here + --count; + } + return count; +} + +void VID_Soft_SharedSetup(void) +{ + gl_platform = "DPSOFTRAST"; + gl_platformextensions = ""; + + gl_renderer = "DarkPlaces-Soft"; + gl_vendor = "Forest Hale"; + gl_version = "0.0"; + gl_extensions = ""; + + // clear the extension flags + memset(&vid.support, 0, sizeof(vid.support)); + Cvar_SetQuick(&gl_info_extensions, ""); + + // DPSOFTRAST requires BGRA + vid.forcetextype = TEXTYPE_BGRA; + + vid.forcevbo = false; + vid.support.arb_depth_texture = true; + vid.support.arb_draw_buffers = true; + vid.support.arb_occlusion_query = true; + vid.support.arb_shadow = true; + //vid.support.arb_texture_compression = true; + vid.support.arb_texture_cube_map = true; + vid.support.arb_texture_non_power_of_two = false; + vid.support.arb_vertex_buffer_object = true; + vid.support.ext_blend_subtract = true; + vid.support.ext_draw_range_elements = true; + vid.support.ext_framebuffer_object = true; + + vid.support.ext_texture_3d = true; + //vid.support.ext_texture_compression_s3tc = true; + vid.support.ext_texture_filter_anisotropic = true; + vid.support.ati_separate_stencil = true; + vid.support.ext_texture_srgb = false; + + vid.maxtexturesize_2d = 16384; + vid.maxtexturesize_3d = 512; + vid.maxtexturesize_cubemap = 16384; + vid.texunits = 4; + vid.teximageunits = 32; + vid.texarrayunits = 8; + vid.max_anisotropy = 1; + vid.maxdrawbuffers = 4; + + vid.texunits = bound(4, vid.texunits, MAX_TEXTUREUNITS); + vid.teximageunits = bound(16, vid.teximageunits, MAX_TEXTUREUNITS); + vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS); + Con_DPrintf("Using DarkPlaces Software Rasterizer rendering path\n"); + vid.renderpath = RENDERPATH_SOFT; + vid.sRGBcapable2D = false; + vid.sRGBcapable3D = false; + vid.useinterleavedarrays = false; + + Cvar_SetQuick(&gl_info_vendor, gl_vendor); + Cvar_SetQuick(&gl_info_renderer, gl_renderer); + Cvar_SetQuick(&gl_info_version, gl_version); + Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : ""); + Cvar_SetQuick(&gl_info_driver, gl_driver); + + // LordHavoc: report supported extensions + Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); + + // clear to black (loading plaque will be seen over this) + GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128); +} diff --git a/app/jni/view.c b/app/jni/view.c new file mode 100644 index 0000000..17ced7d --- /dev/null +++ b/app/jni/view.c @@ -0,0 +1,1148 @@ +/* +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 "cl_collision.h" +#include "image.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 cl_autocentreoffset = {CVAR_SAVE, "cl_autocentreoffset", "0", "Additional lens offset (for difficult headets) from the centre to get images converging ok"}; +cvar_t v_eyebufferresolution = {CVAR_SAVE, "v_eyebufferresolution", "0", "Eye Buffer Resolution"}; + +cvar_t cl_rollspeed = {0, "cl_rollspeed", "200", "how much strafing is necessary to tilt the view"}; +cvar_t cl_rollangle = {0, "cl_rollangle", "0.0", "how much to tilt the view when strafing"}; + +cvar_t cl_bob = {CVAR_SAVE, "cl_bob","0.0", "view bobbing amount"}; +cvar_t cl_bobcycle = {CVAR_SAVE, "cl_bobcycle","0.6", "view bobbing speed"}; +cvar_t cl_bobup = {CVAR_SAVE, "cl_bobup","0.5", "view bobbing adjustment that makes the up or down swing of the bob last longer"}; +cvar_t cl_bob2 = {CVAR_SAVE, "cl_bob2","0", "sideways view bobbing amount"}; +cvar_t cl_bob2cycle = {CVAR_SAVE, "cl_bob2cycle","0.6", "sideways view bobbing speed"}; +cvar_t cl_bob2smooth = {CVAR_SAVE, "cl_bob2smooth","0.05", "how fast the view goes back when you stop touching the ground"}; +cvar_t cl_bobfall = {CVAR_SAVE, "cl_bobfall","0", "how much the view swings down when falling (influenced by the speed you hit the ground with)"}; +cvar_t cl_bobfallcycle = {CVAR_SAVE, "cl_bobfallcycle","3", "speed of the bobfall swing"}; +cvar_t cl_bobfallminspeed = {CVAR_SAVE, "cl_bobfallminspeed","200", "necessary amount of speed for bob-falling to occur"}; +cvar_t cl_bobmodel = {CVAR_SAVE, "cl_bobmodel", "1", "enables gun bobbing"}; +cvar_t cl_bobmodel_side = {CVAR_SAVE, "cl_bobmodel_side", "0.15", "gun bobbing sideways sway amount"}; +cvar_t cl_bobmodel_up = {CVAR_SAVE, "cl_bobmodel_up", "0.06", "gun bobbing upward movement amount"}; +cvar_t cl_bobmodel_speed = {CVAR_SAVE, "cl_bobmodel_speed", "7", "gun bobbing speed"}; + +cvar_t cl_leanmodel = {CVAR_SAVE, "cl_leanmodel", "0", "enables gun leaning"}; +cvar_t cl_leanmodel_side_speed = {CVAR_SAVE, "cl_leanmodel_side_speed", "0.7", "gun leaning sideways speed"}; +cvar_t cl_leanmodel_side_limit = {CVAR_SAVE, "cl_leanmodel_side_limit", "35", "gun leaning sideways limit"}; +cvar_t cl_leanmodel_side_highpass1 = {CVAR_SAVE, "cl_leanmodel_side_highpass1", "30", "gun leaning sideways pre-highpass in 1/s"}; +cvar_t cl_leanmodel_side_highpass = {CVAR_SAVE, "cl_leanmodel_side_highpass", "3", "gun leaning sideways highpass in 1/s"}; +cvar_t cl_leanmodel_side_lowpass = {CVAR_SAVE, "cl_leanmodel_side_lowpass", "20", "gun leaning sideways lowpass in 1/s"}; +cvar_t cl_leanmodel_up_speed = {CVAR_SAVE, "cl_leanmodel_up_speed", "0.65", "gun leaning upward speed"}; +cvar_t cl_leanmodel_up_limit = {CVAR_SAVE, "cl_leanmodel_up_limit", "50", "gun leaning upward limit"}; +cvar_t cl_leanmodel_up_highpass1 = {CVAR_SAVE, "cl_leanmodel_up_highpass1", "5", "gun leaning upward pre-highpass in 1/s"}; +cvar_t cl_leanmodel_up_highpass = {CVAR_SAVE, "cl_leanmodel_up_highpass", "15", "gun leaning upward highpass in 1/s"}; +cvar_t cl_leanmodel_up_lowpass = {CVAR_SAVE, "cl_leanmodel_up_lowpass", "20", "gun leaning upward lowpass in 1/s"}; + +cvar_t cl_followmodel = {CVAR_SAVE, "cl_followmodel", "0", "enables gun following"}; +cvar_t cl_followmodel_side_speed = {CVAR_SAVE, "cl_followmodel_side_speed", "0.25", "gun following sideways speed"}; +cvar_t cl_followmodel_side_limit = {CVAR_SAVE, "cl_followmodel_side_limit", "6", "gun following sideways limit"}; +cvar_t cl_followmodel_side_highpass1 = {CVAR_SAVE, "cl_followmodel_side_highpass1", "30", "gun following sideways pre-highpass in 1/s"}; +cvar_t cl_followmodel_side_highpass = {CVAR_SAVE, "cl_followmodel_side_highpass", "5", "gun following sideways highpass in 1/s"}; +cvar_t cl_followmodel_side_lowpass = {CVAR_SAVE, "cl_followmodel_side_lowpass", "10", "gun following sideways lowpass in 1/s"}; +cvar_t cl_followmodel_up_speed = {CVAR_SAVE, "cl_followmodel_up_speed", "0.5", "gun following upward speed"}; +cvar_t cl_followmodel_up_limit = {CVAR_SAVE, "cl_followmodel_up_limit", "5", "gun following upward limit"}; +cvar_t cl_followmodel_up_highpass1 = {CVAR_SAVE, "cl_followmodel_up_highpass1", "60", "gun following upward pre-highpass in 1/s"}; +cvar_t cl_followmodel_up_highpass = {CVAR_SAVE, "cl_followmodel_up_highpass", "2", "gun following upward highpass in 1/s"}; +cvar_t cl_followmodel_up_lowpass = {CVAR_SAVE, "cl_followmodel_up_lowpass", "10", "gun following upward lowpass in 1/s"}; + +cvar_t cl_viewmodel_scale = {0, "cl_viewmodel_scale", "1", "changes size of gun model, lower values prevent poking into walls but cause strange artifacts on lighting and especially r_stereo/vid_stereobuffer options where the size of the gun becomes visible"}; + +cvar_t v_kicktime = {0, "v_kicktime", "0.5", "how long a view kick from damage lasts"}; +cvar_t v_kickroll = {0, "v_kickroll", "0.6", "how much a view kick from damage rolls your view"}; +cvar_t v_kickpitch = {0, "v_kickpitch", "0.6", "how much a view kick from damage pitches your view"}; + +cvar_t v_iyaw_cycle = {0, "v_iyaw_cycle", "2", "v_idlescale yaw speed"}; +cvar_t v_iroll_cycle = {0, "v_iroll_cycle", "0.5", "v_idlescale roll speed"}; +cvar_t v_ipitch_cycle = {0, "v_ipitch_cycle", "1", "v_idlescale pitch speed"}; +cvar_t v_iyaw_level = {0, "v_iyaw_level", "0.3", "v_idlescale yaw amount"}; +cvar_t v_iroll_level = {0, "v_iroll_level", "0.1", "v_idlescale roll amount"}; +cvar_t v_ipitch_level = {0, "v_ipitch_level", "0.3", "v_idlescale pitch amount"}; + +cvar_t v_idlescale = {0, "v_idlescale", "0", "how much of the quake 'drunken view' effect to use"}; + +cvar_t crosshair = {CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"}; + +cvar_t v_centermove = {0, "v_centermove", "0.15", "how long before the view begins to center itself (if freelook/+mlook/+jlook/+klook are off)"}; +cvar_t v_centerspeed = {0, "v_centerspeed","500", "how fast the view centers itself"}; + +cvar_t cl_stairsmoothspeed = {CVAR_SAVE, "cl_stairsmoothspeed", "160", "how fast your view moves upward/downward when running up/down stairs"}; + +cvar_t cl_smoothviewheight = {CVAR_SAVE, "cl_smoothviewheight", "0", "time of the averaging to the viewheight value so that it creates a smooth transition. higher values = longer transition, 0 for instant transition."}; + +cvar_t chase_back = {CVAR_SAVE, "chase_back", "180", "chase cam distance from the player"}; +cvar_t chase_up = {CVAR_SAVE, "chase_up", "20", "chase cam distance from the player"}; +cvar_t chase_active = {CVAR_SAVE, "chase_active", "0", "enables chase cam"}; +cvar_t chase_overhead = {CVAR_SAVE, "chase_overhead", "0", "chase cam looks straight down if this is not zero"}; +// GAME_GOODVSBAD2 +cvar_t chase_stevie = {0, "chase_stevie", "0", "(GOODVSBAD2 only) chase cam view from above"}; + +cvar_t v_deathtilt = {0, "v_deathtilt", "1", "whether to use sideways view when dead"}; +cvar_t v_deathtiltangle = {0, "v_deathtiltangle", "0", "what roll angle to use when tilting the view while dead"}; + +// Prophecy camera pitchangle by Alexander "motorsep" Zubov +cvar_t chase_pitchangle = {CVAR_SAVE, "chase_pitchangle", "55", "chase cam pitch angle"}; + +float v_dmg_time, v_dmg_roll, v_dmg_pitch; + + +/* +=============== +V_CalcRoll + +Used by view and sv_user +=============== +*/ +float V_CalcRoll (const vec3_t angles, const vec3_t velocity) +{ + vec3_t right; + float sign; + float side; + float value; + + AngleVectors (angles, NULL, right, NULL); + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs(side); + + value = cl_rollangle.value; + + if (side < cl_rollspeed.value) + side = side * value / cl_rollspeed.value; + else + side = value; + + return side*sign; + +} + +void V_StartPitchDrift (void) +{ + if (cl.laststop == cl.time) + return; // something else is keeping it from drifting + + if (cl.nodrift || !cl.pitchvel) + { + cl.pitchvel = v_centerspeed.value; + cl.nodrift = false; + cl.driftmove = 0; + } +} + +void V_StopPitchDrift (void) +{ + cl.laststop = cl.time; + cl.nodrift = true; + cl.pitchvel = 0; +} + +/* +=============== +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 +=============== +*/ +void V_DriftPitch (void) +{ + float delta, move; + + 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 += cl.realframetime; + + if ( cl.driftmove > v_centermove.value) + { + V_StartPitchDrift (); + } + return; + } + + delta = cl.idealpitch - cl.viewangles[PITCH]; + + if (!delta) + { + cl.pitchvel = 0; + return; + } + + move = cl.realframetime * cl.pitchvel; + cl.pitchvel += cl.realframetime * v_centerspeed.value; + + 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; + } +} + + +/* +============================================================================== + + SCREEN FLASHES + +============================================================================== +*/ + + +/* +=============== +V_ParseDamage +=============== +*/ +void V_ParseDamage (void) +{ + int armor, blood; + vec3_t from; + //vec3_t forward, right; + vec3_t localfrom; + entity_t *ent; + //float side; + float count; + + armor = MSG_ReadByte(&cl_message); + blood = MSG_ReadByte(&cl_message); + MSG_ReadVector(&cl_message, from, cls.protocol); + + // Send the Dmg Globals to CSQC + CL_VM_UpdateDmgGlobals(blood, armor, from); + + count = blood*0.5 + armor*0.5; + if (count < 10) + count = 10; + + cl.faceanimtime = cl.time + 0.2; // put sbar face into pain frame + + cl.cshifts[CSHIFT_DAMAGE].percent += 3*count; + cl.cshifts[CSHIFT_DAMAGE].alphafade = 150; + 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 + if (cl.entities[cl.viewentity].state_current.active) + { + ent = &cl.entities[cl.viewentity]; + Matrix4x4_Transform(&ent->render.inversematrix, from, localfrom); + VectorNormalize(localfrom); + v_dmg_pitch = count * localfrom[0] * v_kickpitch.value; + v_dmg_roll = count * localfrom[1] * v_kickroll.value; + v_dmg_time = v_kicktime.value; + } +} + +static cshift_t v_cshift; + +/* +================== +V_cshift_f +================== +*/ +static void V_cshift_f (void) +{ + v_cshift.destcolor[0] = atof(Cmd_Argv(1)); + v_cshift.destcolor[1] = atof(Cmd_Argv(2)); + v_cshift.destcolor[2] = atof(Cmd_Argv(3)); + v_cshift.percent = atof(Cmd_Argv(4)); +} + + +/* +================== +V_BonusFlash_f + +When you run over an item, the server sends this command +================== +*/ +static void V_BonusFlash_f (void) +{ + if(Cmd_Argc() == 1) + { + 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; + cl.cshifts[CSHIFT_BONUS].alphafade = 100; + } + else if(Cmd_Argc() >= 4 && Cmd_Argc() <= 6) + { + cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(1)) * 255; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(2)) * 255; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(3)) * 255; + if(Cmd_Argc() >= 5) + cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(4)) * 255; // yes, these are HEXADECIMAL percent ;) + else + cl.cshifts[CSHIFT_BONUS].percent = 50; + if(Cmd_Argc() >= 6) + cl.cshifts[CSHIFT_BONUS].alphafade = atof(Cmd_Argv(5)) * 255; + else + cl.cshifts[CSHIFT_BONUS].alphafade = 100; + } + else + Con_Printf("usage:\nbf, or bf R G B [A [alphafade]]\n"); +} + +/* +============================================================================== + + VIEW RENDERING + +============================================================================== +*/ + +extern matrix4x4_t viewmodelmatrix_nobob; +extern matrix4x4_t viewmodelmatrix_withbob; + +#include "cl_collision.h" +#include "csprogs.h" + +/* +================== +V_CalcRefdef + +================== +*/ +#if 0 +static vec3_t eyeboxmins = {-16, -16, -24}; +static vec3_t eyeboxmaxs = { 16, 16, 32}; +#endif + +static vec_t lowpass(vec_t value, vec_t frac, vec_t *store) +{ + frac = bound(0, frac, 1); + return (*store = *store * (1 - frac) + value * frac); +} + +static vec_t lowpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store) +{ + lowpass(value, frac, store); + return (*store = bound(value - limit, *store, value + limit)); +} + +static vec_t highpass(vec_t value, vec_t frac, vec_t *store) +{ + return value - lowpass(value, frac, store); +} + +static vec_t highpass_limited(vec_t value, vec_t frac, vec_t limit, vec_t *store) +{ + return value - lowpass_limited(value, frac, limit, store); +} + +static void lowpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out) +{ + out[0] = lowpass(value[0], fracx, &store[0]); + out[1] = lowpass(value[1], fracy, &store[1]); + out[2] = lowpass(value[2], fracz, &store[2]); +} + +static void highpass3(vec3_t value, vec_t fracx, vec_t fracy, vec_t fracz, vec3_t store, vec3_t out) +{ + out[0] = highpass(value[0], fracx, &store[0]); + out[1] = highpass(value[1], fracy, &store[1]); + out[2] = highpass(value[2], fracz, &store[2]); +} + +static void highpass3_limited(vec3_t value, vec_t fracx, vec_t limitx, vec_t fracy, vec_t limity, vec_t fracz, vec_t limitz, vec3_t store, vec3_t out) +{ + out[0] = highpass_limited(value[0], fracx, limitx, &store[0]); + out[1] = highpass_limited(value[1], fracy, limity, &store[1]); + out[2] = highpass_limited(value[2], fracz, limitz, &store[2]); +} + +/* + * State: + * cl.bob2_smooth + * cl.bobfall_speed + * cl.bobfall_swing + * cl.gunangles_adjustment_highpass + * cl.gunangles_adjustment_lowpass + * cl.gunangles_highpass + * cl.gunangles_prev + * cl.gunorg_adjustment_highpass + * cl.gunorg_adjustment_lowpass + * cl.gunorg_highpass + * cl.gunorg_prev + * cl.hitgroundtime + * cl.lastongroundtime + * cl.oldongrounbd + * cl.stairsmoothtime + * cl.stairsmoothz + * cl.calcrefdef_prevtime + * Extra input: + * cl.movecmd[0].time + * cl.movevars_stepheight + * cl.movevars_timescale + * cl.oldtime + * cl.punchangle + * cl.punchvector + * cl.qw_intermission_angles + * cl.qw_intermission_origin + * cl.qw_weaponkick + * cls.protocol + * cl.time + * Output: + * cl.csqc_viewanglesfromengine + * cl.csqc_viewmodelmatrixfromengine + * cl.csqc_vieworiginfromengine + * r_refdef.view.matrix + * viewmodelmatrix_nobob + * viewmodelmatrix_withbob + */ +void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewangles, qboolean teleported, qboolean clonground, qboolean clcmdjump, float clstatsviewheight, qboolean cldead, qboolean clintermission, const vec3_t clvelocity) +{ + float vieworg[3], viewangles[3], smoothtime; + float gunorg[3], gunangles[3]; + matrix4x4_t tmpmatrix; + + static float viewheightavg; + float viewheight; +#if 0 +// begin of chase camera bounding box size for proper collisions by Alexander Zubov + vec3_t camboxmins = {-3, -3, -3}; + vec3_t camboxmaxs = {3, 3, 3}; +// end of chase camera bounding box size for proper collisions by Alexander Zubov +#endif + trace_t trace; + + // react to clonground state changes (for gun bob) + if (clonground) + { + if (!cl.oldonground) + cl.hitgroundtime = cl.movecmd[0].time; + cl.lastongroundtime = cl.movecmd[0].time; + } + cl.oldonground = clonground; + cl.calcrefdef_prevtime = max(cl.calcrefdef_prevtime, cl.oldtime); + + VectorClear(gunorg); + viewmodelmatrix_nobob = identitymatrix; + viewmodelmatrix_withbob = identitymatrix; + r_refdef.view.matrix = identitymatrix; + + // player can look around, so take the origin from the entity, + // and the angles from the input system + Matrix4x4_OriginFromMatrix(entrendermatrix, vieworg); + VectorCopy(clviewangles, viewangles); + + // calculate how much time has passed since the last V_CalcRefdef + smoothtime = bound(0, cl.time - cl.stairsmoothtime, 0.1); + cl.stairsmoothtime = cl.time; + + // fade damage flash + if (v_dmg_time > 0) + v_dmg_time -= bound(0, smoothtime, 0.1); + + if (clintermission) + { + // entity is a fixed camera, just copy the matrix + if (cls.protocol == PROTOCOL_QUAKEWORLD) + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.qw_intermission_origin[0], cl.qw_intermission_origin[1], cl.qw_intermission_origin[2], cl.qw_intermission_angles[0], cl.qw_intermission_angles[1], cl.qw_intermission_angles[2], 1); + else + { + r_refdef.view.matrix = *entrendermatrix; + Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, clstatsviewheight); + } + Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix); + Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value); + Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob); + + VectorCopy(vieworg, cl.csqc_vieworiginfromengine); + VectorCopy(viewangles, cl.csqc_viewanglesfromengine); + + Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix); + Matrix4x4_CreateScale(&cl.csqc_viewmodelmatrixfromengine, cl_viewmodel_scale.value); + } + else + { + // smooth stair stepping, but only if clonground and enabled + if (!clonground || cl_stairsmoothspeed.value <= 0 || teleported) + cl.stairsmoothz = vieworg[2]; + else + { + if (cl.stairsmoothz < vieworg[2]) + vieworg[2] = cl.stairsmoothz = bound(vieworg[2] - cl.movevars_stepheight, cl.stairsmoothz + smoothtime * cl_stairsmoothspeed.value, vieworg[2]); + else if (cl.stairsmoothz > vieworg[2]) + vieworg[2] = cl.stairsmoothz = bound(vieworg[2], cl.stairsmoothz - smoothtime * cl_stairsmoothspeed.value, vieworg[2] + cl.movevars_stepheight); + } + + // apply qw weapon recoil effect (this did not work in QW) + // TODO: add a cvar to disable this + viewangles[PITCH] += cl.qw_weaponkick; + + // apply the viewofs (even if chasecam is used) + // Samual: Lets add smoothing for this too so that things like crouching are done with a transition. + viewheight = bound(0, (cl.time - cl.calcrefdef_prevtime) / max(0.0001, cl_smoothviewheight.value), 1); + viewheightavg = viewheightavg * (1 - viewheight) + clstatsviewheight * viewheight; + vieworg[2] += viewheightavg; + + if (chase_active.value) + { + // observing entity from third person. Added "campitch" by Alexander "motorsep" Zubov + vec_t camback, camup, dist, campitch, forward[3], chase_dest[3]; + + camback = chase_back.value; + camup = chase_up.value; + campitch = chase_pitchangle.value; + + AngleVectors(viewangles, forward, NULL, NULL); + + if (chase_overhead.integer) + { +#if 1 + vec3_t offset; + vec3_t bestvieworg; +#endif + vec3_t up; + viewangles[PITCH] = 0; + AngleVectors(viewangles, forward, NULL, up); + // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range) + chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup; + chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup; + chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup; +#if 0 +#if 1 + //trace = CL_TraceLine(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); + trace = CL_TraceLine(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); +#else + //trace = CL_TraceBox(vieworg, eyeboxmins, eyeboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); + trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); +#endif + VectorCopy(trace.endpos, vieworg); + vieworg[2] -= 8; +#else + // trace from first person view location to our chosen third person view location +#if 1 + trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true); +#else + trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); +#endif + VectorCopy(trace.endpos, bestvieworg); + offset[2] = 0; + for (offset[0] = -16;offset[0] <= 16;offset[0] += 8) + { + for (offset[1] = -16;offset[1] <= 16;offset[1] += 8) + { + AngleVectors(viewangles, NULL, NULL, up); + chase_dest[0] = vieworg[0] - forward[0] * camback + up[0] * camup + offset[0]; + chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup + offset[1]; + chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup + offset[2]; +#if 1 + trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true); +#else + trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false); +#endif + if (bestvieworg[2] > trace.endpos[2]) + bestvieworg[2] = trace.endpos[2]; + } + } + bestvieworg[2] -= 8; + VectorCopy(bestvieworg, vieworg); +#endif + viewangles[PITCH] = campitch; + } + else + { + if (gamemode == GAME_GOODVSBAD2 && chase_stevie.integer) + { + // look straight down from high above + viewangles[PITCH] = 90; + camback = 2048; + VectorSet(forward, 0, 0, -1); + } + + // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range) + dist = -camback - 8; + chase_dest[0] = vieworg[0] + forward[0] * dist; + chase_dest[1] = vieworg[1] + forward[1] * dist; + chase_dest[2] = vieworg[2] + forward[2] * dist + camup; + trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true); + VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg); + } + } + else + { + // first person view from entity + // angles + if (cldead && v_deathtilt.integer) + viewangles[ROLL] = v_deathtiltangle.value; + VectorAdd(viewangles, cl.punchangle, viewangles); + viewangles[ROLL] += V_CalcRoll(clviewangles, clvelocity); + if (v_dmg_time > 0) + { + viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; + viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch; + } + // origin + VectorAdd(vieworg, cl.punchvector, vieworg); + if (!cldead) + { + double xyspeed, bob, bobfall; + float cycle; + vec_t frametime; + + frametime = (cl.time - cl.calcrefdef_prevtime) * cl.movevars_timescale; + + // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then + if(teleported) + { + // try to fix the first highpass; result is NOT + // perfect! TODO find a better fix + VectorCopy(viewangles, cl.gunangles_prev); + VectorCopy(vieworg, cl.gunorg_prev); + } + + // 2. for the gun origin, only keep the high frequency (non-DC) parts, which is "somewhat like velocity" + VectorAdd(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass); + highpass3_limited(vieworg, frametime*cl_followmodel_side_highpass1.value, cl_followmodel_side_limit.value, frametime*cl_followmodel_side_highpass1.value, cl_followmodel_side_limit.value, frametime*cl_followmodel_up_highpass1.value, cl_followmodel_up_limit.value, cl.gunorg_highpass, gunorg); + VectorCopy(vieworg, cl.gunorg_prev); + VectorSubtract(cl.gunorg_highpass, cl.gunorg_prev, cl.gunorg_highpass); + + // in the highpass, we _store_ the DIFFERENCE to the actual view angles... + VectorAdd(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass); + cl.gunangles_highpass[PITCH] += 360 * floor((viewangles[PITCH] - cl.gunangles_highpass[PITCH]) / 360 + 0.5); + cl.gunangles_highpass[YAW] += 360 * floor((viewangles[YAW] - cl.gunangles_highpass[YAW]) / 360 + 0.5); + cl.gunangles_highpass[ROLL] += 360 * floor((viewangles[ROLL] - cl.gunangles_highpass[ROLL]) / 360 + 0.5); + highpass3_limited(viewangles, frametime*cl_leanmodel_up_highpass1.value, cl_leanmodel_up_limit.value, frametime*cl_leanmodel_side_highpass1.value, cl_leanmodel_side_limit.value, 0, 0, cl.gunangles_highpass, gunangles); + VectorCopy(viewangles, cl.gunangles_prev); + VectorSubtract(cl.gunangles_highpass, cl.gunangles_prev, cl.gunangles_highpass); + + // 3. calculate the RAW adjustment vectors + gunorg[0] *= (cl_followmodel.value ? -cl_followmodel_side_speed.value : 0); + gunorg[1] *= (cl_followmodel.value ? -cl_followmodel_side_speed.value : 0); + gunorg[2] *= (cl_followmodel.value ? -cl_followmodel_up_speed.value : 0); + + gunangles[PITCH] *= (cl_leanmodel.value ? -cl_leanmodel_up_speed.value : 0); + gunangles[YAW] *= (cl_leanmodel.value ? -cl_leanmodel_side_speed.value : 0); + gunangles[ROLL] = 0; + + // 4. perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!) + // trick: we must do the lowpass LAST, so the lowpass vector IS the final vector! + highpass3(gunorg, frametime*cl_followmodel_side_highpass.value, frametime*cl_followmodel_side_highpass.value, frametime*cl_followmodel_up_highpass.value, cl.gunorg_adjustment_highpass, gunorg); + lowpass3(gunorg, frametime*cl_followmodel_side_lowpass.value, frametime*cl_followmodel_side_lowpass.value, frametime*cl_followmodel_up_lowpass.value, cl.gunorg_adjustment_lowpass, gunorg); + // we assume here: PITCH = 0, YAW = 1, ROLL = 2 + highpass3(gunangles, frametime*cl_leanmodel_up_highpass.value, frametime*cl_leanmodel_side_highpass.value, 0, cl.gunangles_adjustment_highpass, gunangles); + lowpass3(gunangles, frametime*cl_leanmodel_up_lowpass.value, frametime*cl_leanmodel_side_lowpass.value, 0, cl.gunangles_adjustment_lowpass, gunangles); + + // 5. use the adjusted vectors + VectorAdd(vieworg, gunorg, gunorg); + VectorAdd(viewangles, gunangles, gunangles); + + // bounded XY speed, used by several effects below + xyspeed = bound (0, sqrt(clvelocity[0]*clvelocity[0] + clvelocity[1]*clvelocity[1]), 400); + + // vertical view bobbing code + if (cl_bob.value && cl_bobcycle.value) + { + // LordHavoc: this code is *weird*, but not replacable (I think it + // should be done in QC on the server, but oh well, quake is quake) + // LordHavoc: figured out bobup: the time at which the sin is at 180 + // degrees (which allows lengthening or squishing the peak or valley) + cycle = cl.time / cl_bobcycle.value; + cycle -= (int) cycle; + if (cycle < cl_bobup.value) + cycle = sin(M_PI * cycle / cl_bobup.value); + else + cycle = sin(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 = xyspeed * bound(0, cl_bob.value, 0.05); + bob = bob*0.3 + bob*0.7*cycle; + vieworg[2] += bob; + // we also need to adjust gunorg, or this appears like pushing the gun! + // In the old code, this was applied to vieworg BEFORE copying to gunorg, + // but this is not viable with the new followmodel code as that would mean + // that followmodel would work on the munged-by-bob vieworg and do feedback + gunorg[2] += bob; + } + + // horizontal view bobbing code + if (cl_bob2.value && cl_bob2cycle.value) + { + vec3_t bob2vel; + vec3_t forward, right, up; + float side, front; + + cycle = cl.time / cl_bob2cycle.value; + cycle -= (int) cycle; + if (cycle < 0.5) + cycle = cos(M_PI * cycle / 0.5); // cos looks better here with the other view bobbing using sin + else + cycle = cos(M_PI + M_PI * (cycle-0.5)/0.5); + bob = bound(0, cl_bob2.value, 0.05) * cycle; + + // this value slowly decreases from 1 to 0 when we stop touching the ground. + // The cycle is later multiplied with it so the view smooths back to normal + if (clonground && !clcmdjump) // also block the effect while the jump button is pressed, to avoid twitches when bunny-hopping + cl.bob2_smooth = 1; + else + { + if(cl.bob2_smooth > 0) + cl.bob2_smooth -= bound(0, cl_bob2smooth.value, 1); + else + cl.bob2_smooth = 0; + } + + // calculate the front and side of the player between the X and Y axes + AngleVectors(viewangles, forward, right, up); + // now get the speed based on those angles. The bounds should match the same value as xyspeed's + side = bound(-400, DotProduct (clvelocity, right) * cl.bob2_smooth, 400); + front = bound(-400, DotProduct (clvelocity, forward) * cl.bob2_smooth, 400); + VectorScale(forward, bob, forward); + VectorScale(right, bob, right); + // we use side with forward and front with right, so the bobbing goes + // to the side when we walk forward and to the front when we strafe + VectorMAMAM(side, forward, front, right, 0, up, bob2vel); + vieworg[0] += bob2vel[0]; + vieworg[1] += bob2vel[1]; + // we also need to adjust gunorg, or this appears like pushing the gun! + // In the old code, this was applied to vieworg BEFORE copying to gunorg, + // but this is not viable with the new followmodel code as that would mean + // that followmodel would work on the munged-by-bob vieworg and do feedback + gunorg[0] += bob2vel[0]; + gunorg[1] += bob2vel[1]; + } + + // fall bobbing code + // causes the view to swing down and back up when touching the ground + if (cl_bobfall.value && cl_bobfallcycle.value) + { + if (!clonground) + { + cl.bobfall_speed = bound(-400, clvelocity[2], 0) * bound(0, cl_bobfall.value, 0.1); + if (clvelocity[2] < -cl_bobfallminspeed.value) + cl.bobfall_swing = 1; + else + cl.bobfall_swing = 0; // TODO really? + } + else + { + cl.bobfall_swing = max(0, cl.bobfall_swing - cl_bobfallcycle.value * frametime); + + bobfall = sin(M_PI * cl.bobfall_swing) * cl.bobfall_speed; + vieworg[2] += bobfall; + gunorg[2] += bobfall; + } + } + + // gun model bobbing code + if (cl_bobmodel.value) + { + // calculate for swinging gun model + // the gun bobs when running on the ground, but doesn't bob when you're in the air. + // Sajt: I tried to smooth out the transitions between bob and no bob, which works + // for the most part, but for some reason when you go through a message trigger or + // pick up an item or anything like that it will momentarily jolt the gun. + vec3_t forward, right, up; + float bspeed; + float s; + float t; + + s = cl.time * cl_bobmodel_speed.value; + if (clonground) + { + if (cl.time - cl.hitgroundtime < 0.2) + { + // just hit the ground, speed the bob back up over the next 0.2 seconds + t = cl.time - cl.hitgroundtime; + t = bound(0, t, 0.2); + t *= 5; + } + else + t = 1; + } + else + { + // recently left the ground, slow the bob down over the next 0.2 seconds + t = cl.time - cl.lastongroundtime; + t = 0.2 - bound(0, t, 0.2); + t *= 5; + } + + bspeed = xyspeed * 0.01f; + AngleVectors (gunangles, forward, right, up); + bob = bspeed * cl_bobmodel_side.value * cl_viewmodel_scale.value * sin (s) * t; + VectorMA (gunorg, bob, right, gunorg); + bob = bspeed * cl_bobmodel_up.value * cl_viewmodel_scale.value * cos (s * 2) * t; + VectorMA (gunorg, bob, up, gunorg); + } + } + } + // calculate a view matrix for rendering the scene + if (v_idlescale.value) + { + viewangles[0] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; + viewangles[1] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; + viewangles[2] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; + } + Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2], 1); + + // calculate a viewmodel matrix for use in view-attached entities + Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix); + Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value); + + Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix_withbob, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value); + VectorCopy(vieworg, cl.csqc_vieworiginfromengine); + VectorCopy(viewangles, cl.csqc_viewanglesfromengine); + + Matrix4x4_Invert_Simple(&tmpmatrix, &r_refdef.view.matrix); + Matrix4x4_Concat(&cl.csqc_viewmodelmatrixfromengine, &tmpmatrix, &viewmodelmatrix_withbob); + } + + cl.calcrefdef_prevtime = cl.time; +} + +void V_CalcRefdef (void) +{ + entity_t *ent; + qboolean cldead; + + if (cls.state == ca_connected && cls.signon == SIGNONS && !cl.csqc_server2csqcentitynumber[cl.viewentity]) + { + // ent is the view entity (visible when out of body) + ent = &cl.entities[cl.viewentity]; + + cldead = (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && cl.stats[STAT_HEALTH] != -2342); + V_CalcRefdefUsing(&ent->render.matrix, cl.viewangles, !ent->persistent.trail_allowed, cl.onground, cl.cmd.jump, cl.stats[STAT_VIEWHEIGHT], cldead, false, cl.velocity); // FIXME use a better way to detect teleport/warp than trail_allowed + } + else + { + viewmodelmatrix_nobob = identitymatrix; + viewmodelmatrix_withbob = identitymatrix; + cl.csqc_viewmodelmatrixfromengine = identitymatrix; + r_refdef.view.matrix = identitymatrix; + VectorClear(cl.csqc_vieworiginfromengine); + VectorCopy(cl.viewangles, cl.csqc_viewanglesfromengine); + } +} + +void V_FadeViewFlashs(void) +{ + // don't flash if time steps backwards + if (cl.time <= cl.oldtime) + return; + // drop the damage value + cl.cshifts[CSHIFT_DAMAGE].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_DAMAGE].alphafade; + if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0) + cl.cshifts[CSHIFT_DAMAGE].percent = 0; + // drop the bonus value + cl.cshifts[CSHIFT_BONUS].percent -= (cl.time - cl.oldtime)*cl.cshifts[CSHIFT_BONUS].alphafade; + if (cl.cshifts[CSHIFT_BONUS].percent <= 0) + cl.cshifts[CSHIFT_BONUS].percent = 0; +} + +void V_CalcViewBlend(void) +{ + float a2; + int j; + r_refdef.viewblend[0] = 0; + r_refdef.viewblend[1] = 0; + r_refdef.viewblend[2] = 0; + r_refdef.viewblend[3] = 0; + r_refdef.frustumscale_x = 1; + r_refdef.frustumscale_y = 1; + if (cls.state == ca_connected && cls.signon == SIGNONS) + { + // set contents color + int supercontents; + vec3_t vieworigin; + Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin); + supercontents = CL_PointSuperContents(vieworigin); + if (supercontents & SUPERCONTENTS_LIQUIDSMASK) + { + r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); + r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); + if (supercontents & SUPERCONTENTS_LAVA) + { + cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255; + cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80; + cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0; + } + else if (supercontents & SUPERCONTENTS_SLIME) + { + cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; + cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25; + cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5; + } + else + { + cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130; + cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80; + cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50; + } + cl.cshifts[CSHIFT_CONTENTS].percent = 150 * 0.5; + } + else + { + cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; + cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0; + cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0; + cl.cshifts[CSHIFT_CONTENTS].percent = 0; + } + + if (gamemode != GAME_TRANSFUSION) + { + if (cl.stats[STAT_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.stats[STAT_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.stats[STAT_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.stats[STAT_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; + } + + cl.cshifts[CSHIFT_VCSHIFT].destcolor[0] = v_cshift.destcolor[0]; + cl.cshifts[CSHIFT_VCSHIFT].destcolor[1] = v_cshift.destcolor[1]; + cl.cshifts[CSHIFT_VCSHIFT].destcolor[2] = v_cshift.destcolor[2]; + cl.cshifts[CSHIFT_VCSHIFT].percent = v_cshift.percent; + + // LordHavoc: fixed V_CalcBlend + for (j = 0;j < NUM_CSHIFTS;j++) + { + a2 = bound(0.0f, cl.cshifts[j].percent * (1.0f / 255.0f), 1.0f); + if (a2 > 0) + { + VectorLerp(r_refdef.viewblend, a2, cl.cshifts[j].destcolor, r_refdef.viewblend); + r_refdef.viewblend[3] = (1 - (1 - r_refdef.viewblend[3]) * (1 - a2)); // correct alpha multiply... took a while to find it on the web + } + } + // saturate color (to avoid blending in black) + if (r_refdef.viewblend[3]) + { + a2 = 1 / r_refdef.viewblend[3]; + VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend); + } + r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0], 255.0f); + r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1], 255.0f); + r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2], 255.0f); + r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f); + if (vid.sRGB3D) + { + r_refdef.viewblend[0] = Image_LinearFloatFromsRGB(r_refdef.viewblend[0]); + r_refdef.viewblend[1] = Image_LinearFloatFromsRGB(r_refdef.viewblend[1]); + r_refdef.viewblend[2] = Image_LinearFloatFromsRGB(r_refdef.viewblend[2]); + } + else + { + r_refdef.viewblend[0] *= (1.0f/256.0f); + r_refdef.viewblend[1] *= (1.0f/256.0f); + r_refdef.viewblend[2] *= (1.0f/256.0f); + } + + // Samual: Ugly hack, I know. But it's the best we can do since + // there is no way to detect client states from the engine. + if (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && + cl.stats[STAT_HEALTH] != -2342 && cl_deathfade.value > 0) + { + cl.deathfade += cl_deathfade.value * max(0.00001, cl.time - cl.oldtime); + cl.deathfade = bound(0.0f, cl.deathfade, 0.9f); + } + else + cl.deathfade = 0.0f; + + if(cl.deathfade > 0) + { + float a; + float deathfadevec[3] = {0.3f, 0.0f, 0.0f}; + a = r_refdef.viewblend[3] + cl.deathfade - r_refdef.viewblend[3]*cl.deathfade; + if(a > 0) + VectorMAM(r_refdef.viewblend[3] * (1 - cl.deathfade) / a, r_refdef.viewblend, cl.deathfade / a, deathfadevec, r_refdef.viewblend); + r_refdef.viewblend[3] = a; + } + } +} + +//============================================================================ + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + Cmd_AddCommand ("v_cshift", V_cshift_f, "sets tint color of view"); + Cmd_AddCommand ("bf", V_BonusFlash_f, "briefly flashes a bright color tint on view (used when items are picked up); optionally takes R G B [A [alphafade]] arguments to specify how the flash looks"); + Cmd_AddCommand ("centerview", V_StartPitchDrift, "gradually recenter view (stop looking up/down)"); + + 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_autocentreoffset); + Cvar_RegisterVariable (&v_eyebufferresolution); + + Cvar_RegisterVariable (&cl_rollspeed); + Cvar_RegisterVariable (&cl_rollangle); + Cvar_RegisterVariable (&cl_bob); + Cvar_RegisterVariable (&cl_bobcycle); + Cvar_RegisterVariable (&cl_bobup); + Cvar_RegisterVariable (&cl_bob2); + Cvar_RegisterVariable (&cl_bob2cycle); + Cvar_RegisterVariable (&cl_bob2smooth); + Cvar_RegisterVariable (&cl_bobfall); + Cvar_RegisterVariable (&cl_bobfallcycle); + Cvar_RegisterVariable (&cl_bobfallminspeed); + Cvar_RegisterVariable (&cl_bobmodel); + Cvar_RegisterVariable (&cl_bobmodel_side); + Cvar_RegisterVariable (&cl_bobmodel_up); + Cvar_RegisterVariable (&cl_bobmodel_speed); + + Cvar_RegisterVariable (&cl_leanmodel); + Cvar_RegisterVariable (&cl_leanmodel_side_speed); + Cvar_RegisterVariable (&cl_leanmodel_side_limit); + Cvar_RegisterVariable (&cl_leanmodel_side_highpass1); + Cvar_RegisterVariable (&cl_leanmodel_side_lowpass); + Cvar_RegisterVariable (&cl_leanmodel_side_highpass); + Cvar_RegisterVariable (&cl_leanmodel_up_speed); + Cvar_RegisterVariable (&cl_leanmodel_up_limit); + Cvar_RegisterVariable (&cl_leanmodel_up_highpass1); + Cvar_RegisterVariable (&cl_leanmodel_up_lowpass); + Cvar_RegisterVariable (&cl_leanmodel_up_highpass); + + Cvar_RegisterVariable (&cl_followmodel); + Cvar_RegisterVariable (&cl_followmodel_side_speed); + Cvar_RegisterVariable (&cl_followmodel_side_limit); + Cvar_RegisterVariable (&cl_followmodel_side_highpass1); + Cvar_RegisterVariable (&cl_followmodel_side_lowpass); + Cvar_RegisterVariable (&cl_followmodel_side_highpass); + Cvar_RegisterVariable (&cl_followmodel_up_speed); + Cvar_RegisterVariable (&cl_followmodel_up_limit); + Cvar_RegisterVariable (&cl_followmodel_up_highpass1); + Cvar_RegisterVariable (&cl_followmodel_up_lowpass); + Cvar_RegisterVariable (&cl_followmodel_up_highpass); + + Cvar_RegisterVariable (&cl_viewmodel_scale); + + Cvar_RegisterVariable (&v_kicktime); + Cvar_RegisterVariable (&v_kickroll); + Cvar_RegisterVariable (&v_kickpitch); + + Cvar_RegisterVariable (&cl_stairsmoothspeed); + + Cvar_RegisterVariable (&cl_smoothviewheight); + + Cvar_RegisterVariable (&chase_back); + Cvar_RegisterVariable (&chase_up); + Cvar_RegisterVariable (&chase_active); + Cvar_RegisterVariable (&chase_overhead); + Cvar_RegisterVariable (&chase_pitchangle); + Cvar_RegisterVariable (&chase_stevie); + + Cvar_RegisterVariable (&v_deathtilt); + Cvar_RegisterVariable (&v_deathtiltangle); +} + diff --git a/app/jni/wad.c b/app/jni/wad.c new file mode 100644 index 0000000..4e714b0 --- /dev/null +++ b/app/jni/wad.c @@ -0,0 +1,312 @@ +/* +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 "image.h" +#include "wad.h" + +typedef struct mwad_s +{ + qfile_t *file; + int numlumps; + lumpinfo_t *lumps; +} +mwad_t; + +typedef struct wadstate_s +{ + unsigned char *gfx_base; + mwad_t gfx; + memexpandablearray_t hlwads; +} +wadstate_t; + +static wadstate_t wad; + +/* +================== +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. +================== +*/ +static void W_CleanupName (const 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; +} + +static void W_SwapLumps(int numlumps, lumpinfo_t *lumps) +{ + int i; + for (i = 0;i < numlumps;i++) + { + lumps[i].filepos = LittleLong(lumps[i].filepos); + lumps[i].disksize = LittleLong(lumps[i].disksize); + lumps[i].size = LittleLong(lumps[i].size); + W_CleanupName(lumps[i].name, lumps[i].name); + } +} + +void W_UnloadAll(void) +{ + unsigned int i; + mwad_t *w; + // free gfx.wad if it is loaded + if (wad.gfx_base) + Mem_Free(wad.gfx_base); + wad.gfx_base = NULL; + // close all hlwad files and free their lumps data + for (i = 0;i < Mem_ExpandableArray_IndexRange(&wad.hlwads);i++) + { + w = (mwad_t *) Mem_ExpandableArray_RecordAtIndex(&wad.hlwads, i); + if (!w) + continue; + if (w->file) + FS_Close(w->file); + w->file = NULL; + if (w->lumps) + Mem_Free(w->lumps); + w->lumps = NULL; + } + // free the hlwads array + Mem_ExpandableArray_FreeArray(&wad.hlwads); + // clear all state + memset(&wad, 0, sizeof(wad)); +} + +unsigned char *W_GetLumpName(const char *name) +{ + int i; + fs_offset_t filesize; + lumpinfo_t *lump; + char clean[16]; + wadinfo_t *header; + int infotableofs; + + W_CleanupName (name, clean); + + if (!wad.gfx_base) + { + if ((wad.gfx_base = FS_LoadFile ("gfx.wad", cls.permanentmempool, false, &filesize))) + { + if (memcmp(wad.gfx_base, "WAD2", 4)) + { + Con_Print("gfx.wad doesn't have WAD2 id\n"); + Mem_Free(wad.gfx_base); + wad.gfx_base = NULL; + } + else + { + header = (wadinfo_t *)wad.gfx_base; + wad.gfx.numlumps = LittleLong(header->numlumps); + infotableofs = LittleLong(header->infotableofs); + wad.gfx.lumps = (lumpinfo_t *)(wad.gfx_base + infotableofs); + + // byteswap the gfx.wad lumps in place + W_SwapLumps(wad.gfx.numlumps, wad.gfx.lumps); + } + } + } + + for (lump = wad.gfx.lumps, i = 0;i < wad.gfx.numlumps;i++, lump++) + if (!strcmp(clean, lump->name)) + return (wad.gfx_base + lump->filepos); + return NULL; +} + +/* +==================== +W_LoadTextureWadFile +==================== +*/ +void W_LoadTextureWadFile (char *filename, int complain) +{ + wadinfo_t header; + int infotableofs; + qfile_t *file; + int numlumps; + mwad_t *w; + + file = FS_OpenVirtualFile(filename, false); + if (!file) + { + if (complain) + Con_Printf("W_LoadTextureWadFile: couldn't find %s\n", filename); + return; + } + + if (FS_Read(file, &header, sizeof(wadinfo_t)) != sizeof(wadinfo_t)) + {Con_Print("W_LoadTextureWadFile: unable to read wad header\n");FS_Close(file);file = NULL;return;} + + if(memcmp(header.identification, "WAD3", 4)) + {Con_Printf("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);FS_Close(file);file = NULL;return;} + + numlumps = LittleLong(header.numlumps); + if (numlumps < 1 || numlumps > 65536) + {Con_Printf("W_LoadTextureWadFile: invalid number of lumps (%i)\n", numlumps);FS_Close(file);file = NULL;return;} + infotableofs = LittleLong(header.infotableofs); + if (FS_Seek (file, infotableofs, SEEK_SET)) + {Con_Print("W_LoadTextureWadFile: unable to seek to lump table\n");FS_Close(file);file = NULL;return;} + + if (!wad.hlwads.mempool) + Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16); + w = (mwad_t *) Mem_ExpandableArray_AllocRecord(&wad.hlwads); + w->file = file; + w->numlumps = numlumps; + w->lumps = (lumpinfo_t *) Mem_Alloc(cls.permanentmempool, w->numlumps * sizeof(lumpinfo_t)); + + if (!w->lumps) + { + Con_Print("W_LoadTextureWadFile: unable to allocate temporary memory for lump table\n"); + FS_Close(w->file); + w->file = NULL; + w->numlumps = 0; + return; + } + + if (FS_Read(file, w->lumps, sizeof(lumpinfo_t) * w->numlumps) != (fs_offset_t)sizeof(lumpinfo_t) * numlumps) + { + Con_Print("W_LoadTextureWadFile: unable to read lump table\n"); + FS_Close(w->file); + w->file = NULL; + w->numlumps = 0; + Mem_Free(w->lumps); + w->lumps = NULL; + return; + } + + W_SwapLumps(w->numlumps, w->lumps); + + // leaves the file open +} + +unsigned char *W_ConvertWAD3TextureBGRA(sizebuf_t *sb) +{ + unsigned char *in, *data, *out, *pal; + int d, p; + unsigned char name[16]; + unsigned int mipoffset[4]; + + MSG_BeginReading(sb); + MSG_ReadBytes(sb, 16, name); + image_width = MSG_ReadLittleLong(sb); + image_height = MSG_ReadLittleLong(sb); + mipoffset[0] = MSG_ReadLittleLong(sb); + mipoffset[1] = MSG_ReadLittleLong(sb); // should be mipoffset[0] + image_width*image_height + mipoffset[2] = MSG_ReadLittleLong(sb); // should be mipoffset[1] + image_width*image_height/4 + mipoffset[3] = MSG_ReadLittleLong(sb); // should be mipoffset[2] + image_width*image_height/16 + pal = sb->data + mipoffset[3] + (image_width / 8 * image_height / 8) + 2; + + // bail if any data looks wrong + if (image_width < 0 + || image_width > 4096 + || image_height < 0 + || image_height > 4096 + || mipoffset[0] != 40 + || mipoffset[1] != mipoffset[0] + image_width * image_height + || mipoffset[2] != mipoffset[1] + image_width / 2 * image_height / 2 + || mipoffset[3] != mipoffset[2] + image_width / 4 * image_height / 4 + || (unsigned int)sb->cursize < (mipoffset[3] + image_width / 8 * image_height / 8 + 2 + 768)) + return NULL; + + in = (unsigned char *)sb->data + mipoffset[0]; + data = out = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); + if (!data) + return NULL; + for (d = 0;d < image_width * image_height;d++) + { + p = *in++; + if (name[0] == '{' && p == 255) + out[0] = out[1] = out[2] = out[3] = 0; + else + { + p *= 3; + out[2] = pal[p]; + out[1] = pal[p+1]; + out[0] = pal[p+2]; + out[3] = 255; + } + out += 4; + } + return data; +} + +unsigned char *W_GetTextureBGRA(char *name) +{ + unsigned int i, k; + sizebuf_t sb; + unsigned char *data; + mwad_t *w; + char texname[17]; + size_t range; + + texname[16] = 0; + W_CleanupName(name, texname); + if (!wad.hlwads.mempool) + Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16); + range = Mem_ExpandableArray_IndexRange(&wad.hlwads); + for (k = 0;k < range;k++) + { + w = (mwad_t *)Mem_ExpandableArray_RecordAtIndex(&wad.hlwads, k); + if (!w) + continue; + for (i = 0;i < (unsigned int)w->numlumps;i++) + { + if (!strcmp(texname, w->lumps[i].name)) // found it + { + if (FS_Seek(w->file, w->lumps[i].filepos, SEEK_SET)) + {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;} + + MSG_InitReadBuffer(&sb, (unsigned char *)Mem_Alloc(tempmempool, w->lumps[i].disksize), w->lumps[i].disksize); + if (!sb.data) + return NULL; + if (FS_Read(w->file, sb.data, w->lumps[i].size) < w->lumps[i].disksize) + {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;} + + data = W_ConvertWAD3TextureBGRA(&sb); + Mem_Free(sb.data); + return data; + } + } + } + image_width = image_height = 0; + return NULL; +} + diff --git a/app/jni/wad.h b/app/jni/wad.h new file mode 100644 index 0000000..3c4297d --- /dev/null +++ b/app/jni/wad.h @@ -0,0 +1,77 @@ +/* +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 + +#ifndef WAD_H +#define 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 qpic_s +{ + int width, height; + unsigned char data[4]; // variably sized +} qpic_t; + + + +typedef struct wadinfo_s +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct lumpinfo_s +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +void W_UnloadAll(void); +unsigned char *W_GetLumpName(const char *name); + +// halflife texture wads +void W_LoadTextureWadFile(char *filename, int complain); +unsigned char *W_GetTextureBGRA(char *name); // returns tempmempool allocated image data, width and height are in image_width and image_height +unsigned char *W_ConvertWAD3TextureBGRA(sizebuf_t *sb); // returns tempmempool allocated image data, width and height are in image_width and image_height + +#endif + diff --git a/app/jni/world.c b/app/jni/world.c new file mode 100644 index 0000000..abacf51 --- /dev/null +++ b/app/jni/world.c @@ -0,0 +1,3123 @@ +/* +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" +#include "clvm_cmds.h" +#include "cl_collision.h" + +/* + +entities never clip against themselves, or their owner + +line of sight checks trace->inopen and trace->inwater, but bullets don't + +*/ + +static void World_Physics_Init(void); +void World_Init(void) +{ + Collision_Init(); + World_Physics_Init(); +} + +static void World_Physics_Shutdown(void); +void World_Shutdown(void) +{ + World_Physics_Shutdown(); +} + +static void World_Physics_Start(world_t *world); +void World_Start(world_t *world) +{ + World_Physics_Start(world); +} + +static void World_Physics_End(world_t *world); +void World_End(world_t *world) +{ + World_Physics_End(world); +} + +//============================================================================ + +/// World_ClearLink is used for new headnodes +void World_ClearLink (link_t *l) +{ + l->entitynumber = 0; + l->prev = l->next = l; +} + +void World_RemoveLink (link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; +} + +void World_InsertLinkBefore (link_t *l, link_t *before, int entitynumber) +{ + l->entitynumber = entitynumber; + l->next = before; + l->prev = before->prev; + l->prev->next = l; + l->next->prev = l; +} + +/* +=============================================================================== + +ENTITY AREA CHECKING + +=============================================================================== +*/ + +void World_PrintAreaStats(world_t *world, const char *worldname) +{ + Con_Printf("%s areagrid check stats: %d calls %d nodes (%f per call) %d entities (%f per call)\n", worldname, world->areagrid_stats_calls, world->areagrid_stats_nodechecks, (double) world->areagrid_stats_nodechecks / (double) world->areagrid_stats_calls, world->areagrid_stats_entitychecks, (double) world->areagrid_stats_entitychecks / (double) world->areagrid_stats_calls); + world->areagrid_stats_calls = 0; + world->areagrid_stats_nodechecks = 0; + world->areagrid_stats_entitychecks = 0; +} + +/* +=============== +World_SetSize + +=============== +*/ +void World_SetSize(world_t *world, const char *filename, const vec3_t mins, const vec3_t maxs, prvm_prog_t *prog) +{ + int i; + + strlcpy(world->filename, filename, sizeof(world->filename)); + VectorCopy(mins, world->mins); + VectorCopy(maxs, world->maxs); + world->prog = prog; + + // the areagrid_marknumber is not allowed to be 0 + if (world->areagrid_marknumber < 1) + world->areagrid_marknumber = 1; + // choose either the world box size, or a larger box to ensure the grid isn't too fine + world->areagrid_size[0] = max(world->maxs[0] - world->mins[0], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[1] = max(world->maxs[1] - world->mins[1], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[2] = max(world->maxs[2] - world->mins[2], AREA_GRID * sv_areagrid_mingridsize.value); + // figure out the corners of such a box, centered at the center of the world box + world->areagrid_mins[0] = (world->mins[0] + world->maxs[0] - world->areagrid_size[0]) * 0.5f; + world->areagrid_mins[1] = (world->mins[1] + world->maxs[1] - world->areagrid_size[1]) * 0.5f; + world->areagrid_mins[2] = (world->mins[2] + world->maxs[2] - world->areagrid_size[2]) * 0.5f; + world->areagrid_maxs[0] = (world->mins[0] + world->maxs[0] + world->areagrid_size[0]) * 0.5f; + world->areagrid_maxs[1] = (world->mins[1] + world->maxs[1] + world->areagrid_size[1]) * 0.5f; + world->areagrid_maxs[2] = (world->mins[2] + world->maxs[2] + world->areagrid_size[2]) * 0.5f; + // now calculate the actual useful info from that + VectorNegate(world->areagrid_mins, world->areagrid_bias); + world->areagrid_scale[0] = AREA_GRID / world->areagrid_size[0]; + world->areagrid_scale[1] = AREA_GRID / world->areagrid_size[1]; + world->areagrid_scale[2] = AREA_GRID / world->areagrid_size[2]; + World_ClearLink(&world->areagrid_outside); + for (i = 0;i < AREA_GRIDNODES;i++) + World_ClearLink(&world->areagrid[i]); + if (developer_extra.integer) + Con_DPrintf("areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, world->areagrid_mins[0], world->areagrid_mins[1], world->areagrid_mins[2], world->areagrid_maxs[0], world->areagrid_maxs[1], world->areagrid_maxs[2], world->areagrid_size[0], world->areagrid_size[1], world->areagrid_size[2], 1.0f / world->areagrid_scale[0], 1.0f / world->areagrid_scale[1], 1.0f / world->areagrid_scale[2], sv_areagrid_mingridsize.value); +} + +/* +=============== +World_UnlinkAll + +=============== +*/ +void World_UnlinkAll(world_t *world) +{ + prvm_prog_t *prog = world->prog; + int i; + link_t *grid; + // unlink all entities one by one + grid = &world->areagrid_outside; + while (grid->next != grid) + World_UnlinkEdict(PRVM_EDICT_NUM(grid->next->entitynumber)); + for (i = 0, grid = world->areagrid;i < AREA_GRIDNODES;i++, grid++) + while (grid->next != grid) + World_UnlinkEdict(PRVM_EDICT_NUM(grid->next->entitynumber)); +} + +/* +=============== + +=============== +*/ +void World_UnlinkEdict(prvm_edict_t *ent) +{ + int i; + for (i = 0;i < ENTITYGRIDAREAS;i++) + { + if (ent->priv.server->areagrid[i].prev) + { + World_RemoveLink (&ent->priv.server->areagrid[i]); + ent->priv.server->areagrid[i].prev = ent->priv.server->areagrid[i].next = NULL; + } + } +} + +int World_EntitiesInBox(world_t *world, const vec3_t requestmins, const vec3_t requestmaxs, int maxlist, prvm_edict_t **list) +{ + prvm_prog_t *prog = world->prog; + int numlist; + link_t *grid; + link_t *l; + prvm_edict_t *ent; + vec3_t paddedmins, paddedmaxs; + int igrid[3], igridmins[3], igridmaxs[3]; + + // LordHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination) + //VectorSet(paddedmins, requestmins[0] - 1.0f, requestmins[1] - 1.0f, requestmins[2] - 1.0f); + //VectorSet(paddedmaxs, requestmaxs[0] + 1.0f, requestmaxs[1] + 1.0f, requestmaxs[2] + 1.0f); + VectorCopy(requestmins, paddedmins); + VectorCopy(requestmaxs, paddedmaxs); + + // FIXME: if areagrid_marknumber wraps, all entities need their + // ent->priv.server->areagridmarknumber reset + world->areagrid_stats_calls++; + world->areagrid_marknumber++; + igridmins[0] = (int) floor((paddedmins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]); + igridmins[1] = (int) floor((paddedmins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]); + //igridmins[2] = (int) ((paddedmins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]); + igridmaxs[0] = (int) floor((paddedmaxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1; + igridmaxs[1] = (int) floor((paddedmaxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1; + //igridmaxs[2] = (int) ((paddedmaxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1; + igridmins[0] = max(0, igridmins[0]); + igridmins[1] = max(0, igridmins[1]); + //igridmins[2] = max(0, igridmins[2]); + igridmaxs[0] = min(AREA_GRID, igridmaxs[0]); + igridmaxs[1] = min(AREA_GRID, igridmaxs[1]); + //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]); + + // paranoid debugging + //VectorSet(igridmins, 0, 0, 0);VectorSet(igridmaxs, AREA_GRID, AREA_GRID, AREA_GRID); + + numlist = 0; + // add entities not linked into areagrid because they are too big or + // outside the grid bounds + if (world->areagrid_outside.next) + { + grid = &world->areagrid_outside; + for (l = grid->next;l != grid;l = l->next) + { + ent = PRVM_EDICT_NUM(l->entitynumber); + if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber) + { + ent->priv.server->areagridmarknumber = world->areagrid_marknumber; + if (!ent->priv.server->free && BoxesOverlap(paddedmins, paddedmaxs, ent->priv.server->areamins, ent->priv.server->areamaxs)) + { + if (numlist < maxlist) + list[numlist] = ent; + numlist++; + } + world->areagrid_stats_entitychecks++; + } + } + } + // add grid linked entities + for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++) + { + grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0]; + for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++) + { + if (grid->next) + { + for (l = grid->next;l != grid;l = l->next) + { + ent = PRVM_EDICT_NUM(l->entitynumber); + if (ent->priv.server->areagridmarknumber != world->areagrid_marknumber) + { + ent->priv.server->areagridmarknumber = world->areagrid_marknumber; + if (!ent->priv.server->free && BoxesOverlap(paddedmins, paddedmaxs, ent->priv.server->areamins, ent->priv.server->areamaxs)) + { + if (numlist < maxlist) + list[numlist] = ent; + numlist++; + } + //Con_Printf("%d %f %f %f %f %f %f : %d : %f %f %f %f %f %f\n", BoxesOverlap(mins, maxs, ent->priv.server->areamins, ent->priv.server->areamaxs), ent->priv.server->areamins[0], ent->priv.server->areamins[1], ent->priv.server->areamins[2], ent->priv.server->areamaxs[0], ent->priv.server->areamaxs[1], ent->priv.server->areamaxs[2], PRVM_NUM_FOR_EDICT(ent), mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); + } + world->areagrid_stats_entitychecks++; + } + } + } + } + return numlist; +} + +static void World_LinkEdict_AreaGrid(world_t *world, prvm_edict_t *ent) +{ + prvm_prog_t *prog = world->prog; + link_t *grid; + int igrid[3], igridmins[3], igridmaxs[3], gridnum, entitynumber = PRVM_NUM_FOR_EDICT(ent); + + if (entitynumber <= 0 || entitynumber >= prog->max_edicts || PRVM_EDICT_NUM(entitynumber) != ent) + { + Con_Printf ("World_LinkEdict_AreaGrid: invalid edict %p (edicts is %p, edict compared to prog->edicts is %i)\n", (void *)ent, (void *)prog->edicts, entitynumber); + return; + } + + igridmins[0] = (int) floor((ent->priv.server->areamins[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]); + igridmins[1] = (int) floor((ent->priv.server->areamins[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]); + //igridmins[2] = (int) floor((ent->priv.server->areamins[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]); + igridmaxs[0] = (int) floor((ent->priv.server->areamaxs[0] + world->areagrid_bias[0]) * world->areagrid_scale[0]) + 1; + igridmaxs[1] = (int) floor((ent->priv.server->areamaxs[1] + world->areagrid_bias[1]) * world->areagrid_scale[1]) + 1; + //igridmaxs[2] = (int) floor((ent->priv.server->areamaxs[2] + world->areagrid_bias[2]) * world->areagrid_scale[2]) + 1; + if (igridmins[0] < 0 || igridmaxs[0] > AREA_GRID || igridmins[1] < 0 || igridmaxs[1] > AREA_GRID || ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > ENTITYGRIDAREAS) + { + // wow, something outside the grid, store it as such + World_InsertLinkBefore (&ent->priv.server->areagrid[0], &world->areagrid_outside, entitynumber); + return; + } + + gridnum = 0; + for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++) + { + grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0]; + for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++) + World_InsertLinkBefore (&ent->priv.server->areagrid[gridnum], grid, entitynumber); + } +} + +/* +=============== +World_LinkEdict + +=============== +*/ +void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const vec3_t maxs) +{ + prvm_prog_t *prog = world->prog; + // unlink from old position first + if (ent->priv.server->areagrid[0].prev) + World_UnlinkEdict(ent); + + // don't add the world + if (ent == prog->edicts) + return; + + // don't add free entities + if (ent->priv.server->free) + return; + + VectorCopy(mins, ent->priv.server->areamins); + VectorCopy(maxs, ent->priv.server->areamaxs); + World_LinkEdict_AreaGrid(world, ent); +} + + + + +//============================================================================ +// physics engine support +//============================================================================ + +#ifdef USEODE +cvar_t physics_ode_quadtree_depth = {0, "physics_ode_quadtree_depth","5", "desired subdivision level of quadtree culling space"}; +cvar_t physics_ode_allowconvex = {0, "physics_ode_allowconvex", "0", "allow usage of Convex Hull primitive type on trimeshes that have custom 'collisionconvex' mesh. If disabled, trimesh primitive type are used."}; +cvar_t physics_ode_contactsurfacelayer = {0, "physics_ode_contactsurfacelayer","1", "allows objects to overlap this many units to reduce jitter"}; +cvar_t physics_ode_worldstep_iterations = {0, "physics_ode_worldstep_iterations", "20", "parameter to dWorldQuickStep"}; +cvar_t physics_ode_contact_mu = {0, "physics_ode_contact_mu", "1", "contact solver mu parameter - friction pyramid approximation 1 (see ODE User Guide)"}; +cvar_t physics_ode_contact_erp = {0, "physics_ode_contact_erp", "0.96", "contact solver erp parameter - Error Restitution Percent (see ODE User Guide)"}; +cvar_t physics_ode_contact_cfm = {0, "physics_ode_contact_cfm", "0", "contact solver cfm parameter - Constraint Force Mixing (see ODE User Guide)"}; +cvar_t physics_ode_contact_maxpoints = {0, "physics_ode_contact_maxpoints", "16", "maximal number of contact points between 2 objects, higher = stable (and slower), can be up to 32"}; +cvar_t physics_ode_world_erp = {0, "physics_ode_world_erp", "-1", "world solver erp parameter - Error Restitution Percent (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_cfm = {0, "physics_ode_world_cfm", "-1", "world solver cfm parameter - Constraint Force Mixing (see ODE User Guide); not touched when -1"}; +cvar_t physics_ode_world_damping = {0, "physics_ode_world_damping", "1", "enabled damping scale (see ODE User Guide), this scales all damping values, be aware that behavior depends of step type"}; +cvar_t physics_ode_world_damping_linear = {0, "physics_ode_world_damping_linear", "0.01", "world linear damping scale (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_linear_threshold = {0, "physics_ode_world_damping_linear_threshold", "0.1", "world linear damping threshold (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_angular = {0, "physics_ode_world_damping_angular", "0.05", "world angular damping scale (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_damping_angular_threshold = {0, "physics_ode_world_damping_angular_threshold", "0.1", "world angular damping threshold (see ODE User Guide); use defaults when set to -1"}; +cvar_t physics_ode_world_gravitymod = {0, "physics_ode_world_gravitymod", "1", "multiplies gravity got from sv_gravity, this may be needed to tweak if strong damping is used"}; +cvar_t physics_ode_iterationsperframe = {0, "physics_ode_iterationsperframe", "1", "divisor for time step, runs multiple physics steps per frame"}; +cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "0", "use constant step instead of variable step which tends to increase stability, if set to 1 uses sys_ticrate, instead uses it's own value"}; +cvar_t physics_ode_autodisable = {0, "physics_ode_autodisable", "1", "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster"}; +cvar_t physics_ode_autodisable_steps = {0, "physics_ode_autodisable_steps", "10", "how many steps object should be dormant to be autodisabled"}; +cvar_t physics_ode_autodisable_time = {0, "physics_ode_autodisable_time", "0", "how many seconds object should be dormant to be autodisabled"}; +cvar_t physics_ode_autodisable_threshold_linear = {0, "physics_ode_autodisable_threshold_linear", "0.6", "body will be disabled if it's linear move below this value"}; +cvar_t physics_ode_autodisable_threshold_angular = {0, "physics_ode_autodisable_threshold_angular", "6", "body will be disabled if it's angular move below this value"}; +cvar_t physics_ode_autodisable_threshold_samples = {0, "physics_ode_autodisable_threshold_samples", "5", "average threshold with this number of samples"}; +cvar_t physics_ode_movelimit = {0, "physics_ode_movelimit", "0.5", "clamp velocity if a single move would exceed this percentage of object thickness, to prevent flying through walls, be aware that behavior depends of step type"}; +cvar_t physics_ode_spinlimit = {0, "physics_ode_spinlimit", "10000", "reset spin velocity if it gets too large"}; +cvar_t physics_ode_trick_fixnan = {0, "physics_ode_trick_fixnan", "1", "engine trick that checks and fixes NaN velocity/origin/angles on objects, a value of 2 makes console prints on each fix"}; +cvar_t physics_ode_printstats = {0, "physics_ode_printstats", "0", "print ODE stats each frame"}; + +cvar_t physics_ode = {0, "physics_ode", "0", "run ODE physics (VERY experimental and potentially buggy)"}; + +// LordHavoc: this large chunk of definitions comes from the ODE library +// include files. + +#ifdef ODE_STATIC +#include "ode/ode.h" +#else +#ifdef WINAPI +// ODE does not use WINAPI +#define ODE_API +#else +#define ODE_API +#endif + +// note: dynamic builds of ODE tend to be double precision, this is not used +// for static builds +typedef double dReal; + +typedef dReal dVector3[4]; +typedef dReal dVector4[4]; +typedef dReal dMatrix3[4*3]; +typedef dReal dMatrix4[4*4]; +typedef dReal dMatrix6[8*6]; +typedef dReal dQuaternion[4]; + +struct dxWorld; /* dynamics world */ +struct dxSpace; /* collision space */ +struct dxBody; /* rigid body (dynamics object) */ +struct dxGeom; /* geometry (collision object) */ +struct dxJoint; +struct dxJointNode; +struct dxJointGroup; +struct dxTriMeshData; + +#define dInfinity 3.402823466e+38f + +typedef struct dxWorld *dWorldID; +typedef struct dxSpace *dSpaceID; +typedef struct dxBody *dBodyID; +typedef struct dxGeom *dGeomID; +typedef struct dxJoint *dJointID; +typedef struct dxJointGroup *dJointGroupID; +typedef struct dxTriMeshData *dTriMeshDataID; + +typedef struct dJointFeedback +{ + dVector3 f1; /* force applied to body 1 */ + dVector3 t1; /* torque applied to body 1 */ + dVector3 f2; /* force applied to body 2 */ + dVector3 t2; /* torque applied to body 2 */ +} +dJointFeedback; + +typedef enum dJointType +{ + dJointTypeNone = 0, + dJointTypeBall, + dJointTypeHinge, + dJointTypeSlider, + dJointTypeContact, + dJointTypeUniversal, + dJointTypeHinge2, + dJointTypeFixed, + dJointTypeNull, + dJointTypeAMotor, + dJointTypeLMotor, + dJointTypePlane2D, + dJointTypePR, + dJointTypePU, + dJointTypePiston +} +dJointType; + +#define D_ALL_PARAM_NAMES(start) \ + /* parameters for limits and motors */ \ + dParamLoStop = start, \ + dParamHiStop, \ + dParamVel, \ + dParamFMax, \ + dParamFudgeFactor, \ + dParamBounce, \ + dParamCFM, \ + dParamStopERP, \ + dParamStopCFM, \ + /* parameters for suspension */ \ + dParamSuspensionERP, \ + dParamSuspensionCFM, \ + dParamERP, \ + +#define D_ALL_PARAM_NAMES_X(start,x) \ + /* parameters for limits and motors */ \ + dParamLoStop ## x = start, \ + dParamHiStop ## x, \ + dParamVel ## x, \ + dParamFMax ## x, \ + dParamFudgeFactor ## x, \ + dParamBounce ## x, \ + dParamCFM ## x, \ + dParamStopERP ## x, \ + dParamStopCFM ## x, \ + /* parameters for suspension */ \ + dParamSuspensionERP ## x, \ + dParamSuspensionCFM ## x, \ + dParamERP ## x, + +enum { + D_ALL_PARAM_NAMES(0) + D_ALL_PARAM_NAMES_X(0x100,2) + D_ALL_PARAM_NAMES_X(0x200,3) + + /* add a multiple of this constant to the basic parameter numbers to get + * the parameters for the second, third etc axes. + */ + dParamGroup=0x100 +}; + +typedef struct dMass +{ + dReal mass; + dVector3 c; + dMatrix3 I; +} +dMass; + +enum +{ + dContactMu2 = 0x001, + dContactFDir1 = 0x002, + dContactBounce = 0x004, + dContactSoftERP = 0x008, + dContactSoftCFM = 0x010, + dContactMotion1 = 0x020, + dContactMotion2 = 0x040, + dContactMotionN = 0x080, + dContactSlip1 = 0x100, + dContactSlip2 = 0x200, + + dContactApprox0 = 0x0000, + dContactApprox1_1 = 0x1000, + dContactApprox1_2 = 0x2000, + dContactApprox1 = 0x3000 +}; + +typedef struct dSurfaceParameters +{ + /* must always be defined */ + int mode; + dReal mu; + + /* only defined if the corresponding flag is set in mode */ + dReal mu2; + dReal bounce; + dReal bounce_vel; + dReal soft_erp; + dReal soft_cfm; + dReal motion1,motion2,motionN; + dReal slip1,slip2; +} dSurfaceParameters; + +typedef struct dContactGeom +{ + dVector3 pos; ///< contact position + dVector3 normal; ///< normal vector + dReal depth; ///< penetration depth + dGeomID g1,g2; ///< the colliding geoms + int side1,side2; ///< (to be documented) +} +dContactGeom; + +typedef struct dContact +{ + dSurfaceParameters surface; + dContactGeom geom; + dVector3 fdir1; +} +dContact; + +typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); + +// SAP +// Order XZY or ZXY usually works best, if your Y is up. +#define dSAP_AXES_XYZ ((0)|(1<<2)|(2<<4)) +#define dSAP_AXES_XZY ((0)|(2<<2)|(1<<4)) +#define dSAP_AXES_YXZ ((1)|(0<<2)|(2<<4)) +#define dSAP_AXES_YZX ((1)|(2<<2)|(0<<4)) +#define dSAP_AXES_ZXY ((2)|(0<<2)|(1<<4)) +#define dSAP_AXES_ZYX ((2)|(1<<2)|(0<<4)) + +const char* (ODE_API *dGetConfiguration)(void); +int (ODE_API *dCheckConfiguration)( const char* token ); +int (ODE_API *dInitODE)(void); +//int (ODE_API *dInitODE2)(unsigned int uiInitFlags); +//int (ODE_API *dAllocateODEDataForThread)(unsigned int uiAllocateFlags); +//void (ODE_API *dCleanupODEAllDataForThread)(void); +void (ODE_API *dCloseODE)(void); + +//int (ODE_API *dMassCheck)(const dMass *m); +//void (ODE_API *dMassSetZero)(dMass *); +//void (ODE_API *dMassSetParameters)(dMass *, dReal themass, dReal cgx, dReal cgy, dReal cgz, dReal I11, dReal I22, dReal I33, dReal I12, dReal I13, dReal I23); +//void (ODE_API *dMassSetSphere)(dMass *, dReal density, dReal radius); +void (ODE_API *dMassSetSphereTotal)(dMass *, dReal total_mass, dReal radius); +//void (ODE_API *dMassSetCapsule)(dMass *, dReal density, int direction, dReal radius, dReal length); +void (ODE_API *dMassSetCapsuleTotal)(dMass *, dReal total_mass, int direction, dReal radius, dReal length); +//void (ODE_API *dMassSetCylinder)(dMass *, dReal density, int direction, dReal radius, dReal length); +void (ODE_API *dMassSetCylinderTotal)(dMass *, dReal total_mass, int direction, dReal radius, dReal length); +//void (ODE_API *dMassSetBox)(dMass *, dReal density, dReal lx, dReal ly, dReal lz); +void (ODE_API *dMassSetBoxTotal)(dMass *, dReal total_mass, dReal lx, dReal ly, dReal lz); +//void (ODE_API *dMassSetTrimesh)(dMass *, dReal density, dGeomID g); +//void (ODE_API *dMassSetTrimeshTotal)(dMass *m, dReal total_mass, dGeomID g); +//void (ODE_API *dMassAdjust)(dMass *, dReal newmass); +//void (ODE_API *dMassTranslate)(dMass *, dReal x, dReal y, dReal z); +//void (ODE_API *dMassRotate)(dMass *, const dMatrix3 R); +//void (ODE_API *dMassAdd)(dMass *a, const dMass *b); +// +dWorldID (ODE_API *dWorldCreate)(void); +void (ODE_API *dWorldDestroy)(dWorldID world); +void (ODE_API *dWorldSetGravity)(dWorldID, dReal x, dReal y, dReal z); +void (ODE_API *dWorldGetGravity)(dWorldID, dVector3 gravity); +void (ODE_API *dWorldSetERP)(dWorldID, dReal erp); +//dReal (ODE_API *dWorldGetERP)(dWorldID); +void (ODE_API *dWorldSetCFM)(dWorldID, dReal cfm); +//dReal (ODE_API *dWorldGetCFM)(dWorldID); +//void (ODE_API *dWorldStep)(dWorldID, dReal stepsize); +//void (ODE_API *dWorldImpulseToForce)(dWorldID, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force); +void (ODE_API *dWorldQuickStep)(dWorldID w, dReal stepsize); +void (ODE_API *dWorldSetQuickStepNumIterations)(dWorldID, int num); +//int (ODE_API *dWorldGetQuickStepNumIterations)(dWorldID); +//void (ODE_API *dWorldSetQuickStepW)(dWorldID, dReal over_relaxation); +//dReal (ODE_API *dWorldGetQuickStepW)(dWorldID); +//void (ODE_API *dWorldSetContactMaxCorrectingVel)(dWorldID, dReal vel); +//dReal (ODE_API *dWorldGetContactMaxCorrectingVel)(dWorldID); +void (ODE_API *dWorldSetContactSurfaceLayer)(dWorldID, dReal depth); +//dReal (ODE_API *dWorldGetContactSurfaceLayer)(dWorldID); +//void (ODE_API *dWorldStepFast1)(dWorldID, dReal stepsize, int maxiterations); +//void (ODE_API *dWorldSetAutoEnableDepthSF1)(dWorldID, int autoEnableDepth); +//int (ODE_API *dWorldGetAutoEnableDepthSF1)(dWorldID); +//dReal (ODE_API *dWorldGetAutoDisableLinearThreshold)(dWorldID); +void (ODE_API *dWorldSetAutoDisableLinearThreshold)(dWorldID, dReal linear_threshold); +//dReal (ODE_API *dWorldGetAutoDisableAngularThreshold)(dWorldID); +void (ODE_API *dWorldSetAutoDisableAngularThreshold)(dWorldID, dReal angular_threshold); +//dReal (ODE_API *dWorldGetAutoDisableLinearAverageThreshold)(dWorldID); +//void (ODE_API *dWorldSetAutoDisableLinearAverageThreshold)(dWorldID, dReal linear_average_threshold); +//dReal (ODE_API *dWorldGetAutoDisableAngularAverageThreshold)(dWorldID); +//void (ODE_API *dWorldSetAutoDisableAngularAverageThreshold)(dWorldID, dReal angular_average_threshold); +//int (ODE_API *dWorldGetAutoDisableAverageSamplesCount)(dWorldID); +void (ODE_API *dWorldSetAutoDisableAverageSamplesCount)(dWorldID, unsigned int average_samples_count ); +//int (ODE_API *dWorldGetAutoDisableSteps)(dWorldID); +void (ODE_API *dWorldSetAutoDisableSteps)(dWorldID, int steps); +//dReal (ODE_API *dWorldGetAutoDisableTime)(dWorldID); +void (ODE_API *dWorldSetAutoDisableTime)(dWorldID, dReal time); +//int (ODE_API *dWorldGetAutoDisableFlag)(dWorldID); +void (ODE_API *dWorldSetAutoDisableFlag)(dWorldID, int do_auto_disable); +//dReal (ODE_API *dWorldGetLinearDampingThreshold)(dWorldID w); +void (ODE_API *dWorldSetLinearDampingThreshold)(dWorldID w, dReal threshold); +//dReal (ODE_API *dWorldGetAngularDampingThreshold)(dWorldID w); +void (ODE_API *dWorldSetAngularDampingThreshold)(dWorldID w, dReal threshold); +//dReal (ODE_API *dWorldGetLinearDamping)(dWorldID w); +void (ODE_API *dWorldSetLinearDamping)(dWorldID w, dReal scale); +//dReal (ODE_API *dWorldGetAngularDamping)(dWorldID w); +void (ODE_API *dWorldSetAngularDamping)(dWorldID w, dReal scale); +//void (ODE_API *dWorldSetDamping)(dWorldID w, dReal linear_scale, dReal angular_scale); +//dReal (ODE_API *dWorldGetMaxAngularSpeed)(dWorldID w); +//void (ODE_API *dWorldSetMaxAngularSpeed)(dWorldID w, dReal max_speed); +//dReal (ODE_API *dBodyGetAutoDisableLinearThreshold)(dBodyID); +//void (ODE_API *dBodySetAutoDisableLinearThreshold)(dBodyID, dReal linear_average_threshold); +//dReal (ODE_API *dBodyGetAutoDisableAngularThreshold)(dBodyID); +//void (ODE_API *dBodySetAutoDisableAngularThreshold)(dBodyID, dReal angular_average_threshold); +//int (ODE_API *dBodyGetAutoDisableAverageSamplesCount)(dBodyID); +//void (ODE_API *dBodySetAutoDisableAverageSamplesCount)(dBodyID, unsigned int average_samples_count); +//int (ODE_API *dBodyGetAutoDisableSteps)(dBodyID); +//void (ODE_API *dBodySetAutoDisableSteps)(dBodyID, int steps); +//dReal (ODE_API *dBodyGetAutoDisableTime)(dBodyID); +//void (ODE_API *dBodySetAutoDisableTime)(dBodyID, dReal time); +//int (ODE_API *dBodyGetAutoDisableFlag)(dBodyID); +//void (ODE_API *dBodySetAutoDisableFlag)(dBodyID, int do_auto_disable); +//void (ODE_API *dBodySetAutoDisableDefaults)(dBodyID); +//dWorldID (ODE_API *dBodyGetWorld)(dBodyID); +dBodyID (ODE_API *dBodyCreate)(dWorldID); +void (ODE_API *dBodyDestroy)(dBodyID); +void (ODE_API *dBodySetData)(dBodyID, void *data); +void * (ODE_API *dBodyGetData)(dBodyID); +void (ODE_API *dBodySetPosition)(dBodyID, dReal x, dReal y, dReal z); +void (ODE_API *dBodySetRotation)(dBodyID, const dMatrix3 R); +//void (ODE_API *dBodySetQuaternion)(dBodyID, const dQuaternion q); +void (ODE_API *dBodySetLinearVel)(dBodyID, dReal x, dReal y, dReal z); +void (ODE_API *dBodySetAngularVel)(dBodyID, dReal x, dReal y, dReal z); +const dReal * (ODE_API *dBodyGetPosition)(dBodyID); +//void (ODE_API *dBodyCopyPosition)(dBodyID body, dVector3 pos); +const dReal * (ODE_API *dBodyGetRotation)(dBodyID); +//void (ODE_API *dBodyCopyRotation)(dBodyID, dMatrix3 R); +//const dReal * (ODE_API *dBodyGetQuaternion)(dBodyID); +//void (ODE_API *dBodyCopyQuaternion)(dBodyID body, dQuaternion quat); +const dReal * (ODE_API *dBodyGetLinearVel)(dBodyID); +const dReal * (ODE_API *dBodyGetAngularVel)(dBodyID); +void (ODE_API *dBodySetMass)(dBodyID, const dMass *mass); +//void (ODE_API *dBodyGetMass)(dBodyID, dMass *mass); +void (ODE_API *dBodyAddForce)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz); +//void (ODE_API *dBodyAddRelForce)(dBodyID, dReal fx, dReal fy, dReal fz); +//void (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//void (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//void (ODE_API *dBodyAddRelForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//void (ODE_API *dBodyAddRelForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +//const dReal * (ODE_API *dBodyGetForce)(dBodyID); +//const dReal * (ODE_API *dBodyGetTorque)(dBodyID); +//void (ODE_API *dBodySetForce)(dBodyID b, dReal x, dReal y, dReal z); +//void (ODE_API *dBodySetTorque)(dBodyID b, dReal x, dReal y, dReal z); +//void (ODE_API *dBodyGetRelPointPos)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodyGetRelPointVel)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodyGetPointVel)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodyGetPosRelPoint)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodyVectorToWorld)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodyVectorFromWorld)(dBodyID, dReal px, dReal py, dReal pz, dVector3 result); +//void (ODE_API *dBodySetFiniteRotationMode)(dBodyID, int mode); +//void (ODE_API *dBodySetFiniteRotationAxis)(dBodyID, dReal x, dReal y, dReal z); +//int (ODE_API *dBodyGetFiniteRotationMode)(dBodyID); +//void (ODE_API *dBodyGetFiniteRotationAxis)(dBodyID, dVector3 result); +int (ODE_API *dBodyGetNumJoints)(dBodyID b); +dJointID (ODE_API *dBodyGetJoint)(dBodyID, int index); +//void (ODE_API *dBodySetDynamic)(dBodyID); +//void (ODE_API *dBodySetKinematic)(dBodyID); +//int (ODE_API *dBodyIsKinematic)(dBodyID); +void (ODE_API *dBodyEnable)(dBodyID); +void (ODE_API *dBodyDisable)(dBodyID); +int (ODE_API *dBodyIsEnabled)(dBodyID); +void (ODE_API *dBodySetGravityMode)(dBodyID b, int mode); +int (ODE_API *dBodyGetGravityMode)(dBodyID b); +//void (*dBodySetMovedCallback)(dBodyID b, void(ODE_API *callback)(dBodyID)); +//dGeomID (ODE_API *dBodyGetFirstGeom)(dBodyID b); +//dGeomID (ODE_API *dBodyGetNextGeom)(dGeomID g); +//void (ODE_API *dBodySetDampingDefaults)(dBodyID b); +//dReal (ODE_API *dBodyGetLinearDamping)(dBodyID b); +//void (ODE_API *dBodySetLinearDamping)(dBodyID b, dReal scale); +//dReal (ODE_API *dBodyGetAngularDamping)(dBodyID b); +//void (ODE_API *dBodySetAngularDamping)(dBodyID b, dReal scale); +//void (ODE_API *dBodySetDamping)(dBodyID b, dReal linear_scale, dReal angular_scale); +//dReal (ODE_API *dBodyGetLinearDampingThreshold)(dBodyID b); +//void (ODE_API *dBodySetLinearDampingThreshold)(dBodyID b, dReal threshold); +//dReal (ODE_API *dBodyGetAngularDampingThreshold)(dBodyID b); +//void (ODE_API *dBodySetAngularDampingThreshold)(dBodyID b, dReal threshold); +//dReal (ODE_API *dBodyGetMaxAngularSpeed)(dBodyID b); +//void (ODE_API *dBodySetMaxAngularSpeed)(dBodyID b, dReal max_speed); +//int (ODE_API *dBodyGetGyroscopicMode)(dBodyID b); +//void (ODE_API *dBodySetGyroscopicMode)(dBodyID b, int enabled); +dJointID (ODE_API *dJointCreateBall)(dWorldID, dJointGroupID); +dJointID (ODE_API *dJointCreateHinge)(dWorldID, dJointGroupID); +dJointID (ODE_API *dJointCreateSlider)(dWorldID, dJointGroupID); +dJointID (ODE_API *dJointCreateContact)(dWorldID, dJointGroupID, const dContact *); +dJointID (ODE_API *dJointCreateHinge2)(dWorldID, dJointGroupID); +dJointID (ODE_API *dJointCreateUniversal)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreatePR)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreatePU)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreatePiston)(dWorldID, dJointGroupID); +dJointID (ODE_API *dJointCreateFixed)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreateNull)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreateAMotor)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreateLMotor)(dWorldID, dJointGroupID); +//dJointID (ODE_API *dJointCreatePlane2D)(dWorldID, dJointGroupID); +void (ODE_API *dJointDestroy)(dJointID); +dJointGroupID (ODE_API *dJointGroupCreate)(int max_size); +void (ODE_API *dJointGroupDestroy)(dJointGroupID); +void (ODE_API *dJointGroupEmpty)(dJointGroupID); +//int (ODE_API *dJointGetNumBodies)(dJointID); +void (ODE_API *dJointAttach)(dJointID, dBodyID body1, dBodyID body2); +//void (ODE_API *dJointEnable)(dJointID); +//void (ODE_API *dJointDisable)(dJointID); +//int (ODE_API *dJointIsEnabled)(dJointID); +void (ODE_API *dJointSetData)(dJointID, void *data); +void * (ODE_API *dJointGetData)(dJointID); +//dJointType (ODE_API *dJointGetType)(dJointID); +dBodyID (ODE_API *dJointGetBody)(dJointID, int index); +//void (ODE_API *dJointSetFeedback)(dJointID, dJointFeedback *); +//dJointFeedback *(ODE_API *dJointGetFeedback)(dJointID); +void (ODE_API *dJointSetBallAnchor)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetBallAnchor2)(dJointID, dReal x, dReal y, dReal z); +void (ODE_API *dJointSetBallParam)(dJointID, int parameter, dReal value); +void (ODE_API *dJointSetHingeAnchor)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetHingeAnchorDelta)(dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); +void (ODE_API *dJointSetHingeAxis)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetHingeAxisOffset)(dJointID j, dReal x, dReal y, dReal z, dReal angle); +void (ODE_API *dJointSetHingeParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddHingeTorque)(dJointID joint, dReal torque); +void (ODE_API *dJointSetSliderAxis)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetSliderAxisDelta)(dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); +void (ODE_API *dJointSetSliderParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddSliderForce)(dJointID joint, dReal force); +void (ODE_API *dJointSetHinge2Anchor)(dJointID, dReal x, dReal y, dReal z); +void (ODE_API *dJointSetHinge2Axis1)(dJointID, dReal x, dReal y, dReal z); +void (ODE_API *dJointSetHinge2Axis2)(dJointID, dReal x, dReal y, dReal z); +void (ODE_API *dJointSetHinge2Param)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddHinge2Torques)(dJointID joint, dReal torque1, dReal torque2); +void (ODE_API *dJointSetUniversalAnchor)(dJointID, dReal x, dReal y, dReal z); +void (ODE_API *dJointSetUniversalAxis1)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetUniversalAxis1Offset)(dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2); +void (ODE_API *dJointSetUniversalAxis2)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetUniversalAxis2Offset)(dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2); +void (ODE_API *dJointSetUniversalParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddUniversalTorques)(dJointID joint, dReal torque1, dReal torque2); +//void (ODE_API *dJointSetPRAnchor)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPRAxis1)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPRAxis2)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPRParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddPRTorque)(dJointID j, dReal torque); +//void (ODE_API *dJointSetPUAnchor)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPUAnchorOffset)(dJointID, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz); +//void (ODE_API *dJointSetPUAxis1)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPUAxis2)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPUAxis3)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPUAxisP)(dJointID id, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPUParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddPUTorque)(dJointID j, dReal torque); +//void (ODE_API *dJointSetPistonAnchor)(dJointID, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetPistonAnchorOffset)(dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz); +//void (ODE_API *dJointSetPistonParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointAddPistonForce)(dJointID joint, dReal force); +//void (ODE_API *dJointSetFixed)(dJointID); +//void (ODE_API *dJointSetFixedParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointSetAMotorNumAxes)(dJointID, int num); +//void (ODE_API *dJointSetAMotorAxis)(dJointID, int anum, int rel, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetAMotorAngle)(dJointID, int anum, dReal angle); +//void (ODE_API *dJointSetAMotorParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointSetAMotorMode)(dJointID, int mode); +//void (ODE_API *dJointAddAMotorTorques)(dJointID, dReal torque1, dReal torque2, dReal torque3); +//void (ODE_API *dJointSetLMotorNumAxes)(dJointID, int num); +//void (ODE_API *dJointSetLMotorAxis)(dJointID, int anum, int rel, dReal x, dReal y, dReal z); +//void (ODE_API *dJointSetLMotorParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointSetPlane2DXParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointSetPlane2DYParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointSetPlane2DAngleParam)(dJointID, int parameter, dReal value); +//void (ODE_API *dJointGetBallAnchor)(dJointID, dVector3 result); +//void (ODE_API *dJointGetBallAnchor2)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetBallParam)(dJointID, int parameter); +//void (ODE_API *dJointGetHingeAnchor)(dJointID, dVector3 result); +//void (ODE_API *dJointGetHingeAnchor2)(dJointID, dVector3 result); +//void (ODE_API *dJointGetHingeAxis)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetHingeParam)(dJointID, int parameter); +//dReal (ODE_API *dJointGetHingeAngle)(dJointID); +//dReal (ODE_API *dJointGetHingeAngleRate)(dJointID); +//dReal (ODE_API *dJointGetSliderPosition)(dJointID); +//dReal (ODE_API *dJointGetSliderPositionRate)(dJointID); +//void (ODE_API *dJointGetSliderAxis)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetSliderParam)(dJointID, int parameter); +//void (ODE_API *dJointGetHinge2Anchor)(dJointID, dVector3 result); +//void (ODE_API *dJointGetHinge2Anchor2)(dJointID, dVector3 result); +//void (ODE_API *dJointGetHinge2Axis1)(dJointID, dVector3 result); +//void (ODE_API *dJointGetHinge2Axis2)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetHinge2Param)(dJointID, int parameter); +//dReal (ODE_API *dJointGetHinge2Angle1)(dJointID); +//dReal (ODE_API *dJointGetHinge2Angle1Rate)(dJointID); +//dReal (ODE_API *dJointGetHinge2Angle2Rate)(dJointID); +//void (ODE_API *dJointGetUniversalAnchor)(dJointID, dVector3 result); +//void (ODE_API *dJointGetUniversalAnchor2)(dJointID, dVector3 result); +//void (ODE_API *dJointGetUniversalAxis1)(dJointID, dVector3 result); +//void (ODE_API *dJointGetUniversalAxis2)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetUniversalParam)(dJointID, int parameter); +//void (ODE_API *dJointGetUniversalAngles)(dJointID, dReal *angle1, dReal *angle2); +//dReal (ODE_API *dJointGetUniversalAngle1)(dJointID); +//dReal (ODE_API *dJointGetUniversalAngle2)(dJointID); +//dReal (ODE_API *dJointGetUniversalAngle1Rate)(dJointID); +//dReal (ODE_API *dJointGetUniversalAngle2Rate)(dJointID); +//void (ODE_API *dJointGetPRAnchor)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetPRPosition)(dJointID); +//dReal (ODE_API *dJointGetPRPositionRate)(dJointID); +//dReal (ODE_API *dJointGetPRAngle)(dJointID); +//dReal (ODE_API *dJointGetPRAngleRate)(dJointID); +//void (ODE_API *dJointGetPRAxis1)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPRAxis2)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetPRParam)(dJointID, int parameter); +//void (ODE_API *dJointGetPUAnchor)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetPUPosition)(dJointID); +//dReal (ODE_API *dJointGetPUPositionRate)(dJointID); +//void (ODE_API *dJointGetPUAxis1)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPUAxis2)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPUAxis3)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPUAxisP)(dJointID id, dVector3 result); +//void (ODE_API *dJointGetPUAngles)(dJointID, dReal *angle1, dReal *angle2); +//dReal (ODE_API *dJointGetPUAngle1)(dJointID); +//dReal (ODE_API *dJointGetPUAngle1Rate)(dJointID); +//dReal (ODE_API *dJointGetPUAngle2)(dJointID); +//dReal (ODE_API *dJointGetPUAngle2Rate)(dJointID); +//dReal (ODE_API *dJointGetPUParam)(dJointID, int parameter); +//dReal (ODE_API *dJointGetPistonPosition)(dJointID); +//dReal (ODE_API *dJointGetPistonPositionRate)(dJointID); +//dReal (ODE_API *dJointGetPistonAngle)(dJointID); +//dReal (ODE_API *dJointGetPistonAngleRate)(dJointID); +//void (ODE_API *dJointGetPistonAnchor)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPistonAnchor2)(dJointID, dVector3 result); +//void (ODE_API *dJointGetPistonAxis)(dJointID, dVector3 result); +//dReal (ODE_API *dJointGetPistonParam)(dJointID, int parameter); +//int (ODE_API *dJointGetAMotorNumAxes)(dJointID); +//void (ODE_API *dJointGetAMotorAxis)(dJointID, int anum, dVector3 result); +//int (ODE_API *dJointGetAMotorAxisRel)(dJointID, int anum); +//dReal (ODE_API *dJointGetAMotorAngle)(dJointID, int anum); +//dReal (ODE_API *dJointGetAMotorAngleRate)(dJointID, int anum); +//dReal (ODE_API *dJointGetAMotorParam)(dJointID, int parameter); +//int (ODE_API *dJointGetAMotorMode)(dJointID); +//int (ODE_API *dJointGetLMotorNumAxes)(dJointID); +//void (ODE_API *dJointGetLMotorAxis)(dJointID, int anum, dVector3 result); +//dReal (ODE_API *dJointGetLMotorParam)(dJointID, int parameter); +//dReal (ODE_API *dJointGetFixedParam)(dJointID, int parameter); +//dJointID (ODE_API *dConnectingJoint)(dBodyID, dBodyID); +//int (ODE_API *dConnectingJointList)(dBodyID, dBodyID, dJointID*); +int (ODE_API *dAreConnected)(dBodyID, dBodyID); +int (ODE_API *dAreConnectedExcluding)(dBodyID body1, dBodyID body2, int joint_type); +// +dSpaceID (ODE_API *dSimpleSpaceCreate)(dSpaceID space); +dSpaceID (ODE_API *dHashSpaceCreate)(dSpaceID space); +dSpaceID (ODE_API *dQuadTreeSpaceCreate)(dSpaceID space, const dVector3 Center, const dVector3 Extents, int Depth); +//dSpaceID (ODE_API *dSweepAndPruneSpaceCreate)( dSpaceID space, int axisorder ); +void (ODE_API *dSpaceDestroy)(dSpaceID); +//void (ODE_API *dHashSpaceSetLevels)(dSpaceID space, int minlevel, int maxlevel); +//void (ODE_API *dHashSpaceGetLevels)(dSpaceID space, int *minlevel, int *maxlevel); +//void (ODE_API *dSpaceSetCleanup)(dSpaceID space, int mode); +//int (ODE_API *dSpaceGetCleanup)(dSpaceID space); +//void (ODE_API *dSpaceSetSublevel)(dSpaceID space, int sublevel); +//int (ODE_API *dSpaceGetSublevel)(dSpaceID space); +//void (ODE_API *dSpaceSetManualCleanup)(dSpaceID space, int mode); +//int (ODE_API *dSpaceGetManualCleanup)(dSpaceID space); +//void (ODE_API *dSpaceAdd)(dSpaceID, dGeomID); +//void (ODE_API *dSpaceRemove)(dSpaceID, dGeomID); +//int (ODE_API *dSpaceQuery)(dSpaceID, dGeomID); +//void (ODE_API *dSpaceClean)(dSpaceID); +//int (ODE_API *dSpaceGetNumGeoms)(dSpaceID); +//dGeomID (ODE_API *dSpaceGetGeom)(dSpaceID, int i); +//int (ODE_API *dSpaceGetClass)(dSpaceID space); +// +void (ODE_API *dGeomDestroy)(dGeomID geom); +void (ODE_API *dGeomSetData)(dGeomID geom, void* data); +void * (ODE_API *dGeomGetData)(dGeomID geom); +void (ODE_API *dGeomSetBody)(dGeomID geom, dBodyID body); +dBodyID (ODE_API *dGeomGetBody)(dGeomID geom); +void (ODE_API *dGeomSetPosition)(dGeomID geom, dReal x, dReal y, dReal z); +void (ODE_API *dGeomSetRotation)(dGeomID geom, const dMatrix3 R); +//void (ODE_API *dGeomSetQuaternion)(dGeomID geom, const dQuaternion Q); +//const dReal * (ODE_API *dGeomGetPosition)(dGeomID geom); +//void (ODE_API *dGeomCopyPosition)(dGeomID geom, dVector3 pos); +//const dReal * (ODE_API *dGeomGetRotation)(dGeomID geom); +//void (ODE_API *dGeomCopyRotation)(dGeomID geom, dMatrix3 R); +//void (ODE_API *dGeomGetQuaternion)(dGeomID geom, dQuaternion result); +//void (ODE_API *dGeomGetAABB)(dGeomID geom, dReal aabb[6]); +int (ODE_API *dGeomIsSpace)(dGeomID geom); +//dSpaceID (ODE_API *dGeomGetSpace)(dGeomID); +//int (ODE_API *dGeomGetClass)(dGeomID geom); +//void (ODE_API *dGeomSetCategoryBits)(dGeomID geom, unsigned long bits); +//void (ODE_API *dGeomSetCollideBits)(dGeomID geom, unsigned long bits); +//unsigned long (ODE_API *dGeomGetCategoryBits)(dGeomID); +//unsigned long (ODE_API *dGeomGetCollideBits)(dGeomID); +//void (ODE_API *dGeomEnable)(dGeomID geom); +//void (ODE_API *dGeomDisable)(dGeomID geom); +//int (ODE_API *dGeomIsEnabled)(dGeomID geom); +//void (ODE_API *dGeomSetOffsetPosition)(dGeomID geom, dReal x, dReal y, dReal z); +//void (ODE_API *dGeomSetOffsetRotation)(dGeomID geom, const dMatrix3 R); +//void (ODE_API *dGeomSetOffsetQuaternion)(dGeomID geom, const dQuaternion Q); +//void (ODE_API *dGeomSetOffsetWorldPosition)(dGeomID geom, dReal x, dReal y, dReal z); +//void (ODE_API *dGeomSetOffsetWorldRotation)(dGeomID geom, const dMatrix3 R); +//void (ODE_API *dGeomSetOffsetWorldQuaternion)(dGeomID geom, const dQuaternion); +//void (ODE_API *dGeomClearOffset)(dGeomID geom); +//int (ODE_API *dGeomIsOffset)(dGeomID geom); +//const dReal * (ODE_API *dGeomGetOffsetPosition)(dGeomID geom); +//void (ODE_API *dGeomCopyOffsetPosition)(dGeomID geom, dVector3 pos); +//const dReal * (ODE_API *dGeomGetOffsetRotation)(dGeomID geom); +//void (ODE_API *dGeomCopyOffsetRotation)(dGeomID geom, dMatrix3 R); +//void (ODE_API *dGeomGetOffsetQuaternion)(dGeomID geom, dQuaternion result); +int (ODE_API *dCollide)(dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip); +// +void (ODE_API *dSpaceCollide)(dSpaceID space, void *data, dNearCallback *callback); +void (ODE_API *dSpaceCollide2)(dGeomID space1, dGeomID space2, void *data, dNearCallback *callback); +// +dGeomID (ODE_API *dCreateSphere)(dSpaceID space, dReal radius); +//void (ODE_API *dGeomSphereSetRadius)(dGeomID sphere, dReal radius); +//dReal (ODE_API *dGeomSphereGetRadius)(dGeomID sphere); +//dReal (ODE_API *dGeomSpherePointDepth)(dGeomID sphere, dReal x, dReal y, dReal z); +// +dGeomID (ODE_API *dCreateConvex)(dSpaceID space, dReal *_planes, unsigned int _planecount, dReal *_points, unsigned int _pointcount,unsigned int *_polygons); +//void (ODE_API *dGeomSetConvex)(dGeomID g, dReal *_planes, unsigned int _count, dReal *_points, unsigned int _pointcount,unsigned int *_polygons); +// +dGeomID (ODE_API *dCreateBox)(dSpaceID space, dReal lx, dReal ly, dReal lz); +//void (ODE_API *dGeomBoxSetLengths)(dGeomID box, dReal lx, dReal ly, dReal lz); +//void (ODE_API *dGeomBoxGetLengths)(dGeomID box, dVector3 result); +//dReal (ODE_API *dGeomBoxPointDepth)(dGeomID box, dReal x, dReal y, dReal z); +//dReal (ODE_API *dGeomBoxPointDepth)(dGeomID box, dReal x, dReal y, dReal z); +// +//dGeomID (ODE_API *dCreatePlane)(dSpaceID space, dReal a, dReal b, dReal c, dReal d); +//void (ODE_API *dGeomPlaneSetParams)(dGeomID plane, dReal a, dReal b, dReal c, dReal d); +//void (ODE_API *dGeomPlaneGetParams)(dGeomID plane, dVector4 result); +//dReal (ODE_API *dGeomPlanePointDepth)(dGeomID plane, dReal x, dReal y, dReal z); +// +dGeomID (ODE_API *dCreateCapsule)(dSpaceID space, dReal radius, dReal length); +//void (ODE_API *dGeomCapsuleSetParams)(dGeomID ccylinder, dReal radius, dReal length); +//void (ODE_API *dGeomCapsuleGetParams)(dGeomID ccylinder, dReal *radius, dReal *length); +//dReal (ODE_API *dGeomCapsulePointDepth)(dGeomID ccylinder, dReal x, dReal y, dReal z); +// +dGeomID (ODE_API *dCreateCylinder)(dSpaceID space, dReal radius, dReal length); +//void (ODE_API *dGeomCylinderSetParams)(dGeomID cylinder, dReal radius, dReal length); +//void (ODE_API *dGeomCylinderGetParams)(dGeomID cylinder, dReal *radius, dReal *length); +// +//dGeomID (ODE_API *dCreateRay)(dSpaceID space, dReal length); +//void (ODE_API *dGeomRaySetLength)(dGeomID ray, dReal length); +//dReal (ODE_API *dGeomRayGetLength)(dGeomID ray); +//void (ODE_API *dGeomRaySet)(dGeomID ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz); +//void (ODE_API *dGeomRayGet)(dGeomID ray, dVector3 start, dVector3 dir); +// +dGeomID (ODE_API *dCreateGeomTransform)(dSpaceID space); +void (ODE_API *dGeomTransformSetGeom)(dGeomID g, dGeomID obj); +//dGeomID (ODE_API *dGeomTransformGetGeom)(dGeomID g); +void (ODE_API *dGeomTransformSetCleanup)(dGeomID g, int mode); +//int (ODE_API *dGeomTransformGetCleanup)(dGeomID g); +//void (ODE_API *dGeomTransformSetInfo)(dGeomID g, int mode); +//int (ODE_API *dGeomTransformGetInfo)(dGeomID g); + +enum { TRIMESH_FACE_NORMALS }; +typedef int dTriCallback(dGeomID TriMesh, dGeomID RefObject, int TriangleIndex); +typedef void dTriArrayCallback(dGeomID TriMesh, dGeomID RefObject, const int* TriIndices, int TriCount); +typedef int dTriRayCallback(dGeomID TriMesh, dGeomID Ray, int TriangleIndex, dReal u, dReal v); +typedef int dTriTriMergeCallback(dGeomID TriMesh, int FirstTriangleIndex, int SecondTriangleIndex); + +dTriMeshDataID (ODE_API *dGeomTriMeshDataCreate)(void); +void (ODE_API *dGeomTriMeshDataDestroy)(dTriMeshDataID g); +//void (ODE_API *dGeomTriMeshDataSet)(dTriMeshDataID g, int data_id, void* in_data); +//void* (ODE_API *dGeomTriMeshDataGet)(dTriMeshDataID g, int data_id); +//void (*dGeomTriMeshSetLastTransform)( (ODE_API *dGeomID g, dMatrix4 last_trans ); +//dReal* (*dGeomTriMeshGetLastTransform)( (ODE_API *dGeomID g ); +void (ODE_API *dGeomTriMeshDataBuildSingle)(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride); +//void (ODE_API *dGeomTriMeshDataBuildSingle1)(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride, const void* Normals); +//void (ODE_API *dGeomTriMeshDataBuildDouble)(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride); +//void (ODE_API *dGeomTriMeshDataBuildDouble1)(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride, const void* Normals); +//void (ODE_API *dGeomTriMeshDataBuildSimple)(dTriMeshDataID g, const dReal* Vertices, int VertexCount, const dTriIndex* Indices, int IndexCount); +//void (ODE_API *dGeomTriMeshDataBuildSimple1)(dTriMeshDataID g, const dReal* Vertices, int VertexCount, const dTriIndex* Indices, int IndexCount, const int* Normals); +//void (ODE_API *dGeomTriMeshDataPreprocess)(dTriMeshDataID g); +//void (ODE_API *dGeomTriMeshDataGetBuffer)(dTriMeshDataID g, unsigned char** buf, int* bufLen); +//void (ODE_API *dGeomTriMeshDataSetBuffer)(dTriMeshDataID g, unsigned char* buf); +//void (ODE_API *dGeomTriMeshSetCallback)(dGeomID g, dTriCallback* Callback); +//dTriCallback* (ODE_API *dGeomTriMeshGetCallback)(dGeomID g); +//void (ODE_API *dGeomTriMeshSetArrayCallback)(dGeomID g, dTriArrayCallback* ArrayCallback); +//dTriArrayCallback* (ODE_API *dGeomTriMeshGetArrayCallback)(dGeomID g); +//void (ODE_API *dGeomTriMeshSetRayCallback)(dGeomID g, dTriRayCallback* Callback); +//dTriRayCallback* (ODE_API *dGeomTriMeshGetRayCallback)(dGeomID g); +//void (ODE_API *dGeomTriMeshSetTriMergeCallback)(dGeomID g, dTriTriMergeCallback* Callback); +//dTriTriMergeCallback* (ODE_API *dGeomTriMeshGetTriMergeCallback)(dGeomID g); +dGeomID (ODE_API *dCreateTriMesh)(dSpaceID space, dTriMeshDataID Data, dTriCallback* Callback, dTriArrayCallback* ArrayCallback, dTriRayCallback* RayCallback); +//void (ODE_API *dGeomTriMeshSetData)(dGeomID g, dTriMeshDataID Data); +//dTriMeshDataID (ODE_API *dGeomTriMeshGetData)(dGeomID g); +//void (ODE_API *dGeomTriMeshEnableTC)(dGeomID g, int geomClass, int enable); +//int (ODE_API *dGeomTriMeshIsTCEnabled)(dGeomID g, int geomClass); +//void (ODE_API *dGeomTriMeshClearTCCache)(dGeomID g); +//dTriMeshDataID (ODE_API *dGeomTriMeshGetTriMeshDataID)(dGeomID g); +//void (ODE_API *dGeomTriMeshGetTriangle)(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2); +//void (ODE_API *dGeomTriMeshGetPoint)(dGeomID g, int Index, dReal u, dReal v, dVector3 Out); +//int (ODE_API *dGeomTriMeshGetTriangleCount )(dGeomID g); +//void (ODE_API *dGeomTriMeshDataUpdate)(dTriMeshDataID g); + +static dllfunction_t odefuncs[] = +{ + {"dGetConfiguration", (void **) &dGetConfiguration}, + {"dCheckConfiguration", (void **) &dCheckConfiguration}, + {"dInitODE", (void **) &dInitODE}, +// {"dInitODE2", (void **) &dInitODE2}, +// {"dAllocateODEDataForThread", (void **) &dAllocateODEDataForThread}, +// {"dCleanupODEAllDataForThread", (void **) &dCleanupODEAllDataForThread}, + {"dCloseODE", (void **) &dCloseODE}, +// {"dMassCheck", (void **) &dMassCheck}, +// {"dMassSetZero", (void **) &dMassSetZero}, +// {"dMassSetParameters", (void **) &dMassSetParameters}, +// {"dMassSetSphere", (void **) &dMassSetSphere}, + {"dMassSetSphereTotal", (void **) &dMassSetSphereTotal}, +// {"dMassSetCapsule", (void **) &dMassSetCapsule}, + {"dMassSetCapsuleTotal", (void **) &dMassSetCapsuleTotal}, +// {"dMassSetCylinder", (void **) &dMassSetCylinder}, + {"dMassSetCylinderTotal", (void **) &dMassSetCylinderTotal}, +// {"dMassSetBox", (void **) &dMassSetBox}, + {"dMassSetBoxTotal", (void **) &dMassSetBoxTotal}, +// {"dMassSetTrimesh", (void **) &dMassSetTrimesh}, +// {"dMassSetTrimeshTotal", (void **) &dMassSetTrimeshTotal}, +// {"dMassAdjust", (void **) &dMassAdjust}, +// {"dMassTranslate", (void **) &dMassTranslate}, +// {"dMassRotate", (void **) &dMassRotate}, +// {"dMassAdd", (void **) &dMassAdd}, + + {"dWorldCreate", (void **) &dWorldCreate}, + {"dWorldDestroy", (void **) &dWorldDestroy}, + {"dWorldSetGravity", (void **) &dWorldSetGravity}, + {"dWorldGetGravity", (void **) &dWorldGetGravity}, + {"dWorldSetERP", (void **) &dWorldSetERP}, +// {"dWorldGetERP", (void **) &dWorldGetERP}, + {"dWorldSetCFM", (void **) &dWorldSetCFM}, +// {"dWorldGetCFM", (void **) &dWorldGetCFM}, +// {"dWorldStep", (void **) &dWorldStep}, +// {"dWorldImpulseToForce", (void **) &dWorldImpulseToForce}, + {"dWorldQuickStep", (void **) &dWorldQuickStep}, + {"dWorldSetQuickStepNumIterations", (void **) &dWorldSetQuickStepNumIterations}, +// {"dWorldGetQuickStepNumIterations", (void **) &dWorldGetQuickStepNumIterations}, +// {"dWorldSetQuickStepW", (void **) &dWorldSetQuickStepW}, +// {"dWorldGetQuickStepW", (void **) &dWorldGetQuickStepW}, +// {"dWorldSetContactMaxCorrectingVel", (void **) &dWorldSetContactMaxCorrectingVel}, +// {"dWorldGetContactMaxCorrectingVel", (void **) &dWorldGetContactMaxCorrectingVel}, + {"dWorldSetContactSurfaceLayer", (void **) &dWorldSetContactSurfaceLayer}, +// {"dWorldGetContactSurfaceLayer", (void **) &dWorldGetContactSurfaceLayer}, +// {"dWorldStepFast1", (void **) &dWorldStepFast1}, +// {"dWorldSetAutoEnableDepthSF1", (void **) &dWorldSetAutoEnableDepthSF1}, +// {"dWorldGetAutoEnableDepthSF1", (void **) &dWorldGetAutoEnableDepthSF1}, +// {"dWorldGetAutoDisableLinearThreshold", (void **) &dWorldGetAutoDisableLinearThreshold}, + {"dWorldSetAutoDisableLinearThreshold", (void **) &dWorldSetAutoDisableLinearThreshold}, +// {"dWorldGetAutoDisableAngularThreshold", (void **) &dWorldGetAutoDisableAngularThreshold}, + {"dWorldSetAutoDisableAngularThreshold", (void **) &dWorldSetAutoDisableAngularThreshold}, +// {"dWorldGetAutoDisableLinearAverageThreshold", (void **) &dWorldGetAutoDisableLinearAverageThreshold}, +// {"dWorldSetAutoDisableLinearAverageThreshold", (void **) &dWorldSetAutoDisableLinearAverageThreshold}, +// {"dWorldGetAutoDisableAngularAverageThreshold", (void **) &dWorldGetAutoDisableAngularAverageThreshold}, +// {"dWorldSetAutoDisableAngularAverageThreshold", (void **) &dWorldSetAutoDisableAngularAverageThreshold}, +// {"dWorldGetAutoDisableAverageSamplesCount", (void **) &dWorldGetAutoDisableAverageSamplesCount}, + {"dWorldSetAutoDisableAverageSamplesCount", (void **) &dWorldSetAutoDisableAverageSamplesCount}, +// {"dWorldGetAutoDisableSteps", (void **) &dWorldGetAutoDisableSteps}, + {"dWorldSetAutoDisableSteps", (void **) &dWorldSetAutoDisableSteps}, +// {"dWorldGetAutoDisableTime", (void **) &dWorldGetAutoDisableTime}, + {"dWorldSetAutoDisableTime", (void **) &dWorldSetAutoDisableTime}, +// {"dWorldGetAutoDisableFlag", (void **) &dWorldGetAutoDisableFlag}, + {"dWorldSetAutoDisableFlag", (void **) &dWorldSetAutoDisableFlag}, +// {"dWorldGetLinearDampingThreshold", (void **) &dWorldGetLinearDampingThreshold}, + {"dWorldSetLinearDampingThreshold", (void **) &dWorldSetLinearDampingThreshold}, +// {"dWorldGetAngularDampingThreshold", (void **) &dWorldGetAngularDampingThreshold}, + {"dWorldSetAngularDampingThreshold", (void **) &dWorldSetAngularDampingThreshold}, +// {"dWorldGetLinearDamping", (void **) &dWorldGetLinearDamping}, + {"dWorldSetLinearDamping", (void **) &dWorldSetLinearDamping}, +// {"dWorldGetAngularDamping", (void **) &dWorldGetAngularDamping}, + {"dWorldSetAngularDamping", (void **) &dWorldSetAngularDamping}, +// {"dWorldSetDamping", (void **) &dWorldSetDamping}, +// {"dWorldGetMaxAngularSpeed", (void **) &dWorldGetMaxAngularSpeed}, +// {"dWorldSetMaxAngularSpeed", (void **) &dWorldSetMaxAngularSpeed}, +// {"dBodyGetAutoDisableLinearThreshold", (void **) &dBodyGetAutoDisableLinearThreshold}, +// {"dBodySetAutoDisableLinearThreshold", (void **) &dBodySetAutoDisableLinearThreshold}, +// {"dBodyGetAutoDisableAngularThreshold", (void **) &dBodyGetAutoDisableAngularThreshold}, +// {"dBodySetAutoDisableAngularThreshold", (void **) &dBodySetAutoDisableAngularThreshold}, +// {"dBodyGetAutoDisableAverageSamplesCount", (void **) &dBodyGetAutoDisableAverageSamplesCount}, +// {"dBodySetAutoDisableAverageSamplesCount", (void **) &dBodySetAutoDisableAverageSamplesCount}, +// {"dBodyGetAutoDisableSteps", (void **) &dBodyGetAutoDisableSteps}, +// {"dBodySetAutoDisableSteps", (void **) &dBodySetAutoDisableSteps}, +// {"dBodyGetAutoDisableTime", (void **) &dBodyGetAutoDisableTime}, +// {"dBodySetAutoDisableTime", (void **) &dBodySetAutoDisableTime}, +// {"dBodyGetAutoDisableFlag", (void **) &dBodyGetAutoDisableFlag}, +// {"dBodySetAutoDisableFlag", (void **) &dBodySetAutoDisableFlag}, +// {"dBodySetAutoDisableDefaults", (void **) &dBodySetAutoDisableDefaults}, +// {"dBodyGetWorld", (void **) &dBodyGetWorld}, + {"dBodyCreate", (void **) &dBodyCreate}, + {"dBodyDestroy", (void **) &dBodyDestroy}, + {"dBodySetData", (void **) &dBodySetData}, + {"dBodyGetData", (void **) &dBodyGetData}, + {"dBodySetPosition", (void **) &dBodySetPosition}, + {"dBodySetRotation", (void **) &dBodySetRotation}, +// {"dBodySetQuaternion", (void **) &dBodySetQuaternion}, + {"dBodySetLinearVel", (void **) &dBodySetLinearVel}, + {"dBodySetAngularVel", (void **) &dBodySetAngularVel}, + {"dBodyGetPosition", (void **) &dBodyGetPosition}, +// {"dBodyCopyPosition", (void **) &dBodyCopyPosition}, + {"dBodyGetRotation", (void **) &dBodyGetRotation}, +// {"dBodyCopyRotation", (void **) &dBodyCopyRotation}, +// {"dBodyGetQuaternion", (void **) &dBodyGetQuaternion}, +// {"dBodyCopyQuaternion", (void **) &dBodyCopyQuaternion}, + {"dBodyGetLinearVel", (void **) &dBodyGetLinearVel}, + {"dBodyGetAngularVel", (void **) &dBodyGetAngularVel}, + {"dBodySetMass", (void **) &dBodySetMass}, +// {"dBodyGetMass", (void **) &dBodyGetMass}, + {"dBodyAddForce", (void **) &dBodyAddForce}, + {"dBodyAddTorque", (void **) &dBodyAddTorque}, +// {"dBodyAddRelForce", (void **) &dBodyAddRelForce}, +// {"dBodyAddRelTorque", (void **) &dBodyAddRelTorque}, + {"dBodyAddForceAtPos", (void **) &dBodyAddForceAtPos}, +// {"dBodyAddForceAtRelPos", (void **) &dBodyAddForceAtRelPos}, +// {"dBodyAddRelForceAtPos", (void **) &dBodyAddRelForceAtPos}, +// {"dBodyAddRelForceAtRelPos", (void **) &dBodyAddRelForceAtRelPos}, +// {"dBodyGetForce", (void **) &dBodyGetForce}, +// {"dBodyGetTorque", (void **) &dBodyGetTorque}, +// {"dBodySetForce", (void **) &dBodySetForce}, +// {"dBodySetTorque", (void **) &dBodySetTorque}, +// {"dBodyGetRelPointPos", (void **) &dBodyGetRelPointPos}, +// {"dBodyGetRelPointVel", (void **) &dBodyGetRelPointVel}, +// {"dBodyGetPointVel", (void **) &dBodyGetPointVel}, +// {"dBodyGetPosRelPoint", (void **) &dBodyGetPosRelPoint}, +// {"dBodyVectorToWorld", (void **) &dBodyVectorToWorld}, +// {"dBodyVectorFromWorld", (void **) &dBodyVectorFromWorld}, +// {"dBodySetFiniteRotationMode", (void **) &dBodySetFiniteRotationMode}, +// {"dBodySetFiniteRotationAxis", (void **) &dBodySetFiniteRotationAxis}, +// {"dBodyGetFiniteRotationMode", (void **) &dBodyGetFiniteRotationMode}, +// {"dBodyGetFiniteRotationAxis", (void **) &dBodyGetFiniteRotationAxis}, + {"dBodyGetNumJoints", (void **) &dBodyGetNumJoints}, + {"dBodyGetJoint", (void **) &dBodyGetJoint}, +// {"dBodySetDynamic", (void **) &dBodySetDynamic}, +// {"dBodySetKinematic", (void **) &dBodySetKinematic}, +// {"dBodyIsKinematic", (void **) &dBodyIsKinematic}, + {"dBodyEnable", (void **) &dBodyEnable}, + {"dBodyDisable", (void **) &dBodyDisable}, + {"dBodyIsEnabled", (void **) &dBodyIsEnabled}, + {"dBodySetGravityMode", (void **) &dBodySetGravityMode}, + {"dBodyGetGravityMode", (void **) &dBodyGetGravityMode}, +// {"dBodySetMovedCallback", (void **) &dBodySetMovedCallback}, +// {"dBodyGetFirstGeom", (void **) &dBodyGetFirstGeom}, +// {"dBodyGetNextGeom", (void **) &dBodyGetNextGeom}, +// {"dBodySetDampingDefaults", (void **) &dBodySetDampingDefaults}, +// {"dBodyGetLinearDamping", (void **) &dBodyGetLinearDamping}, +// {"dBodySetLinearDamping", (void **) &dBodySetLinearDamping}, +// {"dBodyGetAngularDamping", (void **) &dBodyGetAngularDamping}, +// {"dBodySetAngularDamping", (void **) &dBodySetAngularDamping}, +// {"dBodySetDamping", (void **) &dBodySetDamping}, +// {"dBodyGetLinearDampingThreshold", (void **) &dBodyGetLinearDampingThreshold}, +// {"dBodySetLinearDampingThreshold", (void **) &dBodySetLinearDampingThreshold}, +// {"dBodyGetAngularDampingThreshold", (void **) &dBodyGetAngularDampingThreshold}, +// {"dBodySetAngularDampingThreshold", (void **) &dBodySetAngularDampingThreshold}, +// {"dBodyGetMaxAngularSpeed", (void **) &dBodyGetMaxAngularSpeed}, +// {"dBodySetMaxAngularSpeed", (void **) &dBodySetMaxAngularSpeed}, +// {"dBodyGetGyroscopicMode", (void **) &dBodyGetGyroscopicMode}, +// {"dBodySetGyroscopicMode", (void **) &dBodySetGyroscopicMode}, + {"dJointCreateBall", (void **) &dJointCreateBall}, + {"dJointCreateHinge", (void **) &dJointCreateHinge}, + {"dJointCreateSlider", (void **) &dJointCreateSlider}, + {"dJointCreateContact", (void **) &dJointCreateContact}, + {"dJointCreateHinge2", (void **) &dJointCreateHinge2}, + {"dJointCreateUniversal", (void **) &dJointCreateUniversal}, +// {"dJointCreatePR", (void **) &dJointCreatePR}, +// {"dJointCreatePU", (void **) &dJointCreatePU}, +// {"dJointCreatePiston", (void **) &dJointCreatePiston}, + {"dJointCreateFixed", (void **) &dJointCreateFixed}, +// {"dJointCreateNull", (void **) &dJointCreateNull}, +// {"dJointCreateAMotor", (void **) &dJointCreateAMotor}, +// {"dJointCreateLMotor", (void **) &dJointCreateLMotor}, +// {"dJointCreatePlane2D", (void **) &dJointCreatePlane2D}, + {"dJointDestroy", (void **) &dJointDestroy}, + {"dJointGroupCreate", (void **) &dJointGroupCreate}, + {"dJointGroupDestroy", (void **) &dJointGroupDestroy}, + {"dJointGroupEmpty", (void **) &dJointGroupEmpty}, +// {"dJointGetNumBodies", (void **) &dJointGetNumBodies}, + {"dJointAttach", (void **) &dJointAttach}, +// {"dJointEnable", (void **) &dJointEnable}, +// {"dJointDisable", (void **) &dJointDisable}, +// {"dJointIsEnabled", (void **) &dJointIsEnabled}, + {"dJointSetData", (void **) &dJointSetData}, + {"dJointGetData", (void **) &dJointGetData}, +// {"dJointGetType", (void **) &dJointGetType}, + {"dJointGetBody", (void **) &dJointGetBody}, +// {"dJointSetFeedback", (void **) &dJointSetFeedback}, +// {"dJointGetFeedback", (void **) &dJointGetFeedback}, + {"dJointSetBallAnchor", (void **) &dJointSetBallAnchor}, +// {"dJointSetBallAnchor2", (void **) &dJointSetBallAnchor2}, + {"dJointSetBallParam", (void **) &dJointSetBallParam}, + {"dJointSetHingeAnchor", (void **) &dJointSetHingeAnchor}, +// {"dJointSetHingeAnchorDelta", (void **) &dJointSetHingeAnchorDelta}, + {"dJointSetHingeAxis", (void **) &dJointSetHingeAxis}, +// {"dJointSetHingeAxisOffset", (void **) &dJointSetHingeAxisOffset}, + {"dJointSetHingeParam", (void **) &dJointSetHingeParam}, +// {"dJointAddHingeTorque", (void **) &dJointAddHingeTorque}, + {"dJointSetSliderAxis", (void **) &dJointSetSliderAxis}, +// {"dJointSetSliderAxisDelta", (void **) &dJointSetSliderAxisDelta}, + {"dJointSetSliderParam", (void **) &dJointSetSliderParam}, +// {"dJointAddSliderForce", (void **) &dJointAddSliderForce}, + {"dJointSetHinge2Anchor", (void **) &dJointSetHinge2Anchor}, + {"dJointSetHinge2Axis1", (void **) &dJointSetHinge2Axis1}, + {"dJointSetHinge2Axis2", (void **) &dJointSetHinge2Axis2}, + {"dJointSetHinge2Param", (void **) &dJointSetHinge2Param}, +// {"dJointAddHinge2Torques", (void **) &dJointAddHinge2Torques}, + {"dJointSetUniversalAnchor", (void **) &dJointSetUniversalAnchor}, + {"dJointSetUniversalAxis1", (void **) &dJointSetUniversalAxis1}, +// {"dJointSetUniversalAxis1Offset", (void **) &dJointSetUniversalAxis1Offset}, + {"dJointSetUniversalAxis2", (void **) &dJointSetUniversalAxis2}, +// {"dJointSetUniversalAxis2Offset", (void **) &dJointSetUniversalAxis2Offset}, + {"dJointSetUniversalParam", (void **) &dJointSetUniversalParam}, +// {"dJointAddUniversalTorques", (void **) &dJointAddUniversalTorques}, +// {"dJointSetPRAnchor", (void **) &dJointSetPRAnchor}, +// {"dJointSetPRAxis1", (void **) &dJointSetPRAxis1}, +// {"dJointSetPRAxis2", (void **) &dJointSetPRAxis2}, +// {"dJointSetPRParam", (void **) &dJointSetPRParam}, +// {"dJointAddPRTorque", (void **) &dJointAddPRTorque}, +// {"dJointSetPUAnchor", (void **) &dJointSetPUAnchor}, +// {"dJointSetPUAnchorOffset", (void **) &dJointSetPUAnchorOffset}, +// {"dJointSetPUAxis1", (void **) &dJointSetPUAxis1}, +// {"dJointSetPUAxis2", (void **) &dJointSetPUAxis2}, +// {"dJointSetPUAxis3", (void **) &dJointSetPUAxis3}, +// {"dJointSetPUAxisP", (void **) &dJointSetPUAxisP}, +// {"dJointSetPUParam", (void **) &dJointSetPUParam}, +// {"dJointAddPUTorque", (void **) &dJointAddPUTorque}, +// {"dJointSetPistonAnchor", (void **) &dJointSetPistonAnchor}, +// {"dJointSetPistonAnchorOffset", (void **) &dJointSetPistonAnchorOffset}, +// {"dJointSetPistonParam", (void **) &dJointSetPistonParam}, +// {"dJointAddPistonForce", (void **) &dJointAddPistonForce}, +// {"dJointSetFixed", (void **) &dJointSetFixed}, +// {"dJointSetFixedParam", (void **) &dJointSetFixedParam}, +// {"dJointSetAMotorNumAxes", (void **) &dJointSetAMotorNumAxes}, +// {"dJointSetAMotorAxis", (void **) &dJointSetAMotorAxis}, +// {"dJointSetAMotorAngle", (void **) &dJointSetAMotorAngle}, +// {"dJointSetAMotorParam", (void **) &dJointSetAMotorParam}, +// {"dJointSetAMotorMode", (void **) &dJointSetAMotorMode}, +// {"dJointAddAMotorTorques", (void **) &dJointAddAMotorTorques}, +// {"dJointSetLMotorNumAxes", (void **) &dJointSetLMotorNumAxes}, +// {"dJointSetLMotorAxis", (void **) &dJointSetLMotorAxis}, +// {"dJointSetLMotorParam", (void **) &dJointSetLMotorParam}, +// {"dJointSetPlane2DXParam", (void **) &dJointSetPlane2DXParam}, +// {"dJointSetPlane2DYParam", (void **) &dJointSetPlane2DYParam}, +// {"dJointSetPlane2DAngleParam", (void **) &dJointSetPlane2DAngleParam}, +// {"dJointGetBallAnchor", (void **) &dJointGetBallAnchor}, +// {"dJointGetBallAnchor2", (void **) &dJointGetBallAnchor2}, +// {"dJointGetBallParam", (void **) &dJointGetBallParam}, +// {"dJointGetHingeAnchor", (void **) &dJointGetHingeAnchor}, +// {"dJointGetHingeAnchor2", (void **) &dJointGetHingeAnchor2}, +// {"dJointGetHingeAxis", (void **) &dJointGetHingeAxis}, +// {"dJointGetHingeParam", (void **) &dJointGetHingeParam}, +// {"dJointGetHingeAngle", (void **) &dJointGetHingeAngle}, +// {"dJointGetHingeAngleRate", (void **) &dJointGetHingeAngleRate}, +// {"dJointGetSliderPosition", (void **) &dJointGetSliderPosition}, +// {"dJointGetSliderPositionRate", (void **) &dJointGetSliderPositionRate}, +// {"dJointGetSliderAxis", (void **) &dJointGetSliderAxis}, +// {"dJointGetSliderParam", (void **) &dJointGetSliderParam}, +// {"dJointGetHinge2Anchor", (void **) &dJointGetHinge2Anchor}, +// {"dJointGetHinge2Anchor2", (void **) &dJointGetHinge2Anchor2}, +// {"dJointGetHinge2Axis1", (void **) &dJointGetHinge2Axis1}, +// {"dJointGetHinge2Axis2", (void **) &dJointGetHinge2Axis2}, +// {"dJointGetHinge2Param", (void **) &dJointGetHinge2Param}, +// {"dJointGetHinge2Angle1", (void **) &dJointGetHinge2Angle1}, +// {"dJointGetHinge2Angle1Rate", (void **) &dJointGetHinge2Angle1Rate}, +// {"dJointGetHinge2Angle2Rate", (void **) &dJointGetHinge2Angle2Rate}, +// {"dJointGetUniversalAnchor", (void **) &dJointGetUniversalAnchor}, +// {"dJointGetUniversalAnchor2", (void **) &dJointGetUniversalAnchor2}, +// {"dJointGetUniversalAxis1", (void **) &dJointGetUniversalAxis1}, +// {"dJointGetUniversalAxis2", (void **) &dJointGetUniversalAxis2}, +// {"dJointGetUniversalParam", (void **) &dJointGetUniversalParam}, +// {"dJointGetUniversalAngles", (void **) &dJointGetUniversalAngles}, +// {"dJointGetUniversalAngle1", (void **) &dJointGetUniversalAngle1}, +// {"dJointGetUniversalAngle2", (void **) &dJointGetUniversalAngle2}, +// {"dJointGetUniversalAngle1Rate", (void **) &dJointGetUniversalAngle1Rate}, +// {"dJointGetUniversalAngle2Rate", (void **) &dJointGetUniversalAngle2Rate}, +// {"dJointGetPRAnchor", (void **) &dJointGetPRAnchor}, +// {"dJointGetPRPosition", (void **) &dJointGetPRPosition}, +// {"dJointGetPRPositionRate", (void **) &dJointGetPRPositionRate}, +// {"dJointGetPRAngle", (void **) &dJointGetPRAngle}, +// {"dJointGetPRAngleRate", (void **) &dJointGetPRAngleRate}, +// {"dJointGetPRAxis1", (void **) &dJointGetPRAxis1}, +// {"dJointGetPRAxis2", (void **) &dJointGetPRAxis2}, +// {"dJointGetPRParam", (void **) &dJointGetPRParam}, +// {"dJointGetPUAnchor", (void **) &dJointGetPUAnchor}, +// {"dJointGetPUPosition", (void **) &dJointGetPUPosition}, +// {"dJointGetPUPositionRate", (void **) &dJointGetPUPositionRate}, +// {"dJointGetPUAxis1", (void **) &dJointGetPUAxis1}, +// {"dJointGetPUAxis2", (void **) &dJointGetPUAxis2}, +// {"dJointGetPUAxis3", (void **) &dJointGetPUAxis3}, +// {"dJointGetPUAxisP", (void **) &dJointGetPUAxisP}, +// {"dJointGetPUAngles", (void **) &dJointGetPUAngles}, +// {"dJointGetPUAngle1", (void **) &dJointGetPUAngle1}, +// {"dJointGetPUAngle1Rate", (void **) &dJointGetPUAngle1Rate}, +// {"dJointGetPUAngle2", (void **) &dJointGetPUAngle2}, +// {"dJointGetPUAngle2Rate", (void **) &dJointGetPUAngle2Rate}, +// {"dJointGetPUParam", (void **) &dJointGetPUParam}, +// {"dJointGetPistonPosition", (void **) &dJointGetPistonPosition}, +// {"dJointGetPistonPositionRate", (void **) &dJointGetPistonPositionRate}, +// {"dJointGetPistonAngle", (void **) &dJointGetPistonAngle}, +// {"dJointGetPistonAngleRate", (void **) &dJointGetPistonAngleRate}, +// {"dJointGetPistonAnchor", (void **) &dJointGetPistonAnchor}, +// {"dJointGetPistonAnchor2", (void **) &dJointGetPistonAnchor2}, +// {"dJointGetPistonAxis", (void **) &dJointGetPistonAxis}, +// {"dJointGetPistonParam", (void **) &dJointGetPistonParam}, +// {"dJointGetAMotorNumAxes", (void **) &dJointGetAMotorNumAxes}, +// {"dJointGetAMotorAxis", (void **) &dJointGetAMotorAxis}, +// {"dJointGetAMotorAxisRel", (void **) &dJointGetAMotorAxisRel}, +// {"dJointGetAMotorAngle", (void **) &dJointGetAMotorAngle}, +// {"dJointGetAMotorAngleRate", (void **) &dJointGetAMotorAngleRate}, +// {"dJointGetAMotorParam", (void **) &dJointGetAMotorParam}, +// {"dJointGetAMotorMode", (void **) &dJointGetAMotorMode}, +// {"dJointGetLMotorNumAxes", (void **) &dJointGetLMotorNumAxes}, +// {"dJointGetLMotorAxis", (void **) &dJointGetLMotorAxis}, +// {"dJointGetLMotorParam", (void **) &dJointGetLMotorParam}, +// {"dJointGetFixedParam", (void **) &dJointGetFixedParam}, +// {"dConnectingJoint", (void **) &dConnectingJoint}, +// {"dConnectingJointList", (void **) &dConnectingJointList}, + {"dAreConnected", (void **) &dAreConnected}, + {"dAreConnectedExcluding", (void **) &dAreConnectedExcluding}, + {"dSimpleSpaceCreate", (void **) &dSimpleSpaceCreate}, + {"dHashSpaceCreate", (void **) &dHashSpaceCreate}, + {"dQuadTreeSpaceCreate", (void **) &dQuadTreeSpaceCreate}, +// {"dSweepAndPruneSpaceCreate", (void **) &dSweepAndPruneSpaceCreate}, + {"dSpaceDestroy", (void **) &dSpaceDestroy}, +// {"dHashSpaceSetLevels", (void **) &dHashSpaceSetLevels}, +// {"dHashSpaceGetLevels", (void **) &dHashSpaceGetLevels}, +// {"dSpaceSetCleanup", (void **) &dSpaceSetCleanup}, +// {"dSpaceGetCleanup", (void **) &dSpaceGetCleanup}, +// {"dSpaceSetSublevel", (void **) &dSpaceSetSublevel}, +// {"dSpaceGetSublevel", (void **) &dSpaceGetSublevel}, +// {"dSpaceSetManualCleanup", (void **) &dSpaceSetManualCleanup}, +// {"dSpaceGetManualCleanup", (void **) &dSpaceGetManualCleanup}, +// {"dSpaceAdd", (void **) &dSpaceAdd}, +// {"dSpaceRemove", (void **) &dSpaceRemove}, +// {"dSpaceQuery", (void **) &dSpaceQuery}, +// {"dSpaceClean", (void **) &dSpaceClean}, +// {"dSpaceGetNumGeoms", (void **) &dSpaceGetNumGeoms}, +// {"dSpaceGetGeom", (void **) &dSpaceGetGeom}, +// {"dSpaceGetClass", (void **) &dSpaceGetClass}, + {"dGeomDestroy", (void **) &dGeomDestroy}, + {"dGeomSetData", (void **) &dGeomSetData}, + {"dGeomGetData", (void **) &dGeomGetData}, + {"dGeomSetBody", (void **) &dGeomSetBody}, + {"dGeomGetBody", (void **) &dGeomGetBody}, + {"dGeomSetPosition", (void **) &dGeomSetPosition}, + {"dGeomSetRotation", (void **) &dGeomSetRotation}, +// {"dGeomSetQuaternion", (void **) &dGeomSetQuaternion}, +// {"dGeomGetPosition", (void **) &dGeomGetPosition}, +// {"dGeomCopyPosition", (void **) &dGeomCopyPosition}, +// {"dGeomGetRotation", (void **) &dGeomGetRotation}, +// {"dGeomCopyRotation", (void **) &dGeomCopyRotation}, +// {"dGeomGetQuaternion", (void **) &dGeomGetQuaternion}, +// {"dGeomGetAABB", (void **) &dGeomGetAABB}, + {"dGeomIsSpace", (void **) &dGeomIsSpace}, +// {"dGeomGetSpace", (void **) &dGeomGetSpace}, +// {"dGeomGetClass", (void **) &dGeomGetClass}, +// {"dGeomSetCategoryBits", (void **) &dGeomSetCategoryBits}, +// {"dGeomSetCollideBits", (void **) &dGeomSetCollideBits}, +// {"dGeomGetCategoryBits", (void **) &dGeomGetCategoryBits}, +// {"dGeomGetCollideBits", (void **) &dGeomGetCollideBits}, +// {"dGeomEnable", (void **) &dGeomEnable}, +// {"dGeomDisable", (void **) &dGeomDisable}, +// {"dGeomIsEnabled", (void **) &dGeomIsEnabled}, +// {"dGeomSetOffsetPosition", (void **) &dGeomSetOffsetPosition}, +// {"dGeomSetOffsetRotation", (void **) &dGeomSetOffsetRotation}, +// {"dGeomSetOffsetQuaternion", (void **) &dGeomSetOffsetQuaternion}, +// {"dGeomSetOffsetWorldPosition", (void **) &dGeomSetOffsetWorldPosition}, +// {"dGeomSetOffsetWorldRotation", (void **) &dGeomSetOffsetWorldRotation}, +// {"dGeomSetOffsetWorldQuaternion", (void **) &dGeomSetOffsetWorldQuaternion}, +// {"dGeomClearOffset", (void **) &dGeomClearOffset}, +// {"dGeomIsOffset", (void **) &dGeomIsOffset}, +// {"dGeomGetOffsetPosition", (void **) &dGeomGetOffsetPosition}, +// {"dGeomCopyOffsetPosition", (void **) &dGeomCopyOffsetPosition}, +// {"dGeomGetOffsetRotation", (void **) &dGeomGetOffsetRotation}, +// {"dGeomCopyOffsetRotation", (void **) &dGeomCopyOffsetRotation}, +// {"dGeomGetOffsetQuaternion", (void **) &dGeomGetOffsetQuaternion}, + {"dCollide", (void **) &dCollide}, + {"dSpaceCollide", (void **) &dSpaceCollide}, + {"dSpaceCollide2", (void **) &dSpaceCollide2}, + {"dCreateSphere", (void **) &dCreateSphere}, +// {"dGeomSphereSetRadius", (void **) &dGeomSphereSetRadius}, +// {"dGeomSphereGetRadius", (void **) &dGeomSphereGetRadius}, +// {"dGeomSpherePointDepth", (void **) &dGeomSpherePointDepth}, + {"dCreateConvex", (void **) &dCreateConvex}, +// {"dGeomSetConvex", (void **) &dGeomSetConvex}, + {"dCreateBox", (void **) &dCreateBox}, +// {"dGeomBoxSetLengths", (void **) &dGeomBoxSetLengths}, +// {"dGeomBoxGetLengths", (void **) &dGeomBoxGetLengths}, +// {"dGeomBoxPointDepth", (void **) &dGeomBoxPointDepth}, +// {"dGeomBoxPointDepth", (void **) &dGeomBoxPointDepth}, +// {"dCreatePlane", (void **) &dCreatePlane}, +// {"dGeomPlaneSetParams", (void **) &dGeomPlaneSetParams}, +// {"dGeomPlaneGetParams", (void **) &dGeomPlaneGetParams}, +// {"dGeomPlanePointDepth", (void **) &dGeomPlanePointDepth}, + {"dCreateCapsule", (void **) &dCreateCapsule}, +// {"dGeomCapsuleSetParams", (void **) &dGeomCapsuleSetParams}, +// {"dGeomCapsuleGetParams", (void **) &dGeomCapsuleGetParams}, +// {"dGeomCapsulePointDepth", (void **) &dGeomCapsulePointDepth}, + {"dCreateCylinder", (void **) &dCreateCylinder}, +// {"dGeomCylinderSetParams", (void **) &dGeomCylinderSetParams}, +// {"dGeomCylinderGetParams", (void **) &dGeomCylinderGetParams}, +// {"dCreateRay", (void **) &dCreateRay}, +// {"dGeomRaySetLength", (void **) &dGeomRaySetLength}, +// {"dGeomRayGetLength", (void **) &dGeomRayGetLength}, +// {"dGeomRaySet", (void **) &dGeomRaySet}, +// {"dGeomRayGet", (void **) &dGeomRayGet}, + {"dCreateGeomTransform", (void **) &dCreateGeomTransform}, + {"dGeomTransformSetGeom", (void **) &dGeomTransformSetGeom}, +// {"dGeomTransformGetGeom", (void **) &dGeomTransformGetGeom}, + {"dGeomTransformSetCleanup", (void **) &dGeomTransformSetCleanup}, +// {"dGeomTransformGetCleanup", (void **) &dGeomTransformGetCleanup}, +// {"dGeomTransformSetInfo", (void **) &dGeomTransformSetInfo}, +// {"dGeomTransformGetInfo", (void **) &dGeomTransformGetInfo}, + {"dGeomTriMeshDataCreate", (void **) &dGeomTriMeshDataCreate}, + {"dGeomTriMeshDataDestroy", (void **) &dGeomTriMeshDataDestroy}, +// {"dGeomTriMeshDataSet", (void **) &dGeomTriMeshDataSet}, +// {"dGeomTriMeshDataGet", (void **) &dGeomTriMeshDataGet}, +// {"dGeomTriMeshSetLastTransform", (void **) &dGeomTriMeshSetLastTransform}, +// {"dGeomTriMeshGetLastTransform", (void **) &dGeomTriMeshGetLastTransform}, + {"dGeomTriMeshDataBuildSingle", (void **) &dGeomTriMeshDataBuildSingle}, +// {"dGeomTriMeshDataBuildSingle1", (void **) &dGeomTriMeshDataBuildSingle1}, +// {"dGeomTriMeshDataBuildDouble", (void **) &dGeomTriMeshDataBuildDouble}, +// {"dGeomTriMeshDataBuildDouble1", (void **) &dGeomTriMeshDataBuildDouble1}, +// {"dGeomTriMeshDataBuildSimple", (void **) &dGeomTriMeshDataBuildSimple}, +// {"dGeomTriMeshDataBuildSimple1", (void **) &dGeomTriMeshDataBuildSimple1}, +// {"dGeomTriMeshDataPreprocess", (void **) &dGeomTriMeshDataPreprocess}, +// {"dGeomTriMeshDataGetBuffer", (void **) &dGeomTriMeshDataGetBuffer}, +// {"dGeomTriMeshDataSetBuffer", (void **) &dGeomTriMeshDataSetBuffer}, +// {"dGeomTriMeshSetCallback", (void **) &dGeomTriMeshSetCallback}, +// {"dGeomTriMeshGetCallback", (void **) &dGeomTriMeshGetCallback}, +// {"dGeomTriMeshSetArrayCallback", (void **) &dGeomTriMeshSetArrayCallback}, +// {"dGeomTriMeshGetArrayCallback", (void **) &dGeomTriMeshGetArrayCallback}, +// {"dGeomTriMeshSetRayCallback", (void **) &dGeomTriMeshSetRayCallback}, +// {"dGeomTriMeshGetRayCallback", (void **) &dGeomTriMeshGetRayCallback}, +// {"dGeomTriMeshSetTriMergeCallback", (void **) &dGeomTriMeshSetTriMergeCallback}, +// {"dGeomTriMeshGetTriMergeCallback", (void **) &dGeomTriMeshGetTriMergeCallback}, + {"dCreateTriMesh", (void **) &dCreateTriMesh}, +// {"dGeomTriMeshSetData", (void **) &dGeomTriMeshSetData}, +// {"dGeomTriMeshGetData", (void **) &dGeomTriMeshGetData}, +// {"dGeomTriMeshEnableTC", (void **) &dGeomTriMeshEnableTC}, +// {"dGeomTriMeshIsTCEnabled", (void **) &dGeomTriMeshIsTCEnabled}, +// {"dGeomTriMeshClearTCCache", (void **) &dGeomTriMeshClearTCCache}, +// {"dGeomTriMeshGetTriMeshDataID", (void **) &dGeomTriMeshGetTriMeshDataID}, +// {"dGeomTriMeshGetTriangle", (void **) &dGeomTriMeshGetTriangle}, +// {"dGeomTriMeshGetPoint", (void **) &dGeomTriMeshGetPoint}, +// {"dGeomTriMeshGetTriangleCount", (void **) &dGeomTriMeshGetTriangleCount}, +// {"dGeomTriMeshDataUpdate", (void **) &dGeomTriMeshDataUpdate}, + {NULL, NULL} +}; + +// Handle for ODE DLL +dllhandle_t ode_dll = NULL; +#endif +#endif + +static void World_Physics_Init(void) +{ +#ifdef USEODE +#ifdef ODE_DYNAMIC + const char* dllnames [] = + { +# if defined(WIN32) + "libode3.dll", + "libode2.dll", + "libode1.dll", +# elif defined(MACOSX) + "libode.3.dylib", + "libode.2.dylib", + "libode.1.dylib", +# else + "libode.so.3", + "libode.so.2", + "libode.so.1", +# endif + NULL + }; +#endif + + Cvar_RegisterVariable(&physics_ode_quadtree_depth); + Cvar_RegisterVariable(&physics_ode_contactsurfacelayer); + Cvar_RegisterVariable(&physics_ode_worldstep_iterations); + Cvar_RegisterVariable(&physics_ode_contact_mu); + Cvar_RegisterVariable(&physics_ode_contact_erp); + Cvar_RegisterVariable(&physics_ode_contact_cfm); + Cvar_RegisterVariable(&physics_ode_contact_maxpoints); + Cvar_RegisterVariable(&physics_ode_world_erp); + Cvar_RegisterVariable(&physics_ode_world_cfm); + Cvar_RegisterVariable(&physics_ode_world_damping); + Cvar_RegisterVariable(&physics_ode_world_damping_linear); + Cvar_RegisterVariable(&physics_ode_world_damping_linear_threshold); + Cvar_RegisterVariable(&physics_ode_world_damping_angular); + Cvar_RegisterVariable(&physics_ode_world_damping_angular_threshold); + Cvar_RegisterVariable(&physics_ode_world_gravitymod); + Cvar_RegisterVariable(&physics_ode_iterationsperframe); + Cvar_RegisterVariable(&physics_ode_constantstep); + Cvar_RegisterVariable(&physics_ode_movelimit); + Cvar_RegisterVariable(&physics_ode_spinlimit); + Cvar_RegisterVariable(&physics_ode_trick_fixnan); + Cvar_RegisterVariable(&physics_ode_autodisable); + Cvar_RegisterVariable(&physics_ode_autodisable_steps); + Cvar_RegisterVariable(&physics_ode_autodisable_time); + Cvar_RegisterVariable(&physics_ode_autodisable_threshold_linear); + Cvar_RegisterVariable(&physics_ode_autodisable_threshold_angular); + Cvar_RegisterVariable(&physics_ode_autodisable_threshold_samples); + Cvar_RegisterVariable(&physics_ode_printstats); + Cvar_RegisterVariable(&physics_ode_allowconvex); + Cvar_RegisterVariable(&physics_ode); + +#ifdef ODE_DYNAMIC + // Load the DLL + if (Sys_LoadLibrary (dllnames, &ode_dll, odefuncs)) +#endif + { + dInitODE(); +// dInitODE2(0); +#ifdef ODE_DYNAMIC +# ifdef dSINGLE + if (!dCheckConfiguration("ODE_single_precision")) +# else + if (!dCheckConfiguration("ODE_double_precision")) +# endif + { +# ifdef dSINGLE + Con_Printf("ODE library not compiled for single precision - incompatible! Not using ODE physics.\n"); +# else + Con_Printf("ODE library not compiled for double precision - incompatible! Not using ODE physics.\n"); +# endif + Sys_UnloadLibrary(&ode_dll); + ode_dll = NULL; + } + else + { +# ifdef dSINGLE + Con_Printf("ODE library loaded with single precision.\n"); +# else + Con_Printf("ODE library loaded with double precision.\n"); +# endif + Con_Printf("ODE configuration list: %s\n", dGetConfiguration()); + } +#endif + } +#endif +} + +static void World_Physics_Shutdown(void) +{ +#ifdef USEODE +#ifdef ODE_DYNAMIC + if (ode_dll) +#endif + { + dCloseODE(); +#ifdef ODE_DYNAMIC + Sys_UnloadLibrary(&ode_dll); + ode_dll = NULL; +#endif + } +#endif +} + +#ifdef USEODE +static void World_Physics_UpdateODE(world_t *world) +{ + dWorldID odeworld; + + odeworld = (dWorldID)world->physics.ode_world; + + // ERP and CFM + if (physics_ode_world_erp.value >= 0) + dWorldSetERP(odeworld, physics_ode_world_erp.value); + if (physics_ode_world_cfm.value >= 0) + dWorldSetCFM(odeworld, physics_ode_world_cfm.value); + // Damping + if (physics_ode_world_damping.integer) + { + dWorldSetLinearDamping(odeworld, (physics_ode_world_damping_linear.value >= 0) ? (physics_ode_world_damping_linear.value * physics_ode_world_damping.value) : 0); + dWorldSetLinearDampingThreshold(odeworld, (physics_ode_world_damping_linear_threshold.value >= 0) ? (physics_ode_world_damping_linear_threshold.value * physics_ode_world_damping.value) : 0); + dWorldSetAngularDamping(odeworld, (physics_ode_world_damping_angular.value >= 0) ? (physics_ode_world_damping_angular.value * physics_ode_world_damping.value) : 0); + dWorldSetAngularDampingThreshold(odeworld, (physics_ode_world_damping_angular_threshold.value >= 0) ? (physics_ode_world_damping_angular_threshold.value * physics_ode_world_damping.value) : 0); + } + else + { + dWorldSetLinearDamping(odeworld, 0); + dWorldSetLinearDampingThreshold(odeworld, 0); + dWorldSetAngularDamping(odeworld, 0); + dWorldSetAngularDampingThreshold(odeworld, 0); + } + // Autodisable + dWorldSetAutoDisableFlag(odeworld, (physics_ode_autodisable.integer) ? 1 : 0); + if (physics_ode_autodisable.integer) + { + dWorldSetAutoDisableSteps(odeworld, bound(1, physics_ode_autodisable_steps.integer, 100)); + dWorldSetAutoDisableTime(odeworld, physics_ode_autodisable_time.value); + dWorldSetAutoDisableAverageSamplesCount(odeworld, bound(1, physics_ode_autodisable_threshold_samples.integer, 100)); + dWorldSetAutoDisableLinearThreshold(odeworld, physics_ode_autodisable_threshold_linear.value); + dWorldSetAutoDisableAngularThreshold(odeworld, physics_ode_autodisable_threshold_angular.value); + } +} + +static void World_Physics_EnableODE(world_t *world) +{ + dVector3 center, extents; + if (world->physics.ode) + return; +#ifdef ODE_DYNAMIC + if (!ode_dll) + return; +#endif + world->physics.ode = true; + VectorMAM(0.5f, world->mins, 0.5f, world->maxs, center); + VectorSubtract(world->maxs, center, extents); + world->physics.ode_world = dWorldCreate(); + world->physics.ode_space = dQuadTreeSpaceCreate(NULL, center, extents, bound(1, physics_ode_quadtree_depth.integer, 10)); + world->physics.ode_contactgroup = dJointGroupCreate(0); + + World_Physics_UpdateODE(world); +} +#endif + +static void World_Physics_Start(world_t *world) +{ +#ifdef USEODE + if (world->physics.ode) + return; + World_Physics_EnableODE(world); +#endif +} + +static void World_Physics_End(world_t *world) +{ +#ifdef USEODE + if (world->physics.ode) + { + dWorldDestroy((dWorldID)world->physics.ode_world); + dSpaceDestroy((dSpaceID)world->physics.ode_space); + dJointGroupDestroy((dJointGroupID)world->physics.ode_contactgroup); + world->physics.ode = false; + } +#endif +} + +void World_Physics_RemoveJointFromEntity(world_t *world, prvm_edict_t *ed) +{ + ed->priv.server->ode_joint_type = 0; +#ifdef USEODE + if(ed->priv.server->ode_joint) + dJointDestroy((dJointID)ed->priv.server->ode_joint); + ed->priv.server->ode_joint = NULL; +#endif +} + +void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed) +{ + edict_odefunc_t *f, *nf; + + // entity is not physics controlled, free any physics data + ed->priv.server->ode_physics = false; +#ifdef USEODE + if (ed->priv.server->ode_geom) + dGeomDestroy((dGeomID)ed->priv.server->ode_geom); + ed->priv.server->ode_geom = NULL; + if (ed->priv.server->ode_body) + { + dJointID j; + dBodyID b1, b2; + prvm_edict_t *ed2; + while(dBodyGetNumJoints((dBodyID)ed->priv.server->ode_body)) + { + j = dBodyGetJoint((dBodyID)ed->priv.server->ode_body, 0); + ed2 = (prvm_edict_t *) dJointGetData(j); + b1 = dJointGetBody(j, 0); + b2 = dJointGetBody(j, 1); + if(b1 == (dBodyID)ed->priv.server->ode_body) + { + b1 = 0; + ed2->priv.server->ode_joint_enemy = 0; + } + if(b2 == (dBodyID)ed->priv.server->ode_body) + { + b2 = 0; + ed2->priv.server->ode_joint_aiment = 0; + } + dJointAttach(j, b1, b2); + } + dBodyDestroy((dBodyID)ed->priv.server->ode_body); + } + ed->priv.server->ode_body = NULL; +#endif + if (ed->priv.server->ode_vertex3f) + Mem_Free(ed->priv.server->ode_vertex3f); + ed->priv.server->ode_vertex3f = NULL; + ed->priv.server->ode_numvertices = 0; + if (ed->priv.server->ode_element3i) + Mem_Free(ed->priv.server->ode_element3i); + ed->priv.server->ode_element3i = NULL; + ed->priv.server->ode_numtriangles = 0; + if(ed->priv.server->ode_massbuf) + Mem_Free(ed->priv.server->ode_massbuf); + ed->priv.server->ode_massbuf = NULL; + // clear functions stack + for(f = ed->priv.server->ode_func; f; f = nf) + { + nf = f->next; + Mem_Free(f); + } + ed->priv.server->ode_func = NULL; +} + +void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f) +{ + dBodyID body = (dBodyID)ed->priv.server->ode_body; + +#ifdef USEODE + switch(f->type) + { + case ODEFUNC_ENABLE: + dBodyEnable(body); + break; + case ODEFUNC_DISABLE: + dBodyDisable(body); + break; + case ODEFUNC_FORCE: + dBodyEnable(body); + dBodyAddForceAtPos(body, f->v1[0], f->v1[1], f->v1[2], f->v2[0], f->v2[1], f->v2[2]); + break; + case ODEFUNC_TORQUE: + dBodyEnable(body); + dBodyAddTorque(body, f->v1[0], f->v1[1], f->v1[2]); + break; + default: + break; + } +#endif +} + +#ifdef USEODE +static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) +{ + prvm_prog_t *prog = world->prog; + const dReal *avel; + const dReal *o; + const dReal *r; // for some reason dBodyGetRotation returns a [3][4] matrix + const dReal *vel; + dBodyID body = (dBodyID)ed->priv.server->ode_body; + int movetype; + matrix4x4_t bodymatrix; + matrix4x4_t entitymatrix; + vec3_t angles; + vec3_t avelocity; + vec3_t forward, left, up; + vec3_t origin; + vec3_t spinvelocity; + vec3_t velocity; + int jointtype; + if (!body) + return; + movetype = (int)PRVM_gameedictfloat(ed, movetype); + if (movetype != MOVETYPE_PHYSICS) + { + jointtype = (int)PRVM_gameedictfloat(ed, jointtype); + switch(jointtype) + { + // TODO feed back data from physics + case JOINTTYPE_POINT: + break; + case JOINTTYPE_HINGE: + break; + case JOINTTYPE_SLIDER: + break; + case JOINTTYPE_UNIVERSAL: + break; + case JOINTTYPE_HINGE2: + break; + case JOINTTYPE_FIXED: + break; + } + return; + } + // store the physics engine data into the entity + o = dBodyGetPosition(body); + r = dBodyGetRotation(body); + vel = dBodyGetLinearVel(body); + avel = dBodyGetAngularVel(body); + VectorCopy(o, origin); + forward[0] = r[0]; + forward[1] = r[4]; + forward[2] = r[8]; + left[0] = r[1]; + left[1] = r[5]; + left[2] = r[9]; + up[0] = r[2]; + up[1] = r[6]; + up[2] = r[10]; + VectorCopy(vel, velocity); + VectorCopy(avel, spinvelocity); + Matrix4x4_FromVectors(&bodymatrix, forward, left, up, origin); + Matrix4x4_Concat(&entitymatrix, &bodymatrix, &ed->priv.server->ode_offsetimatrix); + Matrix4x4_ToVectors(&entitymatrix, forward, left, up, origin); + + AnglesFromVectors(angles, forward, up, false); + VectorSet(avelocity, RAD2DEG(spinvelocity[PITCH]), RAD2DEG(spinvelocity[ROLL]), RAD2DEG(spinvelocity[YAW])); + + { + float pitchsign = 1; + if(prog == SVVM_prog) // FIXME some better way? + { + pitchsign = SV_GetPitchSign(prog, ed); + } + else if(prog == CLVM_prog) + { + pitchsign = CL_GetPitchSign(prog, ed); + } + angles[PITCH] *= pitchsign; + avelocity[PITCH] *= pitchsign; + } + + VectorCopy(origin, PRVM_gameedictvector(ed, origin)); + VectorCopy(velocity, PRVM_gameedictvector(ed, velocity)); + //VectorCopy(forward, PRVM_gameedictvector(ed, axis_forward)); + //VectorCopy(left, PRVM_gameedictvector(ed, axis_left)); + //VectorCopy(up, PRVM_gameedictvector(ed, axis_up)); + //VectorCopy(spinvelocity, PRVM_gameedictvector(ed, spinvelocity)); + VectorCopy(angles, PRVM_gameedictvector(ed, angles)); + VectorCopy(avelocity, PRVM_gameedictvector(ed, avelocity)); + + // values for BodyFromEntity to check if the qc modified anything later + VectorCopy(origin, ed->priv.server->ode_origin); + VectorCopy(velocity, ed->priv.server->ode_velocity); + VectorCopy(angles, ed->priv.server->ode_angles); + VectorCopy(avelocity, ed->priv.server->ode_avelocity); + ed->priv.server->ode_gravity = dBodyGetGravityMode(body) != 0; + + if(prog == SVVM_prog) // FIXME some better way? + { + SV_LinkEdict(ed); + SV_LinkEdict_TouchAreaGrid(ed); + } +} + +static void World_Physics_Frame_ForceFromEntity(world_t *world, prvm_edict_t *ed) +{ + prvm_prog_t *prog = world->prog; + int forcetype = 0, movetype = 0, enemy = 0; + vec3_t movedir, origin; + + movetype = (int)PRVM_gameedictfloat(ed, movetype); + forcetype = (int)PRVM_gameedictfloat(ed, forcetype); + if (movetype == MOVETYPE_PHYSICS) + forcetype = FORCETYPE_NONE; // can't have both + if (!forcetype) + return; + enemy = PRVM_gameedictedict(ed, enemy); + if (enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0) + return; + VectorCopy(PRVM_gameedictvector(ed, movedir), movedir); + VectorCopy(PRVM_gameedictvector(ed, origin), origin); + dBodyEnable((dBodyID)prog->edicts[enemy].priv.server->ode_body); + switch(forcetype) + { + case FORCETYPE_FORCE: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddForce((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]); + break; + case FORCETYPE_FORCEATPOS: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddForceAtPos((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2], origin[0], origin[1], origin[2]); + break; + case FORCETYPE_TORQUE: + if (movedir[0] || movedir[1] || movedir[2]) + dBodyAddTorque((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]); + break; + case FORCETYPE_NONE: + default: + // bad force + break; + } +} + +static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed) +{ + prvm_prog_t *prog = world->prog; + dJointID j = 0; + dBodyID b1 = 0; + dBodyID b2 = 0; + int movetype = 0; + int jointtype = 0; + int enemy = 0, aiment = 0; + vec3_t origin, velocity, angles, forward, left, up, movedir; + vec_t CFM, ERP, FMax, Stop, Vel; + + movetype = (int)PRVM_gameedictfloat(ed, movetype); + jointtype = (int)PRVM_gameedictfloat(ed, jointtype); + VectorClear(origin); + VectorClear(velocity); + VectorClear(angles); + VectorClear(movedir); + enemy = PRVM_gameedictedict(ed, enemy); + aiment = PRVM_gameedictedict(ed, aiment); + VectorCopy(PRVM_gameedictvector(ed, origin), origin); + VectorCopy(PRVM_gameedictvector(ed, velocity), velocity); + VectorCopy(PRVM_gameedictvector(ed, angles), angles); + VectorCopy(PRVM_gameedictvector(ed, movedir), movedir); + if(movetype == MOVETYPE_PHYSICS) + jointtype = JOINTTYPE_NONE; // can't have both + if(enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0) + enemy = 0; + if(aiment <= 0 || aiment >= prog->num_edicts || prog->edicts[aiment].priv.required->free || prog->edicts[aiment].priv.server->ode_body == 0) + aiment = 0; + // see http://www.ode.org/old_list_archives/2006-January/017614.html + // we want to set ERP? make it fps independent and work like a spring constant + // note: if movedir[2] is 0, it becomes ERP = 1, CFM = 1.0 / (H * K) + if(movedir[0] > 0 && movedir[1] > 0) + { + float K = movedir[0]; + float D = movedir[1]; + float R = 2.0 * D * sqrt(K); // we assume D is premultiplied by sqrt(sprungMass) + CFM = 1.0 / (world->physics.ode_step * K + R); // always > 0 + ERP = world->physics.ode_step * K * CFM; + Vel = 0; + FMax = 0; + Stop = movedir[2]; + } + else if(movedir[1] < 0) + { + CFM = 0; + ERP = 0; + Vel = movedir[0]; + FMax = -movedir[1]; // TODO do we need to multiply with world.physics.ode_step? + Stop = movedir[2] > 0 ? movedir[2] : dInfinity; + } + else // movedir[0] > 0, movedir[1] == 0 or movedir[0] < 0, movedir[1] >= 0 + { + CFM = 0; + ERP = 0; + Vel = 0; + FMax = 0; + Stop = dInfinity; + } + if(jointtype == ed->priv.server->ode_joint_type && VectorCompare(origin, ed->priv.server->ode_joint_origin) && VectorCompare(velocity, ed->priv.server->ode_joint_velocity) && VectorCompare(angles, ed->priv.server->ode_joint_angles) && enemy == ed->priv.server->ode_joint_enemy && aiment == ed->priv.server->ode_joint_aiment && VectorCompare(movedir, ed->priv.server->ode_joint_movedir)) + return; // nothing to do + AngleVectorsFLU(angles, forward, left, up); + switch(jointtype) + { + case JOINTTYPE_POINT: + j = dJointCreateBall((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_HINGE: + j = dJointCreateHinge((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_SLIDER: + j = dJointCreateSlider((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_UNIVERSAL: + j = dJointCreateUniversal((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_HINGE2: + j = dJointCreateHinge2((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_FIXED: + j = dJointCreateFixed((dWorldID)world->physics.ode_world, 0); + break; + case JOINTTYPE_NONE: + default: + // no joint + j = 0; + break; + } + if(ed->priv.server->ode_joint) + { + //Con_Printf("deleted old joint %i\n", (int) (ed - prog->edicts)); + dJointAttach((dJointID)ed->priv.server->ode_joint, 0, 0); + dJointDestroy((dJointID)ed->priv.server->ode_joint); + } + ed->priv.server->ode_joint = (void *) j; + ed->priv.server->ode_joint_type = jointtype; + ed->priv.server->ode_joint_enemy = enemy; + ed->priv.server->ode_joint_aiment = aiment; + VectorCopy(origin, ed->priv.server->ode_joint_origin); + VectorCopy(velocity, ed->priv.server->ode_joint_velocity); + VectorCopy(angles, ed->priv.server->ode_joint_angles); + VectorCopy(movedir, ed->priv.server->ode_joint_movedir); + if(j) + { + //Con_Printf("made new joint %i\n", (int) (ed - prog->edicts)); + dJointSetData(j, (void *) ed); + if(enemy) + b1 = (dBodyID)prog->edicts[enemy].priv.server->ode_body; + if(aiment) + b2 = (dBodyID)prog->edicts[aiment].priv.server->ode_body; + dJointAttach(j, b1, b2); + + switch(jointtype) + { + case JOINTTYPE_POINT: + dJointSetBallAnchor(j, origin[0], origin[1], origin[2]); + break; + case JOINTTYPE_HINGE: + dJointSetHingeAnchor(j, origin[0], origin[1], origin[2]); + dJointSetHingeAxis(j, forward[0], forward[1], forward[2]); + dJointSetHingeParam(j, dParamFMax, FMax); + dJointSetHingeParam(j, dParamHiStop, Stop); + dJointSetHingeParam(j, dParamLoStop, -Stop); + dJointSetHingeParam(j, dParamStopCFM, CFM); + dJointSetHingeParam(j, dParamStopERP, ERP); + dJointSetHingeParam(j, dParamVel, Vel); + break; + case JOINTTYPE_SLIDER: + dJointSetSliderAxis(j, forward[0], forward[1], forward[2]); + dJointSetSliderParam(j, dParamFMax, FMax); + dJointSetSliderParam(j, dParamHiStop, Stop); + dJointSetSliderParam(j, dParamLoStop, -Stop); + dJointSetSliderParam(j, dParamStopCFM, CFM); + dJointSetSliderParam(j, dParamStopERP, ERP); + dJointSetSliderParam(j, dParamVel, Vel); + break; + case JOINTTYPE_UNIVERSAL: + dJointSetUniversalAnchor(j, origin[0], origin[1], origin[2]); + dJointSetUniversalAxis1(j, forward[0], forward[1], forward[2]); + dJointSetUniversalAxis2(j, up[0], up[1], up[2]); + dJointSetUniversalParam(j, dParamFMax, FMax); + dJointSetUniversalParam(j, dParamHiStop, Stop); + dJointSetUniversalParam(j, dParamLoStop, -Stop); + dJointSetUniversalParam(j, dParamStopCFM, CFM); + dJointSetUniversalParam(j, dParamStopERP, ERP); + dJointSetUniversalParam(j, dParamVel, Vel); + dJointSetUniversalParam(j, dParamFMax2, FMax); + dJointSetUniversalParam(j, dParamHiStop2, Stop); + dJointSetUniversalParam(j, dParamLoStop2, -Stop); + dJointSetUniversalParam(j, dParamStopCFM2, CFM); + dJointSetUniversalParam(j, dParamStopERP2, ERP); + dJointSetUniversalParam(j, dParamVel2, Vel); + break; + case JOINTTYPE_HINGE2: + dJointSetHinge2Anchor(j, origin[0], origin[1], origin[2]); + dJointSetHinge2Axis1(j, forward[0], forward[1], forward[2]); + dJointSetHinge2Axis2(j, velocity[0], velocity[1], velocity[2]); + dJointSetHinge2Param(j, dParamFMax, FMax); + dJointSetHinge2Param(j, dParamHiStop, Stop); + dJointSetHinge2Param(j, dParamLoStop, -Stop); + dJointSetHinge2Param(j, dParamStopCFM, CFM); + dJointSetHinge2Param(j, dParamStopERP, ERP); + dJointSetHinge2Param(j, dParamVel, Vel); + dJointSetHinge2Param(j, dParamFMax2, FMax); + dJointSetHinge2Param(j, dParamHiStop2, Stop); + dJointSetHinge2Param(j, dParamLoStop2, -Stop); + dJointSetHinge2Param(j, dParamStopCFM2, CFM); + dJointSetHinge2Param(j, dParamStopERP2, ERP); + dJointSetHinge2Param(j, dParamVel2, Vel); + break; + case JOINTTYPE_FIXED: + break; + case 0: + default: + Sys_Error("what? but above the joint was valid...\n"); + break; + } +#undef SETPARAMS + + } +} + +// test convex geometry data +// planes for a cube, these should coincide with the +dReal test_convex_planes[] = +{ + 1.0f ,0.0f ,0.0f ,2.25f, + 0.0f ,1.0f ,0.0f ,2.25f, + 0.0f ,0.0f ,1.0f ,2.25f, + -1.0f,0.0f ,0.0f ,2.25f, + 0.0f ,-1.0f,0.0f ,2.25f, + 0.0f ,0.0f ,-1.0f,2.25f +}; +const unsigned int test_convex_planecount = 6; +// points for a cube +dReal test_convex_points[] = +{ + 2.25f,2.25f,2.25f, // point 0 + -2.25f,2.25f,2.25f, // point 1 + 2.25f,-2.25f,2.25f, // point 2 + -2.25f,-2.25f,2.25f, // point 3 + 2.25f,2.25f,-2.25f, // point 4 + -2.25f,2.25f,-2.25f, // point 5 + 2.25f,-2.25f,-2.25f, // point 6 + -2.25f,-2.25f,-2.25f, // point 7 +}; +const unsigned int test_convex_pointcount = 8; +// polygons for a cube (6 squares), index +unsigned int test_convex_polygons[] = +{ + 4,0,2,6,4, // positive X + 4,1,0,4,5, // positive Y + 4,0,1,3,2, // positive Z + 4,3,1,5,7, // negative X + 4,2,3,7,6, // negative Y + 4,5,4,6,7, // negative Z +}; + +static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) +{ + prvm_prog_t *prog = world->prog; + const float *iv; + const int *ie; + dBodyID body; + dMass mass; + const dReal *ovelocity, *ospinvelocity; + void *dataID; + dp_model_t *model; + float *ov; + int *oe; + int axisindex; + int modelindex = 0; + int movetype = MOVETYPE_NONE; + int numtriangles; + int numvertices; + int solid = SOLID_NOT, geomtype = 0; + int triangleindex; + int vertexindex; + mempool_t *mempool; + qboolean modified = false; + vec3_t angles; + vec3_t avelocity; + vec3_t entmaxs; + vec3_t entmins; + vec3_t forward; + vec3_t geomcenter; + vec3_t geomsize; + vec3_t left; + vec3_t origin; + vec3_t spinvelocity; + vec3_t up; + vec3_t velocity; + vec_t f; + vec_t length; + vec_t massval = 1.0f; + vec_t movelimit; + vec_t radius; + vec3_t scale; + vec_t spinlimit; + vec_t test; + qboolean gravity; + qboolean geom_modified = false; + edict_odefunc_t *func, *nextf; + + dReal *planes, *planesData, *pointsData; + unsigned int *polygons, *polygonsData, polyvert; + qboolean *mapped, *used, convex_compatible; + int numplanes = 0, numpoints = 0, i; + +#ifdef ODE_DYNAMIC + if (!ode_dll) + return; +#endif + VectorClear(entmins); + VectorClear(entmaxs); + + solid = (int)PRVM_gameedictfloat(ed, solid); + geomtype = (int)PRVM_gameedictfloat(ed, geomtype); + movetype = (int)PRVM_gameedictfloat(ed, movetype); + // support scale and q3map/radiant's modelscale_vec + if (PRVM_gameedictvector(ed, modelscale_vec)[0] != 0.0 || PRVM_gameedictvector(ed, modelscale_vec)[1] != 0.0 || PRVM_gameedictvector(ed, modelscale_vec)[2] != 0.0) + VectorCopy(PRVM_gameedictvector(ed, modelscale_vec), scale); + else if (PRVM_gameedictfloat(ed, scale)) + VectorSet(scale, PRVM_gameedictfloat(ed, scale), PRVM_gameedictfloat(ed, scale), PRVM_gameedictfloat(ed, scale)); + else + VectorSet(scale, 1.0f, 1.0f, 1.0f); + modelindex = 0; + if (PRVM_gameedictfloat(ed, mass)) + massval = PRVM_gameedictfloat(ed, mass); + if (movetype != MOVETYPE_PHYSICS) + massval = 1.0f; + mempool = prog->progs_mempool; + model = NULL; + if (!geomtype) + { + // VorteX: keep support for deprecated solid fields to not break mods + if (solid == SOLID_PHYSICS_TRIMESH || solid == SOLID_BSP) + geomtype = GEOMTYPE_TRIMESH; + else if (solid == SOLID_NOT || solid == SOLID_TRIGGER) + geomtype = GEOMTYPE_NONE; + else if (solid == SOLID_PHYSICS_SPHERE) + geomtype = GEOMTYPE_SPHERE; + else if (solid == SOLID_PHYSICS_CAPSULE) + geomtype = GEOMTYPE_CAPSULE; + else if (solid == SOLID_PHYSICS_CYLINDER) + geomtype = GEOMTYPE_CYLINDER; + else if (solid == SOLID_PHYSICS_BOX) + geomtype = GEOMTYPE_BOX; + else + geomtype = GEOMTYPE_BOX; + } + if (geomtype == GEOMTYPE_TRIMESH) + { + modelindex = (int)PRVM_gameedictfloat(ed, modelindex); + if (world == &sv.world) + model = SV_GetModelByIndex(modelindex); + else if (world == &cl.world) + model = CL_GetModelByIndex(modelindex); + else + model = NULL; + if (model) + { + entmins[0] = model->normalmins[0] * scale[0]; + entmins[1] = model->normalmins[1] * scale[1]; + entmins[2] = model->normalmins[2] * scale[2]; + entmaxs[0] = model->normalmaxs[0] * scale[0]; + entmaxs[1] = model->normalmaxs[1] * scale[1]; + entmaxs[2] = model->normalmaxs[2] * scale[2]; + geom_modified = !VectorCompare(ed->priv.server->ode_scale, scale) || ed->priv.server->ode_modelindex != modelindex; + } + else + { + Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); + geomtype = GEOMTYPE_BOX; + VectorCopy(PRVM_gameedictvector(ed, mins), entmins); + VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs); + modelindex = 0; + geom_modified = !VectorCompare(ed->priv.server->ode_mins, entmins) || !VectorCompare(ed->priv.server->ode_maxs, entmaxs); + } + } + else if (geomtype && geomtype != GEOMTYPE_NONE) + { + VectorCopy(PRVM_gameedictvector(ed, mins), entmins); + VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs); + geom_modified = !VectorCompare(ed->priv.server->ode_mins, entmins) || !VectorCompare(ed->priv.server->ode_maxs, entmaxs); + } + else + { + // geometry type not set, falling back + if (ed->priv.server->ode_physics) + World_Physics_RemoveFromEntity(world, ed); + return; + } + + VectorSubtract(entmaxs, entmins, geomsize); + if (VectorLength2(geomsize) == 0) + { + // we don't allow point-size physics objects... + if (ed->priv.server->ode_physics) + World_Physics_RemoveFromEntity(world, ed); + return; + } + + // get friction + ed->priv.server->ode_friction = PRVM_gameedictfloat(ed, friction) ? PRVM_gameedictfloat(ed, friction) : 1.0f; + + // check if we need to create or replace the geom + if (!ed->priv.server->ode_physics || ed->priv.server->ode_mass != massval || geom_modified) + { + modified = true; + World_Physics_RemoveFromEntity(world, ed); + ed->priv.server->ode_physics = true; + VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter); + if (PRVM_gameedictvector(ed, massofs)) + VectorCopy(geomcenter, PRVM_gameedictvector(ed, massofs)); + + // check geomsize + if (geomsize[0] * geomsize[1] * geomsize[2] == 0) + { + if (movetype == MOVETYPE_PHYSICS) + Con_Printf("entity %i (classname %s) .mass * .size_x * .size_y * .size_z == 0\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); + VectorSet(geomsize, 1.0f, 1.0f, 1.0f); + } + + // greate geom + switch(geomtype) + { + case GEOMTYPE_TRIMESH: + // add an optimized mesh to the model containing only the SUPERCONTENTS_SOLID surfaces + if (!model->brush.collisionmesh) + Mod_CreateCollisionMesh(model); + if (!model->brush.collisionmesh) + { + Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname))); + goto treatasbox; + } + + // check if trimesh can be defined with convex + convex_compatible = false; + for (i = 0;i < model->nummodelsurfaces;i++) + { + if (!strcmp(((msurface_t *)(model->data_surfaces + model->firstmodelsurface + i))->texture->name, "collisionconvex")) + { + convex_compatible = true; + break; + } + } + + // ODE requires persistent mesh storage, so we need to copy out + // the data from the model because renderer restarts could free it + // during the game, additionally we need to flip the triangles... + // note: ODE does preprocessing of the mesh for culling, removing + // concave edges, etc., so this is not a lightweight operation + ed->priv.server->ode_numvertices = numvertices = model->brush.collisionmesh->numverts; + ed->priv.server->ode_vertex3f = (float *)Mem_Alloc(mempool, numvertices * sizeof(float[3])); + + // VorteX: rebuild geomsize based on entity's collision mesh, honor scale + VectorSet(entmins, 0, 0, 0); + VectorSet(entmaxs, 0, 0, 0); + for (vertexindex = 0, ov = ed->priv.server->ode_vertex3f, iv = model->brush.collisionmesh->vertex3f;vertexindex < numvertices;vertexindex++, ov += 3, iv += 3) + { + ov[0] = iv[0] * scale[0]; + ov[1] = iv[1] * scale[1]; + ov[2] = iv[2] * scale[2]; + entmins[0] = min(entmins[0], ov[0]); + entmins[1] = min(entmins[1], ov[1]); + entmins[2] = min(entmins[2], ov[2]); + entmaxs[0] = max(entmaxs[0], ov[0]); + entmaxs[1] = max(entmaxs[1], ov[1]); + entmaxs[2] = max(entmaxs[2], ov[2]); + } + if (!PRVM_gameedictvector(ed, massofs)) + VectorMAM(0.5f, entmins, 0.5f, entmaxs, geomcenter); + for (vertexindex = 0, ov = ed->priv.server->ode_vertex3f, iv = model->brush.collisionmesh->vertex3f;vertexindex < numvertices;vertexindex++, ov += 3, iv += 3) + { + ov[0] = ov[0] - geomcenter[0]; + ov[1] = ov[1] - geomcenter[1]; + ov[2] = ov[2] - geomcenter[2]; + } + VectorSubtract(entmaxs, entmins, geomsize); + if (VectorLength2(geomsize) == 0) + { + if (movetype == MOVETYPE_PHYSICS) + Con_Printf("entity %i collision mesh has null geomsize\n", PRVM_NUM_FOR_EDICT(ed)); + VectorSet(geomsize, 1.0f, 1.0f, 1.0f); + } + ed->priv.server->ode_numtriangles = numtriangles = model->brush.collisionmesh->numtriangles; + ed->priv.server->ode_element3i = (int *)Mem_Alloc(mempool, numtriangles * sizeof(int[3])); + //memcpy(ed->priv.server->ode_element3i, model->brush.collisionmesh->element3i, ed->priv.server->ode_numtriangles * sizeof(int[3])); + for (triangleindex = 0, oe = ed->priv.server->ode_element3i, ie = model->brush.collisionmesh->element3i;triangleindex < numtriangles;triangleindex++, oe += 3, ie += 3) + { + oe[0] = ie[2]; + oe[1] = ie[1]; + oe[2] = ie[0]; + } + // create geom + Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); + if (!convex_compatible || !physics_ode_allowconvex.integer) + { + // trimesh + dataID = dGeomTriMeshDataCreate(); + dGeomTriMeshDataBuildSingle((dTriMeshDataID)dataID, (void*)ed->priv.server->ode_vertex3f, sizeof(float[3]), ed->priv.server->ode_numvertices, ed->priv.server->ode_element3i, ed->priv.server->ode_numtriangles*3, sizeof(int[3])); + ed->priv.server->ode_geom = (void *)dCreateTriMesh((dSpaceID)world->physics.ode_space, (dTriMeshDataID)dataID, NULL, NULL, NULL); + dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + } + else + { + // VorteX: this code is unfinished in two ways + // - no duplicate vertex merging are done + // - triangles that shares same edge and havee sam plane are not merget into poly + // so, currently it only works for geosphere meshes with no UV + + Con_Printf("Build convex hull for model %s...\n", model->name); + // build convex geometry from trimesh data + // this ensures that trimesh's triangles can form correct convex geometry + // not many of error checking is performed + // ODE's conve hull data consist of: + // planes : an array of planes in the form: normal X, normal Y, normal Z, distance + // points : an array of points X,Y,Z + // polygons: an array of indices to the points of each polygon,it should be the number of vertices + // followed by that amount of indices to "points" in counter clockwise order + polygonsData = polygons = (unsigned int *)Mem_Alloc(mempool, numtriangles*sizeof(int)*4); + planesData = planes = (dReal *)Mem_Alloc(mempool, numtriangles*sizeof(dReal)*4); + mapped = (qboolean *)Mem_Alloc(mempool, numvertices*sizeof(qboolean)); + used = (qboolean *)Mem_Alloc(mempool, numtriangles*sizeof(qboolean)); + memset(mapped, 0, numvertices*sizeof(qboolean)); + memset(used, 0, numtriangles*sizeof(qboolean)); + numplanes = numpoints = polyvert = 0; + // build convex hull + // todo: merge duplicated verts here + Con_Printf("Building...\n"); + iv = ed->priv.server->ode_vertex3f; + for (triangleindex = 0; triangleindex < numtriangles; triangleindex++) + { + // already formed a polygon? + if (used[triangleindex]) + continue; + // init polygon + // switch clockwise->counterclockwise + ie = &model->brush.collisionmesh->element3i[triangleindex*3]; + used[triangleindex] = true; + TriangleNormal(&iv[ie[0]*3], &iv[ie[1]*3], &iv[ie[2]*3], planes); + VectorNormalize(planes); + polygons[0] = 3; + polygons[3] = (unsigned int)ie[0]; mapped[polygons[3]] = true; + polygons[2] = (unsigned int)ie[1]; mapped[polygons[2]] = true; + polygons[1] = (unsigned int)ie[2]; mapped[polygons[1]] = true; + + // now find and include concave triangles + for (i = triangleindex; i < numtriangles; i++) + { + if (used[i]) + continue; + // should share at least 2 vertexes + for (polyvert = 1; polyvert <= polygons[0]; polyvert++) + { + // todo: merge in triangles that shares an edge and have same plane here + } + } + + // add polygon to overall stats + planes[3] = DotProduct(&iv[polygons[1]*3], planes); + polygons += (polygons[0]+1); + planes += 4; + numplanes++; + } + Mem_Free(used); + // save points + for (vertexindex = 0, numpoints = 0; vertexindex < numvertices; vertexindex++) + if (mapped[vertexindex]) + numpoints++; + pointsData = (dReal *)Mem_Alloc(mempool, numpoints*sizeof(dReal)*3 + numplanes*sizeof(dReal)*4); // planes is appended + for (vertexindex = 0, numpoints = 0; vertexindex < numvertices; vertexindex++) + { + if (mapped[vertexindex]) + { + VectorCopy(&iv[vertexindex*3], &pointsData[numpoints*3]); + numpoints++; + } + } + Mem_Free(mapped); + Con_Printf("Points: \n"); + for (i = 0; i < (int)numpoints; i++) + Con_Printf("%3i: %3.1f %3.1f %3.1f\n", i, pointsData[i*3], pointsData[i*3+1], pointsData[i*3+2]); + // save planes + planes = planesData; + planesData = pointsData + numpoints*3; + memcpy(planesData, planes, numplanes*sizeof(dReal)*4); + Mem_Free(planes); + Con_Printf("planes...\n"); + for (i = 0; i < numplanes; i++) + Con_Printf("%3i: %1.1f %1.1f %1.1f %1.1f\n", i, planesData[i*4], planesData[i*4 + 1], planesData[i*4 + 2], planesData[i*4 + 3]); + // save polygons + polyvert = polygons - polygonsData; + polygons = polygonsData; + polygonsData = (unsigned int *)Mem_Alloc(mempool, polyvert*sizeof(int)); + memcpy(polygonsData, polygons, polyvert*sizeof(int)); + Mem_Free(polygons); + Con_Printf("Polygons: \n"); + polygons = polygonsData; + for (i = 0; i < numplanes; i++) + { + Con_Printf("%3i : %i ", i, polygons[0]); + for (triangleindex = 1; triangleindex <= (int)polygons[0]; triangleindex++) + Con_Printf("%3i ", polygons[triangleindex]); + polygons += (polygons[0]+1); + Con_Printf("\n"); + } + Mem_Free(ed->priv.server->ode_element3i); + ed->priv.server->ode_element3i = (int *)polygonsData; + Mem_Free(ed->priv.server->ode_vertex3f); + ed->priv.server->ode_vertex3f = (float *)pointsData; + // check for properly build polygons by calculating the determinant of the 3x3 matrix composed of the first 3 points in the polygon + // this code is picked from ODE Source + Con_Printf("Check...\n"); + polygons = polygonsData; + for (i = 0; i < numplanes; i++) + { + if((pointsData[(polygons[1]*3)+0]*pointsData[(polygons[2]*3)+1]*pointsData[(polygons[3]*3)+2] + + pointsData[(polygons[1]*3)+1]*pointsData[(polygons[2]*3)+2]*pointsData[(polygons[3]*3)+0] + + pointsData[(polygons[1]*3)+2]*pointsData[(polygons[2]*3)+0]*pointsData[(polygons[3]*3)+1] - + pointsData[(polygons[1]*3)+2]*pointsData[(polygons[2]*3)+1]*pointsData[(polygons[3]*3)+0] - + pointsData[(polygons[1]*3)+1]*pointsData[(polygons[2]*3)+0]*pointsData[(polygons[3]*3)+2] - + pointsData[(polygons[1]*3)+0]*pointsData[(polygons[2]*3)+2]*pointsData[(polygons[3]*3)+1]) < 0) + Con_Printf("WARNING: Polygon %d is not defined counterclockwise\n", i); + if (planesData[(i*4)+3] < 0) + Con_Printf("WARNING: Plane %d does not contain the origin\n", i); + polygons += (*polygons + 1); + } + // create geom + Con_Printf("Create geom...\n"); + ed->priv.server->ode_geom = (void *)dCreateConvex((dSpaceID)world->physics.ode_space, planesData, numplanes, pointsData, numpoints, polygonsData); + dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + Con_Printf("Done!\n"); + } + break; + case GEOMTYPE_BOX: +treatasbox: + Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); + ed->priv.server->ode_geom = (void *)dCreateBox((dSpaceID)world->physics.ode_space, geomsize[0], geomsize[1], geomsize[2]); + dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); + break; + case GEOMTYPE_SPHERE: + Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); + ed->priv.server->ode_geom = (void *)dCreateSphere((dSpaceID)world->physics.ode_space, geomsize[0] * 0.5f); + dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f); + break; + case GEOMTYPE_CAPSULE: + axisindex = 0; + if (geomsize[axisindex] < geomsize[1]) + axisindex = 1; + if (geomsize[axisindex] < geomsize[2]) + axisindex = 2; + // the qc gives us 3 axis radius, the longest axis is the capsule + // axis, since ODE doesn't like this idea we have to create a + // capsule which uses the standard orientation, and apply a + // transform to it + if (axisindex == 0) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + } + else if (axisindex == 1) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + } + else + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[0], geomsize[1]) * 0.5f; + } + length = geomsize[axisindex] - radius*2; + // because we want to support more than one axisindex, we have to + // create a transform, and turn on its cleanup setting (which will + // cause the child to be destroyed when it is destroyed) + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length); + break; + case GEOMTYPE_CAPSULE_X: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + length = geomsize[0] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 1, radius, length); + break; + case GEOMTYPE_CAPSULE_Y: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + length = geomsize[1] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 2, radius, length); + break; + case GEOMTYPE_CAPSULE_Z: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[1], geomsize[0]) * 0.5f; + length = geomsize[2] - radius*2; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCapsuleTotal(&mass, massval, 3, radius, length); + break; + case GEOMTYPE_CYLINDER: + axisindex = 0; + if (geomsize[axisindex] < geomsize[1]) + axisindex = 1; + if (geomsize[axisindex] < geomsize[2]) + axisindex = 2; + // the qc gives us 3 axis radius, the longest axis is the capsule + // axis, since ODE doesn't like this idea we have to create a + // capsule which uses the standard orientation, and apply a + // transform to it + if (axisindex == 0) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + } + else if (axisindex == 1) + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + } + else + { + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[0], geomsize[1]) * 0.5f; + } + length = geomsize[axisindex]; + // check if length is not enough, reduce radius then + if (length <= 0) + { + radius -= (1 - length)*0.5; + length = 1; + } + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, axisindex+1, radius, length); + break; + case GEOMTYPE_CYLINDER_X: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 90, 1); + radius = min(geomsize[1], geomsize[2]) * 0.5f; + length = geomsize[0]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 1, radius, length); + break; + case GEOMTYPE_CYLINDER_Y: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 90, 0, 0, 1); + radius = min(geomsize[0], geomsize[2]) * 0.5f; + length = geomsize[1]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 2, radius, length); + break; + case GEOMTYPE_CYLINDER_Z: + Matrix4x4_CreateFromQuakeEntity(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2], 0, 0, 0, 1); + radius = min(geomsize[0], geomsize[1]) * 0.5f; + length = geomsize[2]; + ed->priv.server->ode_geom = (void *)dCreateCylinder((dSpaceID)world->physics.ode_space, radius, length); + dMassSetCylinderTotal(&mass, massval, 3, radius, length); + break; + default: + Sys_Error("World_Physics_BodyFromEntity: unrecognized geomtype value %i was accepted by filter\n", solid); + // this goto only exists to prevent warnings from the compiler + // about uninitialized variables (mass), while allowing it to + // catch legitimate uninitialized variable warnings + goto treatasbox; + } + ed->priv.server->ode_mass = massval; + ed->priv.server->ode_modelindex = modelindex; + VectorCopy(entmins, ed->priv.server->ode_mins); + VectorCopy(entmaxs, ed->priv.server->ode_maxs); + VectorCopy(scale, ed->priv.server->ode_scale); + ed->priv.server->ode_movelimit = min(geomsize[0], min(geomsize[1], geomsize[2])); + Matrix4x4_Invert_Simple(&ed->priv.server->ode_offsetimatrix, &ed->priv.server->ode_offsetmatrix); + ed->priv.server->ode_massbuf = Mem_Alloc(mempool, sizeof(mass)); + memcpy(ed->priv.server->ode_massbuf, &mass, sizeof(dMass)); + } + + if (ed->priv.server->ode_geom) + dGeomSetData((dGeomID)ed->priv.server->ode_geom, (void*)ed); + if (movetype == MOVETYPE_PHYSICS && ed->priv.server->ode_geom) + { + // entity is dynamic + if (ed->priv.server->ode_body == NULL) + { + ed->priv.server->ode_body = (void *)(body = dBodyCreate((dWorldID)world->physics.ode_world)); + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body); + dBodySetData(body, (void*)ed); + dBodySetMass(body, (dMass *) ed->priv.server->ode_massbuf); + modified = true; + } + } + else + { + // entity is deactivated + if (ed->priv.server->ode_body != NULL) + { + if(ed->priv.server->ode_geom) + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0); + dBodyDestroy((dBodyID) ed->priv.server->ode_body); + ed->priv.server->ode_body = NULL; + modified = true; + } + } + + // get current data from entity + VectorClear(origin); + VectorClear(velocity); + //VectorClear(forward); + //VectorClear(left); + //VectorClear(up); + //VectorClear(spinvelocity); + VectorClear(angles); + VectorClear(avelocity); + gravity = true; + VectorCopy(PRVM_gameedictvector(ed, origin), origin); + VectorCopy(PRVM_gameedictvector(ed, velocity), velocity); + //VectorCopy(PRVM_gameedictvector(ed, axis_forward), forward); + //VectorCopy(PRVM_gameedictvector(ed, axis_left), left); + //VectorCopy(PRVM_gameedictvector(ed, axis_up), up); + //VectorCopy(PRVM_gameedictvector(ed, spinvelocity), spinvelocity); + VectorCopy(PRVM_gameedictvector(ed, angles), angles); + VectorCopy(PRVM_gameedictvector(ed, avelocity), avelocity); + if (PRVM_gameedictfloat(ed, gravity) != 0.0f && PRVM_gameedictfloat(ed, gravity) < 0.5f) gravity = false; + if (ed == prog->edicts) + gravity = false; + + // compatibility for legacy entities + //if (!VectorLength2(forward) || solid == SOLID_BSP) + { + float pitchsign = 1; + vec3_t qangles, qavelocity; + VectorCopy(angles, qangles); + VectorCopy(avelocity, qavelocity); + + if(prog == SVVM_prog) // FIXME some better way? + { + pitchsign = SV_GetPitchSign(prog, ed); + } + else if(prog == CLVM_prog) + { + pitchsign = CL_GetPitchSign(prog, ed); + } + qangles[PITCH] *= pitchsign; + qavelocity[PITCH] *= pitchsign; + + AngleVectorsFLU(qangles, forward, left, up); + // convert single-axis rotations in avelocity to spinvelocity + // FIXME: untested math - check signs + VectorSet(spinvelocity, DEG2RAD(qavelocity[PITCH]), DEG2RAD(qavelocity[ROLL]), DEG2RAD(qavelocity[YAW])); + } + + // compatibility for legacy entities + switch (solid) + { + case SOLID_BBOX: + case SOLID_SLIDEBOX: + case SOLID_CORPSE: + VectorSet(forward, 1, 0, 0); + VectorSet(left, 0, 1, 0); + VectorSet(up, 0, 0, 1); + VectorSet(spinvelocity, 0, 0, 0); + break; + } + + + // we must prevent NANs... + if (physics_ode_trick_fixnan.integer) + { + test = VectorLength2(origin) + VectorLength2(forward) + VectorLength2(left) + VectorLength2(up) + VectorLength2(velocity) + VectorLength2(spinvelocity); + if (VEC_IS_NAN(test)) + { + modified = true; + //Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .axis_forward = '%f %f %f' .axis_left = '%f %f %f' .axis_up = %f %f %f' .spinvelocity = '%f %f %f'\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_gameedictstring(ed, classname)), origin[0], origin[1], origin[2], velocity[0], velocity[1], velocity[2], forward[0], forward[1], forward[2], left[0], left[1], left[2], up[0], up[1], up[2], spinvelocity[0], spinvelocity[1], spinvelocity[2]); + if (physics_ode_trick_fixnan.integer >= 2) + Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .angles = '%f %f %f' .avelocity = '%f %f %f'\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(prog, PRVM_gameedictstring(ed, classname)), origin[0], origin[1], origin[2], velocity[0], velocity[1], velocity[2], angles[0], angles[1], angles[2], avelocity[0], avelocity[1], avelocity[2]); + test = VectorLength2(origin); + if (VEC_IS_NAN(test)) + VectorClear(origin); + test = VectorLength2(forward) * VectorLength2(left) * VectorLength2(up); + if (VEC_IS_NAN(test)) + { + VectorSet(angles, 0, 0, 0); + VectorSet(forward, 1, 0, 0); + VectorSet(left, 0, 1, 0); + VectorSet(up, 0, 0, 1); + } + test = VectorLength2(velocity); + if (VEC_IS_NAN(test)) + VectorClear(velocity); + test = VectorLength2(spinvelocity); + if (VEC_IS_NAN(test)) + { + VectorClear(avelocity); + VectorClear(spinvelocity); + } + } + } + + // check if the qc edited any position data + if (!VectorCompare(origin, ed->priv.server->ode_origin) + || !VectorCompare(velocity, ed->priv.server->ode_velocity) + || !VectorCompare(angles, ed->priv.server->ode_angles) + || !VectorCompare(avelocity, ed->priv.server->ode_avelocity) + || gravity != ed->priv.server->ode_gravity) + modified = true; + + // store the qc values into the physics engine + body = (dBodyID)ed->priv.server->ode_body; + if (modified && ed->priv.server->ode_geom) + { + dVector3 r[3]; + matrix4x4_t entitymatrix; + matrix4x4_t bodymatrix; + +#if 0 + Con_Printf("entity %i got changed by QC\n", (int) (ed - prog->edicts)); + if(!VectorCompare(origin, ed->priv.server->ode_origin)) + Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->priv.server->ode_origin[0], ed->priv.server->ode_origin[1], ed->priv.server->ode_origin[2], origin[0], origin[1], origin[2]); + if(!VectorCompare(velocity, ed->priv.server->ode_velocity)) + Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->priv.server->ode_velocity[0], ed->priv.server->ode_velocity[1], ed->priv.server->ode_velocity[2], velocity[0], velocity[1], velocity[2]); + if(!VectorCompare(angles, ed->priv.server->ode_angles)) + Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->priv.server->ode_angles[0], ed->priv.server->ode_angles[1], ed->priv.server->ode_angles[2], angles[0], angles[1], angles[2]); + if(!VectorCompare(avelocity, ed->priv.server->ode_avelocity)) + Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->priv.server->ode_avelocity[0], ed->priv.server->ode_avelocity[1], ed->priv.server->ode_avelocity[2], avelocity[0], avelocity[1], avelocity[2]); + if(gravity != ed->priv.server->ode_gravity) + Con_Printf(" gravity: %i -> %i\n", ed->priv.server->ode_gravity, gravity); +#endif + // values for BodyFromEntity to check if the qc modified anything later + VectorCopy(origin, ed->priv.server->ode_origin); + VectorCopy(velocity, ed->priv.server->ode_velocity); + VectorCopy(angles, ed->priv.server->ode_angles); + VectorCopy(avelocity, ed->priv.server->ode_avelocity); + ed->priv.server->ode_gravity = gravity; + + Matrix4x4_FromVectors(&entitymatrix, forward, left, up, origin); + Matrix4x4_Concat(&bodymatrix, &entitymatrix, &ed->priv.server->ode_offsetmatrix); + Matrix4x4_ToVectors(&bodymatrix, forward, left, up, origin); + r[0][0] = forward[0]; + r[1][0] = forward[1]; + r[2][0] = forward[2]; + r[0][1] = left[0]; + r[1][1] = left[1]; + r[2][1] = left[2]; + r[0][2] = up[0]; + r[1][2] = up[1]; + r[2][2] = up[2]; + if (body) + { + if (movetype == MOVETYPE_PHYSICS) + { + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body); + dBodySetPosition(body, origin[0], origin[1], origin[2]); + dBodySetRotation(body, r[0]); + dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]); + dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]); + dBodySetGravityMode(body, gravity); + } + else + { + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body); + dBodySetPosition(body, origin[0], origin[1], origin[2]); + dBodySetRotation(body, r[0]); + dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]); + dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]); + dBodySetGravityMode(body, gravity); + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0); + } + } + else + { + // no body... then let's adjust the parameters of the geom directly + dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0); // just in case we previously HAD a body (which should never happen) + dGeomSetPosition((dGeomID)ed->priv.server->ode_geom, origin[0], origin[1], origin[2]); + dGeomSetRotation((dGeomID)ed->priv.server->ode_geom, r[0]); + } + } + + if (body) + { + + // limit movement speed to prevent missed collisions at high speed + ovelocity = dBodyGetLinearVel(body); + ospinvelocity = dBodyGetAngularVel(body); + movelimit = ed->priv.server->ode_movelimit * world->physics.ode_movelimit; + test = VectorLength2(ovelocity); + if (test > movelimit*movelimit) + { + // scale down linear velocity to the movelimit + // scale down angular velocity the same amount for consistency + f = movelimit / sqrt(test); + VectorScale(ovelocity, f, velocity); + VectorScale(ospinvelocity, f, spinvelocity); + dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]); + dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]); + } + + // make sure the angular velocity is not exploding + spinlimit = physics_ode_spinlimit.value; + test = VectorLength2(ospinvelocity); + if (test > spinlimit) + { + dBodySetAngularVel(body, 0, 0, 0); + } + + // apply functions and clear stack + for(func = ed->priv.server->ode_func; func; func = nextf) + { + nextf = func->next; + World_Physics_ApplyCmd(ed, func); + Mem_Free(func); + } + ed->priv.server->ode_func = NULL; + } +} + +#define MAX_CONTACTS 32 +static void nearCallback (void *data, dGeomID o1, dGeomID o2) +{ + world_t *world = (world_t *)data; + prvm_prog_t *prog = world->prog; + dContact contact[MAX_CONTACTS]; // max contacts per collision pair + int b1enabled = 0, b2enabled = 0; + dBodyID b1, b2; + dJointID c; + int i; + int numcontacts; + float bouncefactor1 = 0.0f; + float bouncestop1 = 60.0f / 800.0f; + float bouncefactor2 = 0.0f; + float bouncestop2 = 60.0f / 800.0f; + float erp; + dVector3 grav; + prvm_edict_t *ed1, *ed2; + + if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) + { + // colliding a space with something + dSpaceCollide2(o1, o2, data, &nearCallback); + // Note we do not want to test intersections within a space, + // only between spaces. + //if (dGeomIsSpace(o1)) dSpaceCollide(o1, data, &nearCallback); + //if (dGeomIsSpace(o2)) dSpaceCollide(o2, data, &nearCallback); + return; + } + + b1 = dGeomGetBody(o1); + if (b1) + b1enabled = dBodyIsEnabled(b1); + b2 = dGeomGetBody(o2); + if (b2) + b2enabled = dBodyIsEnabled(b2); + + // at least one object has to be using MOVETYPE_PHYSICS and should be enabled or we just don't care + if (!b1enabled && !b2enabled) + return; + + // exit without doing anything if the two bodies are connected by a joint + if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) + return; + + ed1 = (prvm_edict_t *) dGeomGetData(o1); + if(ed1 && ed1->priv.server->free) + ed1 = NULL; + if(ed1) + { + bouncefactor1 = PRVM_gameedictfloat(ed1, bouncefactor); + bouncestop1 = PRVM_gameedictfloat(ed1, bouncestop); + if (!bouncestop1) + bouncestop1 = 60.0f / 800.0f; + } + + ed2 = (prvm_edict_t *) dGeomGetData(o2); + if(ed2 && ed2->priv.server->free) + ed2 = NULL; + if(ed2) + { + bouncefactor2 = PRVM_gameedictfloat(ed2, bouncefactor); + bouncestop2 = PRVM_gameedictfloat(ed2, bouncestop); + if (!bouncestop2) + bouncestop2 = 60.0f / 800.0f; + } + + if(prog == SVVM_prog) + { + if(ed1 && PRVM_serveredictfunction(ed1, touch)) + { + SV_LinkEdict_TouchAreaGrid_Call(ed1, ed2 ? ed2 : prog->edicts); + } + if(ed2 && PRVM_serveredictfunction(ed2, touch)) + { + SV_LinkEdict_TouchAreaGrid_Call(ed2, ed1 ? ed1 : prog->edicts); + } + } + + // merge bounce factors and bounce stop + if(bouncefactor2 > 0) + { + if(bouncefactor1 > 0) + { + // TODO possibly better logic to merge bounce factor data? + if(bouncestop2 < bouncestop1) + bouncestop1 = bouncestop2; + if(bouncefactor2 > bouncefactor1) + bouncefactor1 = bouncefactor2; + } + else + { + bouncestop1 = bouncestop2; + bouncefactor1 = bouncefactor2; + } + } + dWorldGetGravity((dWorldID)world->physics.ode_world, grav); + bouncestop1 *= fabs(grav[2]); + + // get erp + // select object that moves faster ang get it's erp + erp = (VectorLength2(PRVM_gameedictvector(ed1, velocity)) > VectorLength2(PRVM_gameedictvector(ed2, velocity))) ? PRVM_gameedictfloat(ed1, erp) : PRVM_gameedictfloat(ed2, erp); + + // get max contact points for this collision + numcontacts = (int)PRVM_gameedictfloat(ed1, maxcontacts); + if (!numcontacts) + numcontacts = physics_ode_contact_maxpoints.integer; + if (PRVM_gameedictfloat(ed2, maxcontacts)) + numcontacts = max(numcontacts, (int)PRVM_gameedictfloat(ed2, maxcontacts)); + else + numcontacts = max(numcontacts, physics_ode_contact_maxpoints.integer); + + // generate contact points between the two non-space geoms + numcontacts = dCollide(o1, o2, min(MAX_CONTACTS, numcontacts), &(contact[0].geom), sizeof(contact[0])); + // add these contact points to the simulation + for (i = 0;i < numcontacts;i++) + { + contact[i].surface.mode = (physics_ode_contact_mu.value != -1 ? dContactApprox1 : 0) | (physics_ode_contact_erp.value != -1 ? dContactSoftERP : 0) | (physics_ode_contact_cfm.value != -1 ? dContactSoftCFM : 0) | (bouncefactor1 > 0 ? dContactBounce : 0); + contact[i].surface.mu = physics_ode_contact_mu.value * ed1->priv.server->ode_friction * ed2->priv.server->ode_friction; + contact[i].surface.soft_erp = physics_ode_contact_erp.value + erp; + contact[i].surface.soft_cfm = physics_ode_contact_cfm.value; + contact[i].surface.bounce = bouncefactor1; + contact[i].surface.bounce_vel = bouncestop1; + c = dJointCreateContact((dWorldID)world->physics.ode_world, (dJointGroupID)world->physics.ode_contactgroup, contact + i); + dJointAttach(c, b1, b2); + } +} +#endif + +void World_Physics_Frame(world_t *world, double frametime, double gravity) +{ + prvm_prog_t *prog = world->prog; + double tdelta, tdelta2, tdelta3, simulationtime, collisiontime; + + tdelta = Sys_DirtyTime(); +#ifdef USEODE + if (world->physics.ode && physics_ode.integer) + { + int i; + prvm_edict_t *ed; + + if (!physics_ode_constantstep.value) + { + world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000); + world->physics.ode_step = frametime / world->physics.ode_iterations; + } + else + { + world->physics.ode_time += frametime; + // step size + if (physics_ode_constantstep.value > 0 && physics_ode_constantstep.value < 1) + world->physics.ode_step = physics_ode_constantstep.value; + else + world->physics.ode_step = sys_ticrate.value; + if (world->physics.ode_time > 0.2f) + world->physics.ode_time = world->physics.ode_step; + // set number of iterations to process + world->physics.ode_iterations = 0; + while(world->physics.ode_time >= world->physics.ode_step) + { + world->physics.ode_iterations++; + world->physics.ode_time -= world->physics.ode_step; + } + } + world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step; + World_Physics_UpdateODE(world); + + // copy physics properties from entities to physics engine + if (prog) + { + for (i = 0, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++) + if (!prog->edicts[i].priv.required->free) + World_Physics_Frame_BodyFromEntity(world, ed); + // oh, and it must be called after all bodies were created + for (i = 0, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++) + if (!prog->edicts[i].priv.required->free) + World_Physics_Frame_JointFromEntity(world, ed); + } + + tdelta2 = Sys_DirtyTime(); + collisiontime = 0; + for (i = 0;i < world->physics.ode_iterations;i++) + { + // set the gravity + dWorldSetGravity((dWorldID)world->physics.ode_world, 0, 0, -gravity * physics_ode_world_gravitymod.value); + // set the tolerance for closeness of objects + dWorldSetContactSurfaceLayer((dWorldID)world->physics.ode_world, max(0, physics_ode_contactsurfacelayer.value)); + // run collisions for the current world state, creating JointGroup + tdelta3 = Sys_DirtyTime(); + dSpaceCollide((dSpaceID)world->physics.ode_space, (void *)world, nearCallback); + collisiontime += (Sys_DirtyTime() - tdelta3)*10000; + // apply forces + if (prog) + { + int j; + for (j = 0, ed = prog->edicts + j;j < prog->num_edicts;j++, ed++) + if (!prog->edicts[j].priv.required->free) + World_Physics_Frame_ForceFromEntity(world, ed); + } + // run physics (move objects, calculate new velocities) + // be sure not to pass 0 as step time because that causes an ODE error + dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200)); + if (world->physics.ode_step > 0) + dWorldQuickStep((dWorldID)world->physics.ode_world, world->physics.ode_step); + // clear the JointGroup now that we're done with it + dJointGroupEmpty((dJointGroupID)world->physics.ode_contactgroup); + } + simulationtime = (Sys_DirtyTime() - tdelta2)*10000; + + // copy physics properties from physics engine to entities and do some stats + if (prog) + { + for (i = 1, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++) + if (!prog->edicts[i].priv.required->free) + World_Physics_Frame_BodyToEntity(world, ed); + + // print stats + if (physics_ode_printstats.integer) + { + dBodyID body; + + world->physics.ode_numobjects = 0; + world->physics.ode_activeovjects = 0; + for (i = 1, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++) + { + if (prog->edicts[i].priv.required->free) + continue; + body = (dBodyID)prog->edicts[i].priv.server->ode_body; + if (!body) + continue; + world->physics.ode_numobjects++; + if (dBodyIsEnabled(body)) + world->physics.ode_activeovjects++; + } + Con_Printf("ODE Stats(%s): %i iterations, %3.01f (%3.01f collision) %3.01f total : %i objects %i active %i disabled\n", prog->name, world->physics.ode_iterations, simulationtime, collisiontime, (Sys_DirtyTime() - tdelta)*10000, world->physics.ode_numobjects, world->physics.ode_activeovjects, (world->physics.ode_numobjects - world->physics.ode_activeovjects)); + } + } + } +#endif +} diff --git a/app/jni/world.h b/app/jni/world.h new file mode 100644 index 0000000..18e9b00 --- /dev/null +++ b/app/jni/world.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. + +*/ +// world.h + +#ifndef WORLD_H +#define WORLD_H + +#include "collision.h" + +#define MOVE_NORMAL 0 +#define MOVE_NOMONSTERS 1 +#define MOVE_MISSILE 2 +#define MOVE_WORLDONLY 3 +#define MOVE_HITMODEL 4 + +#define AREA_GRID 128 +#define AREA_GRIDNODES (AREA_GRID * AREA_GRID) + +typedef struct link_s +{ + int entitynumber; + struct link_s *prev, *next; +} link_t; + +typedef struct world_physics_s +{ + // for ODE physics engine + qboolean ode; // if true then ode is activated + void *ode_world; + void *ode_space; + void *ode_contactgroup; + // number of constraint solver iterations to use (for dWorldQuickStep) + int ode_iterations; + // actual step (server frametime / ode_iterations) + vec_t ode_step; + // time we need to simulate, for constantstep + vec_t ode_time; + // stats + int ode_numobjects; // total objects cound + int ode_activeovjects; // active objects count + // max velocity for a 1-unit radius object at current step to prevent + // missed collisions + vec_t ode_movelimit; +} +world_physics_t; + +struct prvm_prog_s; + +typedef struct world_s +{ + // convenient fields + char filename[MAX_QPATH]; + vec3_t mins; + vec3_t maxs; + struct prvm_prog_s *prog; + + int areagrid_stats_calls; + int areagrid_stats_nodechecks; + int areagrid_stats_entitychecks; + + link_t areagrid[AREA_GRIDNODES]; + link_t areagrid_outside; + vec3_t areagrid_bias; + vec3_t areagrid_scale; + vec3_t areagrid_mins; + vec3_t areagrid_maxs; + vec3_t areagrid_size; + int areagrid_marknumber; + + // if the QC uses a physics engine, the data for it is here + world_physics_t physics; +} +world_t; + +struct prvm_edict_s; + +// cyclic doubly-linked list functions +void World_ClearLink(link_t *l); +void World_RemoveLink(link_t *l); +void World_InsertLinkBefore(link_t *l, link_t *before, int entitynumber); + +void World_Init(void); +void World_Shutdown(void); + +/// called after the world model has been loaded, before linking any entities +void World_SetSize(world_t *world, const char *filename, const vec3_t mins, const vec3_t maxs, struct prvm_prog_s *prog); +/// unlinks all entities (used before reallocation of edicts) +void World_UnlinkAll(world_t *world); + +void World_PrintAreaStats(world_t *world, const char *worldname); + +/// call before removing an entity, and before trying to move one, +/// so it doesn't clip against itself +void World_UnlinkEdict(struct prvm_edict_s *ent); + +/// Needs to be called any time an entity changes origin, mins, maxs +void World_LinkEdict(world_t *world, struct prvm_edict_s *ent, const vec3_t mins, const vec3_t maxs); + +/// \returns list of entities touching a box +int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, int maxlist, struct prvm_edict_s **list); + +void World_Start(world_t *world); +void World_End(world_t *world); + +// physics macros +#ifndef ODE_STATIC +# define ODE_DYNAMIC 1 +#endif + +#if defined(ODE_STATIC) || defined(ODE_DYNAMIC) +# define USEODE 1 +#endif + +// update physics +// this is called by SV_Physics +void World_Physics_Frame(world_t *world, double frametime, double gravity); + +// change physics properties of entity +struct prvm_edict_s; +struct edict_odefunc_s; +void World_Physics_ApplyCmd(struct prvm_edict_s *ed, struct edict_odefunc_s *f); + +// remove physics data from entity +// this is called by entity removal +void World_Physics_RemoveFromEntity(world_t *world, struct prvm_edict_s *ed); +void World_Physics_RemoveJointFromEntity(world_t *world, struct prvm_edict_s *ed); + +#endif + diff --git a/app/jni/zone.c b/app/jni/zone.c new file mode 100644 index 0000000..2c72c11 --- /dev/null +++ b/app/jni/zone.c @@ -0,0 +1,984 @@ +/* +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" +#include "thread.h" + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#ifdef _MSC_VER +#include +#else +#include +#endif +#define MEMHEADER_SENTINEL_FOR_ADDRESS(p) ((sentinel_seed ^ (unsigned int) (uintptr_t) (p)) + sentinel_seed) +unsigned int sentinel_seed; + +qboolean mem_bigendian = false; +void *mem_mutex = NULL; + +// divVerent: enables file backed malloc using mmap to conserve swap space (instead of malloc) +#ifndef FILE_BACKED_MALLOC +# define FILE_BACKED_MALLOC 0 +#endif + +// LordHavoc: enables our own low-level allocator (instead of malloc) +#ifndef MEMCLUMPING +# define MEMCLUMPING 0 +#endif +#ifndef MEMCLUMPING_FREECLUMPS +# define MEMCLUMPING_FREECLUMPS 0 +#endif + +#if MEMCLUMPING +// smallest unit we care about is this many bytes +#define MEMUNIT 128 +// try to do 32MB clumps, but overhead eats into this +#ifndef MEMWANTCLUMPSIZE +# define MEMWANTCLUMPSIZE (1<<27) +#endif +// give malloc padding so we can't waste most of a page at the end +#define MEMCLUMPSIZE (MEMWANTCLUMPSIZE - MEMWANTCLUMPSIZE/MEMUNIT/32 - 128) +#define MEMBITS (MEMCLUMPSIZE / MEMUNIT) +#define MEMBITINTS (MEMBITS / 32) + +typedef struct memclump_s +{ + // contents of the clump + unsigned char block[MEMCLUMPSIZE]; + // should always be MEMCLUMP_SENTINEL + unsigned int sentinel1; + // if a bit is on, it means that the MEMUNIT bytes it represents are + // allocated, otherwise free + unsigned int bits[MEMBITINTS]; + // should always be MEMCLUMP_SENTINEL + unsigned int sentinel2; + // if this drops to 0, the clump is freed + size_t blocksinuse; + // largest block of memory available (this is reset to an optimistic + // number when anything is freed, and updated when alloc fails the clump) + size_t largestavailable; + // next clump in the chain + struct memclump_s *chain; +} +memclump_t; + +#if MEMCLUMPING == 2 +static memclump_t masterclump; +#endif +static memclump_t *clumpchain = NULL; +#endif + + +cvar_t developer_memory = {0, "developer_memory", "0", "prints debugging information about memory allocations"}; +cvar_t developer_memorydebug = {0, "developer_memorydebug", "0", "enables memory corruption checks (very slow)"}; +cvar_t sys_memsize_physical = {CVAR_READONLY, "sys_memsize_physical", "", "physical memory size in MB (or empty if unknown)"}; +cvar_t sys_memsize_virtual = {CVAR_READONLY, "sys_memsize_virtual", "", "virtual memory size in MB (or empty if unknown)"}; + +static mempool_t *poolchain = NULL; + +void Mem_PrintStats(void); +void Mem_PrintList(size_t minallocationsize); + +#if FILE_BACKED_MALLOC +#include +#include +typedef struct mmap_data_s +{ + size_t len; +} +mmap_data_t; +static void *mmap_malloc(size_t size) +{ + char vabuf[MAX_OSPATH + 1]; + char *tmpdir = getenv("TEMP"); + mmap_data_t *data; + int fd; + size += sizeof(mmap_data_t); // waste block + dpsnprintf(vabuf, sizeof(vabuf), "%s/darkplaces.XXXXXX", tmpdir ? tmpdir : "/tmp"); + fd = mkstemp(vabuf); + if(fd < 0) + return NULL; + ftruncate(fd, size); + data = (unsigned char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0); + close(fd); + unlink(vabuf); + if(!data) + return NULL; + data->len = size; + return (void *) (data + 1); +} +static void mmap_free(void *mem) +{ + mmap_data_t *data; + if(!mem) + return; + data = ((mmap_data_t *) mem) - 1; + munmap(data, data->len); +} +#define malloc mmap_malloc +#define free mmap_free +#endif + +#if MEMCLUMPING != 2 +// some platforms have a malloc that returns NULL but succeeds later +// (Windows growing its swapfile for example) +static void *attempt_malloc(size_t size) +{ + void *base; + // try for half a second or so + unsigned int attempts = 500; + while (attempts--) + { + base = (void *)malloc(size); + if (base) + return base; + Sys_Sleep(1000); + } + return NULL; +} +#endif + +#if MEMCLUMPING +static memclump_t *Clump_NewClump(void) +{ + memclump_t **clumpchainpointer; + memclump_t *clump; +#if MEMCLUMPING == 2 + if (clumpchain) + return NULL; + clump = &masterclump; +#else + clump = (memclump_t*)attempt_malloc(sizeof(memclump_t)); + if (!clump) + return NULL; +#endif + + // initialize clump + if (developer_memorydebug.integer) + memset(clump, 0xEF, sizeof(*clump)); + clump->sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1); + memset(clump->bits, 0, sizeof(clump->bits)); + clump->sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2); + clump->blocksinuse = 0; + clump->largestavailable = 0; + clump->chain = NULL; + + // link clump into chain + for (clumpchainpointer = &clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain) + ; + *clumpchainpointer = clump; + + return clump; +} +#endif + +// low level clumping functions, all other memory functions use these +static void *Clump_AllocBlock(size_t size) +{ + unsigned char *base; +#if MEMCLUMPING + if (size <= MEMCLUMPSIZE) + { + int index; + unsigned int bit; + unsigned int needbits; + unsigned int startbit; + unsigned int endbit; + unsigned int needints; + int startindex; + int endindex; + unsigned int value; + unsigned int mask; + unsigned int *array; + memclump_t **clumpchainpointer; + memclump_t *clump; + needbits = (size + MEMUNIT - 1) / MEMUNIT; + needints = (needbits+31)>>5; + for (clumpchainpointer = &clumpchain;;clumpchainpointer = &(*clumpchainpointer)->chain) + { + clump = *clumpchainpointer; + if (!clump) + { + clump = Clump_NewClump(); + if (!clump) + return NULL; + } + if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) + Sys_Error("Clump_AllocBlock: trashed sentinel1\n"); + if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) + Sys_Error("Clump_AllocBlock: trashed sentinel2\n"); + startbit = 0; + endbit = startbit + needbits; + array = clump->bits; + // do as fast a search as possible, even if it means crude alignment + if (needbits >= 32) + { + // large allocations are aligned to large boundaries + // furthermore, they are allocated downward from the top... + endindex = MEMBITINTS; + startindex = endindex - needints; + index = endindex; + while (--index >= startindex) + { + if (array[index]) + { + endindex = index; + startindex = endindex - needints; + if (startindex < 0) + goto nofreeblock; + } + } + startbit = startindex*32; + goto foundblock; + } + else + { + // search for a multi-bit gap in a single int + // (not dealing with the cases that cross two ints) + mask = (1<bits[bit>>5] & (1<<(bit & 31))) + Sys_Error("Clump_AllocBlock: internal error (%i needbits)\n", needbits); + for (bit = startbit;bit < endbit;bit++) + clump->bits[bit>>5] |= (1<<(bit & 31)); + clump->blocksinuse += needbits; + base = clump->block + startbit * MEMUNIT; + if (developer_memorydebug.integer) + memset(base, 0xBF, needbits * MEMUNIT); + return base; +nofreeblock: + ; + } + // never reached + return NULL; + } + // too big, allocate it directly +#endif +#if MEMCLUMPING == 2 + return NULL; +#else + base = (unsigned char *)attempt_malloc(size); + if (base && developer_memorydebug.integer) + memset(base, 0xAF, size); + return base; +#endif +} +static void Clump_FreeBlock(void *base, size_t size) +{ +#if MEMCLUMPING + unsigned int needbits; + unsigned int startbit; + unsigned int endbit; + unsigned int bit; + memclump_t **clumpchainpointer; + memclump_t *clump; + unsigned char *start = (unsigned char *)base; + for (clumpchainpointer = &clumpchain;(clump = *clumpchainpointer);clumpchainpointer = &(*clumpchainpointer)->chain) + { + if (start >= clump->block && start < clump->block + MEMCLUMPSIZE) + { + if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) + Sys_Error("Clump_FreeBlock: trashed sentinel1\n"); + if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) + Sys_Error("Clump_FreeBlock: trashed sentinel2\n"); + if (start + size > clump->block + MEMCLUMPSIZE) + Sys_Error("Clump_FreeBlock: block overrun\n"); + // the block belongs to this clump, clear the range + needbits = (size + MEMUNIT - 1) / MEMUNIT; + startbit = (start - clump->block) / MEMUNIT; + endbit = startbit + needbits; + // first verify all bits are set, otherwise this may be misaligned or a double free + for (bit = startbit;bit < endbit;bit++) + if ((clump->bits[bit>>5] & (1<<(bit & 31))) == 0) + Sys_Error("Clump_FreeBlock: double free\n"); + for (bit = startbit;bit < endbit;bit++) + clump->bits[bit>>5] &= ~(1<<(bit & 31)); + clump->blocksinuse -= needbits; + memset(base, 0xFF, needbits * MEMUNIT); + // if all has been freed, free the clump itself + if (clump->blocksinuse == 0) + { + *clumpchainpointer = clump->chain; + if (developer_memorydebug.integer) + memset(clump, 0xFF, sizeof(*clump)); +#if MEMCLUMPING != 2 + free(clump); +#endif + } + return; + } + } + // does not belong to any known chunk... assume it was a direct allocation +#endif +#if MEMCLUMPING != 2 + memset(base, 0xFF, size); + free(base); +#endif +} + +void *_Mem_Alloc(mempool_t *pool, void *olddata, size_t size, size_t alignment, const char *filename, int fileline) +{ + unsigned int sentinel1; + unsigned int sentinel2; + size_t realsize; + size_t sharedsize; + size_t remainsize; + memheader_t *mem; + memheader_t *oldmem; + unsigned char *base; + + if (size <= 0) + { + if (olddata) + _Mem_Free(olddata, filename, fileline); + return NULL; + } + if (pool == NULL) + { + if(olddata) + pool = ((memheader_t *)((unsigned char *) olddata - sizeof(memheader_t)))->pool; + else + Sys_Error("Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline); + } + if (mem_mutex) + Thread_LockMutex(mem_mutex); + if (developer_memory.integer) + Con_DPrintf("Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, (int)size); + //if (developer.integer > 0 && developer_memorydebug.integer) + // _Mem_CheckSentinelsGlobal(filename, fileline); + pool->totalsize += size; + realsize = alignment + sizeof(memheader_t) + size + sizeof(sentinel2); + pool->realsize += realsize; + base = (unsigned char *)Clump_AllocBlock(realsize); + if (base== NULL) + { + Mem_PrintList(0); + Mem_PrintStats(); + Mem_PrintList(1<<30); + Mem_PrintStats(); + Sys_Error("Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline); + } + // calculate address that aligns the end of the memheader_t to the specified alignment + mem = (memheader_t*)((((size_t)base + sizeof(memheader_t) + (alignment-1)) & ~(alignment-1)) - sizeof(memheader_t)); + mem->baseaddress = (void*)base; + mem->filename = filename; + mem->fileline = fileline; + mem->size = size; + mem->pool = pool; + + // calculate sentinels (detects buffer overruns, in a way that is hard to exploit) + sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel); + sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size); + mem->sentinel = sentinel1; + memcpy((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2)); + + // append to head of list + mem->next = pool->chain; + mem->prev = NULL; + pool->chain = mem; + if (mem->next) + mem->next->prev = mem; + + if (mem_mutex) + Thread_UnlockMutex(mem_mutex); + + // copy the shared portion in the case of a realloc, then memset the rest + sharedsize = 0; + remainsize = size; + if (olddata) + { + oldmem = (memheader_t*)olddata - 1; + sharedsize = min(oldmem->size, size); + memcpy((void *)((unsigned char *) mem + sizeof(memheader_t)), olddata, sharedsize); + remainsize -= sharedsize; + _Mem_Free(olddata, filename, fileline); + } + memset((void *)((unsigned char *) mem + sizeof(memheader_t) + sharedsize), 0, remainsize); + return (void *)((unsigned char *) mem + sizeof(memheader_t)); +} + +// only used by _Mem_Free and _Mem_FreePool +static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline) +{ + mempool_t *pool; + size_t size; + size_t realsize; + unsigned int sentinel1; + unsigned int sentinel2; + + // check sentinels (detects buffer overruns, in a way that is hard to exploit) + sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel); + sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size); + if (mem->sentinel != sentinel1) + Sys_Error("Mem_Free: trashed head sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); + if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2))) + Sys_Error("Mem_Free: trashed tail sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline); + + pool = mem->pool; + if (developer_memory.integer) + Con_DPrintf("Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, (int)(mem->size)); + // unlink memheader from doubly linked list + if ((mem->prev ? mem->prev->next != mem : pool->chain != mem) || (mem->next && mem->next->prev != mem)) + Sys_Error("Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline); + if (mem_mutex) + Thread_LockMutex(mem_mutex); + if (mem->prev) + mem->prev->next = mem->next; + else + pool->chain = mem->next; + if (mem->next) + mem->next->prev = mem->prev; + // memheader has been unlinked, do the actual free now + size = mem->size; + realsize = sizeof(memheader_t) + size + sizeof(sentinel2); + pool->totalsize -= size; + pool->realsize -= realsize; + Clump_FreeBlock(mem->baseaddress, realsize); + if (mem_mutex) + Thread_UnlockMutex(mem_mutex); +} + +void _Mem_Free(void *data, const char *filename, int fileline) +{ + if (data == NULL) + { + Con_DPrintf("Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline); + return; + } + + if (developer_memorydebug.integer) + { + //_Mem_CheckSentinelsGlobal(filename, fileline); + if (!Mem_IsAllocated(NULL, data)) + Sys_Error("Mem_Free: data is not allocated (called at %s:%i)", filename, fileline); + } + + _Mem_FreeBlock((memheader_t *)((unsigned char *) data - sizeof(memheader_t)), filename, fileline); +} + +mempool_t *_Mem_AllocPool(const char *name, int flags, mempool_t *parent, const char *filename, int fileline) +{ + mempool_t *pool; + if (developer_memorydebug.integer) + _Mem_CheckSentinelsGlobal(filename, fileline); + pool = (mempool_t *)Clump_AllocBlock(sizeof(mempool_t)); + if (pool == NULL) + { + Mem_PrintList(0); + Mem_PrintStats(); + Mem_PrintList(1<<30); + Mem_PrintStats(); + Sys_Error("Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline); + } + memset(pool, 0, sizeof(mempool_t)); + pool->sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1); + pool->sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2); + pool->filename = filename; + pool->fileline = fileline; + pool->flags = flags; + pool->chain = NULL; + pool->totalsize = 0; + pool->realsize = sizeof(mempool_t); + strlcpy (pool->name, name, sizeof (pool->name)); + pool->parent = parent; + pool->next = poolchain; + poolchain = pool; + return pool; +} + +void _Mem_FreePool(mempool_t **poolpointer, const char *filename, int fileline) +{ + mempool_t *pool = *poolpointer; + mempool_t **chainaddress, *iter, *temp; + + if (developer_memorydebug.integer) + _Mem_CheckSentinelsGlobal(filename, fileline); + if (pool) + { + // unlink pool from chain + for (chainaddress = &poolchain;*chainaddress && *chainaddress != pool;chainaddress = &((*chainaddress)->next)); + if (*chainaddress != pool) + Sys_Error("Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline); + if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) + Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) + Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + *chainaddress = pool->next; + + // free memory owned by the pool + while (pool->chain) + _Mem_FreeBlock(pool->chain, filename, fileline); + + // free child pools, too + for(iter = poolchain; iter; temp = iter = iter->next) + if(iter->parent == pool) + _Mem_FreePool(&temp, filename, fileline); + + // free the pool itself + Clump_FreeBlock(pool, sizeof(*pool)); + + *poolpointer = NULL; + } +} + +void _Mem_EmptyPool(mempool_t *pool, const char *filename, int fileline) +{ + mempool_t *chainaddress; + + if (developer_memorydebug.integer) + { + //_Mem_CheckSentinelsGlobal(filename, fileline); + // check if this pool is in the poolchain + for (chainaddress = poolchain;chainaddress;chainaddress = chainaddress->next) + if (chainaddress == pool) + break; + if (!chainaddress) + Sys_Error("Mem_EmptyPool: pool is already free (emptypool at %s:%i)", filename, fileline); + } + if (pool == NULL) + Sys_Error("Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline); + if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) + Sys_Error("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) + Sys_Error("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline); + + // free memory owned by the pool + while (pool->chain) + _Mem_FreeBlock(pool->chain, filename, fileline); + + // empty child pools, too + for(chainaddress = poolchain; chainaddress; chainaddress = chainaddress->next) + if(chainaddress->parent == pool) + _Mem_EmptyPool(chainaddress, filename, fileline); + +} + +void _Mem_CheckSentinels(void *data, const char *filename, int fileline) +{ + memheader_t *mem; + unsigned int sentinel1; + unsigned int sentinel2; + + if (data == NULL) + Sys_Error("Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline); + + mem = (memheader_t *)((unsigned char *) data - sizeof(memheader_t)); + sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel); + sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size); + if (mem->sentinel != sentinel1) + Sys_Error("Mem_Free: trashed head sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); + if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2))) + Sys_Error("Mem_Free: trashed tail sentinel (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline); +} + +#if MEMCLUMPING +static void _Mem_CheckClumpSentinels(memclump_t *clump, const char *filename, int fileline) +{ + // this isn't really very useful + if (clump->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel1)) + Sys_Error("Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i)", filename, fileline); + if (clump->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&clump->sentinel2)) + Sys_Error("Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i)", filename, fileline); +} +#endif + +void _Mem_CheckSentinelsGlobal(const char *filename, int fileline) +{ + memheader_t *mem; +#if MEMCLUMPING + memclump_t *clump; +#endif + mempool_t *pool; + for (pool = poolchain;pool;pool = pool->next) + { + if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1)) + Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); + if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2)) + Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline); + } + for (pool = poolchain;pool;pool = pool->next) + for (mem = pool->chain;mem;mem = mem->next) + _Mem_CheckSentinels((void *)((unsigned char *) mem + sizeof(memheader_t)), filename, fileline); +#if MEMCLUMPING + for (pool = poolchain;pool;pool = pool->next) + for (clump = clumpchain;clump;clump = clump->chain) + _Mem_CheckClumpSentinels(clump, filename, fileline); +#endif +} + +qboolean Mem_IsAllocated(mempool_t *pool, void *data) +{ + memheader_t *header; + memheader_t *target; + + if (pool) + { + // search only one pool + target = (memheader_t *)((unsigned char *) data - sizeof(memheader_t)); + for( header = pool->chain ; header ; header = header->next ) + if( header == target ) + return true; + } + else + { + // search all pools + for (pool = poolchain;pool;pool = pool->next) + if (Mem_IsAllocated(pool, data)) + return true; + } + return false; +} + +void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray) +{ + memset(l, 0, sizeof(*l)); + l->mempool = mempool; + l->recordsize = recordsize; + l->numrecordsperarray = numrecordsperarray; +} + +void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l) +{ + size_t i; + if (l->maxarrays) + { + for (i = 0;i != l->numarrays;i++) + Mem_Free(l->arrays[i].data); + Mem_Free(l->arrays); + } + memset(l, 0, sizeof(*l)); +} + +void *Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l) +{ + size_t i, j; + for (i = 0;;i++) + { + if (i == l->numarrays) + { + if (l->numarrays == l->maxarrays) + { + memexpandablearray_array_t *oldarrays = l->arrays; + l->maxarrays = max(l->maxarrays * 2, 128); + l->arrays = (memexpandablearray_array_t*) Mem_Alloc(l->mempool, l->maxarrays * sizeof(*l->arrays)); + if (oldarrays) + { + memcpy(l->arrays, oldarrays, l->numarrays * sizeof(*l->arrays)); + Mem_Free(oldarrays); + } + } + l->arrays[i].numflaggedrecords = 0; + l->arrays[i].data = (unsigned char *) Mem_Alloc(l->mempool, (l->recordsize + 1) * l->numrecordsperarray); + l->arrays[i].allocflags = l->arrays[i].data + l->recordsize * l->numrecordsperarray; + l->numarrays++; + } + if (l->arrays[i].numflaggedrecords < l->numrecordsperarray) + { + for (j = 0;j < l->numrecordsperarray;j++) + { + if (!l->arrays[i].allocflags[j]) + { + l->arrays[i].allocflags[j] = true; + l->arrays[i].numflaggedrecords++; + memset(l->arrays[i].data + l->recordsize * j, 0, l->recordsize); + return (void *)(l->arrays[i].data + l->recordsize * j); + } + } + } + } +} + +/***************************************************************************** + * IF YOU EDIT THIS: + * If this function was to change the size of the "expandable" array, you have + * to update r_shadow.c + * Just do a search for "range =", R_ShadowClearWorldLights would be the first + * function to look at. (And also seems like the only one?) You might have to + * move the call to Mem_ExpandableArray_IndexRange back into for(...) loop's + * condition + */ +void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record) // const! +{ + size_t i, j; + unsigned char *p = (unsigned char *)record; + for (i = 0;i != l->numarrays;i++) + { + if (p >= l->arrays[i].data && p < (l->arrays[i].data + l->recordsize * l->numrecordsperarray)) + { + j = (p - l->arrays[i].data) / l->recordsize; + if (p != l->arrays[i].data + j * l->recordsize) + Sys_Error("Mem_ExpandableArray_FreeRecord: no such record %p\n", p); + if (!l->arrays[i].allocflags[j]) + Sys_Error("Mem_ExpandableArray_FreeRecord: record %p is already free!\n", p); + l->arrays[i].allocflags[j] = false; + l->arrays[i].numflaggedrecords--; + return; + } + } +} + +size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l) +{ + size_t i, j, k, end = 0; + for (i = 0;i < l->numarrays;i++) + { + for (j = 0, k = 0;k < l->arrays[i].numflaggedrecords;j++) + { + if (l->arrays[i].allocflags[j]) + { + end = l->numrecordsperarray * i + j + 1; + k++; + } + } + } + return end; +} + +void *Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index) +{ + size_t i, j; + i = index / l->numrecordsperarray; + j = index % l->numrecordsperarray; + if (i >= l->numarrays || !l->arrays[i].allocflags[j]) + return NULL; + return (void *)(l->arrays[i].data + j * l->recordsize); +} + + +// used for temporary memory allocations around the engine, not for longterm +// storage, if anything in this pool stays allocated during gameplay, it is +// considered a leak +mempool_t *tempmempool; +// only for zone +mempool_t *zonemempool; + +void Mem_PrintStats(void) +{ + size_t count = 0, size = 0, realsize = 0; + mempool_t *pool; + memheader_t *mem; + Mem_CheckSentinelsGlobal(); + for (pool = poolchain;pool;pool = pool->next) + { + count++; + size += pool->totalsize; + realsize += pool->realsize; + } + Con_Printf("%lu memory pools, totalling %lu bytes (%.3fMB)\n", (unsigned long)count, (unsigned long)size, size / 1048576.0); + Con_Printf("total allocated size: %lu bytes (%.3fMB)\n", (unsigned long)realsize, realsize / 1048576.0); + for (pool = poolchain;pool;pool = pool->next) + { + if ((pool->flags & POOLFLAG_TEMP) && pool->chain) + { + Con_Printf("Memory pool %p has sprung a leak totalling %lu bytes (%.3fMB)! Listing contents...\n", (void *)pool, (unsigned long)pool->totalsize, pool->totalsize / 1048576.0); + for (mem = pool->chain;mem;mem = mem->next) + Con_Printf("%10lu bytes allocated at %s:%i\n", (unsigned long)mem->size, mem->filename, mem->fileline); + } + } +} + +void Mem_PrintList(size_t minallocationsize) +{ + mempool_t *pool; + memheader_t *mem; + Mem_CheckSentinelsGlobal(); + Con_Print("memory pool list:\n" + "size name\n"); + for (pool = poolchain;pool;pool = pool->next) + { + Con_Printf("%10luk (%10luk actual) %s (%+li byte change) %s\n", (unsigned long) ((pool->totalsize + 1023) / 1024), (unsigned long)((pool->realsize + 1023) / 1024), pool->name, (long)(pool->totalsize - pool->lastchecksize), (pool->flags & POOLFLAG_TEMP) ? "TEMP" : ""); + pool->lastchecksize = pool->totalsize; + for (mem = pool->chain;mem;mem = mem->next) + if (mem->size >= minallocationsize) + Con_Printf("%10lu bytes allocated at %s:%i\n", (unsigned long)mem->size, mem->filename, mem->fileline); + } +} + +static void MemList_f(void) +{ + switch(Cmd_Argc()) + { + case 1: + Mem_PrintList(1<<30); + Mem_PrintStats(); + break; + case 2: + Mem_PrintList(atoi(Cmd_Argv(1)) * 1024); + Mem_PrintStats(); + break; + default: + Con_Print("MemList_f: unrecognized options\nusage: memlist [all]\n"); + break; + } +} + +static void MemStats_f(void) +{ + Mem_CheckSentinelsGlobal(); + R_TextureStats_Print(false, false, true); + GL_Mesh_ListVBOs(false); + Mem_PrintStats(); +} + + +char* Mem_strdup (mempool_t *pool, const char* s) +{ + char* p; + size_t sz; + if (s == NULL) + return NULL; + sz = strlen (s) + 1; + p = (char*)Mem_Alloc (pool, sz); + strlcpy (p, s, sz); + return p; +} + +/* +======================== +Memory_Init +======================== +*/ +void Memory_Init (void) +{ + static union {unsigned short s;unsigned char b[2];} u; + u.s = 0x100; + mem_bigendian = u.b[0] != 0; + + sentinel_seed = rand(); + poolchain = NULL; + tempmempool = Mem_AllocPool("Temporary Memory", POOLFLAG_TEMP, NULL); + zonemempool = Mem_AllocPool("Zone", 0, NULL); + + if (Thread_HasThreads()) + mem_mutex = Thread_CreateMutex(); +} + +void Memory_Shutdown (void) +{ +// Mem_FreePool (&zonemempool); +// Mem_FreePool (&tempmempool); + + if (mem_mutex) + Thread_DestroyMutex(mem_mutex); + mem_mutex = NULL; +} + +void Memory_Init_Commands (void) +{ + Cmd_AddCommand ("memstats", MemStats_f, "prints memory system statistics"); + Cmd_AddCommand ("memlist", MemList_f, "prints memory pool information (or if used as memlist 5 lists individual allocations of 5K or larger, 0 lists all allocations)"); + Cvar_RegisterVariable (&developer_memory); + Cvar_RegisterVariable (&developer_memorydebug); + Cvar_RegisterVariable (&sys_memsize_physical); + Cvar_RegisterVariable (&sys_memsize_virtual); + +#if defined(WIN32) +#ifdef _WIN64 + { + MEMORYSTATUSEX status; + // first guess + Cvar_SetValueQuick(&sys_memsize_virtual, 8388608); + // then improve + status.dwLength = sizeof(status); + if(GlobalMemoryStatusEx(&status)) + { + Cvar_SetValueQuick(&sys_memsize_physical, status.ullTotalPhys / 1048576.0); + Cvar_SetValueQuick(&sys_memsize_virtual, min(sys_memsize_virtual.value, status.ullTotalVirtual / 1048576.0)); + } + } +#else + { + MEMORYSTATUS status; + // first guess + Cvar_SetValueQuick(&sys_memsize_virtual, 2048); + // then improve + status.dwLength = sizeof(status); + GlobalMemoryStatus(&status); + Cvar_SetValueQuick(&sys_memsize_physical, status.dwTotalPhys / 1048576.0); + Cvar_SetValueQuick(&sys_memsize_virtual, min(sys_memsize_virtual.value, status.dwTotalVirtual / 1048576.0)); + } +#endif +#else + { + // first guess + Cvar_SetValueQuick(&sys_memsize_virtual, (sizeof(void*) == 4) ? 2048 : 268435456); + // then improve + { + // Linux, and BSD with linprocfs mounted + FILE *f = fopen("/proc/meminfo", "r"); + if(f) + { + static char buf[1024]; + while(fgets(buf, sizeof(buf), f)) + { + const char *p = buf; + if(!COM_ParseToken_Console(&p)) + continue; + if(!strcmp(com_token, "MemTotal:")) + { + if(!COM_ParseToken_Console(&p)) + continue; + Cvar_SetValueQuick(&sys_memsize_physical, atof(com_token) / 1024.0); + } + if(!strcmp(com_token, "SwapTotal:")) + { + if(!COM_ParseToken_Console(&p)) + continue; + Cvar_SetValueQuick(&sys_memsize_virtual, min(sys_memsize_virtual.value , atof(com_token) / 1024.0 + sys_memsize_physical.value)); + } + } + fclose(f); + } + } + } +#endif +} + diff --git a/app/jni/zone.h b/app/jni/zone.h new file mode 100644 index 0000000..6caa039 --- /dev/null +++ b/app/jni/zone.h @@ -0,0 +1,144 @@ +/* +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 ZONE_H +#define ZONE_H + +extern qboolean mem_bigendian; + +// div0: heap overflow detection paranoia +#define MEMPARANOIA 0 + +#define POOLNAMESIZE 128 +// if set this pool will be printed in memlist reports +#define POOLFLAG_TEMP 1 + +typedef struct memheader_s +{ + // address returned by Chunk_Alloc (may be significantly before this header to satisify alignment) + void *baseaddress; + // next and previous memheaders in chain belonging to pool + struct memheader_s *next; + struct memheader_s *prev; + // pool this memheader belongs to + struct mempool_s *pool; + // size of the memory after the header (excluding header and sentinel2) + size_t size; + // file name and line where Mem_Alloc was called + const char *filename; + int fileline; + // should always be equal to MEMHEADER_SENTINEL_FOR_ADDRESS() + unsigned int sentinel; + // immediately followed by data, which is followed by another copy of mem_sentinel[] +} +memheader_t; + +typedef struct mempool_s +{ + // should always be MEMPOOL_SENTINEL + unsigned int sentinel1; + // chain of individual memory allocations + struct memheader_s *chain; + // POOLFLAG_* + int flags; + // total memory allocated in this pool (inside memheaders) + size_t totalsize; + // total memory allocated in this pool (actual malloc total) + size_t realsize; + // updated each time the pool is displayed by memlist, shows change from previous time (unless pool was freed) + size_t lastchecksize; + // linked into global mempool list + struct mempool_s *next; + // parent object (used for nested memory pools) + struct mempool_s *parent; + // file name and line where Mem_AllocPool was called + const char *filename; + int fileline; + // name of the pool + char name[POOLNAMESIZE]; + // should always be MEMPOOL_SENTINEL + unsigned int sentinel2; +} +mempool_t; + +#define Mem_Alloc(pool,size) _Mem_Alloc(pool, NULL, size, 16, __FILE__, __LINE__) +#define Mem_Memalign(pool,alignment,size) _Mem_Alloc(pool, NULL, size, alignment, __FILE__, __LINE__) +#define Mem_Realloc(pool,data,size) _Mem_Alloc(pool, data, size, 16, __FILE__, __LINE__) +#define Mem_Free(mem) _Mem_Free(mem, __FILE__, __LINE__) +#define Mem_CheckSentinels(data) _Mem_CheckSentinels(data, __FILE__, __LINE__) +#define Mem_CheckSentinelsGlobal() _Mem_CheckSentinelsGlobal(__FILE__, __LINE__) +#define Mem_AllocPool(name, flags, parent) _Mem_AllocPool(name, flags, parent, __FILE__, __LINE__) +#define Mem_FreePool(pool) _Mem_FreePool(pool, __FILE__, __LINE__) +#define Mem_EmptyPool(pool) _Mem_EmptyPool(pool, __FILE__, __LINE__) + +void *_Mem_Alloc(mempool_t *pool, void *data, size_t size, size_t alignment, const char *filename, int fileline); +void _Mem_Free(void *data, const char *filename, int fileline); +mempool_t *_Mem_AllocPool(const char *name, int flags, mempool_t *parent, const char *filename, int fileline); +void _Mem_FreePool(mempool_t **pool, const char *filename, int fileline); +void _Mem_EmptyPool(mempool_t *pool, const char *filename, int fileline); +void _Mem_CheckSentinels(void *data, const char *filename, int fileline); +void _Mem_CheckSentinelsGlobal(const char *filename, int fileline); +// if pool is NULL this searches ALL pools for the allocation +qboolean Mem_IsAllocated(mempool_t *pool, void *data); + +char* Mem_strdup (mempool_t *pool, const char* s); + +typedef struct memexpandablearray_array_s +{ + unsigned char *data; + unsigned char *allocflags; + size_t numflaggedrecords; +} +memexpandablearray_array_t; + +typedef struct memexpandablearray_s +{ + mempool_t *mempool; + size_t recordsize; + size_t numrecordsperarray; + size_t numarrays; + size_t maxarrays; + memexpandablearray_array_t *arrays; +} +memexpandablearray_t; + +void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray); +void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l); +void *Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l); +void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record); +size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l) DP_FUNC_PURE; +void *Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index) DP_FUNC_PURE; + +// used for temporary allocations +extern mempool_t *tempmempool; + +void Memory_Init (void); +void Memory_Shutdown (void); +void Memory_Init_Commands (void); + +extern mempool_t *zonemempool; +#define Z_Malloc(size) Mem_Alloc(zonemempool,size) +#define Z_Free(data) Mem_Free(data) + +extern struct cvar_s developer_memory; +extern struct cvar_s developer_memorydebug; + +#endif + diff --git a/app/libs/cardboard.jar b/app/libs/cardboard.jar new file mode 100644 index 0000000000000000000000000000000000000000..06d5dcf5161a1a3584602f22c7b6fc29a8e379da GIT binary patch literal 620744 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

{SBdzYjK2>e0Cwy4LqR+_d+d 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

|$Qto^?LbdVk5`7IDGh7E_7U^PL;_T_+sG9r`_e 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

Bq<@ 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

jmEZY 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%0DpM6cF-1|F|io4#ay2?9M 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
S zo4RmNHBL2`)BCf1xMAU}3{>tCEO083di%i%L{+-ZFefxwVSI=}lsUWquu4bGF6g^- zKRX%oJ8t*P56BOKtr!_0L@CJcLL_?pSvzQT@Jkf{Ji#7%S?h(n2tMhD^Z_h3Z(mJV z#h!Bju-Y#6^y}lhaMXZSO~mDpY4Gqu71r+Qcu2wS^0Qj+j;ite${GIr4YZHY6{~9H z>WbG>x^pcTi+Z1aIO(LGfL@MvINp!8&hl zb_zJJ{A0awfuDn^<5Ml|7h z6Ss4*mfr4*Lzp53DQ7%_w8G;Nd}bFie+G4rND?zKEO(<0yf8S(1#DCcNF%n?PkA(A z7u|FU^WEF1QP1)E7&AI^nXb?pRviaS)i#8+$00Djg=(RYqgyG5A5JoJmK!S3ue~qN zPGlB}HJo)Jv90CeH9Z}Xq;BGC{jNU1q;1PV(v6)Qaz4-!n_Psoll*Q ze2$x*O<4o5*Ybu*CvPD2#CG^DjGq4PRcoJjCt$C68L(yVmZ~7zBbKmJu}75v?_E*Y z99R#Dj+tu+k)ytG2|mrV1~)DPmqI&X>I!j{43DcjnPH@Bn+_J>Xh(~=QkXbNj*Lw6 z52rYs#tTkvRGOSeH+VLf>IhANjVCM*IMDT?_uHNi{lp%Cr$RK6 z*~OOoOIo54Q&%CL9)F}B2ddgf=#{o=gz_w433!0<8Qu@J|7jMhpU8exr`=$WEf!x6 z|D?2lxLyc`;PE}VO*+W&!NMl6vbR$oyI{3METwG}5 zlxg&fi5EY?@+M(*O3pG(6I|foJ1+;rBKa!@A>$w4ZIqO&vK{ur4bPR7L1eq&cz`3b zWQzI8Rq%yvvh-N##iEkF&H3HGjEntAjsN0aAjx4`t|U?j>u8$^|MAZh67Ky#)g6GCLke7n|oqywxRs1@gZgLi4)KT-cJu66)h#{Ea)OWsgXo> z!S~F*=gHScq6yTpcF-L?a7=N0d>jqQ{istP&&MhtrH)J^&(G{>4tq~V^(F4uhF-)&} zVy(MjD9)BhgaMGDi#-GPTw`3{U*na4k|AmC8W5uEYzjI-|L(m-1!1&)<_;&;8N*RZ zGK0`k1+^=R)r|m}P)X;u7d+r-l=n;aYs9+wl$g>}tRT_yUxXhLg%MJFMS|2NG(c~s zL=9-kgA*iBYj3W|M#_AMX&(rSI^ch%yajq{m~R_pptmsq`$cn~yCeu#hkAG&3Zs@p zdz&l%DKfDU?>B^+y-m^AEpezXwtU8AII{Dm`Rz(3SldN^C=XNH;`@cUqr z%NDTI3#2Rm#HBPY->QB&Chs72E#4GX@;)Hzht5c89vE+BXnI^B=jFSli@0j#{^~dz zsZ63PLmL=rE?8nA`bN26DxG(6*WJM8B#x{o^OArLp4e?mnd0XTgOoHjm_oA9;As81 zCYG+KcFLBCc`^jtiaj?%|B}fEOQfoju~14sXsi*ZCyY(9s5w!AK)CwAbePp<4~c-B(Ij zyPnX_GeQhT$(hbtl+e7j<2Rq9l~|<|jK-E#6IS*Yut=4NZphNBrxg#3yRwz1!?+RH zQJ`>=Z{TRXz79 zW4i{eb$Plou^vT;pn*OV7{riS^ViQ2mAAJr$gYqTIwTK}PKsHowcPI=Jo9rhU{L9j z4Cc`SYnc9Js|uzCRc^75{YEgS)qXRZ$9*~?L=~aUnV``moV#fG-v8R3&xcrIOGei5 z=p|3eL92g+A>9b!DioK`MH4--Y7<_lWn>S3cfx1Lf<4~00&EA8x7bw&WP;x5bq;iz zEuYvfV3EKbw);4+U2@fI*beGQJiBCrlKJ+BXr}kyQ{3Rq(pYF>8544%h+hnq%m?E7 zIX@&5en=O!r51Y%@M2b~nEhInn|8G~#p`<;ZWp{%Lyvii{n$ubBWXUR9WT4X<$x@u z=$6<8Gb~4Ht8-$M>B8`Lgpfx}hMiY*z1I)u)H}#Ggg}-GdP3ju%j*iR>L>!d86_&v zCWqq<#yV%j?SwP7F>3%O_qQi=GcjJU{yDD-G4!AV1O4%X2wFkyMa3*d(|noSg8T?AxREP%Ii&bI9|29oqJz$u)XY6 z=lFu!BWQ8H#;Tc03=vSDHUG}Qv>iD71lfIt2hA!jH4r&Ex?snV8hwjS_bxPbU1*6} zxFj3(DqG}LI?QG)$K=KPJ@4?t3Uf3dm0u*_PadVc6GcV|kkPjjGS(r6oa| z{4lCr1?r({Es&vrKKTVFtRAP2#Hx(ab}o^()!evx6s#66B`;useVV!ZRNW1XTl6JSr^+9mp|>CUob zJaZ|i2A-QZJ*X%)Y|UtA;#?o|)(RF_q1 zn8A(ICA+pX5@M<-aeZ`Ln-*I|ZMchi(F2I_#AkV`GU>2ejuJ-1@7d+biGwIoCnr+W zVE%A{o&&NRCA|;5T?Z0$tuoctwCZK;q^-@FZFFo!eox<)uM(Lmhcdvdr$BRG1yC&P zVA|H`&p;S{f4*i#DN!dJGU;PQ2fK-*F@|^3ds2dlHx&=V895r-em}vk%OCIY*hbl4 zY)1QmJv)~^Eszh$_!$)Onn;zTx3;)!QNLlbf+EsoNiAtlIhALxm!@qhNp9s&Pn3_>szHpPx^EyV<_q}GLK_+FkYLhkrb9afx zDx^&TWwYTc_Y()waW)CQMdcn8UQG+-OgPm&RLWp<{q!R!cr0FZy38Fi<!=O1x;#W>-X| z`jTfBu^fmYH^8e{D2{M8$dK&ZY0n@rnA^MaCF?mM|>>q1Lf&uf7mxwsf`?@=;D(I;P zlPXm@(8CyhPi_&JP}KyzUq4b_N01_^N`*=fZA`8Ju`*!#*F82cuA2kgKWA;GfoaV1 zJi53B#mPjY(Ia#iHc21g_Xr2Va>;wCBYm2nXYs6&*M97_{ivJA0UBqbQb1w+k-FZ~ zDU12!X4_C%alb(|e*;%773S7NmiLhrXsH8na{9;i=f0*1Z#*{6+Tin5>ag5bU;xmT z>vb*1;+k6&h)9(S%i}0_U}z~?DuC$p16Gu`smHCLAzO(^jt=Y*SiQ%6A?vL4Vd(2$ z9Hv5=#Gf@=hV~eSs`l6yl zLH9jKO(}MV^JN5xktZ#$F5=0tIJ=smr~Vs~Pc?3WhdjPqzOvqzRVd}aK$@!+tBGu$ zY?_JHE$^?1CU_8=ysfUF%>bV}%-468`!$q%@C-+638Zt^`ZM;{$I0nH*G40nd8pU( zSa6}=i2_-Kj~`&C_tjL#M#X>HJmt4Ka?cakrqQU5q0pP(mGLQmIZr97h{AZzUx5Ipi^){HMD|4&i6qE=o<_b;x zVc3YFY#o-V!SVuVR}55VSw3haTMwQ#SLtYfWuNhVt-R}HAH6_$Kzld)f8P5ZY769i zwn2HMlFfKOP=euBYVBzv%m!=XPPi~l%Amz~Vrm+aJ7Q>npn*S}*o%y$WiL#RB=h1p zURl=?Vh~v=a8xb5y6YIXA<1jwC!G}!lT#HF(YngC-Tv0Q#*+5KDRyB_j(Bn@hN7U$ zOzS|;tkzzs2w-Zfptv*-U80Fg7+L%+*Tap=f#^qPB6N|Uxe>8sM=rr!U1~Z|xM_CSNH3v)J*ekpi zG@UNNX<_HCfHM~XRZptjlHI^m%eI|wb$);Zoy|$=a>N^)EdKacn*E=ioze?wgE9jN z-aaMQ0~~6rko}z)ec)F(y6IR3?bWpl>y^@%W;X3LCKG-QUFF4xT#s|T5oi%K89ALmq zDcJMDIy533>`~0?tDsG=wTeu@!dBN!?9AMSz`wgxS6Y=aOjQy3XDEtS{Y!kJa5@af zwQ!JPJov9$Z1LTxK(jK=R$=pS6ADsblM(*TF~XS?%oJW2VK}XN=ukf>XBtg2ju%^T zsE=x|FT!qhir%)EF_u_pDO$+pC7M8*w%+|Qll!*+ z_TtQ+3l|ylTjds(qY#tPBtmnh5r7HvQSAj}U?U08KGP$K#TLgMY|We8d+i@<1(hz( zB8#H-p7UwX+-+V%YCW~%XE2a({IzWfx6RYpj|J&-p2;C zcrtnn`83h@L4~H@^uCZZKlVuW_Xd2f1wSp_^GMD~e!PObI$@|ySL@~TzM=gCBYy*8 zi0|0_gMj-V_y4+(zaRdezAbxzos*rRvnk#GyaMBYSYc~mYxf_^zCQ`^k3SJ`XAo#i z+kZ1eao?~1a&G*eAN|KNH4A`=s2#w@z)AM|EB|?JWU1;XVVNNNY+By*u3LCIw$S=yqTl>arhTYfFhWIJ322C3XK!3T)P6+&mb#;OxxQ2 zCNW|Hg7@IH4#KqMGc&>xM2|kQs@z0mi=1MiL0W_67)IIzUBmtycU_slO7T@0 z9iCvT`AJz^^9(#%XSRJlng%w z3qp7o)yM3AjjMQ0xxm@{?6qfmx!SlHTU2RVc&r`DPP4JI%cwe5$|4;Fr^Yo%^@RKp zoC;88(#jT*!t?8)7g3|ipqaZKZ#AdcYaOgHU4^wfDr(y|Mi{H@FtuB(37>PZGTq$$?0>9!R=uF@TA)F9v>FpD~{AkO$fp}2c&K}sQ9?>&Z4>qCRUq^O-%E{2%d#4in)0R$xyHk{}W+UO~ zfnplVWw5RzS+_$?y{TU%oNqpS;yZi<6K_JZ1(m&F$L@&*klKTMh9Hc>_=glKp0TFk zU5mcJXDuoMLY+9*1(Z2)&h^DPqnzLqWczSnr1*p`^#kXF;6#h&%)xKacAGvbUQ7tZ z3Ti5+sT6YuXl5-_%w_QA1d}Q1@F8eF|AiD}mozP*{3ZnpzF{xjzl(S(--h9KuC}5U zCf3Hn22KY5J9sJSIL>`DgH|J|yOjNK?4a?i{4dvH;rI;lf2G3m4Aw`6VBper_I|Fc z^aBwT)e1}cO01ReHqg1BNaw-)O1mAkGvwrVzR+=db;c=_nhSMe7eA^cKtDK zNE^dV*+(z0Qk*=*%&T(P&Y0{6?XKM)$yf(=3Z!Xn2NBxH-}uIz2<$f=kj!6o;wI~s zCEN0mtD=E2ZTD)WsPEKsv#)qxPZfaDcE-rqxcy}9x&VjWAQ#}V?5bYgIDMC+iPhP) zBWcBSE!2fosg-^4vZ!+vc4X&%7wxoUyOOs7PkwW4iaZ)^OtbW&TIFm$T%%3E=M8Tc zS=kMF5Kd=b^ggwKveIxsZrp;pW+`%Z#;9&soaZs};vky)=}QT*-}PQh#wIlM1O`T1 zll{(FtMjNuNypuovyyD(iM0rLsyPpe8udOsqssbB&Oi29PVws&C#(0AL%o<#?#k=r zIVKA~0^$hOj-POSCqEu>7sDaPnZIf;vo%Cck@5O5*AD@Q(QLTOq|M?03yUPVMmY){mdrph?50$^-}JR^6~wxWeNKa$3fW^m`@nI8o0Oytgy0|O<&>F`&K zu}a<|cLfshc>4BVh|UkF1RRxZ)we3c8_ zcYzsdQA3ZQ5UnYO*Ci}hy&wVjvN)2HdIJlk764Ux7e#nRAv5?%B!7l>PCgjv z?6)abdsMz6)xNr1z((T5E;L$o^{Fd&&%OHyOBl>8=o%b*qQ6c}vn&*&-mynxUvOXT zvR?g>(bbEaBE+D+Kx*n7`V*bNE&@iv_!7t(Fc+CV9hK+GZqdC>4IO=7wf;+qf)skd z)W9;o+Kp%RLEPe*C*L)+rMJ9I%BB1*F-=;-Jn_|MOsAM3JUNd8v1kre0-b zrDj9p;%liQ@yF5T1Zg+eE?HU{m*e3$#}~(4jz-Sr+jYT@XoS1<)EF&gYX$pqESL4& zLFV=1Z5I^R=C}|7Hs*DTj5cG(CjYCkPjIM9hd!c|i)OVR@7gXY)+Z@Yt%KvAD8DG( z#0Oa2MOULVtzGx9(32;Asc=)HT*zM&p~MXD6x6=dXnRSsavcQc3?G)zzQe?{-GI1^ z97=FJC1RyWk;sk7@TuKEgLWm}btzt3fp*1}cd1-+u|*GDsc;irxT_A}DRYxuccSK4Co!)Zz;D^n&>HAw_-`%xURJ4?aHui_VN|> zuK^BoYFpF>x|G|AVwcui%^j@Teper8dspgWEg11M*!&SDUaaHK&85JVD!x~@Y{A8$ z2jL#WoYI|J^ig#@i)W#U&;k{%%lhdN?{P|0BVH!Zt*gzw)@BJh~L#lI%dEs1!JUe z)2JTc1!g0K0jYU(o+9KYe^AIuTRM7>zx{%;hnilXP#_k=8r-+u^4$A(CMUe#2)fYO zND#7s%Q8@@VWOtNNers~EDV>3MOXKvE*g~`060Y8nuM0->mCmR-q=@5b-edu*C0iF!J^^2e>dRD{9DAa8mxt#9?#vIBEeg=@CAZ zW41etKwx=&l)RN6;;n80pY#I(bLc%o%e?6|4AF<6WT&f1$ld^knZF(w9q z8_Qc-ose-KPfAP#^jGM3ABJ})x)ILKVV^M?QsmDW_IoIH)U#k0sSdJP>^536*Q_H@ zn0tufI3Uq`U|?*}$+z=KJ}kgOBfo3)v_X9qZ1Yf#cnAe@>xd%JgtMMV5Y2W(w`36Q zb2t+5amR{ZFBj`(4Th2qQuFd#aZ6>u;UJ4lRkS3OZ8+yPzxAZn)NWH-(mB=b|xKD+_8b&Po;p znnA@A4~$YGygilXigh@Y?7*BHg!*|+d&n!=he@9>_G^G#`7e81DA}kC;@%_RPBeIw zr9I{svsdVs5zy71KI)5M8a`_IFHiZ}wjFx*x z#*jBuFlqO}0p=b#vjLKe4Eu4Ey(H4Q0nfUXQv(AHa~v76ZVGl2iKD|GgD6tvo!LMw z))(bav%umopq&}vyltOq((qX2Ksh8O;Tr8nE5ou>(zyw73&U0j`{i<`)1bEv2pMcr zNf0=`ew8gU5L7mceC0%jUqgpzgL?`>F&2iw*Vpa1?)N+Snc~dw+!-*J3ykUcf_?a` z2$~EDdbTpkp&H?-m0?8vaezm18Rc-wTOm8j1-gl9)77eUF4s#A%&IudVi|k7RMdQJ zONd+2N?i8cVuGWf|xL*Hx=-mZVM!8$i)5CawTMd?MQ^_alBltsZa18gD&t-Us@<4w9-G%?6kwBz_iR6_Poa#=@kO%61O3!J3ga%)L zJ(yc^o(irjjp3iGqzdD45W>`DL&*yf6C*>FZB!P8K#8@Qlf-KkP_3B==MR&jhu&WI z7#1O=Qq0yj2q>6#*3>d<*v%GAlqKv%&kSX^&|eDx<7`LFGm;`{$)-2MVa}{Y-;BqI z^x!j9h9hYnRk{53K6YspC;p}ixHq}5_~8*k3KF2X-ZI`{nv+IzlzUfagaHJ{$>`gc zhIBhjEgu>ewLR<4)-&`59DHu#=?FJOP=;fURctUHrDLJ#4R$ z-lkZU^=Pn_xvA>>O#Rc3?DI?eq=(Up6KY-Kl42;@Q^Mwv;1@Go^g_osTs zRE``gc5vPFAe%_r3rp5k&cN-tD>!na*LNY0#LRN#4id=h!6me^c$l)${cvBq!n9li zh#fq~=xR4(|1NRYbOsK5->&iURA=~Z<#OxiTlj^2edy^pIXlb|JSyECh2yMz$c|=Q zuqS*K^KD43^ZD;az=R9(x*a64EH%7zpC_LjjW7jViE}MqTGt>>al?Xr9Z#GdtW$Md zxs0}+jj6j?qOrU=|f^^Wv>tTxa?6V!kmnd&nzQ7HXz}*5zSq{GiY=~0X_Y9`sEw&_?A?z)u6@(W4VGR3X z2X%6~*eCNW!)m3EGQAc5EI;lpPQHC8_{(_CrgKT5m(E&#A511NcQ~*Q+aZskiRRI( z$Fj4IQ&Vf0{kPG%)D}oIt%7hF@zJb0LCx-gKGP5=AWcj$n0%Q>v0(0>Q^4$}aL8b{ zz@Uzns9|ErBi?c&A*+JA` zf#;?b_P8V@t%GE!5fu=IxE+F)NrNSD7kOS|UBwR@d$BHevd9lVQYSMMCdPAy-ubdM zRwgsGgV5D>-#K$^pi&HJI)k9?X=wYS)I-*;LEnGq^#?SAa9xv}_o`iEcZRF|{b{H0 z$`j2uxb%Xwi{;fPCc;~VnAEH}zpLp0RD~4PtV`WXiZCEke+%ZoYl}=_jf&+^*9_AX zPG#S=9L#0$g0pJ?6DDTg^o-)n9pKr2*R0ka`PQGYOu0E2u&cw}AJGxzN^Nsz*k(f- zY$NbKtr~*U=)rAh)f*!t>lV=TLQ|_1iHou$0ubY~n3HOwIz9j}_68Wofy4_Rir(^v z6Gdg8qHjk783Nc8)F-vp!nDFfux`T^R0(V0Xg%~x_C?5ZI~Iq(&1CRp6AP+S5Go_` zX6i&Mj!J*4Ta$X&*dwKJh3*X0SE_SI(A~j+N2C3MpCit^{}XE7=n#F*@3r>B(TSoG z@$lGcpCN-IKGKv8qcXGOU}~^}59=hR$dza%o0^Q1L1-m_lA%}HK8=`VtB{&YqC&N2 z3G~-;gk+Gx{;950>RjR<6|^w9ZTMZH@xM|0S@ut2_Lo6oJtqDknSuVm1I_u{fCvJP zSgMA_lzFZ&SXQe(3#dbmccO8#DS{_#x5@p-NIuKJmV~~uF-BeANW--okx6c^xr#>C zPxn-=_oz&Y@hOLBhJmyKkp&+^3XARzP%_n&Vh4cG2`MtzSny2hpy1|f8a69zKKrpw zUs#R1+Fxln*5zSlu1ZEIFy9JmUfHK?eTNkh^K9c4FQ_E9^eg|II_uAPidzuP>kR9a z%t^7HrfVBZd!sye5#tqZrUW-i=yMg*l|+$R^hvqxJ>r0S9EXE;BX+FxS^=Z;qe#dx~6vIR4e|;mWIxNtiG%3LxIYc*)P#Vd-tJaXs3TmGK#8PrEXqDLmOI^9p2KGUwj8nFJGP-*y#9k?6*(WkRU z;qf)Dgj3l5K5_ zV%8Hti1{b_81~!Vv-{w&U#^x=Qi6~!MyQ`d=WBf>>tyUn_p_6!qRpsiE)^)z)})h$ zwwwBbdnJwqX>LD9&PgTwu)XOr!jy8&J#!ILeqX~U8-_*V_l>43PJDs?v!nt7kBqnb zTN}0f>%Zxv{>Pl`KUt6>RU1dF1r#4uO?MKLy?#grc7{K05`<&Kggt@%?s+b{p;`lQ zabbSOR{xj3_UpH4M3 zvB}6sLN+`vTb{D-GLJGnUAo@3QuKh`K0-Mwdp2ef;z!Pt+7& z8-k9g*&U?G;)DfGBP1Xa3zd^+BZDNdOZIOqEb7zysn?0Q=lAd3p*z>Ln&8pJQ8RlZ z$q%WH0)HBf^Dk|NYe7C@g%*R$qSOC!6RD~gRncbHOwB_5EM(FtGL@O6VqZXt){Aqj zWDZD^+~_{k?#Y-)=Bd_3SxLVF-E=BQbjDd4!$o;$RYKiMd_q^(K<)8^|M5y3nDo+3 zk;!{HU%!BRISS2L21wYnSX}rU9c>xKPp#8<_#uf;$^#rzWCtTUsG4aGQcv%}3SSVV zDDe!H4%0EFL*~DS_$rLv8ok85_k};I?z)56#q=2aN zDw8F)C9L|o#V?_t(6>?7biK2btt^s@&{>O%*&g6zEnRCmT(K|9;V9dEP^`3E6JBn48Mj7`0Q_d_WjUU;2TFmPFzT;ng9lAUK01CqQIEdtUS2^j zIUqGrn9GykzP|O-bI{mxEdozx z(R5x1H2z6CM=Q&g!a8vZfvlTWx3o5VO(X~To&?tstOp-LReP!$B5RY7VY40)#mbty zHHd0m%Yd)9Rx{U|8Rec?6W5a)Rkv)ef5G@P(*4>vw+G8sIvzf~ixfc<7gq#CcTiY7 zB0L(WTtu$h=l!lC30N_p?Df;=s~~RCf~q@>Gz;ZM;F$ zW&L{ucRJCXx7SM{=|%E5z$N$`9;J4Z9<;UWhSSw>&4tx9gvFZOU+4$UB~i5Qndz>X zE{kQIJEAu-3*F4V*e`UF)+c)R{nxPlZpFu z%Tj_5$VVcNP1ca-~v^yqT%=i!|#tv5(ZCcmd6L zgR!)Tm(~}xOg4*a>2rIK;vjoqoyA|0rQDXA%>{DfH#MQjp6MR?c_C)>j1|6@OJI7U zu_dRq%#sn?)!x>k$LBrZrkE`ibT=gO!8&g%IXV z@p_wbDGLCBew=FId2r@PLJTF3Gg=CECKLzTy#NJIV5OH`fi*xnHTYcL0QPm+-PK%Q z>`w$a;mG!a8!Zz$&igBrVE|fkzqYY9P`Nx*%f(K0yOUL11OXvS;z`!(y%{skUbDsD zuT83BOjaiELlX5{lrJui;EC#3FVl%|-aE!~D>M~pD+~6#J6FD4uO$v>aux`q=(D5d z?^%^D!2{R+{vj^<=Sgg4h+CNZrX8gN(Z*WZEx8Hg;bTt zr;ARN>8DHuDStT~4VKTDsx4+0wFg(NM(yY>i+MO6=VJa$+Z2Pei+I{4r18;P`1W(Y zhjD#L$6VPTwY5iIQQV86duDQpYK)Vr6&PRP7ez^*5XPLSTA!fCSYXd`f5Y&b$@~lT;CK0h8GyQ6lr7K1`Y|ALiWV~JBbn#d>wV) zCta%vbZR#Pj-6^#p!y+{$68aRhNha34#DCn)Vujv)n6gJ=(>o_570eaOI$D@urd&;G@tz^>%_d#b78J-ko)H-gIs)OEFwh+wtIs1-4BINp3R0( zS2prpMkbw)@>exAm8r2V-;bPBG&vPi7iGnOH|9)=)GdnFMH=*{=YG#uqk|>LFV+F4vqv?rU)mt?9JDh~*PYj6_n# zK7kG@nF?;QU(MvoP&Zl+gIK4uSh7h=LYK#8JJa4tPZej5h|w19x#_%6b1D?!oSN$_ zVrNM+uQe{~JlOc%t$WQCoHL8w7Xip*nGharzq=u|DvhMj?s#yZ+#eoZScO!QEs`do zSA7B;p*>#M14^;U3oRA@?CT4UeJa>gOXbweo638PfUS(qUeEm;BKP$Pjk4^jP5?2m z{)OO?epg6gf_8^*q;&{sNI|3#;MASuPGVXN)iMP$*Zk+Z891c}Tqy-)Mu8Qc68l#L zbmn7FJ-FzhwPFqns5c%M>k6a;19ipgFghgq6x?(9PPk>V|1A5pK=GdRV9V@r%ROos ztVVQ*U~sX(&Y&;V@ZO)eK1=KE+J|dl5e1|@luPBLS#$eBwLcYnMrK&oFMwX~qAlqx z8gP`Ts z;6Yyb5OWRo^5_N{=u})3YPsZMjlW-)dMUY^5J3y1gRI!S@Wkl-(uW3UBgjZ2*!tXp zj4c3)FTRV(=WLlc*b8n|9=#7EX4>(lA+`Y89kaGby}!9nC)6E5Pf)6kPSLV^SZu$h zT=iQZ*RVGumRNOTpNk9^uPam*Wi)e1EBCBELi3^TX%!wGa0#KqkAYw9kj${sDd zX4VrHl<3Sqk0=8g!qMDp{l3h>y6A(xfZm6go(Cx2X|B=CuBDWoxwa2rc+-2Yes?hk z@bLs~f%>|G>1Fh~cKb30@G%AX`X803O!2<`3$A@J)`o8R-piDTKYmdC`~Cb~Ua&Q= z{=eFU2~`VwEj5(SDv}q8@b(b}O}6MgRtc*y;|+>`@GirlmVNQ&GPGTFD=LeGEEVfc$}^EjrHG`r_HYdfIjo~UWq)&|76@uACEf_S-L_cx{{0scIb7_ z%yUz0pEno=^DoHvGK(_aF^O7g=SW}z>QELE51~KiPDclzSteFzP%=E#yu|U=%KGDDADKF`QVp+KKTC z9Ufx>QPSz>(t<##Ot5Nvm@Eg(=ep2YP|pKRW|vtUS6OGN3MPqEB3C@_`~P;vLKli+ zR6AJ-Q8W?q0Cko&*mGvq9+I7}z@>p0&6pBKC1CJK2v$-s!ef|cAI@6$iVtdnjuHYd zHL#k{qhln3nZyYc1rzO5V5(Z`71EVIQaE!mW~oqc%fyNQ@&)u%u6>wVJ0*kU^OFP+ z5q?n1r7{>Pd`h{{Sfo05Rz17|w0y$q4vU8;8WapAY8R8$$zC$Ev&R;rBW~CdW{P%I zUUO$L%xurcqUHe9DFh>7ro>V1ef1`#PI|tSc}9RSS?rWhxpbG2BGZc!datBV+Bl#A$D zb4nhGoovOho*_;<1wgJF-Mr}x7yVuY=N<>v1lb5&_-wq@J4U?cqHV~YMaS`mUC7`? z&&|km&-DHZ6w%@i%Ha$YgGFu%;d18Bg}-uoOIX_X`^KKf!hV!9huaID^K z9r`XuvRPf3MLZ<2u`1&9!}bdGO}uDLvf>-^B7uu0vq#RdP0xiH=d&bFO6rDW9znl z-wHW2W-n25`BSZx2C+j$S8XHqV`V1p=#By!nt`7bUTeY31)0Qt`J0c}$o5Kj=6)iM z7W?}QiLifEktF(B93!qP`N)kSw(F_2mCM7z!UgG!Afz5jg0MX2?k@9ZV(Q*q^|+Ym z$z8$^z14MMFE+3B>8}FDXRsY@k{?Wa0p=osck?p5l(L7A8=!#=RFJ<+AYBh3%|Zzv zKLom{#F}kKue1aQDxYynK0!FLskiSAU*4Bh{9|}B_A&}O_N^dv{kYs-Se~`mEp~(* zvqR<_2$pLjN1^M<_r0Rg%^b+GryLP~UWtI`ntHM$h0npJ3|+93=c+$d1vQkVK9Cr; zOE0R0t8?8|WRYmJE%s{ajK6X+@QN)uid4MaR=i2pUg|+x$uOLug*y0E=usQ;#G3KQ z$3JXqs(%brNcF3eo@IzsY`8C8##iuYs5)el+kSd3*3h}3r0;RRecbwpwbhZ7G-%tp zF4%E~l<9k~skmiRARTSJD0O4lX9+n=b^lq+)PD2+D4sgvwxLV;I%1)b|Du12YIV)O;h z=#4h`h6fjIE5r{EKN_z#!8Z`}Jr(B>i90CgR^*E*v*+8jJeqOQK-Gipby*7mSN$W? zg3;%Yx&q*m%mK~BW#Wb!a{XfniaYq{B=)@lLO>?Ri3H*=z@cKxM)+vc4$8(Z<{~7V zolxkh=97S|m*6PWPL;Ad-Yeh8n@EN4Qu|lD!&i9RS31L2@XTlO%Nx$!C-~t<%=lYQ z+E5pLfUn8s*I@fsmirgk-6!4Q2j<-;T()UZ7J?y)JKp4x_p@)JE3X+q=aK(X^-k}K zG0mE$IkG!yQc*4Q8d=-H2V0fQS2VAbratv)`WCbp47##V>yVk1`9SHXJTH+Fa}_XCUL56oZyBh zH9n#?E>!lT{8>0%5mX%QxQrWr)Qv-~+`edz#a_qg&!5>nvuAL>!mqfm!LNvAH>oer z6JNZKtCBB+SKrXjr+2bYDb+iD7OVp{ud2pOHhuWYKi z!n^d$4j?`Zs`dyAx3I3#EUq-Thty*yzpwAOr|;+{XhzZ1T_ItWysUjdGe}y=-Rwrq zh9hrzU-AAK(aWg&6N^Lt__2ic-yAdknc4ambx)C+yPNU?%GX93F&##5><>r+0Yn5N zMx;=npGiM6e*Ebnt|vAmuob!$2MbPPzYG4+sPac@;|a9PnXOUAN*NtdzQ1T$^GvtW zxx5YKqu}e|Y^dZT>uIxHLa^WbWw^uao7k%8a=i4O@@_E0``z+98=$G393c3v7(B+J zy(19Z061XR4k|Zk77eyy(Jt9}wO-%uVP8M)k!jWl)(Uh#W4G?MVYGhg4#4SsPLgl3 zY9~K6M(``f8Rd*@pFAoEtfceB9bP#Ws+0+l8IeIJ&k#lohRP38E!=U^HSgOpv#KL1S)A{3BqwjWQ`b`rRb5-dWvR-EU zOazpRh8lHy=mL3#71fgMc!D|}>?nIH_W=ZaCS)o~;l2q`Qz^%$FzgtLAzjX@iwqN% zlN-0cN=-uYy!}fggn1m6^~9}h1q?!%j;nnmCi$K#@9-svqbHjdn3S;d5n$9y*JN~`k*R2BGdly0&k=$LsnFti%r+WA>=mwHebj_P zuIFm0bC}R4I3}X?ktBQFO%-IuPD!9+oPz#PJg5w#*qhc2U+%EJ54)i4$087P?l+9O zH@hnBhXY&oH5D_f^tveq1-+4Wa=B=B+gF&I_q%w62i*P4?Id?={vlv_n+TRI@>ftQ zbn~8qG$^Mzf|UrT-eC0?*O_iNKY8yBp&N^Vc(E&Y7sYh%w~b(P+-@j%?{@W`Gtv6h z@%IMg9AbaLrqLaaH-Y3}d0AY?^*n(VMS{vfiJaIp+%)4RESS`&Gm{>A6U_P!zPT1U zQpC*eUU<^MR)7h`fJTv@(Yrp&ObG6X^u+y$CA33FnfhOZy;G1VQMaXAyKLLG?b>DA zwr$(CZQHhO+x9M3-RgTH&b|Fd^y!Gqd{`?oA2a5fW6W<1M)VGc1ruhQRKA@o!Mb<5 zDPFhnqLN^ns6=`3d38=G^~RszI%rWyq3qJ5xvLn~nx8~l>wsU$V<0?=4w4i0+9nzY zLfVj|JcK$&=yB7k?uLAD_=X-x#|@)>NT`ycSZA_ZQ^Xn_Wi;djd11ST>0g@|<>thR|fk7KVszfs1TR zU#1rH?9wC&tF43#LMnzH7>g%GS8ZGM90(7`*M#oVcq?&N3t;H(G|QC*V$qsU6s6v4 z4hMUD*YjmEXVy3RU^;NH6@)u6l>?iyokH|%%klouws|Rc?)jui+Enea$Lq59-DAuC zh3$oRcq4css!38Gy)&!=mZ}(5qEn(m>9pfK7nnh{O&;V5v`k^(V~|#tj!7ew8Oz~b zOzIv}>&8m&jC-zYSG5{vabB5Ac}r^QYZ|o7w!cyfWYyeJ$U(f;*_APR1Iur>6VXT+ zJ<6VZtM8jWPKPoem*$}*H>whBKcyjM4>_(seJjjw*SPo{Gk$9K^B6nc27 z^dSog9y@A7$CS~BwtVY^Wir>*ux&4F#Xcnz^R^T>?MqgiYRAE80h!JkE)j15x#1o4 z;}y+DDN!u1@xPG4Li}CKXg<+N9uyzt#DZ+i#0NZ)FZuw0WN-g`IZW$DZ}li}WgFqs z-yfu-OdKPT@``wizy2y|F7V=94oDJd4u~lq>UT2P9qm$OS~br-<=~xdtat1%Jmbb< za6v9XT?;!uT08c0O@!I$Vz!fx6e)P29{I5{`NY<6x`BTxkxx9$W4on)I^j5*=7R1f zAY<~@LeOr$@k8kiN8}?&OoKlQo|RC_5l~#le?Vz5gbWXt=v&ZYqzV^51@-9tE+Wnr zrAoR+-siT&fp%CGdcVWKdO=) zEQ`GWM$@(T03s@;#;t^uO*SaC&J4M#s}6GA=BbCdE!jS0|CTEpEBb&gOK4364Xc!# zc#+$MRY1v2Didb)pTJ1Yl3!++Atuc|;5|q-JOwu0JUUhs1-SWqpkIbYG z%e-f{*$;eI>H1adZLj2Pw(=kBODTuDmppPS27pNMy~gmf1=G+0!IcvMfy;p<<5P1f ziQH6v=kuc}&})tH1j<7O3J@Q4ea6i*!lQ9ZF>4FS`BlwzeDG_ViY86pb%!AbUrEFH zlZX78M?_J(vyO!N18nhpd4`@v$InNNxC0977X5FHHZ{y)i(8s)L~I)sZQty?rweH} z#(bm?9oo`sT{{nE8a`HtbrBnJCvBeK^js2aDZ?#%dmZ`Jt1bQ7(TzB+@~655HB>7S zEsv~CMqcGeXh4oI6=>fcPFg07@mAen%B4N!$1?Y*vP`$uiCmRhRQRME7`-{Nuf|HO}J3ivNB34ykiU7 z*7+j6UOuA&qAI*!^d_ihKroWnb3-+0XXLIZy4@xy0+RO9#i`-@&zvt9hBH!z!bvYF zOR*KJ&c(Bg8fF|T7=|e&4~!CB#pv+tM)M7s3qf5h@O2aQr!%BeCf=}O?-2JmZg-u>bSSM1~ zD|89kbcaFQU{dQUYWgm#8rWXX+;HFyq^}NAPycicZ`&SvcLfHzp@qKsrw_|cQhb(i zW8#%@yvl*x#cM>wE<1P?sO%{=W9F8_&Rp8ZrFiGF9!Me?nj-G276#$qi!EvSNqlRI z8EFs5*db7~YK(7=9sTC7v~TVeEHOH?#&^zF#p#L#mr1iKG%5#~X_>2z-H$a|xOvIg z->V8N-}S!3MQ9H{%xXd2@uik5S*RtcQt6hu{88SV&67f%gIgd;G^TwI;dW!RJ}ysC z8|syu`bz!&kIX~2J#F702mpXO1ONbv|EVAM|5oGt4i5V6|J6s2R<*WMQpNC@x#{*y zoIXKfMR#cw$DgZ%2zoGvA|NHs9}1bn3<7LEF>w_~W$ipS36#@3r!QmTJZvrOiz08D zhQkQf2s5)dcQuu``QjC{KO0x)NQdPZSL|qHQ`E72UaG>IFqi5`q~u?#>9tjj zwOkK$p~#o5n0;t@8>}i|=OMhf!ib-jPsF@vRhmaYXnx1CC0@CzNa5z*} z5QO^0uR#qJ8YKnBYm;-XuyW@_TB`DZfEr3OGp3wa(>bTYmj)GGLP`f|fWWQ9gt zKHfh->IlIsg!Jo-b?(_~r8Vl($Br5(Ad)tR$E}8Fj%Hr;>DFA?<1@&M9MwC15CU$+ zjJBA;VUJ55!k1Q>gyfI2>XZpdgNnl>7qJC^=izUL|AIem>F$9rPL+FQM zR}CJ(ujH){kO{gW#|GaKI8jh%hguVOA$Jz7BMI6=*?5T?=KWeZQnH2mYmXAgk{nYrR6d6UDn{Q=bm}m}^P7p@yC%S*6 zQeScc#~Z^0ptgk`iNt)cgi|4^Ci|}7dbfsYHPPzgdX!2AKKq8-#Jo?K=jRockooz^ z8HLhFu0M+QBXfXkztU-T?c>(LYJ_DOV$?K1i()^1d#5awrPGkx1ZJHC6;#}+ON^IV zHN>5^a5W;ds|Pgpu{=lD)S%q0z8m7Q$JD;u7Cr|WH*xb5<{bdb)v+5M3$GXw9;HCz zl;H2RC>KNu;EXa&&5=M3i@q%O5wx+bq`9!aJ2iui42}i!1IlD2GNY%RjljBU1-%5q z+!s=Z!4tiaJfE!ZxE#Ytq=AN>fMapiCX2(i{PdiP(<-73$9dP97f~%uBvMA-4=$dt z^#$E44=9zG4Fv2S$B@)-!VBerPNCV(>j!u$7gq{O~`$F)k4TipSaf#(ufIa*EwZ++jUt8d2_5MiC1 zYSuTDfIX0rCLS^3q;>ds5Z%PXihf|ku|L{mP0zy$dJNPz`+OD4H!N=K-zvz_=EAOX z$&o_#4Dm#nY)+p@9^9n*Qv(!T4W5yHVMZu9}DE$-a#A;W@wQu_}(>H)gqAv@Fc z;?tC=*t)6s#%UUTZYf(&U)&d?_Z!O5Jqz~8s`~}jD`8LgB6~QQJ>>3i>m78j&Oqxu z=ga|PP9I;}18NCR?Wuk1ze;`x%Xxm=jHJa8Gjn2C&S9vZ*6q7gd9wKTwr@HdGN0>b z2jCimd<|Srw3ll2A}Gn!%&eD&)IjB!OzLaQ4c{52Zh_N{7x1$W^1(&n5S6b6_?WI&Fhu<3@m?*_=1Du zzux|Gy2MMlsLJD*v6YxAvilX_%(c9#<50w!LeMQE>NwGk)qMQJ;vqZjD`@id+SKNU zw@p)GRT!TfcSDQ25}lGbp@X7z$7=Ho>hq)$5Qixu5ZKNl@&g~2z{d=?l_?q@i4M#5f*cK zmXw7~mGmiH?^WmG@&1L;1@>NHLKoNAt&_nQJPrLXvca8Esvt2i_ zy5zsl)k$kZ)F(5zkELrKmNCPAD7`9FD9dGYENIhu&x(LOo|6>~h`9=%P3w6z_^h}) z`r+wtzd64Phit7ct11apYa+#bw@@u zsZo9kO?UL`+Xi@U8@RO%*V}06gsde?dn7d6w8h-R=SM!aC5u-ZD^i1}@|~bUnx>1N zPGoA!lm@#(6pCx~!xfHi`^etLQ;RL{Qro0~M?MuMFK6>wl2KdkOBYYu_%C*uZ3=WS zlFS;EKwcy0;gyRqZ#Zk-wnIa>Wesr0&@Tm~MunqfgVS83qK>Umi(Eo=m)URj5?6&^ zl+m;osXI6eGzFcYe?Z81{Cqn>^f>-JD3?>pkJ<-TPynJo1E7wM*oed|6oRok5T2s? z>Hkrqk+ntJn|-B8Xc3=3cSA+-bknW4ekV+-IE=m9d2n4}(#pu1d^s&Mf23v0sJA<7 z%O(9Rry0nsvaS)kz$|(tRdMzLrY0RnpjMV|D)+EDXwzgdsI*vc8FqG}cCJNiPcg~G z=Gg!p4%-x4YFrKjdFA;oj9(Q_LREHlyymY77rwp;)>|mJd&_L-Xg(vP*CxR`oZXue zlp2lolzk}95J-tLMOb4B+`z*pUu~j9Tp4juqpJJ)k5VpJtf|}e*Dg5ui?;obDB}OU zu`2BL8zJEM-;Ri3b$2hURr?$;>Nfmendlx-Jd%^zAAnq;NJ^MkSQA+sgB4D==t#`L zLU1S|1O^bgEsp%uY=N^Pv&|W6RXVFsW;@Wna7BSiULk42hPKr_LB~F(<@cu}t;M36 zs3T8Py4$5qjT%ZkF;4duXuI2$&GtCmmG0iSSE~CqwkWhjWAhRp`7Kl2t9p*-byPC@ zac1JtgB+>5w;##v6&^~*bjbH`CrkO&7|ZO@6NOt^dv~XttV3Qb@s8R1jfTe~tot$_ z`2>^mMK#+quC@CxFZpCUc-+dRzYFo%}s0TKxn>_Z64>Gd}2h zf49r4A^lUh@bi8q>J%RO^SChC<)&V&s`Os33f~0&2V`J4@R#Jjzn?FJLdn<7om4S! zT3B5G-4`?>$l+MKmmh#Z>0YKF+)QZ!{Hy#3$X-W@o}50r^DlQQ)~}}_a23GOp?etc zrbzw0UHaZ0bcK<=!okKtB_0Tva3w{06d~5XiX2+(z^XwF@Jg^Yaxxf2u5Dwa+P^Q) zq3Jr93EQxwqkt{Bq1CwuNTeYD?ARwrtRyy_K2iipo@nk550}@uGbxglxrT_nJt$s? zdeZhJ{daSMqARknc6W3XqdnNAlCqDv#mB-uPL+XFR$jwhXyfK}i%wVNhbH9=D~Hk^ zN%}5%{Hw^A%7bavO~u?leRco(}8&*Sn7%BU4-`$_diT z`R(?jwB#MM?}(L&kxnulo1jcrLaDTHz$XusI-JI^gyi~S6W8&;DfLn zeR0J=`&T^Cr1KJd*OJI(^{4$8`>Z4AnbfMT5@p!zYXL1Ht8JVa*lwFQr?+T1*^uF^ z&TF%kD1%))f(Y=a!u zb$fm}NkaH`{O|bA88TYVLi^R{d~P&b3fS^~Y{Iu1p$RlTYNT=>ko89!<}Q*TW36ru zoWQC(u4U>npoj4{ zE&t|Y%6l!eXRY9x+)$X<)^Q>ztSdF6sq$^Vm(eO&9Skc`qMkJ=BaRA{JUs-YPN-1Q zI65p_@oecK=&q1(*Ade$qgrNK)Ha;q7UJ|fU?e0^y(|iq^j2d1kQ67bIES65ea1-K zPz)D4B1>uKr)o=}?SdIQLnQK&(}~AFH3i04O}4;w9YNBzM{{xZSk<{b(UI@ zbWN~NV`OZ%nvi>LpCLF~V;}v}#in50*0H6CKle;vJH4+~t&xBMxRtCvO*J}O*{DnIUNd7TNQIY{35l6Z)Oe*aJ4&1jfz?hyP?%1|j z9*j#g$!uN(9~*eC#$8dm#uk?AFd3%u{b{)@lzMieA4zJ1$TQWbEO*&#(L$+H7;asl zisW6uKbNtuM44`ptc{1Joec7F3Q4PR%2b-Dc^t1>0!lkj^>;SQ zqp}JyV~rM+*&{>7(kVx#^1wuTi;&gQ0L;_+5XIYDl)5;USg{dd(CH;_tvsAyr?CTo zTmwO{6``JIFate5)^YA?;S4ElzBH{%If%uJH{V6+glv3yW;?!mEN3eq_I9W1z+ZNt z0EGnm#A5%SCeh!vc~(1jD74;fxO@r0jLSXzy8vgh3pGanFh;r|OkYj^lq`73^UyI~>CaZ`X6MV8H zQ8rqqC=TMdFK!Ax;~vv8F{QY@=}RW9i5x76)&0K0N5$YZQj3lCY6ZwJ;}Vsz@oG~m zBz^*oUHFiXw>~F6mf0k8m=5#PLQ0~)!0HgOIr<+xNuoSgjx$aEP@E_0JX_bf!n{%J zC-yT4ux_j;OPnX%xkOkG$R{1JZn!5L*mvi=7p^m)JUGrXF8?fY41TM5GRforb=Qgd}V#*uCBTfyB@8=YWbC@K;;1m9BaS~!* z(Vo9GUzGvVH;u$H4{&=%ceU$rf^|&M^~*<%O?OjEgG?)X1w; zl!~BWI*Y~s7z}$y zg3YQt!|9WDKuuilV-mSaV2Y7!&9c9uLNv{OzQK8lYfePyq#o)ONq)L~stbO#c4Kr^ zyyJKXOY~nzX0AAoSk=hm)zj@ z4PN+KB`3<|Pye8fIbgb*-WB_~>Yq_*`)obmjyo%a?-s>f|Kk>DihHFY7(4H2+(xtJ zqgD5LHeBBW$ArfGOwi{>_rVI_<9G^ol?}JfwQGF)iF4&8^xkvC_@?BcwdEGhO_xYY ztBA8jM@zulAbQ8o#fTe9$a^F6+O6{!P78y1_HVcetezAnTM!ewD2(J1_^FAuDvdu+ z?AbS9@_cGpaL<+4m(1pp%;Xa4(9i9FG_B~J(}syNXTYd*!4zoqT_}+bKvN~I{Gh$# zJoJ&n9>9I$g}MbMTub1rXG}(FS@Bm<^F}2w)~{pu zPrbdr%B`t5PY%>lM{mPEb#=K;r_iMZk7ScixDB@?Rt|<~$sEVS3uS`2bRnQY_{NRN z4M3av2B%$XZt-5FLG2FlshuqjW?<`rNE0yF@uN)C=h1U1ynWY-J&c_%63k%h9B@|<4qE-`COO`&|IqC|*3ZYtZV&7|M8pYmjP{IpARd!M%8H4Aa9bKXO!@M>#uwmh(0VMWi&Ufyw zdTQ78-zAXXw;S0j@E4V9rStOCbI_<}=wPQ^#FO>kqT6B z!X-|$awQqo+=&`hn675>n?#y8nIZh@)`-a3Y^)X zr)hV;1PEeMxj3aR4%`E5wE|i$V{raB=?oJp^A->e!z!7!^Xmff_iL4dFta|8k^Xg{a5Om;6sN`F zC;2LOyTjBC0{5+dxAvR8qvx}apPpO$yNs0gY_)1^;55bXA5J6fQesrxqbZsM%Oc!S%f z8jiKgoJ(o0hMS4Vp96kB}#O&c~n&REW9~_ya!f3I4arB z9BgOr4>?Qms4{^_A(&llQ+GZk98p&^ZZL$=+J)Hitob#zg0%e&2oN6E_LgyUO+MgXqrFU z6RJl{fO^Myk^TvYRKnq;t)qX;g>IX^oh_;uUJ2^5lG(q{C3~ZCHl%r>lC~=6@`dI^ z=lVv*#7x#i+USEM_eH+pzkUCQE2{Jn)Lriv;)efgist&CbeR7>yc7Q-Sgg&R%w3HC zd+EQFnQnFnx5VWJrc(3765n$`5WsS!zv7#E##9Rngu$qh#_h;P%Ho?%zyb;lb>Wa< z5g&k*l$m)V#rR=C_>hzbA)R@zcHK9#mx{OEyvG%*T#nzx=88F!A3du+rY1A#Z?ox+ zGgDdVU9YvHumFAdUIUO&`^8G&gOkuY`gav5to@cMSc9)plT`_d&b8v5Yah8HxT zwwn6r*rpdapg;Y4K`0aZ+9f-Ncf5gc=w4%cM4-OLcfaiQsk?Fv-bMl0*DXL@`tO8( zU&hx7NS-}glh+NvpW!36^144g#&NS|o#0fLQ3b4Q&=qqRkj4YFW9n`7Dy>rwn z>k(dVQC(0|diF$qK2TWDH)u#|wXsC5_Ql-@Q+)(QQzrC2J^Vm^Xiz5ffxNVSInYyj z^pU(Eeu}_-=n3>BCUpG~$7yy%{`)s?B<<(NEto`YX>hgZxQ(q1S&W-|cY$MYR#E3^ ztyKZl_|;=eO3Y(tkig<)ri#i(y1(?%4{U7+j27IyFRyo>oUVEel{1n=>nz_MsV{)4 zeS_ZCbI2Ko5Qw%0eN4MZ57bVow6N{o{IR>D8%iHuH-1^$(u{(Z7hjK&8K2*zwVh=g zdvI@;1JS~~sk6F9UQ2BDISM*P;!M@aTDQ(L+7WTdd0YYtVQgj)ZJFCOah?AEc!BaQ zHKWZDr7sbDWs>(3N0Vi8v@~=k6k8Yd+eXBypPApZ^6mUmIB4$Elo`IN#C25%%~Z#N z=|}7>vR_3oE4-)o<%SdDItjPd&S0a+M9h7*o{%n1IxYo^{wz#zP!1l_RpiLEx9x0W zE66gg4>saMzavEw6s?AgrH!;_G#e^8Jy&`Y@Cm&AGz3%hxbyxH>L!m~C+j9vK!yn7 z+R8_hp;I0oij^l;&IhxNF;RR1J<7*{w*~6khM5YES@H1+?79dJBEi*mEk&W2U>lFj zgC~B&ZJyiN>=>*R_>mpeJilfP=&1hfezy=Uc(UD^4YDf(vdnv1#QfCn$b{0`sdHLi z2^WzovYg%R>?$#200tzTvMtxs+)0kLgkkhn5vp)u8{DTxW6{heArG=cXH`s|C@&%Wdb~W+ydgkYa&-ii52A+t*w) za%~AYouAh~BY&wru^|T9&P5}N)UmwAx3PEXq^JJ&M1ExP@UGBo0~xRLUc~=JTfN>K z6vcmezR4{L?8o z+24;ZZuCCGWZLnPERn1>hA+FaPuUCqQSX;IoK@QwZI>9p`$V-i)v4z92PClT7XC6} zowtF!E_s$Q3W~zr3{45SEmqbQfwsib97`5iYXGbnnNHpgLq|X+4xS&mD+#3y8Vk8A z>o}zmP#q#(pdY1bN204B+T%i;vJH|4QYT!M!i{CNDWjhSy5^Xp*6_kZB~NugdcG0O z0jqSp)Hx6kOfM3{R_Tt^O~hXi_|BwDxc~Qv5ny@G3Sv9Tg{&3on!u>&l@(mST&XI0 zLO*<}vn54(V>7mxn9^pMZxs?WV|NnleFLJO%0_oITlpAzawH$Hsylu5fa;)g2oAOSd1KH*YWSH7;Niy=l({#FhS;UXjZ_H6RurW4EwPw4Xfo+8ExjF7_DL(1MRQ zi2g{n*w*Qy_X|hh`_|{#*^o8IJLr!udoAPPA-FLP=}|A4Bo2PAcjeSj5uO6=)mZ7% zFtu(4MD!Y%moh91J@Md(M3h$qs#-B1X7WL*SAt^ z8unWj8M*{krLsar9!YC+2(G=hih{P($HW=^=uup`cSL1-x(;X1cZ`rQqVpmkPq~?` zr^NMoN}TSlp^PZg;sOXx)M&I+4$>W+fp7A_xbua1(c4yJg?E44q^c|_^AbZN;g9Sx zxOh!Sh$1nrlRJi&LZVh=8>!+fZ8HaUmf~Pd1uo8d_&O3cM#WL%q!Lnro4d1E^Zvb$ z`bx%Fk2x7e0+IEKo)QDm@+Dh>sIr(&G68c+@RED!kRx@I(Z?((%u<>~P0708K^j5n zQaNaa^pbc)-8|;xteLh>H+6Jj4MnsvmiURLd0}OJ6epc#4QpJr%$iF2E5D$n_4(_% zMksXoO^jlOoYo4W9h=8_O{7SLySYUoS5axTN&$A^~{dG_VvpYjHZ7>kEqmyT9lm0maxqUYm{vQ-zQU2&BF{$`xT~U3s)8W1UG-ikrD8Xh-GOn#(Ywa6^`a7O{8n!xXmw zES61|u!d?dvFv<0SX7p8OIc@=&RPRC(=54Vh?en)T$@|ap^6Z2fKqTlWE$$}XJGzUeNCYoG0d3ErSqdjCl>D4VBVB?uWMg!w)Nt9NS$UUUx(%_GIid9 zc)Hji%QTASt0F)A8#o6Wtrv5_JJmV!gl`br^ms+^5Cr;727}@c7j#;WN}ZpkKS46~ z;;D*vquHXl_gJI8=P^Q#x(&TXy!GQj6y1jihm&)eeN}f;KTzFE8?r?(vP$^J2+=X8 zJms&>j)pl0rSrrOo~e%ks)rJ?=b;5|Y0pqKT5JbL8~Ab0xaL1e5J9yMP!nK!Pw57t zI;iPJ^BJ}}DBi`tp^3ZwCN5Tp)fH?FBHeL};7oN5UW`Lw1(Go8(v*?`)8HGRZgM?q zq)LTqMvJ~^~x*gbcHjh=ue)!_}z-`hFJ-HV}Np&d$Z=n|b@fT!vztOMNfi+FP5QFv40!Hxfq&zrc}Ye04)dP3Z;nO5((KYN94$&`ewk3M`96+DTJak;eFzm z7%B!X8&mS+;R5Esys3<+rPGAQA)B5S6)pAhi;@MZ9A z@#8i)Be1i`(~8t^A^Of6U4jVC4+M|cbsH4d${(aHTkD^`S_IcVzvgba-RkUp(Q0yUq7Z}(f1a-fwJ#tT|^6Q_K zy-;=#z5(-B2A!Z>JtUt9$9qSs5jr~vpYX{$s*TOoHk95G&wH$`m|gKw_ju}M!I>76 z8xmD@i5o{e5DujELO=vJKWcX(c{s#mftK<)!@6kP*3xi`d!Wsx3)Xye0fW+*NeJ}a)Mxt2iOqOXS;m%c;f5MiyjO$4+f4}sL&JOU!gugfLzVQ9x#}@*~($vF0}%N$#cP_Ep2xi@RNA}z6z*gC+NyB~!4&v1#(x}rNNlH%gV^!R+a zTo#qc`8tTdo(gj#0kvD76b~R`I?gKGzglJ$0 zxTGHYcJ`bq5j*VucgXW-rQuBTB=7s&15iS|AwmQ?lv!>p`&dKjZjJ0%x5z+tRQq7V z_*MvlcCq9mfkAMQj(6_z0kx3|-2AUZ@*%ll2(QiTXukNLk!A4sB9Th+6r4yc;S2+` z73WeTk@5##m^fslb3eok@>M8_(Pu7TJhx!R8r_?DIxJo`MiN(wq}O5y5vs6cu#q%R^E6|d#YAO`|b7Wtrb7R zg!_U1`+?$62paY^%`@($tYaE<0aQkmptRrYaU7FKbvZIx;8r_-(ItOX<^jNYV1j*r z$zd%uf|GvAfmOL5QU*L56rVOt=0VbWfEM@|Ip0ojg(GmqBQOiCe1-IP0(WM^+Em&V9sy)woM41SxJ=6Mxf^kUZNUC|tnvod;7U3kzI{tOWi2iJ2+t=zLEn?R54yq=kX$ z@B9vEU`?i2B^mk)ji@FdkFlu2DVtdSud4?w6Z+)>J{sds?RGD9DQjKS&hLgJOgPD` zYxI=G%mxm4*Lcy|Q0n?WR|ZH=q|)yZo@Fwd0=5&~52%o0J#5J<7wX4~LY^ug1Vm;@ z>ipMI(T|DTU!PL=4Kk%;pIHb@?-nSF4$hh|#`Y+SLoO(aL@eJZr<4}0ik-O{NgIs| z@5No8Aqr%#DqqM<<;U_|nH%j51`UqG$Uv@<8g%Q%-N=C>sLdJ;lNJ=9(iVKfw3fx_ zQ|9tiB%M`B27B^vsGU`b2K1`Or5nb{$bs%O7STqjEDF$FG#0@|t;NH7K9RqUJZlMP zuZz@k7j>NBzS@6W>&Di|fhNtl`l-qC(5PiprW?lE$bo(nvkj9Kb?xz?#H^3Vb_ zy`_YVRr*9vM3!cMBG+JH4)h~%xCroZ{f7_#Yn7e=2i}rh_bV90*51h?3)WMG15TM7Y5;4quv~*&5i|Cmr-L zL;#7-Q|yfRAFvMxxRRq{mr@@BtAx4Mi*&^%4uP>tdJ)syi&IYWC}EW~PZ~4`HM^)w zCuww65lK{QDv zT7m!fRVhM=6!V6V? z2^X5h;2&)8a|a075zun?8(|w7U8P77=1d2J-N_wX zM<^2;Pwl|OFTMf{2>^ik|JtTC(l@X&{{KO<|EoXStZJ!Z91FtnDgSjbK0G?%=i7c+WUt+MmErlpW9C)jbBM$ z1vVVNf`Kg52tbtqPY4pqfrw_6nqzWo-xx>zE$VV?97nU~==e$lp3XoXcJ;Wf=r9@o z;!e9AEp_mvX#Mu`l^>pOC^mrk#}J1PVJ%a3wzPWqNp3-EcowsTz|PHWMB_|GO@+|d z#k3*CTKd$qb5UgDLPgPos#`q(?SaXizLW?O@lM~UX zs7QI;DN<|4EyPz3H_PCJ@z=L5X(b@Z7LK^wY?j6eZ}FyC1uj4`mqLDgb~o>lsWow` z?8SRU|GBJqMd0H$;=3W%z6gWT4LV5RsbYUOw;TtorbRLaD*S!zognT1f6quAN48McsB> za^Y+2b77loG)H6i`gNy|naU~8X|ZGFdtSc;31uXicqS=UOM2d#i}gZ1&$Hk@#~&a} z_9iN07LLt{3?!22iYUa0VzyIXDU(pP^j|f}3k~ut$C?=UlVfvi1C83_nkd-fAiIP* z7bO)Gz3Y>+X};Q8+Ul%dsxbFFEw3j%DcJ-$CfF50AeVEh^Wano*~JXnw$$wF9%vsd zWiWXsK1Z8nqsIXTY_!VDWdvJdBIIohh{Z)*kAOR51->UlRFFNu47|6GPB3h2odJ9G zz7jr1v^7RI^bV^Fb>PzB111Z0ztxQ?sP(R;@6cGw8L%48_6u=}i{KOXHsmfRtDDaL z6PHck6#x&iDHX@7{JapJcLYzMEsP3Ko6AshbQ+$wAMf~F(rW6sjFx3c$aRs|MXbP0>;0vTp3cLi7QV7-G{9N1_3Z%C|w5t9UG7O2DHc+{ppu^iwc#h%ys+d#cqrQUBL(BYxi<*DM`d34p^t^J`uL2Pe}dkE|kbO+$M5m)>!o8oL)=@vrO zZEK}FoU?}~5njPzG_yzUMPgGBH(ueuEEbf!XjT{0J@4|DWyt!^Wj-uh3YrBQD5n_F z@?&(sPXzf;q@XWi8XQru90fPR36$*HY#~i?(~h}mq^1jls=XbAnsCG>ZQ6~(h=2&+ zLWM9o@vu0aBr@W6P1^UcA$PcqY=t|p$UUw?kXPg<-|cn3PmCDvyF+FRacd~hvKQv- z92!Df0$bPz{O-0`?gPTqMx>`!WOpMRhge?}M0Y3|%FR#CzcA_U8_)ZoxwyQVICxz- znhuCx(C?>rXz=LguYesb(9?}0@4Uy)90qu#mxX1c?!hneqKXKbR33H_sF&e_?{fKa zD->`V+DS1=bj8Fw5^jK%WsCCO8gbYd8N35upyKv>J5Kv8?RLZ0(RR1|Xp?uYaZh{K zFmYrMZy*9Wghi1gahnnU>w2*Y*is3iE`HY@Qx+aGbsm}h;~kPWYcThRhPIBkOKY~1 z{R8|VF7a0NsIc8ng3MNcjUExfmw%WMR5 zMQH&J)tcttX~qB;jiy3BZv={l5q>=18$i%S>x^>7z^|}L-OVHYlpGynh$$uxg`jMc zzf9<(lWBsms5L~9B*UtB+8hIJVm8EuZ-kESsT>?w1C37Gu^?WF5SRPra0W?>$eHm6 zSDXv}r^ zyNR?bS?CWfFh5~D{=jT#xI^pFjjp0Utfu4G#yzvC@7Ts)ww^z7S>fL{80{J^^vc@W z>H*?0V(}RW@sd8WjSrATTu#Pt35TFzB>%GJgx~&%wssp`Xh!U7j3_x&&rcXf*^_Qw zKSu2XpL33+$uK@TZ{Wz)Kc+HA4JU-mLt3LOA5eu5=M~D2Mh5tDmN+FJT#-MML<^0{ zQfQ*UMipKBGCEHhVqaBXEa`pG4x&CFp*awe+{;g(Rl`RR$5jlq_a z9nxt@VrKJJ)u9Ow8&+GpUnW$0`&b~_p~#K(!=A|}?hEbyiGodwUE^}#?&xIO3y{g3 zgH4UyL9*8uA6(QxW!sCO&K;3WjmrTmZVxFKN>@}S-s4@fOxKJI>G14N88_6*ktV2jnda5$3BoTh)fnstB04fcIJz{YGpo{!q&mPo zJlGLqW`*ohXlpCVF`9w-t7BM$;onz6i1IT z?>0=#z$800C219pH1hv&_6|UrM9aEp+qP}nwr$(CZQHhOP21hmw%t8#du|`Sd-slW z-`Vf|5v$^l6_Hi7Dl-=nU(O6e8l^H6l?8{bhG%)io~NmIj@YWQY*4weKx~D9jC6U> z;8+Td)7Q?=%wff}r2Hu!1nYa;2f;2MEy}%u0Nlt@%`6Y+;tHZAEaVHrp6@P&q&(6H zBH9ebnN!pfu4@>sX)P&nCd#!%(e82yLz{l7A))Nu%IrDhte+T%E_xDFir1oo*=D!o zGZxC2vu4U?WTx*N;hAT*6gIAGFt*d>S@YOAA8^C8`LOsX8cGjwXW{TuTiv28#ACw|Wb+oL zGIa|ma-2bV5aADc9qdS!cJZHSXlLO>vC+Cz%d&nN&!-E68afw0@>)n)Y|+XLD42dL z5cP1J(w-Ds-t%(i9iBd-z{|pJ%1CS&;zxNxU#kc_FhQuk!5W+;2Iw}iC{k|HZVYpA zTp&Z86t9uPGruslBW6vVYF3+U#webaol&TVfU1N(hyblIZ#})eUtCr6g+Ai9O86?XQhJ&BpBg8CMa>>d+p~fUra_iuJbyUN) zIx*3z3ZK4EIP`=ra-~F0Y1FwIeOSeVj*QZ*k3a)mZCtY-K|z?Ci^aw1P^di&FKYzHj>XQ&68w2zPv2uX zvgMoCM}Mf)=OHl6e~=N2ZvWg%uOq_yVc(V9uR;)gcDVtL+`4sLOm4$V* zs9{;q698+vstcHQwos$#;XfgQ8(pf`yNe&_3W94ZUukN2A z+48KPF#M;n;OB&iTH7Glhar*r4Emwb#8-k$_R5mt<}_%wkfXw+f}_P7QU$)1`~0{0 zW{K#bL9)=qwb(B6vP6HO|5om+zuLq8G8^#)6-SWr)^4$Mh**l=-D}7C28XwN#lB+U~5@t$sUAj2-yBZ^BfMQQ@5YF1#OTSR=gfLYSbBa z*n#;Q8M%`^(wp2cG%VRMDvbP41-9Ig8Q9#4BidYkzbq-6YDaOVcYRA+CRWz8%X#fC zYB5Geys+a9g3-yXLlQ%_Bq7N_TvFSdc%2CY{$AF?mpiqhu&gm_#?IM-jojLWZzV~` z0h{_1cIIR-Fl)y4!J-W(TMUy{(s{p%wWxo2MmDWV(}E~BzjIiYM!vS6Qo1%8bn~sJ z@R!;6C(>9tQxC(+Ft@X^-p<@&6`Su543hZMv1w`MNwXqLWVVOzzAaMjyM=8E5gE?S z+!VT0qi=Hbad#Boj8AR+0Rlr{VSs5$RiBuWpQ#SL+gZg4L|c0}k;^1zawUo+b`qu`R{qcluI&bDJQ>J^ zepX*Xy#FX<#5yGl$qd9Pq&vxh9?vFr#NdTNxDTc&{Dpd}3(7CtDa3Z@V``?*CfZ;4 z)stq6efx1;BKMrZNr>tK%gZuEWglG%G&nY;+MH(gHn5u5ak^&U7Pjbub9 z>8zhQEn&HN=rdD25Tn7+ZFkzL7%;1Yt^v2mUCjeedxuCt@4|s#Xci@D zP#{?Ag2d90lBL#i1vL#7;12L>*T~TJr!SK(pc!(jm<`EZfWDMlfc&U8xy}(sxd(p) z;67s_)!u03Y)*MOx8E(sNY;e)*R*SZH9StMu4_skW&p*jkY-i1>M zvg_^H#@|CrP})?8zJ!u801ljiJAkD28u1*i*%WY%eEI|y9$9atjj)Hmb)EcS*WMOE zk1j!1n*;>+@f@@X)1V@dd^1BNB;vx3*e-TqU*=K`(dVtuq@YnMwo8r{?BYFA>rZPP>D|LlX=t`xu;e^Y?ndK|m5lE@y zh0A;x_`6*l|MbYFv>}#SdkLO9{*VqKpQl{PSh}!3wkvhzQEUsOw7mo^*wdusg_M(& zHj|R-7xWWSz5#>EU1%Y%)Qa4&6}1Du&s!vw{Vq6Xws?;?SwzeF#cE-eK(|Y^{X0Sn zU9r0weL<6w7x>qdoMk}j!nVjcUXhDEJ;kxt-r_eyvq<$lo?jo0-#uICQ?pth7w0>Q}nw2bU@HcN~J21xf__k!<>g1Sz9_sSOwn5u!e0C z?4!YJ%K-XihR6f_0gdH$5Q0beD@@xjam=#O1mvzApdYACdMh*0NUX30J5*Bv*HF9| za>1a0D+FIzQU8R*8m`c)SBw|1N_xRrGzmOT-4R)%F$YWTk|+e#CWR!$BwB>7atV(0 z432-2Epd!lavw59fSD(`&f*O<&(0ie)JhIVrU>OlJEGbotLpeJq&m$k0D0!#kfAA#xPT2r<&Jy?W`aB|U&Ev8oCRo>!2esmM6IQ40@ zFXbBn_0;6MbzEqN(c2PZ?`0rkRIQtTR2i^)t)2~)Jq|crkPF^TK(DX@Y;4KU*a{t% zJF7w>k~9~@`1p$1?lRr?AtIwM+A7qkq6kb0>HrhTm8MgU1GdLOF(9cBMm`{u1M}bj zMKhRe$SD_!AQ$YG1Bbo`(}7_=sFw5NDA(!0qBg`<8-S|`qsxJHKg8)kmq(@27lAAY zsptW(X+Bnfxl#TtSFF7coH*p8^718_W6@>tDE!L&)HZ;ei7%!i4h+6XPN0(HjU+9jE*{|(0KZ&V3SI!`C+7Y?6%+9MXku7!=Dmew! z{v4hhl)T)_;F;NO1TS-!y9KNKFafpLW%!Pl(OB=0zMsQfNYAJaFQ)@zrvt><0Ta~# zDA(^?h@y^AO}%ddGg!F>0o@o`<3N`aTD^~>1DtM@J$FsAaO8mjg+H__I=Ty$-(T+H zIwF4Yx**1v5kUlm*&?OT*i6(hg>Hx*m87&^)u)*>t*v6>w>xfU8AWAXB}#3;X>ylQNgbTi3I~c2Im}oq z1K>|cj0d2~p(q1BJ(;R)2!~ymYsD`%QX~%MPv>VBM3N zt^=?>DJg59XZ!Q9zgd1D3#{L`+k;2o6qw}lf)Ae?L!k8sagqhC5(w~%{KUC`vi)M_< zV$i(I-{I)ZK+dHTiiYrdX$(HhwWe_p^##NafaU8WiZmDlq)9 zp{;Is>Ca>zgm_*eYONeJbW{~zQ2k1Y^EOZn4c_B_;qK{Ed51HyC^j9QOcdU6V&eQ1 zygx53KhZT=>Mn%e5w3jGqZr*r=>Hf$ydf|52DrEtgfL<+J?3?QeC}`UNLRWozD4+k zg8K=MF%YPf#4JV}RJ&od<)8MxvR?Rd9j`Q}mdY4jDt-W=&ZaAqW@XTd`Fr zL{nQ!g%UTMpM)yk9bm(iM*oodm7GJk=Pt3>5i)d?I?p`cxNx(f_G?5i^FVZ`5qRsf zM5j}FTG7i0rH84peeigd9lpR5=m}{Qjhjgfy{>@Mt^1D0+`bD~>Pgd0DBWSui<7|S zgeZHyPSH<&5L}nr5bnlxZs**I(z8U`!{kD58<=Tt;7`mRNeHf=_yQ;Rn=W9|flMD zneJH2_O`-}cFy2PlCMqCkmE1j%$fQCLz8#&*O%T$6tA?;56YYbpy;kDC#>_jbLyC;6AwBG4?$#ALQ%7_B}-(Y`szUeR&UrzR?$jp_lo1d?SFr zG0L~ZJlKDu2tTpwM&j?FKDl?I^7ndQDR<)Y=O@+g=wC}CLTMAENfrBU-O%L{6!%A) z3+0}L801Al!(Z1b>WxoXjrNVJYKE(|u#)SoD$9RWx$c7#@u?&|5#Z`}09**?_!Ab< zz{Afeo^VYj1xc!(j&&XX~ZbYce8%^|;Ifb;}$vNUWH+LRgywUgXu zkraeZ;T>hAo7XfOXjkmDZ5EE3F&t#iS9ga#&c5T#gvTe>crt$MmHFu@k60QQc}+Uyq2txZsf_VTVc+{G=yU4Zr~APhzd3z}l1`9rupX{R5& zePkVafTxk?SJW0uu$QPAsLbhBoW6iwb~eD=0X~bj4t!d(Wl9ijkI;5UrV{S~4OCSA ztHz-i{sD$Y*DKIf2tFq}%+*P)#x8If|10yAC{w+}P}OY2OT*yUd_*fVOw}2t29Sdx zImYD30Ba>vvvK$w7~J&OS`|xei18IGC$)Z*rDoLlRy810vmtAtL95w_m#!hoL4u5i zYFXG)BUiK0kGLVKQN$=WX*?>%RA1I&#?k^?xycYnHhFy|Rv4Cr+ML!>Bi-~^W(-SA zRL`tt*-}H@e56a+0QR@lgag(J>{!E5q-NtviQ%>%Obw!DVFykwfLFO=)u)1EUhpt)zysUm0YN7|;(}e=2 z&HTQr(W#_{;dZ5#J6!XnkIrRIjPlX!y4d>9wxc|mK8}KcGr>cF8nA)dlu|MZ88@OG zNOyryezY=7(nar5#js6#J=215VlgP!a`c3RyM+^)dod#S9L+6nWqsg0DHoGNnMe*K zyWr#mpC<-_#|##pYmiLSDf(!XW`?Q8Xq=d5xT$l6DBdnZ*{i*i@9<<&?{#P$^Q*9m zU2ZL99n=Jo)--x=1N;K~j} zFq0o0!Y(P)Yii0db8-_l&*Yav5f4alik&hJXv{k|K=++Xe+ZhC64mG1=)7SXODnTN zLoN1-W~nC#PShLc3CnFRCLA1eOtML7${a3*@+(c}4pdM4QVai|fdQ`&9e{SpJ^V@c z&chOG)NQ!04sA7!C0OiNRa-MzE!0<%BMSKef@4ey^*q+EBkP=jF^&oF7bN~SEb?9A zaeMdRPf8s+7Cy#RGQ6|Eph3J2f-jM>9)aJ*=(71fykNTVcN43@<{Er--EZy#D6o!I2lE^|Q>gR>Ag9vHD#f$#9^n>rZPTG!7VL2Bj7H+B zeMcO8JKT}Iw6Z4+MEMi6D0~K&U`6%LM$4ab-M59_uc8F+2B^QK-Tx-UD9Yfkk7rn7 z5L&T-Wc5&9YFHcZq@Rd5$4J@>WfA<6_1c~Nx;gg+f1zLgkh`{D{-C?oCwqsh*Kq0V zL9DJzVK-V=y&uh0qQ5IAS5Tc(;f7JcWzcaQRApbPz|$x?5h$(_?9Q@Qat`+a zX^7z5TX8ze7yB!*Dh*>FE&VoWvd86)M|}P@p7p4Le^lYgpzh48e5>;id+fzIPLdVG5|ft!aO~h!@f&c)>{Qq)Jk^Fe948k_%P$)#~)B>-t@OUqA<3cjt`pLm)acM$C^&o}`SpnbI{4 z&J?GN$o*p;FGteobsC#6BMM-34{Rm~-P%0WYvu-Vm|kkFP%(;T!XAmT-9FE+iwSnt zkpxYrRO@TTl3JZiCqQTFd<{Ae%d|B#n0R;{4fa43 z+dg8UK4gSuE63u_y*P51dSy0rK?1i<1z9|Z5m%EAHxCTxL$u0$O&!`jtP_kdW3Nr* zDpO=yMOyK?)fBtS`YW(^~aFMinKHy6^* zjk+bcOEh?BQr6A8j|xthMYX3F$J#zpY_moc-WlFkTQY3A;m)@Vb+W zCJ#r6KH+ai-Z0A3=ibPavj!k%MT$8$X?pz_g&?(ec5LK?UMFtHmNFd?4;iX5A|Zuf0i)g^k>mL-ukRBUaUn7%i{(2a`TOprdh1h~ zF3aEa!jt`~tlsg#-j1rI{$UMz%O^M+z4MJs-e*d3_vFUi>v)gnF`wzFt)9W{e2#O~>(3=oerILQuN>}Qdnc@U-=*1pqQ6dN>YX3- zJ2|dl*?T2_?O)q>dPZmO-W{~#ntXQem6>^sN&dCv_Sqi5} z*Jr0Kd!TzK_WwH!%SMNGR3<9a5dt0sh*6!{@FU4(3jEGZS1P;FQedAABT6}6?)tm5#|WSuKF21*ILev^VqJ^JsU#;o2(jg1L~rC}@@~tE<8|FDthZEjq7%8|A=vKVR$O zW2q=?(}H^$LTeD5qjV-TxVP_gw{J7-tsu-cs<*1zBOa}db-6*YV_VvrG_V$l4~<^3 z5lA!k@#JaLlP4GY=@yOfu@~FNmBWsxsInXL!?%hZ7N+1>sz!Hh7*&csIa%atm57a= zb%k;W+r{C`4e=zO-{nMm%iejYFs+xpx|JX$V$7wgsJ7ogUO_L52{(Rg8K=l*r}*V2 z&n2H*MA32$5Jm32i}3JLP-wVX&QR}{HkEGJ088TNdYW<*$m3Tp-!hQqR{p-A=1GsA z2|Rst4(U9Yztymjyy_<`QLN@%k?qaiu#PMRM`%~FFVmydRqHBLZJoNjl_7Lz3x9Uz z!B`|3oMi-PjV!zL+#&SZ)0)^$@UGOF$CE5A@{*>(fgH(*Uuh1&mRxpJ=D*WA zseIBIn<278b8ZI7B&&HLqG}U;Zx4OXB;=+Gk{oV2$q4MV!tFMY6DC2EtQ7#kN`&b} zBYj#rsmVExz|x05;bJ9^XUN^MC6mz*nm?8Zz5@)Yj#`!`QI~+A zh8+c8c5wVf2h6jMDlJ-Mtf^eOwah!=fr68mNQ|?SK$N7Do5XY9FwYdH=S+bb)UTS5 z^hE@I4!&0yx%0Y*pgmpzmSE{mf_5Ea?gsoDBeVQ+Aj1TNjdE4d_?BBd)iI!W?97|P z*raS5_s*qA-9FZ#iQ<*-uY()o%V{HQv)$8zvJ2Q$Jzcr#-=De)r16E+zN z>*i?)sPQ?-$1tNt530FhaHGA9sLRE4P#&YUiX*c)ah3U68jIEfOdPEAO;P!Nm6o`| zlQ>RGfjQMc2_)+9gGL7dPzbSyY@z*r1G7}oRc!C)v)LUdbz0J0HqP=@*FF|b> zS0<#L;o#moi_t5Z?rlWl#F}&JYC31(j2!HAml3!^T23^AyiSiHeC}{CLqpKX;lTu;4%zMISLz3+AkyRjGDl73TX^tY%jnsKfLyO!sxim*HUx-Fo@+Kf#J zHU$wng4(y4ib&+gRWF4ziHA>1w2G6gEwV(%Uz^L{Y)%NjNbYBoR&XERekagoiw2t@ zGNe(W$!t>?GP)vDz_Q%)^i8u7eu$(FAU5sFUl&}laN3Xuot*?g@rlM6AK{Rma+1j# zl*;CLuyW4p#kzDR0w{keE#Y-adrT+09m1Q+<~}0J+>h$* zQXKoudJNjB%WL{AsO{II`A5I*lO-a$3K3q{J|n*#_5QXyGY{c$BH)J*1MUBV`(sXl z#EwTbzM{}|ogLm4(QEOxz>9hU!V2&owuFRTV9F?nOuC(CX}AfdzYc$Y9!L+{<8C*) z5zM$kDB&|o>|9OhOn=T|I!$uclasSc9LFp--hxXx>RNE5L`Y+Ky)N%5un&=nPyAZC z4P}?985ypBffvHWFCuzpcz4e>=Po$zoh+21Eps)#@w|_6CoP-aXB@ArgqTwS5eP44 zIgX@x>9yAZ!N{r20XsKKPG;aljbB*$ZSKg$23ZdBXzNg=nt`*&a&+*1EJ1Ev*dP5Fdu0p?rpPT?NNQf z8}D_YFSwZPm*y3_bT7K&cIc;qCbL2h5q1ULsfH;ym}qNEY}w6*p5x~(QPBh2V}bE# z@Czql-U*z*=3fd2@Cn%aL`WZn&pyOiqWxkz)A#-B=afkPpgvZm5Ln>YOEoA-?g_ws zNmB}9mh?fV$W8+N=8`8p%ss6?1D48BRF%&j) z)eML#t3?030b){XxF|-M5oSpL-he+xr!Pyt#857G9xm z_tX`SV}V14{linpttJ`NscA8TW;}}~H90y~^7=JavmT$Nr+2HZXzPgq^?_pcIlp6w zER4Q~Q|e*%jd{Wo8Yf*O0LO^zI0|YKxmn@Be9=Wwa&>QAo4Cp{5n_RgF@7Zy>jGhQ zLDq=xDH=2d1={jgMY-?+SC=wPQMZ7<2u-Q?Fcfo6IKt!0ct9x8G(bo8HyAIEWI_g9 zR%K<1&MDv?k1VR+U(fr&f^fLxodeMsWMa<3gR=G@nQ;OEFvI9uj_Ax57cSdiVx#yB|nEWNJ31csbw z()0#nTkfHRG4v62IgU<8|8O~!=pgL?i)%0_EW+VTaJ-|K5wi^?;UbhKLy4lNM$sa9 z^*V-B{te|wd%77#KEa@X9Vv~%127Fnr8-kq5~1D$A48!pBSz?;z|BKwu)%GbNvu_F zqub3TRdHUU*RHodv*;A`43A6OfOW!>2p0qsIKePMl_(dS1wUsRClwZFcBHf}Spyt! z7rNC&-~k!%HW<^h;FEC%lBgSF;Kl7zIgL{RuX^Q=oXTbUnXA_=2|(kg3Ke#DtH81ZgH@{ec7@K0&O+7 z?0s)*k;40X(M5MoKh8;gwB<%6EeJo1-X8~wFO0x5p)5kYVDAtGAzo-8o=_r;mb7P- zW}o$5l8(f+IL4*SE(ud`ZNgj=PtPVfXOr&M&?+|seV{TYUqQjbe$>Nf1BzB#OU zMWTKsYOEmsoc2P-{%1MBo#fglixIjW`K(4&J?g@#NsHQ`o4e+XC^O^hOELizQxPgU zVO4s>1-;NC4}vdjgdRYVJ-~eQ4emT-&lQY_^W9h$3g#ll^WVIYZy`t2&&}#d#>-V7 zqtqv`tIg#AH^buJ^>hL>1485NKln?A@9Bgi)JI75L~VXi(5t@{@ciVC4_K=Zeg&D- zYnN0pl~xT(hm=wc{EboRVC^2&-EcELfK(p!UY_#B)bD%sYm?$4IRgXhz2!&+Ck^~_ zLgft0WjgdZ1P#W#D*px@_6mEg@~hP74lOmZJ#lTf(Cf}yi|X6J(}rHTAR6$!JABA&NPPfjs2_u|_kz z?5D|MndVlN#bld;+!GG}ypVEcsxr{(5Fw=skweJ%!m)tye0A+Y+f8a#f3N^G38X zQ>?igEqoVq@3frNQ%kz(UYWGvE5B^|rU76)im8lSd(_YI2<^q<4273! z(to)zmq-d^v6QUCTZR$L*e0AH)Gov+G`n?=0BgxmYNeozVy|CQ<@0@`eaSPi{eAoU z@1_(e004*|y9odx&%a&&>xcUD$JpMM-rU~a+{TpN&B?{y-p1O}<=-RT|9cYr{~L+1 zp_7S`{mh(sBvd5;G`uZaV}F6EFlg=E5y@$ zBkFEMvUu<&+E$P3M=K=CZPszFLcW@XINt8{p3TdSxXC;_6VZiz*EPLqG7@Sw7Q)<> zu5Ny%*K~yEBDHZ7T7>r+eKbPl(KeU)EYU@f!ghs~c5oKDwVUY=yAU!DZOslAf1~l0 zG0bYvQ<1YUc_v7cr0=-qtC~Y>i>})6m)*o1%y@FZIJFOltQ9JcgYXWm`+E-a!1;Cw zp&dGE)5IYX>0fk7sJCUlf*BXY16K8MQ^3BH!Z4*Zm5g_y@ud%Z(wLA>f6_IKw}%0Q z8dv2*mf?B=v1lB}
hQoWnU_!$6)XOY`|pHZ~C;kOs~lMjib$nty>&B+f3LHm3i{ zE(KZXApr#6&6DET`4uhx3qhWUB`B~vi#sJmDAB^S9rp7iyKNIfN$9*!*^%JA0sOsq zB=W`!MfwM`ooR38>5s8L*a6U&+zj(H{F(x&U~RUS8*9cE&mK&7tfAHusc=6TK#*W7 z<_%p;Y3r!MoxV(F3|?MBxf=qb2X1(8M3|2Hh>I9!0o9E1CVKS}#MzT612WBHJuV-P zG)Z{}mQ)dT@Ibhpg)4`d-0Vdl(z zdvsJ4T@41C7K}K5f2SAbMe~jv&UHVS6OCiQ{arZ7;WJ<0#{5cPQ&KC+fh#yuI7Va= zYJLD}quH=VsSUd9FFo^vHNbTpgktj_1{V!4!!9*XNgv75f1>ncg&Lz>g1|L`y)*!> zmH$UGCmy9F%-hfBR{;h9p#9fa;AClM{+~QhlC@v_;XyV$Ic!*q-8&-R0)S;QN(CiO zWrvDT6-uB=m0oRZvuhj2&bXVB;{iJ%egelW@T+1(=CFtaZ~t*`do#1WnfS-U>I*)A z-k~ZiHV1_tC9t)IczUYAvazbcvbm~>>v+}h1!gr<^=S=_8a6~QdX zb6MeI>dX4Hkv$h%;=M}>*6;K?3kwJkE`QVM)-J_6Cel@PvOEbUYZ7*@r!oJ*1^L!U zyU_B+Oc~1V)chZGymJGz>O}ShCYHeT3lbRB2IG1;|g0(;TP$_aV z5m0}CaVuY%Clp4|oyOH>`(K%QQW{U3@n}koa}&gqM!BFsE}JQo?kp*iMHGAZZ)b*K zV<3f&XAhS$ZjWQFJzgI35pGk}+euea{**d<3O ztVnrM!L0@cwLHskrqZxF4)U7Myyn}uh*T1Jl5MPZDOcRyhC&w_3|*%{5r zTKRVY%mzx_oY({VKg!VC^aT;uj|?6Bw0}v4Yz#f^U0wbkJ(mB;)%KN^hHiyAAjg{v zjyxC`^+@p`WF#caD%iJbGYyWGW?!enkpCt-7#I%b@5eXAftoMYJNYT~@M6Z4uYZFN zFx!Y;5FvXy0yyc=cx*g2MkhRim1njfmAfNf>S1Jn3sz66Y)Oxqb7+=7VEZSqV7*Re zy+_RTN_k)1>Ug1+yoxZ(a701Ivn6g(wTF zy45R%O{xQPI7?`WTZe)kL#kGUmLAgXX_(|dYF6E&cM&oF9)UDP*yGlB2{Z27a#|s` zns{W<&;>bOL}+P1-zaB(H|kMF48J5b1(l*4ngUEkG$f|M;~tD{YLgnJH^+vc1cMH& zA&SZn@(=%k*iPZO);{Vijs8RR4tc%Sbw?nSp+HTvZB5}nXUnVP`IlY(FhJ%FL>rKKAaN{9k>40UQF%VQC7~zYhx7z$10lP}N>E z1DAo-NY&sqRW+}E(po)hCTs8-k!qfCaX37P_CU<6fN-HBj04@Uswo&N8|Muy7MJ3{ zZ;V)1fF77r2d!o`M%xnw%tzli<|XNrzBqfer1&zI`0*+7)zv?A{I;@OFT?qPt;5Nf z&Y=VEVfNor-Kz@T>g!^fbSoE|dudULsC}c zIYL|0X=%7L4$qmLF}Pr+VX9%MHJp zx0r*>O6e1w=uYv9MY31gK)OB-bZZdZD#%5OuUz>0Cx8XOZH^F)ACW=(*(cHeD|5ez zlcD>+0T29_=1xfg3nJ7^SSQa|8TpK&WctAn~79fzWGIVnfM`q)$=MER| zl5j%ceFE@HU9OANd!1KZXVqC=JpB0r?#Fbq)zJ9eXA*z}wZ;&Gsn*_LYM5O}_2oy@ zk~U9pp05ug4^uN^@Fzn&a!E-PCbTT3q|ay^kIf6F^C#L|xRjXKkr~gEsP9xyB3VoP zjpy=CBg>C(`W!ry0VOzt|2LT&ca+E$lxGrzQXF?5Rwr;NSfK-XqZ*Y@%Epr?jz?6~ z=Jwz9UXuJW{Mq`(nGr?0M>4UrHMRRk4oN;I)>KE{VItlUAn|rYhzF+!AV5GVI>9z)8!|h(gOMfce3k79 z-tK|FDjJ!?dM!z-x<9G7%lrHE^#XSc3Id>S9-D(#3=YJ_^WuNNgs(WTrm9)7#?j0u$)PxW`f=xI|~+G9-CHUkDP&JzzP{E;NRHuI#JCXQ!T!s5-nwds%5Iia3! zH0CsQ5NASK(H0SrZS1ZJc6H&h$Nq;-fMVI46E%rATeHS#)xhcO=&l{44k$DsQnjE6rv z1$wbXhiF#AfR%7=lJx-@ptzM6Zf>%cdl=!IhAOadFRj=Q6Ls?mN1liC2o=7~ez@Lf-Qy03(882ohGtfu> zt|+9>%#REbjoC&b5_PV{U$BMlUTnm}$lU57f`!XJoi=U+XbG z%(tBqcesW8R#_%xV{EiXE+iG#ODk$?W09;+Ygy?xqNTb#Eis3Guv+UN){AvJrM52` zm^1Zgj&{JIu@f%gOMcP+|VN zb?!fIVP|M(|4)a+5D-$jqMuiI_-U;F>Z|<6eJt$l{&NaUmFtEZWI%BCV3}iTXkvB- zCMHHgLQZ`RVi74Nohf8_Jj8ef;DbV(9GsMFGu?hWI{otv&>%*}n3y3|0;K6@X6|&X zx(GG>Jd63OwaQku1=Tm7w;sa!dHnfeTyC2j zckLp-75Ac6$oFg~d$z2G2rM(_%hrw0se9jzd*7Ju4$t=>A^_`a9y}e)TLbK-Dok{G zu2F{=Og`#Rt6xsIuHP)*>5yxO-Z&q9820d>9V&ZO$3(o)*5w%OYfuyxe_w?5h(k6; zAIXv(`cV4FA6%o3#dz9|Dfy1>kxObLw|M-Q1HQX=RmMxip|68AU85Udqi0q|o{9rP zRCsENGgh$V^L?+Wh48l(Mgy`Kxa|dSWvCVhB14T>N8VJXSFQF&QX@FEmuxftt%@D9 zQd#Cc*0j2~GqslAM+&(u(=D30bI4|`AX(XYKGh*$U%&;~7(#m$wCeccx?q{C^O3CkAqdSbUuezWgXm_KVi_oQUOCfny7sMs+wIz^aE_2WSAY-kXr)g{a637(eb`7CJB zO_`?zj;B9pwViD~UUcN0)!U)mvoZe!lFMYNZA7qLMPN+0Ov^x=wrMxE%-d3RbWmlJ zPe|_0nPsCP%FjO+x;Rm6Gvu&gg|XSQ)v(pkpr=u|@bXucKh>?t8Aec|qSAbm1Wbp; z_)?;Jqk=>T@fJ@R2#k7)Eb)c2Fnn!Mz8zq*)c6&zGl8ROls}N+l4o8)=eFow}zU`M94W>uo>-F2X|IZS!`W_VP>V#1rg^3{%!&=QeM=QI(GImw`q^E;mm z6_OQ36{6}Z+;@zrcr6P$R^AgG3awaa06@3UpfHObo{NKnwVtmz(8lVE#ezkT+=nb& zjw}i4#3%hg$>FS1`~7SJX_;)AnZ|J-scPUhsC1VSR(=-~=DSwE50JO)0J>uR%HqY! z6CR8u<|r{_c=yhuH+M^9#o7~+u8K2%3#GSwi`)2|HOEE8;NqhW;|r7z>VGZX2?feb z=4r|vRy2{$EZFGX&(yvd)y86`7QWfcq4C%#Y<>_cw}mX%KssE6D}=##c$nQJm-9l{ zy%?4{clb=XsC`j?c@Eni+U>2qfxQ~hmq83y&2Q#H$?-Skv_4)_tl1Lw!g4d{pll`X zI&bGB?fLzB=Y4ke9WTsFBpxOvwO?R)f-Ex1XMT*nMVJ5c$5qnj@7>Bh9yo zTx6PLQ-EPiHPku6#xArMS>lB>TnU)g4R}I6OVWJfj_|}ReO~fve<_N_fzIy-m1lqC zxG3$uT`-R#;C{l2A|E>Ul;}-GQ3=CuJM|KJ0u?`qErFaH!j;2z8jUqJ77*6PvL zjTdH}c_B!A9KkPA50*!$k&lX+LY(FfQ?%K{-#j|gcQjc*D2_B`qcAB2D5e>aoIDPc z>QMV!VN9s$HENBQz8#+5PD@;BDi4*n=a78hFN>Hm^(eEWP;ptc0bDgHvo%7!&7G+x z5a?0C&Txacm!5EVFRtK`t@OYwxl{#|c+;hX4+&3oIR!&atns(PcN!;>s*J%zPBQAF5mL1TiC$r8{*J=52-BZrar>&hI z1my0nTYX7ewUZOuSvgyk$(`1-6S~rN*D4b~IJDgi?fP=3D>-4^D_dKY5CZt4icvD3Oz#UiDSCsxJQT*He!l8P*)TZ7WyEu;)5zl zKWrPOWTwPD>VyPIFsXfmv9^=iKq5hZTe>Ntg<|zN8|A`;jK=){;@H$gRp)@MW2Gv? z50($D4ifT{QOX^q#xmSe!NjAM(i*3|IH53$Da}GlTJBG*P&z zY;+WcIWOtp0G>fy@q22=301TxQ)eb|cViax?`G#7px!NJtFeeIeYyzlXlAz6SVfi| zUFGDs3T3iM?1aQBC!DUSu}iADP1SZS#W8BQVq0aK4-a#8=3GB6%rrM9fjc9`O_}ox z1I&$Sen))WRbl80voD?jsb|9ZBZ97fh98g6AAD1e8`D=lvdT=^X;=|VVv~NtVPPV6 zMKk1s;Ot!0Oh#im(9d3jaLFCTs$*uIl~6Iqm8d9k0%x=)*=YYMlJr3XL~kPPpNvaV z(^&xj<6WNbZHz7SqV(ezYR~~+!5~$cvnJx#bmD0%d}5DHM6=})#2!qlEO(4l*PtQx zg05FX!gHMixDIOe-Xq-;$c~o+iE$lMJoNx}R_Z;v2OLN7mxCClI;gqU!NRBR?U*rl zrY3{T@CnW!zrI{u^eUYH#o9Lo=@xZK)~#E%ja#;D+qP|6w`|+CZQHhO+f%KX{(Cy2 zXL{!0M4S`f7yDsnoH%Rc&XqZML3Aa~)HUERr?>T&We2{v^q0*M<0A4+*nEc(`F>YH zgav|2bMkNpCZ&SV8EA^ZaYPT3{m1Eq7f;kHRyN_POzkFTzkXNt;1|IA0AA6H-q68) zM?x~(PaeuU!OBp!Tl)*eHOkjWJ972Db4M@fE4R%DsGwVXyN_rkuH2o$2NF*&4Vw=n zPd~>C+gFs%4(|CC8F7xU z3dcPf`m8ug85g=aeELP4{7n4Q4bEoY!ulZYj$t&$gR^(dbxIW(TCYJE*y*xljt)+{ z(v4jCwJ>iE?nEa8@bOguuBLqlbcQ`NW%97vN>bzA%#_V?%V}wyX?MoIVE?h}UXZACE&VBw5q~;8p8u;t zS>WFer38(f%?$pvPsog}h4|?cg1!~48rWG|S~${sM_c7>jUs~UJTHg2Ff7kS-7>v;EiJ}o>ZYGIe7sfjwUM#6!$`hmugQjDh>?KTz z=c5~!Iu2*}Ii?yBX^hq=D~9`((5g2~A*L#v2EJ{C)f33{iA(H(_RxCa1;jSNwRg;o zF&O&nqik0XKtaK`g~4?v8o(JNFn7*)O=SP$E_fooGbsF=*bOrLZ_@t%qSyKlyFmCa zoAK{EhaWF0UB$&k?&B^Nx71OB)BwpKy3jv@;0(N~1QLF$AuvFIgn)dEP@@D;lE!-z z0U^plLY9?IHiNi;rtXb`S!q-ty8#Coa}y2(3}}2M<&SRG&?= zWkiCgcoGRu^V~f;#3K(|>&rDQAw7W%3L`fV+-&d@ge;DKJNzeA|P#2g~|0|3gTU1j7d@jJGPAh*HE$G!t964S> zEbT*E78nl_1k`{$n`*(7Tj@N=-@PP2OSkR?B#gCsK9}A^hY_U z0h!`M3QG~eP~$Xw;1?3BFI*j@ zNNT05vQ!AK<_Y9GTRxstRMkU#wFz{_?viLUkp$#B2EF-?qT136;N?L;qB2X7JUN!o zc={63jOQ+zmGUkCxfD^s@r`P+aY6CuZ%LcA0PFnyf>kGCOnx-+-phyw7Vh>McYsRg zIIkmj%|6ZhTFbhv^bVs?EIN{S7)1LhSzTtG0n529lpa?nY-0a<$j;v(;!R)~+~W2T zC#MWMf5Ok-u{b{_&V!}zCQqbudn^TspiKs+$j^k`olH=v(Rr_x>Zti#+i1ysbxAai zh;ZTs!ybrY6A0y#ViE)=qOXDK`xAx;hS8!$YF=Mv0$7=|W99c?-|`s*1E>n-1!zOq zkq-Lvtc%`#*^7y=G!rwpS&%9%Y%KD}g)Fk%_~Ms_Y`_8KPQl*u)xE%WANmFg;m2z_ zyaHcpkirS%+1hS4qKDdJw>!`d)PBR3y+39W1burg}?wY8D?} zC)}9wneF>A?eoVf*G%a0PDx!MVOUkGglj`^6;p`p2)irF&jkJ#-a2jv3}@<=J21imD^wM2fmFjAgbs$R`2n$X90y-Y(6aLO zY_W3ne`S^JnX$?Tw(qi#Z@{XQsD|V#I_8TE&NBWru&oFaVwE1e^>hT3RV;<&B{BzbX;g6v!&EYS)zju<8*>@qUcjHqLE%By#Kw=^<&|ngJUC$m2=NpONMl! zCqCnP7HvB}1^EWpmh_NzM+6rnJj8H)py7;nWVpJT--d}~4cN}N+Mj33Z#ES1Brbk1_TQU&u7e^T_?sLBa48By!n@qpYNwM-!KWx$mGHDS^RtO)vRTZZfh za!(Ez-yU_3&fiX|?R63S$OJ8pX%_-h zacC1pU?7Gyo+8)1hJzw8eHwT@S`(pO2b3t2_?N5L8)coBv)@Cnoo!yxhc#U4-8O5Km^m_3clbF9aNDTX=KPl9YeNovd z{>2ZF+9#?zT3DdfV*oVcnM0AtD_%BXS}7|8y2UT&@L9+%-v|m9b8)rpGf3?c`zw=7 zHRF3Lh2R$#rA0ehk{`)2Y{|rblaWDbC}6hQSX~*QZ!Y>q7rbZNIeUdYY#!!--IG)E zlZ*17Z4@4=2%n${ugDc1sDmjaXB2QH`LEp-9+u*73?J;9{mSx9ScI;V2Ye7y9UQt( z79j+fAN;dAbsoIEC?Bfm`DFHvAbLTiX4^AYuK(D%q~$#;%&$nuM0IZe+%nv+NG#7{ z8i#FNhjhnJthz?5w720t1U-gt6&d6{JN)y{9@9vj!J(h<2+gZVofdn-#CgfFSRT>o zdC!n7OO#Lajt^s!vmS9T+4v65PvKkgdLvGsIVwvu?$cP1o#&GVGy)>mW(p5k1W(6e z8<0gOo4Rcdm!l__bVAodFH@CFGnf;z^^gzrdYNRNK6t;XXD)Bd0X_ZqZ=j=WHg$$} z%b9n^9nbaO2d^K2C>T8UlkslaM-S!_TYLHMW+kM4d4|6{$8|JI(QKwmvDhfz9c|h` z>{RciH-qx7b*Qobb$m%*y~hK83AuP}(E)he^pM~Im@`_&{R%(^klLqKYv0)rSNe9r-`Xj!i9?^a20^24Qts5lT#9^@x-@W1N z;y@xWSgfarB@S7)hGcExkMed7ClH0pcnd<1s|60S1WvyCvkpN*^b>E7fcRJ7U{z1l z|9Z6DT0IPxw3rjHf0s0Z@G&1=51&584x9l{4&%v43yZ^+>_HI7FX$sO1Rf*%;PZHL~v3Ev`HsbvrjrEbw#Byd8xHyE5 z#7Xllhl2U!%x|~-uiw<+D&>V3kVgiq=_%rgw-*g4SiZSJouviLB%j*?T>Pww??UzyxJ_P$T4?!cOjlE zA3a(huKgIjcEB1hLX)TAMY+hrmhxKLsEq-31emwpQSsc~m=uI$C}U>&6( zuKUQds%mGo3O$)eqxt-4u{0siJ-WZFzFMf!TDAM8@m_sOhFs&kR*pQjX zeXZ!TP2<^sKG(_TUj2^tQnJa{q{}y@hxdq>lL41cnv!9-Dl)-z#fi*Dm65ds$O2Tx zf>BciXmuqQ8WctI50s6tCKZ4kd_z->FwjFs>4m@oEw|&W=moEdI)i3KuNu~GfiCX( zWJSgqG^>Fw?vGamY_CPqE_|b+^nb3!;vN)#0V&@hRnCW=9**Qlz5l|81nZ9M zxEk0#!2;pn1jVlW+m(cgX<5IZ@yreZ&6SHI~ zI1bx{D<<eF+bV z&urhhzMNG)Au-B0WQ1zd4wftL zfgxv-172skZte_~EfOmhTP*-Ll)t^{7_qA?Piy5pnXVPm_&cW-Z7!n?;x_VfNQd(G zvALbo??PTq>_ZyRuU%kW)KBTcZA|@rfT==vs88;~ZNoF0Tz3pBaM;Dd1s^%h+@7j@ z_u3V5-gWeqb;as}#=|;rkW;F%_0g=%t4SP)(9q`5!>dVadTaUWXuHh1^*_X(B4-KM z8LX|#$1&3AQ2Kiu-3shGwb83EgA6akYtUf};HCOJ$m1|c5KIt83v0Rt*4#aZkd)?@Dj!cJb(7)4F<>% z`D{KmUOT%b9Q9rBr&;}ji>(C^eKM+-%S#ZmA6HcD3GcHTq~Z(p!v{LYx_zvwAZB%hRKOPB=u;fcjZtdbVgR;O4pv&`dUSPa7u|CQ#$H;R%3t5C zQp|!s-{p6!??QF&9B1#QiP*%Z%(OP|c|WQ6z&2vS+!glxOP?-f3u+zYaVzJV5>+W; zN5L7Tbwg?Gk9q^{itf^*?TPTTJAWgy0j#sba6`l`V)Au=gWbh@{AoSWhdLYTGXVI3 z7&XY{%Kn8eQKIErJ%j#DZp2ot$JNE>HksZ6wapLxEMIibT-EP#BfcThJkail`GM^t z@%Z@y>j|_yT-k!#ydT^G$%8M3yFc#wm(WXGo;!c**cGn3r~3Afz(-u+t_mgQ_n_ti zPS|!G{|5_Z_;&5>3m3(ZwQ?9w4FqT3*)1tY@-L04n81_)_LPYwxlZ508jF-ZYs1nD zmLzu@#`wNU3CM!Z&v3AV(sKcx%1Gxy}lH_Yfs9Ez6SIs5-YJKll&nEFJ-SWdoN^%=L>^o&=-wuB*Ql5V5xNL*u5s#I^J8fs+ zZd+1+v|ro3@~$H-Y9^r^%00}QAe*3@2yagr5^Uo8Tkw&2* zonS(7R0d{68#Hp}a-a(})lB0dcI?KIF!_>%`B6JN#nLx^%?BctYf7jA9m^gJCZO4p zmCkvuz;>f{WcP4y%AYcpvK}e;2-f~#A#jquu?=x@i6P{1NDi?MaS@Qdww>M2vwA-CQtZ%FSvs9A6mbh( zy7i&vJ;l#Yxz?fM$q4FjKqQ2bo&DpzNoH5@Mn0k(44-ZPWb-7_iAe5-Sd$)hT)?SD z-KjWgKI)-m+%VT5?8%&jqF~z&Z7VweU8sQ`+gQ)_L=_eDkul)8d}K+)z9C$s^OXVj z6+QwP4B}-Xu7Mp$>i{lB%meHXeGTxV?$iH&p|Jmfyd_jNvUfBy(6i*TG&8aOQJOg_y4n6K z%Uu~;`_B^;J}faabNpmf2p%S!v~>KYg)lJ?dD4_swRuRxRah+YI+4CVGwyK7_yu60 zz;rL&?*-c~#qH10%PauNtl_pudOdJkgl1_QbT#M#G)+YheJ_DCn8-1R2O%WSrw6&j zLvRJ79nu<5nIi3W@=^|!XhF5M(-IQ)>;fW=J0eJoK4ZzbClRq}y_e*EV8xF5l z#}+1?hr(#%J_~3*fvvWAq{EPhp45R|OK!#xMxJe23j5acf~*X}t*YU5iUIjL-jCB}oc%dCxHimCy~2Kv zxw8(^v7I)tg0KGvE}i#O244OLj{6@tH2?p>A!Bd$gMpr-nT_?o2SP#ykPa!(#x3#> z4ZPcnc1;sE%9uME6r?{o6tx&SCOvC|VNuM>vgSW2&4x4t=X*2l95}Ywin*kYKldM@ z0jhQu{DOdkfgqYbS=n)&GBlR$K!8MLEaU~lz?lqt{YdP7!;zlpzLS(H@#hpQhNq`w zsE#Ku)3J%=pip3LK58~!vtwTtfi3Jq({V`U)XE{>Ggxe&M7*N-Ztzm`N4tFfMJ!pP z^u&o&3|m%sE?V< zQ|5VSm6d#z=j@oMrMFoN;lgt@1*HsQ)jw6~s;CzHO-$UtlVvZXX3L-R&a+G~^L5Yn zvIKvKv)nn_tq=`vP!S|uIBGBvJP?_3kiZ6D*=)m>jG8v=Ndy(YqE2(qL;f0 z`J=2K{wOV_te=ng9sD0(EvVz{Dbyb<;eN1G`TvI{zmucmKf*XE-N%a*I1OwG{0sip zW_nGn#l94{0WzFtu@e2PfGi1pPFl>936=XVtWn3HDMs?pWb1P}TdRY^(LbTs0}iA0 zpa}&Qsf!T-et^iHHQSoF#y!#?>-6NiqnW7%v|mGrZy7M}aa|XHk$VnG@a=pN7|m1c z#D6}8q*g#IRtEN4##n}-pI*M4P=45`FNk37|VD5Mz>|~ufDYaJE zv^4UC$>2q)%7_^C^`@g{>Ey;}w7RjJC8BGI{9ZowIILEw@o7v*klcx~sJ=C(Lg-NB>L+exP`VfxuirB^_ z`=rc2Vey|!3Q7KJEF6ri9c=6!{#gw8pD#lDf4+#BwWE=}wVvfauZHw9@AgjvZ+M)3 zdq8gFAU_9(FaQAD|Bcm@e@@SB>>2)5pFgO4ZiA$R#8b~uzfL_rZ2e24#0&iDin5MW zxpxlGSqNu64=EfN-nhBndG!)zLfXPi@*#hATAXkQt~HONFR@5WcY@gPE! zkVGLKfh>QiflN-LN|9;!*!aH4Yi&e@7I9h)IG^5Zg~Duc(qZo^en}BvBZ#g($8Skqd1uNPwJ#GI(q|vd9K9{ zvN{l5t1&x*Sxo-Y1#-E$@@*M$bZDbI_%t158Vfl>qa>?vE~l~Pt*KDWX@!{v0yGJ3 z7RG)_5`)1SnuTo^wshN#ZCk7PYQ1n_Lx>r;Z(=bOoTtU_znD2=;7m6M@Y7*xRO}4+ zxhYXg5o!)|B@?NQ&_Vl@k{I(hj<2yVEwzF{R`tv(b}bc0aDIZip=nqaeYFycd4lQjr5i>DTO*1Q=5+g0dpVAZQ0=Bm8U3&7JA#&^g{*vIfERi# zM=;^~Arlyo`=mAr(*aB-s1pQ4RbNSOQ=5`9`P6GgvoL4#rjS;PCv+&8lv%}I7?(wo z0g{o_a&q|u4|T$3+THP43nzcDXHLx4h~+Fz+^2U6yZ$DWbnbqRei-Qrn+oS6Xhq4Y zcSOKy)|Ilp^viu` zUc5)|8ps56ekQ@4IB(rhHwj*v?6S1gHzW*d|HE#a^fr67Zfh|@Xa|@hmhqd;IgAbl zTFh^Q+8Q+hLs;oMs=$a8?<^=n|DX`UX=ZYaH^I82jGEFcJ7t&+38k_@AWgai9S?K=Nv zn{u}uh1el z0RStiUffr1i{vCL#k9L_G3_{qyCdrm9i@OAYseuWV`9H5^~Mu6WVqr4NR7KJK@|g6 z2@;F_Nlex!;#QP*Q}y!Yd6$>gicVosBiz03#PfUVb~K{eLE0qC@lE6Gm4m5Jc<+%<{~sT){#peY#Bb>GqL(CF#9($CN#-={0`)j6g$ zT{mn#F3^-zHf|#~jd=yM0OT*d1D=~Orw)DW>K2%-;F^co?;(zp{myXny+?v}PPE30 zUeZJMoRM70E@UpL(&R`@?dVCVKVB%h414wHx2q8^mN2t=(UTsc^wqdCDy3?vI9Fc* zicYMZ{IiZO>k#TH?49BmTN)T71^^@(Ck~9MG&|!6Z`a8uTFrJYl>WWTq(wG>k{~n2 zn#8{Wag+bVh|G@iM>5R!F=ZAe1DXV(lk8XS;+9y6FFcYr%1DOxp`?*oE-8~eEvC(B zgC{u8QFIu8LGP~W1TA}VK(#sVi)fYK?pIB|cr(SeeUUX1vnxTBbret+YAX4jf%1#o zgnIL{dJFfz14mw}@O}ni?z;4R`ChxsI(-Q;yinNIL%IJl>tkajR~O;1jy2dbKK0w& z-!q;SGC%Z4NH9_}?<+(6isjjBUA>%rUhz0kDgFIzA@jcN8{_z1%tfLc`3d=tMM|0m z1Sas$Cr%j!0D$Yi@fA|AVNh~3v-}sG_o9lGt>PiFxAoO#`s5MuFHI*@a+ESO=FoIF zA?AR96ke@BAkiH8(wbGvzP9wv7LWU1c_>2Xs4u?A$l;3NrB;;)v;)y)m5=q?^Xv*7 z^JfntCO>D*((m~UR+U~;?JVg)@53v-X7nCg4pTqZ^n1on*yvXC_veQMz}amPELBS> z5TtEAEJcmV2o=BeV=lT*eCWDh$EL^?4E#0HE%ojbc(cxrg!=_&_X^oQI|MXfgJy3z z{Pu5aonbFe`4Q<5i}kwyCw7Y>B#OD zX7aZr6b_S47Cv_DOqW^L2j5mlz)>`~o90OK!1Am6ZK`Aq`yiFQDa}4be@lhS7uNUlU+N{hRM3u zsh}(E`HC}pqGR8!YE$t#G59e;YDVT{U_3fW?Bu}Qu2g7?fyuc?k_G9s(?a#s+NYKP zbK_+(xw^EHW*Hu7^2KfCj-@F%hM)MEbzkc9k~1pQvHLieqeJT2QQ{0nlX~TB? zO*8YOirW3!hay#Gvbu7{jLW*h5fYg0`Ks*`!ug0!OZ5wkD3vKrm14U?qz_=`&S7WO z6uPgrP&4LOOi=~7gi6FdpaduOT32%`%i!=0^lu_O4Ckz=$?Q5{s~8iKRP>9rEZdgo zJjHN06o=6C+{WLG7<+OK19|uA&^RPE8uBHL=vI2-e;BsAEPD~hAHZ9LxElF^-f{G+ zk1autBG+4!K0M8+Q{^lrSoo?(*0@#;w|Vi0%QTrL80nHA^}yXti}Tt= z$KMfB1(}CHE2N3%xGnkij&0Sx=Hib^$>Y%3^*^J;B<<)Vj@YDNq~*UxeidZ z5iujwR{lyu%4r(!ig^zAx!iI=s_c?MZYPH_(cdy=)y_n=1da=F2FXFHfVpT&F6C|Z zfpc2yhUcBb*+~*h>u>bA*X$;b=l7W<`37`s_Bpt2^#OoTb^JwT(xmU_HrfSso$Zt0 z*B+ukSc9ed5FJnntcd^X9ia?a4eq8jLf4V2w<>ua;<7XmU!b={2#3A7JVOF2!fA1w zQf2Us3+=qt%RC<{nO(1?CExK8%pFfP5-;HZPO=t1!YXD$g4b9-<^0YNF5(WnKU=e> zz^T)bV0dBaLz%ge7-OAntA6>w>mw{M54ASoI4sSaG+HY$($3%Ah9Hx*^}g$~^2o{7 z1u!a1zP^wyf3;Q-pS(s0F9ujNT!?q(6^A5a#7NFyY^0&#%_q5vMrTw2eLsvb=Nu}= zD2~{LPP60kOIMGYT8M(NL5`fC>QG7HATU8iCf;ifaq-+`0h`8Um}0{&lA|uXthOI} zx%KVQ{9%p+lgSLVkX9rzpTrSijqb4|@{TDd0fm{Y4C;nRvsC+-Wql{1-!n#UEa>x?diAO#yk=$5skU~!+6jTu766sj=4rfi|7 z&}f0ooJ@U7JD);IC^GkmLbMcZkdnJ%s9)~Xm<5ebK&71AZ%9#r!Uls;b3Ki20vvp7q1Cgb6u2H`A-lr z;VU}B-^7+Iwa!pw7kZm#hJ2BfL6XpS1x+VEbVS~CFdMk+{l%3rFfiPvk_oV9Wc#$e zD&wcH6CcQ?xcSpYob?fO&n!cQZ&Z|1qi4J9Y>k9Ib9#lURD1Cp18B zp!`Gl{%AM&__e?Aw5cTy#0)&Rg9Vob*sSS=4AF!1*;U;=tB~kjmOJ=~kF@R^HT~qO zkxkx&Ev5KXDUsUtAj@he1SWO%O)>$cmBuqDDlh^3l<}sAtUm$B;yhDcH}EeMAF8UU zXW=Q{8K}2Wf5t+EGE_xZqs3G2lx3S~57omi!BCWepg8s*(e}ZBJxfE>@GO;ddPK;O zZ-W4hdpK%WJ&%&}A{;6F*N1HPpt?biZ6S{t4lsh+Biyw7k?=$rU_TF>dwLro0x|we`k8n7jQfnCAuLgj};!?+ljtg0xwET!f#M%S&*RWP$Zq@0}7ZN*KtZSS>rrVcWTt47Fm ztXsS4cPnTo)f&#POV>Jd-vVa2$+ty(^WSLwSijmCAR^rYP(A~Nr_mP@NmiWxLWzZ?{$sO#X`dt~ra;QVU zHZDs|6kO3}5zwygRO9BUF1`4WxJJauP-(qgCUhH&w(z(kLiru1&xmReSoJjm5Ie?( zTkC{|h*;Ksd$?tVS$#Jlw(iQ}2nhdro8Vv?lbvycs7l?fIDq#QyGXQR*+$K-b2_*b{g8JIg{xAf9|yCDOQg!?OB+~M;Gv}^p~ z9g4)B6=zuXP5=4vN7fs#wqBTbn9gqVOQZOMc2l&xwx|Gkr->e0kdiwpEft57J4^ke zm0W!%*bRN$ss?1+Z{W>azpF&QC^NE#CKsjqIi%%dZHMbJ=VQIx%e`MCIx5Sv{u7Hz z(~EAZ80E(p>l4`Si<;3;oR$LOr=t|mDs0dtY!#F{&mA>iJsgi*)`wn=tJBBW_m*1K z{AC1^m*fTP&(@E7Lwz1IzsBxd79mw@UkTHq43vE-$Zfj-O^{pmP-i5q5A70ATUG;C z3xTI-@GQs=ga!a89dP}h8K&>WDC~%nXh|YFoKz6!ojL#*nSoc2vi`-@=YO#r^DwJL z2|wcCacTg7pIqAiY8dw4h?oD#nfyEEQbupZkmwAg# zYt>cT-yP5NG;s@M56gM?Jjd3@TOL=dIGo?BzhM#O(7P}4%H68s&E2y6VO?T{Y$i}i zQA^-h`FBKpfdL_bQNR`1TgHS^-}3T-%7D#*%z@8R5?d+2=) zfTEC1QB2`YkyWW@h;1`^ZUHX=DS)KmSmkyIeG>u8fs`R%fZ2fn0W$&le3=08d>aAv zP<1nHwerG4I_Ct|aDPOFiHF7%#ySsSTXi&Rg$yvtm*L(_v_uLhlC8PlD?FJTeCnI{ zPlmoN6*4WRY$TWAPd4#9>zC0@nP!xlQ(Q1tjVkOUUK{ETs$HG-k=**#7uYHCy|9$AMw^;$@Kt@P(u=YC|>?G+*r6I&aVr)KdL zoGQZ8h*zGw(x@%G%&V3<58=M++;T;qwJK5ACvNMy$srFCz|@E>n!4pZ$bc$iv(<5KDiZe?yG@}5mrFvSb@UcLsk3a)jZ46h zG+p@d)eg6hp8ozehIQ0dWLA26>_rjgOi7||2BXYA1tcR0>kBoGN=i;nR{Ldz;~47Z zDvgYk)@6Mg80h8f-YvBgEol!V{pJ;;*%84kv}7c@&eHr;7T`k&<{i{k!qE!*vC>5Z zn7_>%SPRN>MQd7EvJ@9ZRan)qZiYEH6nX9VHDXC&hU0o&CveG@jFPNK&p82$11E%i z@K+1QoL5NQBYJ89Cncjy>v`b7gbP;jWoc{~0Ym{?D z0G=D1%g*f}e!>k&=xF72wlShWG~&KYpZ65@$Qhdh$f*1T&L`nFZ*^@{FU1r`#gfZz zN#|Ee)-a<2%iR6#d`MF;O0>_T18<14n0CQnkS>tG@wsB5oCSKt{43{!F!gr{oi%zH z$(InZIU9jZLV*y`EOo~q^aOQ$NnrP-goFJ?4gPRpiRy<7YwcF{nz|^ACPOEAkLqG7 z9})SDzU6cyqLzaP?e*&F^AaoOfcS+5I1l+Og5ItQ<08@1UhY)s87D$trZF^FT*Xv1 z;(SSDimlR3v!-BUt@9+RhgH)l@b_aflgdxjHqyvjQ42c z_#D-3Tsw~r{-ldguJollp=PSt?amG$KR{|wfv6M3~}R+e&QwTwFI-J^e00nS=pO9Hw({Y-|pNK||w0P!nI6wcU+ zhaM_g73`RX)Y89NxjgfxuwuxTGGvn7?^Zb#jKy5B)+&7i(JFsFO%pSyU(x$Aq?Qr~ zX6V6G)x!~cFNg{!fZ&hgs9E2as01t0Bd&w&`-=Y>!gyb(vFkM1+UxED0Y7MaJhLC~ zc!(h7eU4^@M!AfiAW$x^N__Wv%X|nPOsEISLWn*6Z?0R`DJ`CwrA@M;Eb}^`XaI$; zohxI4GlGZ_HR+g~>?nnw8HQMG(#)*gJ|IT_PNS7{Fpve+Vr#uf;hc)gK|45O4h_6E z4g9Ku_=E&sAXY*wNW4!Uk@d14OY&A@DS_uONHw> z$=pBQGHmfn*dV1%hD=kGig5}v&-+Ikg$J4(%Pju(TGJ_ZPuQpW!sq7g1h7ltje(Pf z3X3Y+gg`G)f0bZ0bD&*YD_PLWBcCsz81-zPExNkqL-<6qx^^5ag?tUk-!_zlyd>&; zhk|H?wtxySB?W+u&z}FKQU0~$$Ij-aF7Ls0YUgr#+Nlm*)mu5=p4L~Z2u}Mn4#*LI zT^{UMqyTejzrEpn*p(looQwc^lT@QNDek4iwan`!0)j8xX4_c8b;}FKKF}Whq0gD! zIJJH5GB0ydY~AK7E2iS<0Nip)+_oy!4CX1aqwISPu|ZrTu;c8@abjHbx~-^X-4=gk zKfek147Nd0qoAAIW9`cY=yA%<@(BJg@6Cb@=PC+wQ`190e<-($gXpTc1MW)#oQ2@3 zzJu;-Vsz&KI1SnH=O(X50+0sMQ)UM_^~1|o1=#z~jesvMcn9%KTMs5+H%jBS$aDKE zv8`u)57h%V;BKyw8H-P_jnjO({dP0JhgR3*B*%+0%XY5|KE_x%stBCl!Ru1nDeQv? z%Qn%z3#97G*^$SKHjB(|DZXWKy36c4%+}@6`-?ZrXUY?SOPYKc$XMc3+_<;#*a(O$8L{p8kBIbaWVh+jj$Hr#A}EzU`u7o1j)!8FMyet)aCTR#pab~X8tIJG1=L3mZD;r zuExCS7pg<&G*X4qcFZ8i77~Y=f3;tCV`_Z~SRC#_!r;-2yK4Z}g7+TZR8s(xnYhtM zB-;`vC5mZUp1lgou{)&+ECy&;@_iFb3I!)YuM=8{xFa-@Jf9F1cMH&x7a2qY8Q_t{ zZqW9bGp$t)H2@+U6=NFY75ke#`zWA(`zG4k7d!umsThfob^7rjB!)g~1)I~r!rs`4 zbb<^z`EDl!Jh43UHokevKw+eaPHS-Ii|C=I&9tiZmsr~7zx(uI>=BERCSN4CLQI^4 zB;RX+_sjvC9fds_5S-A<#wZyMR75`L*~=JG!17bX3&~z<&ctR2%L>awPrxvwmS>pt z*P@d6;Tx(8&*d*8O?7xmI)CvfN?=5%iR3qdmY}y9e{h&6_@0 z`)?V{ctE$!=d?q$t>=*9@;Vgk%&wKVF|L`&8tO&n0nU-i7YM_mT?R*d;xeBQ1Z9Xs zJ{f>`ZRE(HJ&5^p8_g6$zeVt6GaYc6%p60%`SIy6o=AXrt>$bqoKOU1Tw^{c`G57~ z@Gzc4L%pT(>9Cw&f_Tlh9Bceo&=orJaiH3S=AphY;7bsz^~CPoUJ^VRnc&)95Dh;6 zQCoYCb)s37T(Yi%iI-wfD;{l=WZpE~Bu@XujA*%}J;uBWPn>R0M$e!8EktTrnEOfEvl-L6UMI7@uia7cb=;HY&}uYDUblxuG94ijrcP zJNhQsG-7CycA-biF}{(vVrY_X89JJjW|=xVMYsC1@U$W9^W*HtX4>Ni)(gfYF!6}^ z>w&P~NIo57>d>4XW7N^SYgrL^Ljtip$DTNeuwt6u2wmb-p_wC@l!#!eFR3iRG*!U! zq+fAD59Co#-?4x*Fr@?hXB7FVS6QA+Nf35JibF}(@a(K6Z=|NMR7Xsb{coy$W%eMI z+1ie%wASFH`_zRY)LA=EWbEka5a+IR(jX{dC~U#dfQql8j=iu zUdvFsf=Z1=rb~)VkWrgyQZ%chV|=bL)I0Ooe66y;j4u^c-b zA8hEbe*pu$3$EoksCUL<783F}*Y5hkqhm)iWK zU`roInl(ya>K5>EPPeW#h#Gf3e)!-WxKy2CzxKBO^2w8VA){%~i6!fGsDv?6(1Qj} zv_zxR%y z`-XbxK(ObkA~?F0ZgU8`+^3iHA~+i5Z!HDUUzItqJ#4f4g|Mf%t`J4v`92s+vOx+V zg{)roHC_v~=YJgDUjI1Q7fqZJysg01;9`ygqfEdpOJmn zNl^I0A5i^36odqR@Ow9%bjHwo=JF&cQTT+;Kf(mA2(Qo#KE{HRQNquL#Rui5Mqs^(8G8n%S>Tq7Q?ypJ)Gm~9!-NjUF z(FI24qFozVl}@T@>mY5o>FJThWwM#blGC*+V9=C1vL-N#ZP@Sl4wK@V<%K&)$cNO+ z8F;kn(R@P8E?<{qorCzuStK64+lcu7XiHWRaglFb6aSz|j7V~*ckUG9RCmCBdXnE_ zlb3~bZ^&^kl?LA*0y#RyExwPB(aT_lg)2PoilTI5*)gk0_~f?G7fe8xtdK%s`Wu(; z_y(|J9ltGu;#9aQkE1os*&h0Ge=UI{LcsV9DOCh3pXU(m)AhBTaq?;Z^E!B|vH?`N zCX(>a)t;m+^W|jy$P;=ZS(tpGsueDtG3gzP?a+H?;3#@dC4+70hb#|K(u;9U%7ZKd z8$QG{ThmaU%M*yZQV1_L!YX*AgKBZE0%j zd`j!!)2f`)jb!cVNi3Q%yXz zS7oJUS(hqR13ui$=Fuq*?r#3JoAfo2V@zfi(Li+_zIeytlT= zVd#kkBS{8Bv~aAUKB&%AJd^mkvTSO`w6(9d6UNS)^dgC_5nb#fpkQwNsXaO`tDas$ zqA-=qo@a1z=Go@0cdJ)!Gsa94jthU*U&CT^qF05p9XLz1@Jn{&le_afyxVy~p6pmB zl8QYhv*z5v_@2~*ub%AwG&zuN3|f&tUa}}{nKVK7n*1{Ng%1Q<;@t-nC)1upUK1*{ z;mx(l)%$>5S>dlBRXdoizBYTxU4bgMm00`htWz8{RFvq-K zSwpWobFzS?7lX@8cd#@^vo&nxsw;mF?*ci6UF2-r!oxU>;~o{#jCP|*pWr*W5tP|c zkh{OM+=&j_8?WV44xH<*mMRwMJtSh0dDbte+(#kXH}ySHl~fz~ry=7zRE0a{o*w6k z_zCR{%9hIxukkyZ!9p<`KTxciv|!Vu)>%16K4_5dT~v?Q95RDmrz>pTwDiBKG)=k$ zCUhjLRef&s4Gt~)KTP&r&g(>X$?jdmgHyU4VqTL|j&%HVO3l6s zUlLCz=|3`b7{BBAj&#b#Ntp~2Qb9DHY$m$}aj6z3yA_i?V|&>rz+t=&bW(gmQ+326 zKI(pNv-meyUVL3Ihjufje%+yz5$$=~-*~@F_%jB<&KP>5DZhZ_ofgOp)e`O-fUN++I#p*SV)T;hOl2@$nx!YtESL-Ut8i$QtzdnOh9Cc%8n4FE=5xdKA#-&c{fhn-pmR9=!t|A~t%&qhslWS-gy~bYf}9*zWJoS;R1jD7x{fjM zRvFaYdIH?PJ$Kt%^q!7bY_s$+Nq2&&+~VTe@ug+)q5=Q?OK3#vX58I7mc(3XU;Juc zZ0914MH)|I?f8XJ(m}S;pF{&Yq4e9v7i&_;M=2_REwC5^{GNq1&U3f2mJ$u}IK^6x z6=ooOSsrVDDN0L=(HV=oEsaG@cgDs>{x44wotqZXdaj=P(b!SqAb-lf7_iTG%-vk}y5qFt$tEJ>Fa&)+&qS%F_Nzl%-F zutm!)T;0paCy38US`J7IMHDeU;S&l*y7$ppyrJd}hQb}F%O_hqV1_X|v3EVkwEqWd z?-V6klw^zMIceLrZQHhO+qP}n=1JSOZ97jo^JaBb-#4n?Pj|mJ#@;{sGe+!~YemdC zBO*fI1{tj@(5pLZf(}JH)p01v8Jl6XJG4bZwYE3u!GT5;IJM-nE6IF>rz{}}-AEo{ zv<68bWWNxrIP5+tor#~k#Gn{Rm9m(__&QJaVyK*wN~Dk2H`Fp8BT0M1j-OLG|7AS{ zr%eTeJXau&0edB#{q`AivG{u{7X{@|`8aLP1jfhF`8hGZZQhy*9&*ybB*|-p;(=V7 zymW3HUa1UAyfGO#uwo10ATHvAv$WnG3R9D>6b1c^P861tUBo1dG#%c^gjd`AI+-w4 z#bT^_aSpB6zl2P($(!W7L18>?d}!VCXXV#%wcbs_-ZKuf)6KwB7c8#L&CzNHv?p$C z*GA9&wz*b@!V8vlkeQH-HLiAZHr6t>QS+v(=&rGl`5=;^A7u4!E39+^y0*md{l3+=;_YrT9<^GGbxVY3M|%f!Vb0yqXD5ONuUIvyGAZHjuuKw^dS zs~o9vTf(!^MimpX8Dz29#P}E2#p|#Ey1!Xv(Fnj<`WB9E#B*ZR?1E8B6~9_M}=?+c!My#1e-OI;Ux-D=YJH z9Xp8-<@y=yswH_JHF%4(se3`BoO0^r#@A2bnuRO$jkmZiBhj+V0{HVHnn=1e(R#3} zlYw76Rt3!P7k#adQ2Yj1s&?55Jo@G|5kb6t-xNxw9 zCSj%Mje`pj&5@>L%lJ9+jLYP}l*`n?a#l-Cp%y}N8aH|C0J(n_G}gsj18jaDfFZO+ zzL`a_ED%}qqh6r4$|$B4I>tGcry2xIQEfqpBhG7xg~ToMHv~Ch7P;V8hc4n5LC0|f zJ8>4-;9CbZNemvskoM977-Qzd)`X4W;VLlDX)PC9*{#Jjj2SDAqoh)khqhu#u+L#2 z6*3}P$cxfaAQjG9L2s*&x(NbsMadP@#mwSt0+E<;VwYeu$#Rcw+Q##IkZr7)1y80xkT^0rPyr1z*>p?y@Teg@_ZT-9=R+m+IJ1A`faR4lk5W^o3? zGJjz2Opp_55lcPx9}bgPJY(JJ*KTFO6D^aYCLnJ8Z$^kO; zc}e6QdnIr2YZGmYbSCojQoIX=n27K__Z#?a9w;PS{;(W?^Vm1EzvM{X{j7-dVB?6U zt=`49dqnQRP39xaM&9er(c$!4=kJKOpGaQ52;IC-xbNHfE`!QOAr~{@*!BcVx(TA% z;vorA#Oe|d|P-yXAm-f8*C4z z$XOi8P8|-msv(vmcYB*@IIxVy#@mIAmd4wyjP}OclZ>v$+dGY3$J-B$fF~$IWZ)+# za%8Y4C|YF5Cu(*-jFC1ici)i@4=Q)xn3LXW3p2a{OP@0z!Mr1Rgm(VgcbBp03Oyt= zTRl3np$23@@=pijoe0D^;*Yk?j{oba3wUttd-dG?@V5K<#r6%CV)l4SaOO zGFb&Z##LVIVqR{Dn1&XY&|J%5LIJ@7(n7J`kQDjov;TIxqSkL8*g9W69~}YuZ^DX^ zTsh?LD6CK5>;q$`h@OIhFKFp2yhGP>gmt+m2$QT@z`chgG3s4?dggET=$3 zg;KUNX7vTmaq-#(&24v?x4`Ec7-k=;&3>x&egUTOb@PPaGop(;j>uWyWpUXCn)d#7 zZ)10KX$=sYwY6QXeS9myxM8KZ9MRjn85*L`Uli{7^oqq*sL5rVOIfY2Ox1ZM$g@lz z8Tol7oXnrw)qc-%vmIy8Ho%>s0o&3&u9UmnNRK$st+61VqM86gfM5muU~?!?a{ysx zaKekAfZPp7{e3pZH-@er?#8H_odOQ`5MvV;t%~3}D53tR_Q}7eB>k=-d*sJWl=7Hp zrP^u5X3?3sNHStWuTA@&sty5q<_DpC(!FB% zJXgc=+E9CcX9iMWT}81k7DC@A*5AQq!@G} zt^9fx8K0v-#(^ON+Sc4YG1+~P8y9bWZgb&&FEQnN$V^>^+Bqrtedx8iuiLTh=^gAl zVXK>(doX&M3MVZs|eP%DGkYTbu!SmG1Kq}2OlS?H>dC~xc7|*PupLlr@xN++`8T|{fIY9tEIZ0 z_1_J@TSHu#T_XA?OO~v1SoYX^9nSqkZwcSvZ00(HU^(ap%x-K^t9>L=f_>$L3~P5o zSqojmpjkivi_RgZOXA_-XWc;bkL*G4e{mL+vUQcycXSjnxB8J${EGmfY^{i?jO4=- zL_`JotH?Tnpw9xluR*U8Y1~qLZWyj2zv)vcb&8nE%EjIl@Id#p_7?PoU(QU_^yAkT zu_;!rCn8{XRLoIe;u!l$PS-R0jQd&#@Aun)EP%~Hc?@NmD70l67uBR50orzZnOPtb2;34LIk0;Kq_C#(WL3NG25j#~Xk8sfK*uHS;-gjW#|u zEb}0tJnw8=nkyHn#vz9)+D?JSQ)K`i@d)CPh_@zC=5mYV4ByxvYS#$}tTr3=gSi^P z&f@RMKZm&74gGe~#nj>((W5(S>X3t}|6nScpO%N0dHFkv+GJIAR9Q5i&DW)Qelj2% z*Lal0Wia2w(4a&+zV^%^2gpm}Q6?iVEqd#a!rh zhC)Z{iwn^KH)~H(Wn8H?Tj2v)fr2`)227-bt}3+JmF_g&t?;Vzmj{f!RY%ChEYn-) zH6(Aj6&mO-4vD$hV^5C0;&w3R7T|BQ3m2L2a0&5JR2zqZi4QrD%=^S8H3k`|V2U2K zm)>~36oCVyWjHFnPYWDK72dMy(X}8f_T8M0muz_^Y1@+n8f=ZH{F-RHBM@<))7kUR z?v29&(*SfZNII62A31Cyo5EN4fsId@u>H9v zMAB!hN}~VXNZ!VnExt4zSF%(#^>q4(2`ulFy!fSzEwfMmE9ede%cI4?ExLOpRu`miUwdwd{yxHXt8H<)u-B2u_d z1_XBb#0dTmjv$*PA-m$c!?p&dRHKcFc`b0ETH4a?J;nl0<&2%twH|1pp7Lv|w-uo$ zW^*4@w)$4~Z;qOYMNI$G6-r7}3q{+AubV(ONkP+oY0nT-W74dKt8`*$kN%dad7*7P z?S-XT#LTob2^!*)>71D21FIsd*}^Ptc@qA4Nbax;|1I<7_-wHovhsVlm=cF zGDyy){xKn{&#R?7ZP#mym$}RIMFqj1a+xh7Q=H1c_@H=}-gZbNEA;}#o2UPssEpVc zE=7={B~f~O%)l7FW-dQ7he4Rh{2+dEZ@ylLpE1c1d|Po)bv$)joN&VS>O28y8m(Zn zrjO_%z2Pijvx;E4D#D}X$z*fHZZ9SHe!i5TxKpcGl$f%&Z0e%=$($ZGk~*KRMnXSF zH-H=bQlPuXt8O^Ca$t7q02y;oo!(|{!)sn$WybcFJ%&12b&^EDF5qf=jf!Zi#Ofs? zKX`In8DoVP_05PdM;9k%J0CuB@KCShC^XoGPvU=6L0!pSw72P6f&{r$rN}fCsaRu* z45h&Ptfny!vgIJ``cTxHW~{m03bHfn4-EYUPHM`4BR;`mIuUH#m_(oQkaZ@`p-$MN zmqZnBndoCXWl&|(O{y{9oFcXIh}LE>HkMJNsk%tV^Z1z0S!|U^l!!;s9HmU>egiS2 zu925*0Ck#h=`l{W9CcBRU)GyOT&h>$xm95kKvZ`oz0#mEa7Wz>uIU+0WE$}R1p&{z zy$HZ9KfQpAePl3wJ2|ZG;k;jEUR`6)o#ZlJTs4*{e7Yt3_p&c?_-9uqL?Z`7+LGOi zxw*5Hp27%Hn46cRFrVPZyEtb3g*EmFUCBW!(*fE--EB`Bzr!jghs+)^wz&EBP(aM{ zEhx6{V6M{#I;&G>EUeS!U?@k5@e`p})dB7Pd(Zw79?zUTy1>$Qtfp!+cR7pl@qUr3(?h4GQ&7wVYjNuR%tKz2D&HIKBP))Ie z?~%m)6u#{y)h=e`zO3$3N< znha?(um+H9)?&36CFXOpAQI!ULWq(ma)Pl-x%G+qk*JYrZLgiy&?I7gJvJC zr_Ud&ddC2VDsi4MSV(^i+464OyOJmKaYpGAqL;mF`GcZ!KrKUV15VL1G*9X7DQH_h z%$mF-e+BNT7Qp)itiW8q4X|eh;;xD)_o5|Le<|<6o2&v3x?Z5i0hq9;%DC&(s`tmSSY z%b9xXUYce78NGavcVPX`OT~d){r6ElU|zI%d0@`9W}be=OAli;eqCCZt?t;oZ^ajH zGlQuvlo^r6W# zK{Bk(;hxK=m&LP4?fnN`5Y3BZF#2jOisDJ;d78M=lQL>&uPIKwJ%nZ0rP693KsrFa z_;(?4K9SxCHt97&F{(@Z%%<8r z(}2|b-;v8;Gp5I~+QCSCDtw^pujBucf_A@=ZyT{ko^BQv5ZLE zQSl#we?viA=YQyr|A}qQ|60Xo$!VX^UL>9Wt6%h$t%-dXP!vu;2uK(LPacV1c8jgD zuDTI(EmQ21a+8e@Rw)dEf(YgVzz4~|B~b)<9}IM6da~QyHm8}_*Zcd|E{%<{9A9A+ zfT~q1#=b`wbjZ0_h4nzR)H*tDc$U92+A>15L%dW}R)h>shbh^1sze4TRG*1yrKqSR zEReiYF~STDg4M&5>PsID@`z3NXfzNKuL4)W8)CdK521o?*rGiSYM58{ zJ%EmqOIM^R)he(`W)WZRGmO4nSTC;z7&7*5Bw?({E_+)sRc|Ga(V)YadQTLxX;cnQ zO@73ipFx=<~orRJO7gA#4yeB{n6vkN^?G{Qu$W!D=2%p{B?FJo47MI7y)tF+;70 zFut-uhXwmR4Y&*n_|K+K9*3hAF>=W5!LJVM`rS*h$u^oo}ppJ zsFYrnvcvEK$T(r>UMS(>Y23;R?+D);e3Fl;2bc+E`n@AQi!i8|kLZIdZDfTm^F8`1 ztrlk=#^FsR80ga`5^p2EUKF8dgoH^-t2eWBhf%J{+;J-&I0Udv4tVs~RNSW82XKPi zT#CCLh+O+{Wv#4u^jT7I=xNKWWj4YnLx&VF(Z*NA{0Q+KFjSK4SaB=SKk zm;pxu8Si<)U+)t7x*)M>S1`@zgZR+$rIe3S%I*_1eIJ0H{9_?akHm-JOFaKQLtg~% z@l$~S02rYDNAgs~{|J?!t&Po(Ny3lm$v@MyT4m#>ZGiTjO=KkAaO6Xtq)}NGr!a}WL6I@Cos3H$-1`Sguga$Nh6g#Hz)ce?Oiv08u$gwLAZDx70dG?%I;&jX4SGO z!RYT%*J@cyD<2 z!NJol7(WFW#MEpm9VK_C45h7$N*tZTp`b`r#c3nS(U<;so0S|i6|M^hlxbcXjs&WpseRvs|z%Zt@B$YDxn^r z-56TyNGqONmVH-`n@y=7=#Z(G<2_*3)4X}4gFFHbBAi3~-%6DcP_EiERL((bRQpM> zuW^p;_eQm^!r=d^iRLoLK#`xbKZ19(D;G4(;O;9Ec9qGpMg=k?a5{kHq`1sH*L-@Q zIaAK?o`EmnF)waiUtPwRlk3A9U7dz^`QOS))R07^N|%CI)plLlBFiik=7YjN?z0)3 z#$gBMpu?{*aY<7LJ|LL(NIdOfy3fLc0-)OMWXE(d`GKo?8-Z7k znh6Vb)qzJdGZ#3wr21MBQu}u|QARCUsctCQ`tOLA-dMqa>oMY+W!`ONRjni1|sxj=5z)i>L3fB4Q)q%xdkMY?sCtM zoQeCA=Dgtkd&RR8r~`ca0fm+yaFF_+g2Vq)@reFe0;SA!v!M4c8-cp4cx8d|_QoQ(5~7?5+rd2SPGvrayuNsO zg4#u!M+_h#`a7}&+Z%B!2j6k2wrDt-{r=NvJXT$mei341%I)}2&_(4-RdU#8jIvV6TRebv2I8)4S{?f!5)CCTus=?L}O`=;A* zhWmNb@#`cjlk0PPAQpb^cj$sBgls|y8Dz9>#@M`6yh%m>!r=xv55~-b_ahjnky}VV zqj%B0lY4sctyQq>gF}7ni9>j7iG6ugs=Iqm>V&se-vctwmZ-26`2l2uJ3g&~TYbN& z+p83=^bxU6O@dE(>I_0cqj9mZfU67(_t->nxk~G>=#W;WU3RR5P=-MbY6gh8%4m|K z@Ulq!E|-4eyr|$Nk#u7}wT{kFp>U_rw(7*mLs#dpsB@=^Nwwn3?=wwrrGbkh^T5kG z{ymm6R*FvXH&}A7d^s&5Efz_~`c4Z7TY0wALK2(j2AWS5bB@l`CK$_y^eWv>{tx|FoJaxaMlvoyF*x20Ym=3h~%ycdOy z_((EW9QyC1SQI?qz_jmo-LxO)Zh!4_!orq zSLC^S8~vtG@=|gn*;9CKml~YwWkV?oLm=B`eQKPQ`jyOd2vuQ=X0`VevW%4KzC|FC zllF6DsaNS#vyG;RI+U|Awal{KpI;a43 zV@0}kv|z3jBci+GO&`Ms<4ZAHzt%?zb4CQQL!SR!uX(W!oEY>d4j8Y zv$C#!vMqev@gl|PnS;A^_^!eR3ICO+^s;MIlX7@bZpe^ss9gkT{utLn;& z*c5FN@<`z!RKu(ZMEd2*k+Sy??_;Ayl&kVypgGt`tUVJ+?kF}TY@ zTgGBcqSxQZ2&ATm4n+EjEUoRQXWZWAnK z#^+F~G;5TIE1RT5>3fA`>JVB})AA$tN@}l`+zXNkXQ88DMv%SSia)UXU5xay9M0*u)vXi?Lw2vx=%p`a)ww(K~4sJ{#7 z*KP=|9ZzDM0(OPs9L8vkOMhb#h6>`BG-Rw4Vu*lkZ_yr?iC>AV*hTf~bM@n#qnJLoM4fBFUpk&{{NB>%(!+ zUjv~h)gbBjfx(a?W-(;=n{zVklmZ9t(s_P;yh=ge;Eus}GZ+!aU_UHW$)YY(^1@xv z3wDgPJA4V02;&Ah7iNb`uL9rS`?Ix_q*F1m)kOat4B#+8f*~Ctph9&nzcdIPj|#!b z%T#KQyjD3=X_qeM4ia+vde_z|27IK$*z*AO6)diuUx6cKzzdi7vw$7eKqxD{XWOr$ z0AagKkYDY=MURPJPl*&eAXiWLE}1W`k%L1es#ATNP4RsHN9l`Yr+A(^2rR)kd~ES| z1|Jztm=L1B8^t7WLA+lPhX3`nnGmdy;V(TgHl)Qt{@+*f+&JlpU``erkA6~rs>^P- zC~l5C<0^V?#Jt;2EdwN66>9sRE4*;Ifn7OuO5(Sl!nm@{O(d{ivk3zJRkRsX0o<9PYB%rhg$TyBBt}aH5=nec^=_q#(;PvDqQXegGvueEOP`7y6#?8t| zLk;r^{10Yt9W#qaVane1ml2Te~-#5Yr)da{SDGr*LdyS1w~Jv zuiR_wqiFIs(azVTFF#ugCoM!p8cBEMz3!`R*@g%aLqS?kO0FqqNwk{!+f}|K%{a$bTw3?GALud|%K#%lX z>(=&2tk}pe1yVAw`4jdm0(BAP(!ylo>aG_I@ApJbhFON>T)yDS>N3|~N`65uTBRtu z){&z}hNusPw9`b-6M?7BZz|QKS#|rX0SDSjQSRc#)}-!jNWr@IE+yNXMce|s8UK6SyOozHrm?!K>WO3a-|^s)jG zPw4iOCac4v-4mX%Z?|(sPX#%yj9|vttkML}{~8u(X_@uOc)R5jJtGZ(c%hjsyHr7I z(+Io6@mXxECYiL>vQ0Ast*WiS-Ja7g{LXURRFf1Jigv=RZ*)@xX*NPjq+w|)Zo8EcS+n@qbLvT2LPhgM8 zCWK2fnw8{_{I?)@dX0PnNE?PaXv=EBSaTGu4K!V{agwuC?_I2WM}JWSbkSyr`O_-g zHrw*==(A!*?H#1EkOzKf4^b(FyLP!wO-Z2qj~M#vjF^ENAl8pe7Gn@EUWWAgqR|90 zE0DlT8g$7nV<=qA#F$16L4TXW@TY`4^ijJk!C$wqD$3oE@c5`X0G-r%GCH7w9MzIEl8JgNaFH&*`W966PH;y+Wsyi3 zXo9_^f6f(z_S)laSq6(PjxC2l^`wll2Pq6RFWZFSD~J2>Jp#IqCJ6ffh7;YQe7NHl-x)FTjO0mwOhM$RavX=qe z=oVyFJ<}e1QZ{XP^rUz>0}JpRBz-ggN9xAaF(qDQo;(q9o@ z)Gh1BvhZk}qvkonNY*#dI-dC4hEskIu&loa*39g8LQ1y)?lE%Hc;wc^pNHOYTxhMh zxLJ##ETM<21sv{Xlt=PmZ+9gmq#64#XiZt6&M>nBB+n;f!L9|+yXndb>!RJCN!koz z7Mi@#8?x+fSg|8jpNBM4GnjcFTWFNndEoEn2DI*yXx?LjOm|@AufVUtfK29}Jd@-I z=%4TA_dJrl5@CW!!yejh5wk=Q^HS|m667M0^8wHTzDIb9zj~~cqTHM53a?We2QqI zn(ShV8~3tjrDxO+_ki9^hB{wTO~f^#^w(K`TzIE`JF|Sr=B$V|u8@}Ij4v|W0A!P3 zmF(%mEF36l9o=`lnc19WAChx6)w-T4goCM=Tq{9YKz&(n`p!x zHmQipRITZ*lrWrw1Nh9uAMtG>@#f*E4$VVu%L{Y*2TAhdkB~Nr)aw28am&!or*GJO z-fkKgTko(tlI}0e!f)4k1Fl$k+T(6M zjOKtZ(8q%E%u0F+u9MXu4uJy@b9v3LeIJekJ%vujQ0yfrH#T$~o&|(zxKNq|vM8`I z7zzW{DWh2FL3S2+Wd|Z*D=CY!(8t1}6fM=hreXhu#1OuaNLq1lCF0-qkg9EP=qV~~ z`bDPAVU-@YO;yI*`VndH#p4HBRREGR<@ax0vDDKJG=Gs_AR25+gMDoMYa1v!26MM$ zCtMZv{To6*d}4RDM3*kKBa?N;hc#O|wGR%q^G!j@OP~pJcq+V;&fm(u>@7}9k$=;Q zmhpA}9==%5@_E)UWOJ`#C4O?b#D^ z$%^Z!yD6O}a;pH4MczFtQ3t~{a}Ak_Zx+;I#YMLPc$iN(;e{}^h@{#cRB>V+Z**K49t_~!c~H07YL3W=V=YynTsHR zbgX}BEhc=)@Jl)3CD#U{&;ps~qiC>_myMtA0)0lLe_>Il@b#baGP`-sCWm5yYC%3? z;)O{S2lqB0UI_eFT{a*ljKFF0Ic#LK%%WM$OsVN@DaLKO^qYR!jMvp7naD?L@pB~y zjUti5I55l5iDbEb+|yVRt?l2=l9M_>z2H~;1Po%SXz5$UQ^sNz1Kx|oYnm;Mlk9x) zDB!up53|$zJP{?1i;4gRgZ5eW0iB)M_wJw#aTD?VUTG-zqE$i=km_T71aF9+=mv)a zg~fl2a@ty~vwi1#CY=$`5bhDwOT-0%gqM9Wi4!o1xvOECb34vR2 zGJE_>`twfirCEMSQ2mmKq9z6A!>1RHNMnTuf(FlG&7?P!q+pc-hG7Rt{WX>xxmAXQ zMO^%D9=?dY@i&nY{bCrkHGX@SkTBN;0tL6En4vAUMO7SXEe5Rst3;sZneONnxyRMd zr3j&5DChSKjsi8xK%Eaia>1Covd->>OwXTK8eBwP(9?knNUjd+C_G8=aNV=g*vnE0 zb-@;ewoDbYblYUs>^BwT*T%_1*9xxmwc44R2TDMvp9U0?aKH|v(sa$Z$juB-nvt@? z{-&%9l02^E#J3x-c3W;ue`qDhnFV=8O}g01erYTZJJu|6JHk?5v=hrGxF0*VM(%WD zaVRDAN%U#unR=lwOkH>m>%H)>=l$S~Fdg1@w3R7r+pA@7k|tSfk4)l=ir)q{Q=n&k zx~)9>j&S4)PQ|{bIr@(5(g)sBK7`ewkH!FClRvCn7H&Qz99PXDDZst#{L=^5)+kuF zR}ju#=@}ibplsvE^|P=?x^BVFeJuXd1XYjoJfX7``1zx;CliQ)%OLOvz zpfZ=%=v{#co59#Q;J2NyWD23bU$wd1<8ZGT+Ij=1@pc4m^lj$%LCJTxg-kQTwhZ$y z*75P`54g=F^xf#1zFDGm0ReCY6HrMh z6APIdxA~-v!Rn{YRAPr4+vvl?khei}MeKLe=uz=gjj{`qwB)>Z7g}(wmr3N4~=Vey4Oxkw` z8dO`XDYfJcf#9jqkk;c5ido4dD$V^9ua9;@KdV zOY)7J?oGq+$bR_k`|krAF-xn?^PeF?($By~`hPJ@Ad;ZRaT4n+Xpn7e4Tm@vi-ezL*(_~8H!o0K=^+X)c*{ln6Z`Je~!PZm91qF z`Qd#2YIr=B6;p$CL#j1X)2iwK%ZHQysz8Q9gYvoe(4N?PO4-DYzGHncWP%rGx&wVF zjA~rb;1fqW)o$SA?SQH;5UdQacEfo_KZGYWRdu}}dUs)KlB!pWa6`W!$+XzvtC$_K+CsI{I)^>Z75R?Ro z2Td`2jYZQjT}Sy_B(^3UV#lw&7>t+lQ~}3V=X^~ zlbf@AXUiw8g#%{q>%|@{eeLMI2Ah&Bn(H9r(@%siMR^f6c3Fbj(#}Uh&W71TYo~k8Z zm)z~E2@fqVlMfJ^Qtq^vq^MFLo?6Ti^vrWs@<3R_I-W2?}wupecOOR2+ugudyIGaz|kiroLDbOsWO_*WMR=x)~ z`)~qTmivAiuD#<;;kRqC$N$0@{3u3nKlrIOaX-Wu(f{v12NA=+=9x(wHVb@kA>Z}_ zQd+Fg!6+JJNOW-^;G%dn5fO5EM{pYD!d8Y+APfTu27X;+pvO zip4FRIqBK2CN7;9JH9?&zi+`Tm9qvM{2*#T%J$cxRO${7+G8o!`?NX8R284YMlS_AKPc7>8L)yY35h4ux$I} zULzYk(%NS~aK}p=V+Nf>mz!I@2RUdy1L@ZgCa>bawD)&Pwxeqvb8<*Gd=840%0?Og z(Gc)lUz`)vkr;zQj)hhgsVfa7LC%~vF2@e#W|I;DSA7;JPH$0o+KKq!dluLn76^L) z6P)BA@7KnCZXHlu5iaY0IDOGN0~ZqrZYlcIdjD!{f?kz}A7*m?&421vVzaees(f?h!N89c!LMCw0L{xRpUhTIVc<%g% z`Q^pqW3pg)nLUL?%{3*@{hPAv6?*%mzjV4VGU!h*Bo%E;7hP;5A3i(Aoi{in;<86R zW7iKXVHe|)AkK3Nq`v-X2trRuaW9F;#KOKc7+!(6 zaHUx4`FG^H(4^$M2Ee0YueKic4)p_}(Ayp~L{qYOf!OvM_7H-|lj+I=ORU^ zNR52&mPs049~$YtKo~OI3jEGm{;REsR$N62eLCfwG~W#&ovK)Vb({v*uEIt;q<%jB zk_YuH=Df8vCL$6%NgHXe^_K3UAc7ck!imigRW#5T0hB&66@a{R$*$oY%`g7xnW8kp_%UuB<6q&9Q*Y~Aj z#Pr3HnF&$$8xdLXvsFqhuVWZwKwK@y^cVt9T2SOUUN|>Yd_9|B5sy=}T}yKvu#);CDbwf1Zz5Rdf}Q&BIwv`WJo!y;N|z z61rObB5Z87(t+MGn2?8gB4@2$;cy!9!~_$mjHZyN5c`njx@({@D#04FNa{usp{b+e z7F>uu8;*Q)O`m3h(X?OBzxO~*%(rxu?NU@`*mDqR=%h+Bba`5a;b_AsOiyVzaA=uZ zC^l&|ky9DEg!MJAGmbbJwq=Kl)j$l_9$Izns_}M_jx)D8(h0BVd-md`#nH1X^Nnq5 z)L<7yFla2(^k!9s2mZV!5I$eO{U6reDmbzr$r7y+m6%y2sl-evW@ct)rI?u+O3chE zF*7qWGcz+|>8amLuWh%j+0M@HM_PWRrQI9h$2~lbpVQ`U(6`zsc1JViEWGX7fQGjy zyxW~AD@ABBZFR^jh12X`24QSF(d}er97|6h0;a8e_W`&UUoa+e z)T%qT9C3hW!9u1y)6kh{S6tb4elC(L7AmiiNiimQ@Qmr6Uv*S``y(nhc8;yOK+X>@Sd-JoGwB^`v;H1 zyD3i$e}H1OSpNNe*Xfx;?13nS3xB&pEpkkPb6=@WNDvYr2lLSuo0GgIXzFK>Iy0AQ zVk+LnXQ{eyA7@p7UHx=SK6LkvAYI|>k+jW zA|~SJ%zA5eBYGUF=dpi3zG+xrVe~k-b&i}U)5js}c&DbsQz#Uf7b)cBJIP}Z^u_M~Z|(5^1l2@EX&aQUgMjs{rAu3VE}xm1Uwys;2Y2d8l=109lg#AQ?NEcM27VpgU(48s@?06kWltVXp8 zr?bldPEWEZfo9p`BMB;(?(1@9&iB7if(?fDBh~AQ8hAPxPX*kEAN~L;ZX#E^-iq5Z zyV}!qpjexRY#pIa%+i+pGGp*IBU&)E=b z+uS#?h%n5>qFr%fGytr{Tr*}Ik%NAaXTdu|GHE1_`&3BAzFUc~zC^(fn|w}Yw?L6F zaLa;Xg4-GAFb~sNlF3T2zQs@Nj_Tke|77d(Xy9^YVv4>)YoSh?#MqkfAE;Sen0h-b zfIJQy_O@FZP^Ie4P?1UW3dA7B6BT!Q)g-OsZz|#&A1aR*)HUzO8=j z7s?N>rfSp_(>zcJpYQ*=I~w9i$h*Jruj6Z$k^R43$w}**SOXpZg^Q-F{SN@-o;IT+0pj#@b-rA&B3+k4+bN)u~WYuX>6|p9G#=%b^-KZ!jnX*8!i^LsoMNZ zBop{2Mrcta%> zK4K!f$?rJU`S0CiuG*!J#VI?t2%t3{T&mB?+uhS6{bb|m^Q2NGkWbstGsf&xMimUf zSBsnMugm4*MI?je9_X%(ZmftG8%dc8_(bbWu_{?_5)58AwXcHYX~fCqrwdD~e+m9W zyX?YfqvEvO4M~crf%8YRP)mQ4k=~a-*zpdtWC9IT5R>H^69qyg(JfENh<1(4(;?n7 z8D*Y$5%W+Z<_Y7;`XwfxVSnwqmHxcGNfI_-1*hsu>hP$<4K{@6WExCTos-~Zp)p!_ zXDbYaYVbsGNm92D^P@OCR}}6K^Y_9uN#}$-t1!d*$AeS77MT9WqO;%G1UJl5SVZXp z8RuNMT71~y&9XCmL{JFVh>#t2T!dnU5QP4l&?Ub7{uj$rUV?d1lZ>YOW=F^7q-q2m zWnk^-$e5AyzkN$i!t{7Un27mz-idbzv=nx-1yzf05Saz%gXLhrNEZywu&!cD27Nx!D(}$#%SvNQyw=~t% z092{B7%etPQzaXiN;-_$F^_4_-ew_*(BZNNAJ}@R)G^tQ(#On{GpDCpj5tl`tSwp+ zrB*EdqBG|oQx6`4>G!3c!~^n|?zEpYL)0kdFy2pUnklFsFeO;WQjB1s132i29Wst? zMeN6%*{5vMtQC0a#a@Ln_sfNz2!f*?#g0cg7{*|ZipGAn#AiIpiW4LpwUh5_FWg3O zq3)Iy0$Z0bUk!jQlQi~Mq;m$|+l9N5usuw=jO2`1bAZG4-co%!^D;L{vb-c>!7jt*$h_?EOvh)0@McJrzW-kX7s!=%#M3A*Qa^tA6a8!Nkmu@rrI27lAnm?sB=HZ0Dkka95jM%o+ z5_1DIQCcro(mE9(j(L%PF%xBkyf@30Sdb_}u=F90*iS7+rWcC2i8@Wwh7Kw*gxLjW z5djK&ySWY4n=zDO^{Pk3Ba^~@E-G{R!B7TY=Z9hLD!Gu!ISVF(`zZDVhe_|Fp(?3i zs`kh$#diM=d;8@nn$dEtWT~&!!y@0NHFm3MRV?32HNfjq zTOiANSl)fpass(&|xr%Qfq zI5b8DoMoeV;|xFhHH*ZU|K@zIfvXIU;7b@~zs+Zhkpj$c=(mHd@87kj>7iajws6GP z<0kz1>wEs0z#$~mOzE?nV;y!y(6Ll^wNttHnevzk@~pfYN}~VW*G>e^qX` zATL_YLQSuyVXg=hGqi>;hV3aT)C=m;UlI5}70i9t?KrPj)(IU+Y*s>SC#s{Np!=ij$yJ6YYgYj-r>p2t=EJwHspR_ z>w5}1c2(SB(7bs-ElK>X6yxM5V}lewxGF`S7-iRQj!HH&O8G_E8GZ&x3Tb}sq^ww= zolW>gsv4g{7*4vLkkoYimyhnmMX}%!Vt}>!(;@b;FE{DmomT3)4IaV1YKg`#;FSD- z1DeGD<3ulQ^VJ#hS_^Ep%OtfDhyE_{Ree(Q=HT&jBaVh7)GI4KblRyzX}Vxkuzq|O z`}G%I0m&a!6#lFFEH~r<+f`UeGBGiB*-T$qd1$)I?)tXe+X0~6Nef4=OqL&vWG~+? z3{d{j^mE;qJk>6t9*@nGK?%VLHCTWbO$1ED4C1OFLBPc@iqHb~Y?|VC9qPmIeyiAzgK_tPNG7*3CV_}7J z8JQ3P{9Apgtbr_OSI>SYqlGU6ltd0c%=18R zsA~s%v*n(?1T>5CU5pURh~xBiQ);l?)C4#BsJRf($}0X`==BNya5@#BWoMkHZozlJ zdiCftw4c-YaK@F&uRq~jHab4!8>wbGv_}mmLorNPU-E}v_^r}>A1l~xlJ8al*d`Mbk!ik#dO*K@+7y~rL5&!1HtC_5#jF&T%Qm`psoiUNjMo>J z^xq0s`Z)M^tS^B_PsDHE6#l!L&D0*~U}|G&^uJEkY8H-4s%U>F$1__-_HUuZ^~k3r z2eVuoBy4@U9kS}kxfo70ecR_jlqt@|mdtCBOX0^&9?h3vu*F4jIW`6+6;O784Zi`Y={7G$FdX`omW78i1836B3%la6wd4wmCKR)wtNHcwv(O@KV`>B)0(b2;)I!~@<3$yQwfemq z&xqc{bPbgeC0D*$zZB4PjedpJjFQ=twVH|xXP=($hCf$;Z!(-4N&AfwUMv7)(x5zR z&NJc@S&mqd3J-<**nIJSfW%4daw357ejDjc)Bh9^ij60SKUFMUU zBHi3jDAhQ&oi-h4{l+Al(+kZ6Xkb-5={~HfWMS8fN)VJzD+Br%@O*hvAAGK|EQddY zG~?;u_?vD=G*2UpfjDg>2}}!K`Fzjuy?tuR+^$47X@pF9dV!pjr|`~aS`xaoV0_Sk zTCtpS1#}{uI*jBE9!%5dwKa9k^sheE8)g{MYbThkZWP$LGs%@+R=fG$csAo5P1jxl zj7^iBH8$%VFc}TDpgDAipbdY7G|XCC2w8Qp?i$489Wx{8j0RiyDf(riUd^~HX*F&( zn_P?|X)cQ%!LA^fW7eCDpd;`l>~i2yw9S~Cs!N!iO$r6>jdt0U zktKJ_wH3J`X>}*sD3xf#;KGL2{G41v>_Wbzms51F(Bjp?MSKxT6kU;K*`{mOLh^oP z??O++UXX#&M%yiHm7ndPxErXEw1nB7a8G`5dtnZt%kpR#6{n6#$9_lX0L`OVL9`WJBmDYwsNCFnH?serfKT+D~U?6_dihb*8)*_`>ouW@ZbXOWLry&HS29;_eylOT1a7Qu+cv^H#*;Vh-di5K9BPYMM+HVZzA><`3Yg_%M(zfVu- z*|TVhc|;ecz<=3cheRJQ zl{FCS9c(O;G3THTJ$-*PvX_+GWp6i6{16KD!tMDNB`I1a-%Zv>h@SFP%sFO1r$|Oa z6fKCi|Hv~%-ZQ)5C(QT&9oCaB!(>-spLc-tGmY+gS3u;}ox(HG+q)!YcXl<7&tcsg z-SXJg_xD8gd)A*rTdCup(_a?t2o3UoIXDymR<_F%0jn)xt9bdr4gCNNgl!q)SpJD8 zeb5rbhw^@r%HR^S@A8&~383SvPw|wqeyIW1Mp~rT)lk5c-;_XPN*&>b8-PG^b+Ciq zH=?1l3d9!VQL5dQiyoj`vb4H^P^5s+uE5D}q2$2cqh1{U8M*3C7PYN9=Kv%)tcQl+ zm|RnGC0!gsiW%6&u_`)jmeYf!C0w|We|&j;VvTRMEtjXVjA*rS4y)l|+I>V~5As4? z>Xx4;o1J&nBu>BGVAnPaVdySew`Uqx3DIoORW6SzZmgo!9rt4%<@;FTJ6||o017DV zDloI>;Ni@Z)gjx1k?rQFj`y%_UIa$)2+8zIsWa!a<`}NpWma$HTI?{!$Rq>tsfG$9Y&RLof9yeRH4zU=YT)oT5P?IARI*RtE6l_xkyX;Q9RP{Vx570u|CC z+W>wEJ`!h+!kmyiEm4X4xpc zymF3+v_M6eL29dhbBVN2q&09hI~gIpCgUWYnEJb}e|K3i$)PH}pCUy*jBB!m@I1Y} zVjxNGe1trWBHWnL?d2R)QML3Ir0_7k-(BzFDVjMBZ|2j~b3qV{m{|=H+?BY{dfu8@`c93ojYaU21@X535ZC!5BHD}L zmtwcJmc4quyh70TIrt5M$Oh&%w>-905IGMqyp#3#e$YK+Y+y|1c~!frO${aiZt ze?HO4cJ#y3S05_^5DwOIypS6pNGm;Ds-crGFF6%HTWBp&6aM8&+82e+pwS?MKs)_5;xUdxL3|5oa(R;oCQt zU;js4c`=~=SFx&ZXz@=*$$%P^tJ0Fw-)Q4}vI(vjOaebO%NmUcFl5Q<6(npp$ogfm zK?t09{reaQk-Pm=GX3>_3zZ?6U1Dd@C=|=0o(JR~7*LQDY}3>-X-txP{nF{AX6f_N zvrKkz#ss;a9aj?|5YWzDRrurFF6>Y1b=i0K1-xFbY`#Ir%(i)``0#w!{(e(QyZL^K z{0ZAOu%46MN1)_=7_goUzQ1%}b5M1m^$2yS_s+-6pEW^s|6vM{gRZOGw^g!ZVgB5T z-KoEw4*jmw+|DDylEcolspUj^F+#l-wc$0QzzccMc5Xd#tC53_Ii+TQK4*BLYM#$Wb z!u6K>{6U6LvLZ!68;{HY@>4=mh5PMY>s0G1nWEm;XJE7A?VT#?*_n?fz?>cq>kr}} zgzcXM90h`A!dYyq&dv@KO%sc;V5_rMmPV_S({nTHtwpp*=cY$UVoJ<8gCc+o^?_v= zNeFdMLLIG@`Ns0xqJnL~VfkKErI^KAqp5?W?2^c5X&awOisQxLqL`+ntfuNwV^(9- zqLo$VTC1jJD+kfWUo=pJN0^9BA!B;1HKJnc=mPgS=e#C6HvJ3hh~~F3Fto)=T<%8> zs>QYVr~wysGyWNAqed>n0)TVtP?V8)f=55gs?50fGDXjG0@~Js{*#9IrZg~a(|H;T zQwfaqhQv?3T7!?Wg>y!2y=E>*X+1NFV5n6Z(R>RFCyJTWu%vUa@`AIXS|hPVqI+vz#jE{XL2^Zfbdr5gP{%%b%#oPfA#K{8-6}~|V{=&H z#di^O=>y2tQ~M}9RgW(N1WrwsBZX9QNC=)Qn_P=on>7@QG6z$=w#3U&D_M>aBI=)whUG4M2>596AGLa9a!(E|52+|GF< zoOuxjqn};_GBYN@!#!E+>56pEhqWvZI-z5pxfD|af0Bo|Y9pdpfa+vP&hGZ=qpC&Z zsb*A$>@8px#y>siqx-Z@To{jxMk6@pZ~Cd(mg31A60~RToXKL zMw2eSmzPH*yHoo3Gf5jGA_XN*60ozI8o;rhDfY0cbeLb~{{qo*rk@JXDFuU}W`Oy2Bc!U#dIvd4Kio9%Y zP$aNi5S)(u=R7-=}F;7Rre_V4-8P0$gE=!kt z8b*eNG66{4^;2Duqp<)z38AioG1w^hgF1?&Bl{pl>_b#isRFpeN-ez!R5$2~=D@U2 z0@!qbb|Ds^FCi5$)}LKcx55=)mOq)mj?7Y^lMAoFI_oP6mufM}WyVwxniTV5-pIGI zPj?N~bKma17AIatmt-mP1P3PiEnukof3z#r8dpAiSewgkbZP4l1$W59A>L5Y08iI**5=39n7~l4R{o?esz^pA$>7E<=fXfqLyIYYILE4Ygfj@G z!BX)eOGn72g(Go_6%!&;PD^!TW}zR>=SXSXQz8BH)}NT1-R5v{yKvRYd6qD$5^jzdkrV|^4VO%hJaoi z9GPvMP0KwzIrprvW>zK(F2{i{;y}CUXpFRRsL1MU*$}KyMY697hx_s2IaBz4dH(0jqU0`b9CRwn1(EAg!T23#M>eH1ID}iR@145A20&t`|#+C=~=--5!v(Bu* z&+sa@w5p@*Iy&@lMa2@8Ck0DOrmJ=P2p7bTA7pHNl7GZ+zWBOKlKR_5QpUSaXjJ6> zc?wr5Scu8=4Yq_~GU`}(+AO_7E4dWhGQ`N;*}!WT?XyqV(P@v&=*lefkcY+JdABV# zMeW4cwm}F9`%+COhvgq)NU-J!uAO)YL1GKuKJ25%fj1m4x>vl~W`iR6c}1AohO|v& zC{`bb@YV9q1PbONDY=*3;FaI%IW7O}3A|>IB91l`m5a}ofqoOEXV=P`F0}QaY^uWSNqjN0 z^5&pfr}sbEc|{uEK9sVa#O^u2UPsbGdyLMb^@QB>5~V-VlL6I~o4Db>?La0?W5A=C zm!K*%r0G=)0auGIo8d>%o~l8>F}s~$a-f5=oGWhH17%wLQBoIj&BGOepilSd1s45f zQr}ZuhSZ*1G|hMbl4mjs6?QLmGCQ>K6pvCdmPgy_!r;Uq=L5MTKmYc$Ct}YVIo8ry z_yhI2EvNa!PkwxF#qz4%4pllsW_8^zPVes#lEN>a=A51R?+MN<8EGE7z6l=pk^PN>div zlg!R@@Uq_`uPVYGN>ix99DE@rH`t@=c@9v504%P6#a2M)h^7vE*nqjJG#ZzGS>nB4 z!QWs-=D#Rei|vw2Kl5w8Y*JZg$yot)h@(s=Nz#GoM&bTU@%HJNj>y|6kh|XkcEza& z7298!2wfpIo{8@!92}!%XO=@wu!qc+Q5-|3cGWZb{tog^05aati)!z%66;-0E)@(uQ=Si`MICippXP#bV5PM)vn|gx>a_VDfbAd8kf71+!rucaU%&@N<3I`a6dk zdTojblh1=ba}-X=lg#hxJr1GB>BE2zqYoUXvdkH_eXoe159CQ0{1Z_IL3|f<>|$vP zDUs~?oIl{OTf=m_$-%wBKzWS=+j|q9Q4Ic~D&8kdCxCg?cFBDVZ1}3OF#Ljvg||2)>*%TtM>${)Ora3VXgoP?tOIP3}`Jw=YaL7$=xv>E%PT%E2-h&{dgpU`HQwb zVZ1-`W{Qf{^A1Yw9T7@bt$-&Om{^*aeso*fti)_o8BANHYK#BQaWF*TUz_n>*-gB- zsa}g6IjhxeqZqYS2*P>zjGO%Q)@Af+|I)Egcd}pCyL653yQS)Ln%Ztv=D1UCOeN

pdbpm+b4JIxVgTpVdAZtCTTex<@wpPZ<-_}h6IT9=;9 z;u(^~R_79?;fG1f-Aa1$t86R(RtZg2koK^9jn}hh3koP2l_8sj6b9-~1&50-5=h-AldF5Q0Vv z^V_^7oU62G>N>)L`O!4{aSWDog~nWUgWto><%v4w7%;fAAr?R~mNDA( z-ro9nVN*5h0o=I3HsXLcAS8Z*J{LjTP5pYX{7L}EzO!f0b^0y(JKtr0nSC_sNE^wo zrx8cDs`2C}aUs0y{ zwxgw458rfwpx3t#32+oVjJ#1=gTot)!`hbBd%Y2NRq8~O*a3d2n-$(KyO$z*c+szt zsxQzOUBW91BG-cQ9=TNgrGIUbz&*Gxts74U?e8scSpxM8i=)JPOqO>HEB;(>8*3@y z6!2Nayf^gu<6qk(`3O5QNna$>yD!0b-v4@=LT?`Lg^>{{fm}h zY=Zo1+Vx5eF*&!c)Xo|f%NP-*nXoS|Ha_PbGq`%yi8&eNo`P)BS^KByS)5!VrXq~F zmTIIW7f>@T)+$M^@*vKwF9!i?)(r}cU4LKdOKWPryqfr2qF7`Q&>-ch)BsRbmi#h* z;1mnm4I`Fv@F!uR6H94n<`hq7X-l6(4b&&A&!BwF{!w*NdUOqq9d@jmi8sNry_y2K9Te##ge%k zL>^!Vm~+tBx4aGxia?DFbF`ytlh{jCGSl`lF^mU2^l-6w9QMF7s=b!@a%V{0#fW0s zAD8f<=l%pH(8L}~ERapdEq2^P7ml|lqGw`<>@6Osg{W!u(9To1!VjSeAu7v7cR(AM z%Gp8=QJ|@?DPw_ytICV^Y;aH0?xp#QYmr4L7mvA0_N=*z_E?|iu6r6>&9gF;xhxgz z(xd%yNp$EiAXQWA!SM4Cm-dOe;0K}kqZaJoQDo^Q8qqe5;Jb;m<{t~eVd zrwsl$ldtBQPy=3=qh-)a0&M?YR?@aIh1pz5kCB#K>yB7>8Wv+IC>V#@)pcWR5w_of z<(38C7uDZDY2TOZfjHeqt$erV8m*3;OWl+q$uO6ZeL25JU6GL$m+?X?VjKBsdk8O( zdqdD)VwIoD|7?n095sfiZJx!L;{R9F`X5-mjw@UzOzCe8ppOs!FTLHcn==g*>CI_q~R$YvlSCk zbgXBC(L&ZZ&n>k_jGH96hd#622ZN$@VtbXn9*dF1?y}v33-$`n#r8bJWEDG-Vtxc> zk-4erc)2xu>H@jr0o{rp_7h2m?TLOsXx>4HM&d6C8V{B}R*@0B8kUt$JZb3J#UC@P zH~f0<{Dth_i@13Ycky%3;L}m?(db9uZS@H+>)O9R0Veh~u~U*1a!`SRoHGsn)jn3e z8^`MW%S|jh$=A1l9rlEBX*NF{S=Y8YkmoCY19h`d%WqyV1lmUz)K$<^25)pRh4`zT z*}hX8U!G=Vo^mAjlH(s`j&1+WhrvOL+Oz&*UH@Z*kpKS%^8Yzx(4cH#gCdH`jl#KN zROgElM_P}%&f_HEUYUd+oPd$3SUSgkI@q({t?60TWwYoHQ zVlPl$+T)kjX9gpqlx>#8AJjen1otT1r-6o)su54a{TVPw|FGUvN za(yzLKJ5PEAEiJtE=bN@ZWVyN8Qy5w;JTO64kzw_v2tSqRprZS>M1&XmHOOkMTqq; zA_HwCJHbUbtr}ajBAST3<{&6fap<;CY_*zeG!;0sCqnR-*b5#_0;qH$O>y}i+kKQ>2=ygsvxHjN+EJ^Al?JC_1 zUox=WG%!u_1v)(a#*9)fbiFEqP%@kzHx)39up$hq41GqGF6q%73>V&$ws$w3?5Sg% z+K{IaPxjostyv{&RAI)GbaH3j9w}3RtttjikCHAB*?xp6v-d==*-+t znbVqEX!_^R^3=V7#19dV^WG6V)|a0oPiP944^~I`KaVwMUmLeVJ6Toi)TaRaG_z-c ztFkr&-h8;b4D{JMTG2e`GpRtMlSZsR;UPf4Yw<4&-@hm+U{3hzz+1)ppETot!Bxn4 z2DMKlNffyS<|3Ke+R=4W=pH zp&CPS?@?e?Ih=1XDGH6V_3o{A)o~o?=sQA)_C%j-%Tay;$SwA|)E&f=3e(N!xWkdK z(}he!-mm2QWz`0!ntgSv{dG^;U*VYFH0f*bqTkw?Tc9? zyKRDE^UNRV$=DefDyzSHFz%?yAYw>7F`1Fd?QrP-gTa_E zygk(J=Vkvl%LOUSl=DD8qEdGA?G(Q~*puSRU?LRQpjx7<6=n*HtZLN&F^Q{6oE3P4 zQZ(^MTxi||e$%N?#WXiP<+no!h-x2BdM4ses)SbJ!?dKtHViVnK3Jn zKibK2U7mK2yiBY5v6lW9r&hHaao!~a-OtIT%zh4of`3ZIamJEWoze6UzTV+rR=|Ny z-UUVE>a?I$ny2sBaY19(PLS0xXnjH647<`mv|$H9Hq*nvI%Bn}n3lFHz9wCa)=yo* zupI_~Q9jmYPl|+boS}uOO<(*~_T8DRo=m~*S?c^+5$bS16i0rJiN+HYjal;MHf2Xg zu)Nj~vGq2l^=xcM0T4cRi+r^P1&cT_A!(biVnbTsDP|*NU-cgAn2G)xJiq}0qRUi+ zqmN-s6xv8m*Swb6T2H>$Fl}Qr%uXS7emRTTk@)w~T=SuLbd||0!xU<)Z&uzV>#fpp zMF3YR8@!)lb0qsblWY|E?eR1h1xe9>VlVyU2}oi!K2g13czKsN%Q~^-wr}Mr|Ia)g zaUa1y%avtfA=)8*2>%+T<;z1sVPB~>{p$nxuczGq$w>k?k{{lm9#!aw2&DEFGY#`^ zFHuUf?cSFJmHFJa0$z&Y9WB>y2tdosfia`FI=$4p!PdqVy?+uRvm&yIrQTg2*NkcuH*Xs* zBC}vX2n3-IZs6U_)kKZSz5n&e@F_s$!oKjw>Z_Pw{NF#BijAd{6;KlB_74vh;D6qt zD{a`!si1yt4A!LUnWoJOm|^s;MluyNdqzfj%ZX`1ijN7(5tCl@*wOaPH-ujV_q;vw zN_i}Al1jU!GHJjOyB%T+k&5&!R{(RV`(kg z3TG_MKEp3Ddsgj)Ffpwk4`r|&1*st#FusPunk6cL@6;dy)K#PGKd)LEx3FlB;ZNSeie(E!m7lRJg|+PYZ2e zxLGK74Aad4@X0Zh$4~2VQzz*J@`!FfK=BrNOTJXbND8D&;2PoG<*1c;EMMDQ>MVcw zYsK%ZV&EXzvR=P;tN9o$>>sVqN5fLM$O4-^T_J<_lnNVajI9T(B;08k!l4O0tpa$X zS2HTz);b4Nt#+92?UHGE7}g4-l;>}JivN6uBgPdWJ<3zG)N z2L(j!GrYG1I*re^v4~x1<8!OktK5dO_{pF#31<+ni>!LpKFzSpt%Fm^bP4G)+#rwg z0`xMB(4j}%;$Xz|k;rUObYp?U(1P$L-(N^(r*VR~CI_}vM?yjq2KGf$%&^+Rh%d#c zxo^X2Fgpi@BC0Xx6vGX(`HPWy1H3HfX>rivmCE(*;5s8~U`s$pcDv*_w8@pReO5(@ zS4iyfg4mv2YDtgFe{XjI;r*k$2^;v*a(rlKQaAZ)|2XOhdXZ;f=m>hGq^=A5urvhR zKf^~|@NEs;H0@`__z{7@yUw>1DS3#QW$Q!JJt}{x;i}}O6UL?`%_njx3MpgIqo7#z z=dkjtJT5=&!g%a+bN5C{oAmSvQ9_y!dFP!eKBY_|4&1kSWMsA$nu|Up-j0N znJ=P@7w8d9NRCh+zMN^UCZ-2+A_}W~vO7OPIFV#D+wq4(A??JDnfe)l?2R{P>sB zk24~gKdhQd?zwa&kRa!L)TRIGI65QND28{{E zuHbj0GHft<`8+VSP%u)4F-8j9CyA;jh_@S`WV8QCVIyPx>TsP=&^k*OFZ6R+Amb|hj5hztDlJ-dz5}!y<);4HAuN;&)TH-D$b5a#QVgYEBrFXM+{^qcn z*!4`q5y5PE#A|&_tQiW0+lcmbLndZTd1kNiqOlhK4jzFB|LK9QPaW!z0NEzf;YH(R zXqa04R;1UvSan#g4EswR`SV9L{qWfYDOJD(*L|eJ_=^qKI2uW|uTui2%xL%aA?Ptr z1FCwRnFG3Ec@Qh;AVX$nwzv~|{5!RsaxWoiZA*Pxt$o$MuBmJ0blmvY)JW%-LodyL zVNK0|F19xIj{mWAkxJS&bH=FNn}bmsF;U2?3Z^i4hB46snA28r5cP5r1XirjL9<@l z#5TAA7A{eWVTBv#_)=-4R>%r;g%<`L%lY0p1T|k2Y(pQzH0LPXIJweLG4`vyy*-Dl zqYT5(hbx<@?-_#vAYRSOQ94=%jJ?JQ69-_GdJz-KaC;n;BsqoxeGg#HJ9$w!p6JU` zrzyJ*8bcwT-uZilQCPT5j_Zr`>D{>NK*pk-EMK+UPp}VsnBwSjdpV@vs`*yRARtFp zOYpRi{j;g+-w$e4lR(;F8mWrR!-Y?_0O9a%3gA^n9Cd{@cTO86U}$ZWF%${y1MLTH zNkn&J-rH`If}F$2Qe9g2!}}&yFQy}R0s4O0%2@5qsME73_j|owtQOXKbfZu%E0wDW zUj0rT-LRHZ1<<0pmD6#r&dN!m__FfbwfXnB3Eu6~)G@GCCKApKr!OE-k`P1-NL#EW z7&rHxN}9|>qHA1E6qhvA(}D@+r1X*qWD^CgYTVbxAY0BfewB`e*WFqycTp!AFT;`p zd$)IKCx{!Dj$;=myP)dO!Hi6yDXN~`6`lvAcGv!4#KG$1#CSx$duh_X}h4RIgzFuKKQ|x8;2Ehk1>H@uQIrS==-D z?WbuRWuF?mNp+Ff6U50T7HrVv&=IVkb06eWtX(gCUgkc`O+k0fk`^Ug0r6;zIP6|K z-_hgYESpr*xra0R6^;0k{q0^*O{yZ98&1YyVZEk|p|nn#u2*|Ixt&8OAOSq;3iUdy zY!fZ5G7cW2B0K6cbaf6u#u|gps-(%1nU9C(sYFD$tK?Kwy9b zUF#Ip5;LPGIBB~4Er+U2CU7xyiepASZ}c@@sUd1eaAzfq+{!@X&AA|6*(rT4UI1xnV1tTe5qiAJAP`FE&X(sf1j!t> zJcPtuC6fOre4Q+EhMUD6dGz8)09?iuOvjDGhV)#*DC%Vid^uidVS@y-a` zm5Ds6}@NGa;Qi(N~1zS)y9hH?cu!tnU z&4B}#TD>BSEQ?_MH3JpS(lranxf%2wGz*wSF0sa*V!sszl@OS@_pucbydv>dKDkpN z^NuD|oB!qD8TOIR){RPZkEUoT&;Y;GcyUfx5w$j()5DR@;)%ElQ(?2}^RKW-%uqFr z@CAulNZ-CO{O@5=(a;_Uw3gGi*SGp-R#OXiP%=UL{PGBFla1Q|BL_R4HE3JesJ8lQ ze->EjkXR+{uuUEIZw0VF+H6WBd9@H(A$~7n?Vd57 zc7M82P+f(aQvX(^BR!MPZZTbxPqC-VM{Vc?TJRocM%DWI4CZ`bp(D5j2S*#;@*E@E z?Bd!M|AgP=&Lq-Nq5mq8$ZFd5fHn9f)COjDwW$k7fu?)zauLRBgc-Ns+KzJ|VG;<(bebq8{~Ht$Nre`}%^sap&}5FA*$rt6cfr3)Y2DrIka&Cv8Qw zf86!ua3*3Z^Y?-Iel-$dfBf#=34*!=N#i3?bO^E*BQl1p+V?c%Yl6^n(o7sRt}p?BaH5M zc6|&}llTJ?(dI!9rDMeGbSkrtS~)7S^+PJ47VCWlddAL~N@Hg#edq*D0J5S#)`Jw?mA&t3eUncpQWHwI%AlX!5R4_9HI(2^#}4j!+yy8R95FLG zgi5RqvzbDGnxskNrfa>6lLB6YMn=e*Mlo|9T460(*qSW~cf%x5vb>EJzhPsW zz{H+{C1{;l^7fGX+4P?hDo7{l3cVK%Wy1}+Nu!{r_=-MTC7!1Ia%qb{loji&dNL@( z4>W@5EK25f30iP^SkdHW?J|^QY`DEEb}8XClxn;+W~d3)iXtRk_Mr>q9WKve9=4*S zBPuuLjz4yK&w(;~&ms3E?O1$SYsq~(j9-hXG>u+SuON42)Mdu&)sw3TR)al$zOcxE z+F=R;d5V^@2EA3w?EqJpF7*?wpA+nYSC6u171lH8#WgT zu5KF*l{BJG!@A5>l>eJl2nXP05MtG)Y{_g_E%l2Ic@@VZ>JB=SDR@5DAYtY$Ae=jg zHFsMY;WYMIapJJG%cx`R$pU{*Ah=%(`}-lEH5>l^CKPqDwn%ZwW*T?lLUxB;9@ojT zP(Nvv;jJ_?DO)V!;Y(%E(d4N!GnbcqvVWw@1t(E7xUD%c=BjPK@;F$BMRZ%9$y~d& z5OFl4_wbd$#QNe%l;Vnm^`c1Dx8q2$oC})4hr~r4kaEmPF|Ge;EV}Vwwl2PrF(__ z0gLe)BQj3S8}|FgoFhnv3Y#M+ctKUxP|6u*vIZCq#Md~VUi0@-o2MMQ#w{8c2IXmYk&f=LJZ+_9Q z*tjSm>9Wuj(AgExY(b_S?O}cHgu!VJ!Q#wIUB@U_*aQeJ57A58noT=Lngo{M|`hjz+o2!!60W#waR!@(@8-p@Z%Z2b1uR%_K&|N;+CN41I^+^AM zw7EiO64vGbZE$1n6-f5JH;lWePdj%}fHn}i|AX+`kB5h^GWA5iuUFgUE6p8=OHgUJ zsqip&I|7&T&agb26{`r`At^H{=Qo`vZ1Ee_w4X@Xp3@kA?QeWZYgSF}1x%pFFbz3> zNA?f|x)A3WIIh7k1GFY8R-ECm6xN=^v7f`BX6OwMPfaeG7cn}gB;95mNw?2X_skKl zK5hx6Rog`KCSWh3N)(-TL}i`_xJkjg!C28I<2BNnWS1;)k_^2RmZ%YaG@|o~BiVGF(lDylUIDGw~r$B)HRff*^F0vz9YEG7%^{+?1{#EQuhsIp}F zRCJBrIL_%!h!?X*UdrlKxlJ`X0oh07i2qcLIWP$WI{j^)rU+ArC00?rV7D}x>~Vt% ztFvobd6t8;?GZUii!fNDzSWaga($0i)l+rS1#DacS4%4j-Ws;`GUsp&Dt`{}pecyj za_I^5?Fo=TTAd&zvb)w1Kq|RjziGc$qqVt!7x_C5)yj^IUvbLC5@?HWkK4k5i7#rH zWM)-azIR>AY=agB7bpB=t!fEE$z)SgJ|~xlpk0Yz0~l>{V6Z(11o0kud=5Q;%jEMp zM1Dci8P2(d{rq^;eQi?%;KvWT|GT@8GqbfZ{@=~Tl*YfTCrs(jOzu>O z5wSpw!&K{_CUpoEEPS~z;=e(fZw()aU~s2K8*15P&X%p)iOjp0%JS?l3-QPO6{%|B z`-Wu{H>}%-wGmCPyNRN*ijc8J4tt)bB1HsNR~vUyWEsC*C)szcKDT>ppUNm-M+5MmTZ2BOk6&eEU&g!dYe~O4cun?y zg}?fIr;~@NdZ|UPBr5PK48jQ7!>2uR4g5~K55(FDz#9t1e-loPESkOYzpbj82q6NiITn>q*5zT}s8l*7{#g+w2 z-RCLRoyVSrYjTli1um z>{Zo)xxRsQj>Q48psf<-N~g4h962;b)DYk0fQ1HZOB_B*+$r@YdqD_Y#X`72WMBD+A-5xq`r=j=_ zEFuDX;+&K5@EMgq6aEP>OTmFD_l`dad;SH%_u2vPt0{BoxPNdnIf0JGrNJftmom;P zCea1nkq$FVw7eg{wlC31rg#<4{gW|1`L+2OlEXS}U% zYx>6}{C@P`L+4QylV?~GAPpaFcW{#!)<1E5iR>j#gO|NqQ%|{9SPCSrZu#`p18d&; zlWNG$Z>8Z#(hz8t&<$wK5HH(btk;Tr%*3&wB3X7^f6m+VkLAk$>@%CQZJo<`SnO zIA3H>&5iOIy3!#W8;#(?JCQJhiP$#>amVY4-e5csmV5P z$F>VS91wT2-UuSmw=CtZLx&Wip3tu+*5)??v*)Io>R+>0d+vgBE4Fx5;ENSegH@%b z5Dsci&hkr8Mv|zTJs$koNWx1oxDQJZzeEaeH6*{UbpgX%dXO=3Q`uA7 zzc^^(u)JWQ$hY0PL4(a#sDfGbw&VLYc(Ab&u6l(z|Y&qmgvl7!K>-ZYl@kglXYd$`O3=H zOt*(k<*LSZbxCa{H)E>m5k|Vbsj0ZDyP{Y-ZfE9lxN@ca%NHqBvtBA0%OQf8(x?c( zf=ZpbMZ+PZvaV3W>}KhjI!~=$W*G`#`RlGkrskQbsb}5Cb!S)4?(crK!&jWqM8EBC zlRZ}DTg~zpc&IhsKw>Q81Y+iLWlHDd#fDzf8+AcU5X+i@@?@)FQ|b>$@1k+^KRidEpAgPkpZb!ZZYR zF3mTkw{#8>#cgZxjEmYrZ4Ro_#4P{$V6#M?K5Ih_@Gh@K2%&uLC2vvuopYCfj`@D1 zL}7q9T8eguJgBm5izwY>dR8lMl3dw?%_%P2V~2Fcq!1E|^z`HPNf_7xE>TKA1fy#B-)C`RaiSvg@ z&LK#~g`?Iu7lHJZw{5*0nd}`3M|0A3)>J1}%_quN;PTu7-tdBCwpLlXFY5*;iA-p8 z3#2~y7{Q@ZRk`H6!_*ZE<-c8rCvc+sQp|^Cc2`KaQBd3X=TIL9_L-w<_K@R1l2^&G z#K7Yb1Bl|Zif*oV#{Or+nK+0l2^E%8inb=xc+>yM7M!n54ltS>7Mh$HL%to|aL1KB8i(IkJeNqR7E z6KajY=18Y(u52?_&u|ZAR&A_Q@3wGkkyN=%uQNGTb9`5GoKS1X?pS7_U%%(v56jjY z>?wCh^ReveDNDeZa)jfK#8UKamh=C4v`D4dY{h>57w{XAC6Js4|JN%fRtGr?qDF?O zHU-J>PBa4{@j{YmlH#alZp6l5^~@(2red* zVb{x5(nA?F&kCif&Xy+1*YOBmwD9wf`4!nfQ=J&M#YOczf8F&eSL|f_RoZHsUe2Dc zB8Mz%tdso{UQH(p2gN?#~waiXQMkQBaBPxe<4u+a~teM5?K zU%#k+Fw%re9GdS-+y6gSHV5zt@&mIv`lyWaM z9~=^=9Ba)5CF=rE7i}r&EZ{83FWAsLJVh6tChOELGSvq!?-Jf_paT`P@3Hs;nH^HI zPR1}kP8rTcILaB0J2a7gwKN$XxsWOlT%IjaT%KKw-jKaLXI;wSgA9tZRctXWH+2{- z?C$XSOO%drExYfjl4d3>Z{pcFCwCFI%AEL4?Fv8EMUU`G2UfR((@2M2zz&Fy93Ev5<_*?yshr|=wK`A|tB%L?7APhjdN z08@A9KxesU;9AM3Ckzo7PNyH(Ha5hvJtUM_myzblHEFe?>s*AsgQJA(m{^KEr2mRB zl@X+Y%oId;XTkM1yoWN~;Nk*~j9(AQIQ?=$Gb{`xN=_6u~Vum?x-R0k*JmEA~IYCF-+#l|WTa$;R6ciN^k%E7$4k@c%iu zl1t)b`od^fSJXHhqq&o+r!!9@m?2B%j_FU3wzxob(4Y@b+9FhQMs6ci;|8fX$F|vO zxQ4dD8cMImPdrPrWOv-!m`+Sknvzs1P>cSC3!k~Kwr|TymTN@$U@y6AEm{1}vxZsC zojP?V2y#52bxT)u4{lSql{{}iJlGu%U;R7O(k}Az=Kb&v9rO0ri9zXR5b5Y;!saEM z`K_$|GCVupair|Q#EaCr3l-QReKm?h#c?EvbfZ81Bf93=p^AWajG{k!a_j*q+co{x zTj5h8+UQ?Jaap$?ZriMNv%R-Ddth;_^gF#Jw1$|2yW3RBx*`bmtNKW5U^dRYDPgMN z=}81`3l-%fD$26$G#5@i7Y}iK^UG8#DS|&+JwwG^5Qe^0qvJg zp>M_WXmP3>{=xXJ=@T-|wU%vLnHI7`j^FVhGMZ~nu$t{9DM@wW9XrlonoyXcwNc%* z)*u_o(O3dQFJqsRV^e7fO%dp7z8MfiL8jozCl@YIDs^z_E-)+!%_1x1I}=)^Z{+~( z0vtwlZ@&uJ`9Rq@`QWi*rnczVYjp>n0cX>;GbZ+!*k^SI-T+PYnm)$OV|A0|!b59D_jN4Zioj6;# z-i~(wt|-+0&GpI#AxUBWKj7=_6yq}$<(2-Y1|Xc{a6Bi&! zG1%0#=yiXou^c0x_sX;1)bcpzYRb+5^6j-@X6CyKCl;2VU^3h1&l$nuqhz-`1{RG zBrX!v`3{NF+>qC5e||es$FzitUl<@GsYyI>7kDN0D3eL$uy;xdkH@DP1K7MWXk69T zM&qT=4lFlbn7hBUUIlTlY7Ag?2p@mCbdGY<+OMq0kGKEiHQ4<~^`y0Xj@bM{BzDaL zat!PE0Qq&Jc;)ODuT@BuLN;~IbV+;#@axb${7fP1J7=0C4&KrEDFACrAx~%ECOk=uF69WG$8WKbSdQd`+FmTITkQ~I zArVmwX<9tZKs7Q4IxwCgH%dKB7&=7iJKhi zY)1r)U1c=z_D8rk?7wd(B>E6Foxhjx_1}wIuK!Q-10p#)b6J3~gM+!zzobc33Olk3 za>$=o>s6ZMkudW7phA3P0e6xHAYl+;_6SrE!M}E{#+@mhr~zAxyhA;Fc%Jn3>F5W9 zaG&zSj@Rkp4@2k~51c#PEytVJoL%40{#P(P97__ZO{!d9bBGqANwL%E#DRmf0pYjH~ED!QF(578B&>iGPXyg5ki-y z&|Y>kp**%-dfR3b8m9cTRBy{1Qk{T9dah4f8MJJAXk3y_&aGq9GNgMti;-;ClZl}l zQ1OZS&3^D?D(K#NIx>AR0r`G93Dj{i47KK6y`f%;fukPv;sl>CXG_w4N%TgySKVMA z7k(GMPP2Po5-xXphAxIbbDth4srizY^Ow_ek}UW+eN3=Lb*Uotl?LiV&|QSBAoKhe zI8`v=j!&j^9(56s+NS~yDebeD^j#5^-07DDrZGqDbUdYR6M+k(NF1|u0um~xlgwxB z(eze&h%R&y(pq`6xR31z6xHM~juO<0QfE_SBq)~Q;#2Jg3eGC@WtwlD(O6|?HA|}2BuYFsR;?6e&8~(GIyVU_#j$)Po zytLFh4tJbzSgbakUS)Z*9(uKeZY3Tdoxtp-STtKoxovaf$S?A;dLa~GJX)*ftUO{)x%3q1h%6-G z_Rip-h1-}O9@s$c9}O*7_E9C~zQ-`IO9MC41zqHs^j^g`mV7|Li|Bn=Is7KrsI_$< zx_R5W12~ia{rAaX4=3O>+uJ0yl_8;zBE3UMH>gK+LfGnFbE)Nua3p4myz0X3l7C1p+>j2sy1kdB#TZmGrQ7CyAwf|{_Ox& z_0$Eaz=ad!zn^vqkUXX@(s27TB=c%rprxr>cD0Cw)s&=ajD@jjMD{`YDP1*BrYn&v ztYw=7eR`i~!}J^|iS=z5Ef6qel&c0OudcbbS8RUZt}wHtY_3<8N~+H7pxpesjbn75 zf~HnBXm%R0Q1H&f*TeTg)VDvEfK4=kKPC2z(i7lSB=}R1=)K7?Rp&$wk`I%x@Yg;9 zAYp@!3^$eL)1Und%WLdl{{sS%RLncz7NhtUROC(#ElNH_47fl{KXTNF`R#@Lr`rfq zm-(F$1h1$ml1O+Im#LD|&z5#!T}1&YGS$h4oZgQ>C;Ei>kcdB2Fx-MLlTS?X=gH%z z#fS$WIlYBfo{-PZm{q{fp(BI;A%&v-l@a9kErkO4)`k8T!ZC4cJ1b*rW1DY9=y%yF z8e9D@E_IfIwxlLMJahjTV?Y0&7+jN{7kS@=mYdJ(b0Xgy&%@L9U{FlLHepI0706}$|qNNqB$ znURf7o9GnKZA{1$MOub?J}GHywY*fOvfYlFSDl%x<6=YUA>zZEiQaEU8MoG}&Imtl zlAV{2^Z~ciF1Z>u9bER3>Qr)-p~T^-f~TIf?59k$xjd7zpFw5^#o3&I^$LEFxAg1 zRemxi$Z!luaW0tbPbY#2#22R(+HiIeNh_Wh&vQNF+gh7)WK9>sbrD?(Zkr(q^fYwD z2N~j8%v`Y_f6aVlUGsh!KX%0UJfix_9@K%e?8~83vtjqaN0*|*>J$A0EkKCeivy1) zD8Sy=VSmpLH|!Hkq3!ZmMKV&3gtGD`V)Qm5dv|?$xv3iwm6bBCA0Y)9Ozrg=FljTe zH1^P-RCfNeE9esm9(d$r4OpM01%H{gSG>uUXSv`9@=<+m^kuM`KKqH)AfldAN^|IR zo|sH2KcCKguVJpy0NwT!7|v~~1oBqz=7_J%G-V(zyF|6YBzX+OnY2>5mN}++MmED` zZ2m{$+h+s@q7mNi)z~L^dX_A8#j8%eG3=jBz7iSE|B>gg*2uh(i}uswil+eL!$~-Y zyPl~piaBewuiDWN<5Xgn3YnsPs$=wqrr3(w$6HJDA$4R_Z?cgFUQc6Yqj<^!ASqmXEe5~B$TqVsYOsIRGAcvSIiwuG9d$@$uwd1n1qDeSdj!@mOCgTJ{Eq>JBE_k26_XK41(f?5Zdd9Gn)a?XQgPPo zgh>-yO6j+Yk6S+@3@TaQk)ec?s!M@-4e@Va_!yatfy7W5nT#PvIHR7}(vMdp;5o zr2R#Op=FH7S`+nkg>5aPLHG2jO~PLc=b@QI8?_XqP{Sf+T>5JaC8F)3Y-T6{XlS!) z!SC#VD7i?S%9kiA1H5L!U}?R?%q5fPNXTRTade{Y7JKJNj=s98V=y6Es;7+IjGM;~ zY@RRa7hM;rjaM7vgCBsqzwr61!lheWKQcLoTk&vWeX?AAQ4!gMqZUDlRxM$2a|t(B zjIeJa@g5o>qW$?exq?xyZXBhY1`QayY`gs5yDcB>G6P?=JUudg9+cBkTJfsw#4ce=wmF!d7g}&O7OJ(vw5wl7zxb}|cLV`&0H?V{h zVe-j24iTlRBpb8Zv%%&pBg=@=JJIHg5gwkado{SaT5j}2|kfy9* z(#OE2h}^l;$DGZ_>sK{PPHAU3`mMCCbcQ-Qh&ai} z3bD_~YsLEey9i{O!dH6x11C7*YkQjJZ96-efz}|JqNuj->cX+Uh;Q=Yj04-;`L`a( zAJbqr&SKIv!7dA3*fbtlfbL2}Q7$C}bLs1WZfI&H#RHf=+eJuruhKJoC8nl&`KrjDpYDOdKC-(%{o0;My-hy- zfjT3^KTyCvhfhAU{+@7qqFf(fd_<(Z*pkv7y6DAsqO7KS9`kE58&PZ5ZB30 zk*KHj{~a=hwt{7CqP3r45P zrd8UXB$&HT0lMQ<_c!^&b0bJfi+XHjbg#+5H4DnPRp;r6>?InBmF-p=tvjSE-Z1CG zQ&(pDq~9~)l7!SI`A`#ivwW8Yw1x8)812q31nQu6C#a6?w=u30elRCWBgIP|l*?YM ze~0lqAzJYsF6p|FhnlxH)#FyhE)Qw+s7(hFjtsW4T@Mmm>#ksl|E~}OSX_sFebA9Y z@))+;(#CyKnGdDDnZkZb6fTlByp-XO%^(LZ{4v>fJN7H5{Z{0^iAX(iHQK-&ijE#q$pgZv28YMYd^2Xt3FM7XfI+G-!1m%8tp1bMk2>zH&F3`;M0X#WL$9GK$${g}@9n)uVN6Zi{Q^rEL-X+-@2ehJ&PicWboV}h&F`F}OAlSv)o!!oi4A=`6*x1N9luCZIjW zt*ILC;3+{RsynK_XwQVM#!9wYs1fEu)YysD7+H5O@9ptcj*W!Uhye2se(T!iqsamTO3i)^Vp`AGj3tH62o}Y5 zA|UFFxD%A*QF8;ivuNM?LtD@4d7}4DNbD#f+-EmOVWkKC@tkn|iG=$1Uu9AI>`>h2 zMRC7}B;vZsg8dy=(IKCk>To(8121mrTjZO{P?5({(Pb-(Cnn|-1Spdz_`$--FA4Do ziU%P!vr^`>4$`DL78_ZuYoIMDzdNQ2&HT6Cv zkZk@Ja(~%gPTzQZpm*JxavovWvR3GndVpv7khi)!28hXJ7HjIynScThi8YFraJbvJ z@R-}M%|-I0KzmQA@D&%}D4*-#9xHst^Km5Au5= z$Nq7g4Dp}Df6Jt0VaQ7}*1b_BZI(j6jQSmW(##<*`xx|sxKSmq5VRrM-6vFzTKH^i zTat~U=-F17g&tAw`%^bIFidI104qx{7YwYUlq9w*2d+(LgxmE^5s2Oeqo^u?oeq01 zY_xO7%Us(oCUc>Ad5C3K-69=XJHelzLEJe8+~mR)FK>I<^R&(bhFj#oUDONJ*rybP zXp>kX-n3vSMO*Q1q!{X{GI9QQkRCl(<8AUHV>%@zqDncGp#mzuD<@1xL$8K!OxCG( zN-EAlrcYq{x3inq^r;o_Z0T@yor((Vk{T&Cb`}eTUxukKJ!ZINg$ij8#G7_t+zuz)Q7o6UURP zC`G(RzE->RlVxSFngL#B&R-F)>zaFhi1)a}P+m9-XmG7}icC~EYDATu8II}g!1=$} zoDDbzEF>liq(Y)7|6riUT~dSbW5zcA{maJ9$7F~4`oPMOtpykBWovW}EmoLDPr?3| zP~9^)LpW!g`b1nnPbI7oo}a@i{G*#-Xuyu!$Mgt1Rj*KHn1;e|sz5EoF|dd%#X++@ zkaB9d=P>#xMK_#;ri4*5zm|Teyfm0(WG`CXn#Kou8{^vYEQM*&v%S=#1pOuYJnRZj zWIV7fXK=gY=0LQ;%do*+)JgAXIbwZsYULFmvR+McJx+3YF8;B0kHvf(V-x8lovIvL zavT{`nNQKg9&Ms6#?gFML(44njDD(4YASz$HZW&+x}V94-}eYi94|OBMlLt^f)JVV zADi< zl+_i2zZ1EwHFNiJp9Qe-V^S6Qkqtd=U(s)5ga#fHCHx&wn{ zrM4?My{6=do24p2QG*n#y1{ZPmKImha#*2VeQ$DX(m{SHtga~wUG*H-2N{Wjt`0b% zoJtjbbL`LHUob#1_TbXeFMH)C&XNbRy9w;9R25DGk?eo~fK*Q{Fyp3aW5Ms4K3Pu4 zn0zzBlx$lX?U5qO`4sp0WcP*SGlOI4k7Ey#`!&9v|?^X5{A8_f>an>O3kx#gr5rFBI{qH`e z-J6vd$m4X>OUsRr@Qx(1pz^de025Bml(GreXtP;ipL+6All&Rhf|u`aRpah&e6ynD zjobx)ugs1#$CiZV9LHa)&G7&@kLUUonRWT*EVe+yR;&?r$DbiEt;YzxZjtYFnC4kF z4+J8(S&ag}foI~kg?e#ZG12fX{>Xy{XXmG-K`Q0_2J_}Zfh=apu&!GgmZi6@PmqF6 zZtWxA79FMw%6}nfA#jaC>1&HjgMO|AOnQSjQgl5VR`aP^W1675;5ibPj zIF=TIZr~F-|DtIwyx!+%W6)K}8#ky?4s`&3=7Mk$*Cah!iSNv<(hLU73&R{G&qA{BNaD173B4%tNZ$s_w2BTG!v=1I{NNih^> z;;!8?Dvk=JXo~X2@)?9whUF_G<4@}g(+GrE)G4dsld{Nal1>^8!=&zta9*T}p2>JL zg(Z#s)K%tHvM!QwE1Zt)7<$IV6m-L=MN=5LCF998`YI{K4<6UuX6o-zt&y#VZ`ptt zBk!1^)EScgs*6yLpus0&48QKyc{V2Y0@2znMLaA^Vt0x0c1mH?+;F)iZPv{4);LUA zrbextmbA3K!DQ3eGFWZ1e5g=G;F&Od_DHl$7RwqBgWrvAuS5pyK~7Zg6V}x84l{wK zEM%1!kud~gJs57JuWjz~E_Zq! zV5gMQn8ePeGG(u#u98iNOxI)nS;=kcnWB+*ZqH*3rplNdjtIQxXuiH?vEuNrzV zS#vi~ihY+lKPezf)jIm*s<25766zb+qE4t++iCPpQ8zrfw~)jy2o1X4Lhw6ta0sdJhC(8Y^qF<-zyJNyh2F5f}VsRo308iMT5fK*8dXqTXk$RLX*|J=C!}!QzG0 z1VFkzXy{|9_L~Y;(L?6rkSQ1j>5|{}&XfATvQi^sQ$wo^5DUB|&OFEUCdG&tQ^!c+F}Q%GiHw;y651;->L6F1V;*5FmhYvT1nE*Z`HkOGN4uACP)c?he1Jv z$5vV;M-;YNxW6L#GG;AF@eN6q@IM%p4?Mxe#uh&sw{ED&pAQp79;E^oB|EvSTiUX_ z9%W#*KoG`FTHk6{Z*(fm=b$u84QNVr8Gy5I7oUdLu{lolVh5{j9}GWH?A(eH$Gccm z>+>`V&H6MaE&L=6$K8x32vzbKD>rHqQ{8yrqt%5y1G#K><$n9)?K zbl=Y4bDlyP!{3P{r#YB%0HbaQV|JkSF$(9ClMkldtI%a4cPdQCyu`sHQ2czFz& zO9h$B_w{ACm>9gT1v}40leB?}f2H2I1^WI@$_DO?z5MF0=sza<3pdvk5~!Ca#x7(8 zr*Q-9Kh6V07Oyl3c9SmUfT%Znf+Bto7Dk59By7D_47NT(Vp_Im9ae0aX#^AB0CCDi zjuWE9{PD{WvmY*KF3~CV^FLUR_z3*7A>W*!^#5*pFDmsvkPdn@_1dfttpIWKUwQ(CKGz&y?;2FyEbkh-Btr75^@ST6vW7Ngu2jMv{%c@^)F8U)BwRZ=q? zVHm5SNuw$y6)W1KB8wV2FyBZr7Sg5G0&XL%O{FkqIIFEQHegt@=d+x8q~Ue5mBg=S z6*n9O?@22}C9$lP<}BoR)|p=Nqq;CZvHUf1s>2YDyNkVWW)RAV)?`nEIjvAM(R3ONg16O0i|TBQwD{6l7i4pLXwv zKoeHPmtJ`fLt%f#Ej}r~#X@rU9+z@(Vh<#7v)H0sG&{;j05B*dk*H|)+aah%!hbwL zaK)g3Tn%&oq=v47er9N-r!rCV_xQOwqX-AySRgpCC~iSJ8&-t5{^jU&vBB^6eQEBU zP~#twZ<&v_ECJ+6p~oJg_d8(2w?nLf>sCpek6pSzjS%Lo5`k7 zlA3{pb)_4t_qwnTMQ5bCSaf~M;wY*so#B)FHR@#1iaBG~FzEQp1rp`KLCv9db|Gh#Q3R0`T%MjX(sbh&%wOJ5^V_hjfD5 zD~J`=wSGQ9`Gd<9C~ws`6b4P+3uwi&5}+xLE*M*j>Fw?ZwK#8!i76NIni?IH>bD^$ zi!eomhh>*D9(ealyz=K))iCDFO46YR#+cZJqLw2DGnPREjlnp0|M>_2svM&VToJIU zp{*}GrV&WBQv-0#O$^`^t1phfjQ;IV)IFF2ExA9ZS)VO8Bk`KqEq3>%HkOgNnI6DJn3bPj|0&{bv@t-tl^=< z>ixAd7W#) z4T%-A2NBPuC8-XFnCS z-@Yo_2v{cZjMK8Rd;P-xF)MtWS5Ce3`kGBqN02wYkzYHJr@h}(xim_Fu>-}}=RcC3 zaN=)4!@pa?k#B{J=>Odk{@bxeq+;ygWbDfCrUYl#SR z;AlULU>n>KiqaN?Jr?xT3BAzJ6+!-z?sb-(V;N+zk*NKm<>h2KS#*wr7JkP}g9>KZ zD~|3&Z?a4;6iJLLkh%l=rBX@6X$@=cqdK+yZ5c~hQ5q0=cwXbwCR((!WL6A@iF$l= zcMEu%+K+doj?;Tdq)` z4;m+eW4+o?4XF*WBg#;!vjej;1;O$B192V%cY+43^*o%0d$?DcuD&6txcb}uhLc#o zZ6dz3e+%-chs26@-`96jccz+sb>Ty6b3vOEa2WLhCeUo44$FU0U&z5MnD+xEcL0sTNyxA z?V_lJ+e_@A4ba7yvQ#!i|x}qN^FL7;ke(_8B3HoiDt?-42jX zVcgC-;)h?tt=iup*rVJ*?inWytKNT;-$y=TKXjv*Z;6;~Ofw{|V~Cti{8qjoddPsN zpx2Uhor4lW5fu9i_U{^u2Zz;$*l%SG(0@l<6LGe(a{M0xgS74cD{IVB)>hmQLFTr^ zHYy|N+v6m+&XqC9AfkY=78DnZ>>G@-B3&&_=%lkWA0b0PBpfqxwe%6ueTQ2&pORu+ zz?&`k%$KP)N{ZQ)31%4B+Ujtb;eNhYdaLpId_n5u-(U-@6j*q0h zO$w|*5o<+q!xd9g$=$^QO{vSD^$S7ljzWzgs+4e@%vI4=eK8LC z^_bN(zbsRsv0-M_08Jac1zg@B7>~lilA}YP)|)~EQ?_4*ySvm-f1uiO9=4Txkhnl!ZOn1l7Y}G> zkXg2$UYg^~oU;jV-U!Y(>TKkhIP6$>7&S_)*#BHW>#suKvd1WZ{J5#i&?m!_j|GHf z5qbvS8fNR{a-Vvf-iR?C9-U+E$f`wpTs=2iy4g}>ufdEvbrMn$r1)U;83WwlZDT!Y zG3x!;QdG^|wRezFI0djcJ3OvYcy}pG=t>MA7Z4>VmgSObr|sT#-G4Q^7Cf>qwoY*N z&zyeDo(Ipg&ODPfxVw|<3kri~AeK{P8)Oc0>y|*`FvmX$j31#A7CWQBSe23KMW1mG z%>6FN50eh=Koc-Qj|!Z{MpU(I)P-Oq+WXan5U`1$uL~Vq=E;wji@3Gl^o1Hjqu*;KO6eTA8nMk;-`$%CbYSrP zgMhWJ;*fTAAwYxKq98TK2lE%C)R|KO!}jNbdnWg-b_4wC45{Fau`!KdNh3>2r2ueMfd5#bAM$msf970sjBg;xPQ&wO|GQM1 zT(IbNozzdh8RFZ~RbDZF3px1V+W_A{pcb3gmf2mF5}lPCSp?iHL| zoj8P|4j;|~hP-~?pg4;e$+9$@jvrNKP>4H~tYpnX*z{ zwV`%ecZE~t6?rIt7YORWtNI@Mx+(D%z21raO}!Zln>9v8y9FIVPXy!*8l>d+3YS(9Qegd?B2hm8PaBU+pq!fP zu5rZ*;)l(K+&!(_BBcW4rKk-S=YZHT_}+HHcWQJdkkyV}l)mvkEEy=D>MS(A(4>Kqj& zCMiQDG;&>(nB3X>59O{_%9<sO$R#I=xI zttCt*D|ZK3WJ)&I)Q4KIR}>dmXo^4kvUOF6ojFa&(Lne~iLf{b>f_5Z?rPEkzGvss z@M3ZEiwqyj>iO~h`CA*K4JqM@lpi*QqV9^d51tL;in8nGOBGz4A+~`HrKIF0tC)lM4KAf_)W7}6%sJQX-QVvOG&5CilgW_|{Pw*5k` zaubb?AyAL5EG!>E^Tr9kW|m1BUKu5cQDK)Uc0=P2&BHn1y`(%;`b4=x=+SNEs((+3 z95P=}y(8`8ful3XIB$|gZcvns1IfaG7@e|u+!|m66AdGR%JEm*u2VRqwSp5~V1p%G zv9e@tXI)uUhiSRj^6Zi_OO<%R#PuMWDs_LIdu^VLHPD!ml%XU4Zo4tVZ z(CzZDWQdP7!p?7$N$3AX`0Ii8&tLiXZwcNnzTv-tZV)yzvNV)2R{q82{m1oElCqVJ zh8VKlR@V3r*0V^hINbr9?-fRJwb{R-xIvF7p)iS(L*;tCQ!}#YOW3 zK!=f=PaH1*p|bj`e=-enBLX3^P|y+N{5L?XD>5!0065{RFWgL|jaAKsDB~QLgYogC zL$<^5WaQ4*jSTJ|R|K8t{(d9GW@a^jb-4a=BsH?-!rvItlqNCA*!6ZKHZo?(LxNTW zA&zQcx!z)=AyUmmNzI6S$P|KGLyhGAm|Xmg3;500t0^$;uw6v>PK-VhDNk|T-O0iJ z#Y3zi@#EF;x}>!*RF!#$w4}6#v!SG*vy*8mh|osf5A+t*=d1jjI!I)Z-Cmdr;u93q z6Jua^msFk1j(@hbdiSOhDPB}mIQ};_Y!$gp{tefVr`p^teaos&UOQVzU?0|DTPF8I zoj&PXadS{nGp!bpMl+J#r7;>$C*6hK7%Kv61mtYZ->R z(S>g$fTB^HFoBwR9pAwR;FmO>j1Xhj|{v7H#ir1M0{K|D2sajB1|sT`|^>cWWHdwBKN{1P%A zt3Pz(HXG}sv2%}HpxHCBZZ#?+@SfK%rmS$EG#Y6fEhc2@yQnH)`;yW?Hq=<|y?!U9 zFbtsfbm`Nc*chs(oGhCobBkDw?Af5McC+@TI!eY$wk=ndz0fYYRAF`#7;;T4UN{Rm zS*(>{)Iwz49DgGa;A58->nZ2{aHDo^?Eixc(v9Rv?p_AVuN&G0*MAAi@&wEDw6im7 zWAFng^%eK>C{Q1qm<_gWI2&Eo9MN3)yBGJEz(TczC2Yn+$lA-{RghPim!0pdNRCl> z?$5;v5Dq2fV+TVxk>rWK#|>5LvyG%F^<>KF2L%*4$*pL6^$JXGhIhl8TT}kp;b*if zIo4wl08tUTWqjTfU|Iw-$yP3n|GxX<6j0i(S#$~uje9-^=F$Rg74A86&n8XLSW->_ z5G{|X1fG~KsU~VhZ>Co?)@U|<5!P#w&OA?E-bvh2Td{UPsgh~(=`e24X|DBvW~3>D zPytP1N8bC1COMSHbJzQc<7g*xOa_l5V|oDY#if2T6|ojTE=MUrhW z@^3UHJJ_Zy<+*l&`6I>PkGX)L@Kgf4D?;Ujqi>SD7w>i8^FT57tMLHLX%n_KB=Sm##!sG|kGFhd-!-Bi}^4}kbHErj}vh;1wJqmWf$sZ)a6 zd+9pYyoQwj=ojKc*CY?Ok_C<3zL)g%YKJ!t@y?go*{N~8Z@n6KL_XwCuB|TL+BPq0 zwgg7FF1zlY@+e3Yrvv`3rJT%}GSU(Sfdq{1SyzeN(78`$kIvq5Ic`^JAp|%=eWt_z z1go6cyj6cjqh8#gFX6`a;nqd-ke$;goh{MF9yBqbWqv^R(T(b5uZXLfLAH(>*oKDK z#Wk?g#q1RRvd9jl58&BAQa;{Wu4Bj%YH(cPj-!%gIz z@nhG2obFFF*ED!Uv>=4ZjQK^AG|w%x{er|aT=N@J#!=qOQQVjERn#9_8fnW>yyo|L zB_JEj>vYsRZ{#AT1C*M)3o1InzUATc2!n#v@&=6JyaiHUnRg;?LYssAy(^SwaaF)5 ze*VjJL8qF-ApbjAoc#hEN&nB&g^=6-v_d8+NhoY6BYhh}j=}Qvy3O+Q3)qIq;an4V z0mp-oN@w1S`mz3<52+23(Dp<;axeykFeyhY7jNnr(bYxzmoJ(EZOOzkCfWP zd)m*w$*#EBbm(><{P~)(@d0qf9RiBpe_)kQMV`ovegj&ZZOA=P25@hEuhsu{OF}nO7$=!h4y9`jVJ~V*i znlk-Wvs%yJ{QT?I@>`OqJha>NO)h@%v`L`Su~h2bW?KjGRE)UTDsWr3=MdAl!=r4@ zMUAz1p@dILUN_xZP*^ir+l`y`TKeJ@5b;VIHA+K#Sz^O!jO`~jZJC^B?r7(^+=)*vG{DMteVIyD%87(^wL3iyX+H~mQJa~j`$Gd} zS5}Sde<3d* zrm?t-A>4(a*C3RpsVgDpU}=0i9a-Z<0Bejck1Km!x(gVwx|=dRd*Yjx-{y@*3|mff z9NqY&TnBLKW086+cq5bT5sCuy=jF-G$o^a<&iXRrho>ali)JJ0v37_LjKJV)v93wF`r#JnFCkLY(Efm`Mk z>{!ZcBkKYTlq5gQ0D--?WmxW&NNaze+td4CAD!#`-aFXImAV6zcfQIf2PFh9r`vgJ zdxW-}h>uFoa?Q(#^V;b1r2Hc6YZ{-=9_AATlMgvf8!E{9iZ@z^G*4YKk0=6&M+og}Y+ zpZ^AH`}e&>sOa|VSu(KHb8v`~m6GX~h082DszBlU6l^n+~u6 ze9WLCEU*Vsxrlufrb~#=bJUZc&G|-`vUeYpwgxSLzUCKdFlIh+w>X(j$^>566pB#f zZ^Bc@2_L03q}!Bo&+4R&5DCf@!?||1P(g%~DKo^MN-IaU?`wNMqY$WW-Ut9MUD?f% zq|MLzzEO#bAHoO^4ShQ5pdZADYdcC>bxZGH5L9C)a+VQ!QK^a!dT(NryJA^1t~xqM zY#w<$1HfFHG}Xee*+;ArV8V8pSDn)H_dk#HNY3WYi`akuJPQ7|M*3gZf#Wap{MWfD zZ)9y~WdFaM2U8rNu9`!03=T>qCCJtQ^jZtloEr9v2d^8c||8BM0ntV$#4K-wSK=U(T;oodg8bHiw0*C z7ZVc`_=}-&hpADC`KX)5YTAhNq5rMPL=v}I@G;#a#cur}&J9d4V zotr@nw-992iRda~c1=htqIOlgSE2z2x9n!xG*g)KyL<(11xPGnJJMW;!;&wH*&N;j< zkdMB+un^;VXr28f4xhFsPmq5Q8(V|I%be6=>L1{@KS5@hPKfN-&eG6*-IU zIm)LmQll0n5T~Nc8;%d6PqG++Gitrp7meD*Yn;Q+du8*sNslME7b3k;FJCf9V;mI% zq;ai_8DKFk549g{+eu^G6oO0NgI&u>r=J#zSw<7dTGINOr&f2WJKGVNRF;J~~;i3%m)guMcx;uY+G z`4{EogYJq7bph{%%##GX`DbhpLZGyECmNQIVok7tE^O2 zn)3FlFRS?lq(#IqGFF%EcWVlYMx1TcO^0eckUv4FWK8 z*z+bu|E1f7XPj^2l(a=96&x4T0S09Sno7cU|8_@Y%kt(56!YFO6@?cz@tdR$7J}pD}`Q93JSL02Q*6&doJi#g~ni1H&XR{m;h&nnjq;Ly#svaxYyF;oR*(x z)OxJC>KhF$S)U-7gKv>cNRfUw|H{*3DjZ=KS*Z zp_?ceei^1>UGS34Qcy0I7(zU_bblaw(zsGFF*C!0mW%e7L*3sm8r`9!!E(ww`pqF& zBcC3IYM}#Q%3a>zc&vkaH>Qc`Kr4H#OB2;O{;QzfZ9uuDv36^i<6^1{qv^^a_}3T7 zhef!FK)D~U6haUg4Ts?j`JS<(!p%=frSBbW9iZ^6y+-luP~^hgRcuR%Vr|l?n))QJ zrFmG7CUDsoG*HhC#jy0*a3@NLk%(D%Q6{2a9mfZK*zzv=id~x+p7PB6fYjKG2_Bl4 zBlt_GTDq69qq1-7c7h3BXM7 z78=z_iN_q?Ztt15srj2j;BpBz?t!6MS?D7eZ;8N{nuEeZ8wZp zBoR~Vd@gm5&u`Iz6F$VTe{fuWhV5s~g=WLXzF!e@IwHlHQAWv*K!KGyLrKAoZ-65@ zOq|h&5OoX9$+on&inZt!m#(Wsh!8E>AZ4>1Z+Z-!r&*_ppwoN?5?{r3YH`xs75Y_^ zdIOM5trI)(>}%L*DO~BU`Afl@7- zf-9Ncio7O(*z{(2%KD^H_<{HYy)eCIAmKjn-^!>}p^2EgVpY$Yk|~)tMwT;{7h^y- z(1`@_KyGhn&f4pp0={+#H#t@cn-4>fDbJHfDKpSlsnZl-y4t;>b_UVnwe2+ZLGWQ z_3@zj%b?{)Ir@Wu0<+8I3IJpQ*|47)MlsKkVZ611Ruq+p6&TAU<~Txotr7|`@L%;@ z3FqpisxzAZ-Vj6qU{LdN=df5b3c33)R?CTo*D`VxvL;FMs=g*ov&+c}7LjO zE5+bPv6o4VS}&DqK#dX%F|$h*EDQ+}OEgG^A$WNw(O=v#Kg!;et+Ut)s&gp!iJjk(NTafP8@q54J=ttQ5>uIc6ZWI25Lp%u%mj z<#I5#BeIw~rr5f*2a;s$iz7sZzT>-!&wILvCuaTi((u_3XBY$B8^A3%F|MnO)1K$GQhq-(T|C zlFsJ_CyPs)KzJ`_aSvuhiWaL%+S6slPmZ50T&cxiu$|UaX7p7Y`!^Ooflnk!_x&Km z01B?8x$NHR07_ojT1jR-Y0}PUnW%C)pIB-PbZyA5xsEjx$`!WgeWx-B2Z#EjvA=9P zeEWm1{TagPH1D&e@I#^fEL6NbGnteu4=cA&k0_j(yh;~!JpwY#tRBGRUdg|f+KFGW zCG`(aQexhGX^k2=p9F2h5RZ$D5I5ElkE+frM}(WroAoeZbqx>}JFp)Q6)lkYfp!_4 zag6IVls}dJ&|l!+GJJr&>te;jY?spLOY6fIgPOQo9AThBPH7 z+E;BLwz>N9ACKsplM|{m-VD3fi!=wu^$-d;&4<;wMT_8&8?4278awT+#apXzKw@!4mP3-;;PW(BldHI=E|yaS^35 z#R!s;0h>|1tb6}=+4GMU2`S$;)ImhzGDcy%+~7=pFE8HhdA3LbX3QpcdYVlwF+o# z4E~Xix{SC4;qjInW;Yp=aPI>K3>(1vXi2Wgntxzt=MAczOyMe@SQZ%^pU+;~A+Q>8 zcdscM=4e`mK{(;WJbY2R*TaLLQLUv5Axg$P7Vz)e13#U3$+;uSr8n?qb+%bExVJ(1 z`2$8n6NeFjG={4>S$YooJ`z(i$j-r-he-|-ah;+#eGOMoMuf^<8Qp!Q7(+o%st8F6 zt27VQlOFejKFKdXaOO_qG4BYOdHl2Uhq#rtma;Vu!{BYiSa2Q(UkS8zb6`lob}BMM zm9+e7!FzMyurep4dRV*+0AK1<92lC-%uAcMR>sqC`&E%24@uCQ74)5%Ysw}t zT~*E*loU1RFJ-`Q?HfsnL3i7sw;q4+2Lly2&fQ8<#hk2ZgT56-nv1`&JcRkPiS~n+ofYx@uuWSEfijMN5g1M2hR`ePkLTt)KFgjVpZyFHS^kp1jJLZf70jC zA%P}T0?`qj7HTE6Ed;3am}1dc`dbCn?4AgtO_J?|{xuTKO)EN17K3r&Hxcl$QAo4V z*$u+IF=%AX+}MP^rnj7aFXqmYnJHe&nw5_8w`vr{*djR&%>2>ij12w>O8N7&OQT%FF>oHiq>GvrAj!^qS z-d1_qnSB3k^5r~%F^XTX4c{efKRU)=b!xbbD;$Q)IjK)2w`q&_=)dl8Q8N2y+l~17 z?HMZz@egh54f*w#J~Uzj5zrLrYc@p6e~K}8&;CmiT)GMU)IkFlSAZt4g>Fqawr;Sz z?glipsc}FIH!6`uc5LvO<&FICg?w~|{;0yejM~*moU|Ev1#?4a>2+Ae1;b4G!VnaN z!{eRHIHUL10hidj&+6`YA#M&eFY509Hn{vh7T*7@WR3V1zzRcvCL_V%0AOP6D&YiU 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 literal 0 HcmV?d00001 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..93d38ee --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\Simon\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7b8e199 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/commandline.txt b/app/src/main/assets/commandline.txt new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/assets/config.cfg b/app/src/main/assets/config.cfg new file mode 100644 index 0000000..b72b6d5 --- /dev/null +++ b/app/src/main/assets/config.cfg @@ -0,0 +1,58 @@ +bind TAB "+showscores" +bind ENTER "+jump" +bind ESCAPE "togglemenu" +bind SPACE "+jump" +bind + "sizeup" +bind , "+moveleft" +bind - "sizedown" +bind . "+moveright" +bind # "impulse 12" +bind / "impulse 10" +bind 0 "impulse 0" +bind 1 "impulse 1" +bind 2 "impulse 2" +bind 3 "impulse 3" +bind 4 "impulse 4" +bind 5 "impulse 5" +bind 6 "impulse 6" +bind 7 "impulse 7" +bind 8 "impulse 8" +bind = "sizeup" +bind BACKSLASH "+mlook" +bind BACKQUOTE "toggleconsole" +bind a "+moveleft" +bind c "+movedown" +bind d "+moveright" +bind t "messagemode" +bind z "+lookdown" +bind TILDE "toggleconsole" +bind UPARROW "+forward" +bind DOWNARROW "+back" +bind LEFTARROW "+left" +bind RIGHTARROW "+right" +bind ALT "+strafe" +bind CTRL "+attack" +bind SHIFT "+speed" +bind F1 "help" +bind F2 "menu_save" +bind F3 "menu_load" +bind F4 "menu_options" +bind F5 "menu_multiplayer" +bind F6 "echo Quicksaving...; wait; save quick" +bind F9 "echo Quickloading...; wait; load quick" +bind F10 "quit" +bind F11 "zoom_in" +bind F12 "screenshot" +bind INS "+klook" +bind DEL "+lookdown" +bind PGDN "+lookup" +bind END "centerview" +bind PAUSE "pause" +bind MOUSE1 "+attack" +bind MOUSE2 "+forward" +bind MOUSE3 "+mlook" +"cl_particles_quality" "2" +"cl_stainmaps" "1" +"fov" "110" +"sensitivity" "4" +"snd_speed" "44100" diff --git a/app/src/main/assets/source/GPL.txt b/app/src/main/assets/source/GPL.txt new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/app/src/main/assets/source/GPL.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/app/src/main/assets/source/QVRSource.zip b/app/src/main/assets/source/QVRSource.zip new file mode 100644 index 0000000000000000000000000000000000000000..517671e44cec70396553205ded8ecf863ac26bb2 GIT binary patch literal 4200763 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 QEr}lwzEk3#q8|l=b#*_UxlBu)lgQv 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

nZOM%mV*7qebJ4)-%p%v~ZMB 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 z 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⪻+zlmB}icDJ2nxl4>}cJRYz}j%4mu&^M=fs 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%0Awc>fzKZZp-q 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

o1545k0QJ`-D%=9xbvOY2Wv#9 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Ġ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
  • -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 %J$$0USP-mO*(3Q|mz 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

    e^+9xKj;_XN)k= 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

    1}L-Au@Is)n2#i36xcIJ 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

    j+@IZb@*BIlUu!`2X%E930RJw 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�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�`u z<1MO?G@Y_AI6N{S(*$Zfmmr{N1c*rt8ZgtL@FsaSSLxKFrPGX64KmKCGMZ`pF{#B( zeXU(PYcY0f?q$oNQVTSj^6^^pS4*K|x5O-uwkPet8>z&A2|}VCLW~%I4GOmu8Xs#b zA(k(8&e7%sB1nv1qqnX(KWSro%O6@>{kV51t~~gQKeAFr z2$x4ScTEl7QI8i8V&c{A70={5OMzu5bUBBPi7#6=DOanhRj5ICm7hqNqSBjLODl=` z_}I~_0Hl2yE^%=8Ls${RhJe*_)BpgK?ifTKR^t#0R0G{;?+S zEP2(YbLCamV8K;U6$EZEE_#x zD0UPjWnq*aQGm-F22kct&)G8EPgoS&J%~64cpCn4BKZ zT6|2PAR#jp1uTIHaXGsUn!sF=@j^vQXWkS?KBs|4xG-Mc%%Slz^=qe1F=d~;jSh^Y zlq2)tVH?F%Ss4aTR{N#R!Yo{8^RrZtKDtQ}F5+5Ct`DAFR`d^>#=Z_VnzF>jM0c0C z1SfVF3|2}c0K~vCOdRnOODvcKMP9Cg0h39@cb}Ff+en*ONYx@S`)%}yT$>S&beW}- zkql;}u~Fl_UaWCZPZ62)df}|ufchMG5futXs8YAQjXU_-&hNMHwYqC~uf5{K_>s1J z$Bn5eoYocMYt|pXtlN@(<2Rs;1{ljd6fdGP(1`x5B00=e!nc+c9k^v$m*%3;v2{^|v)ES|T2%)W;BybE! zU?61#XsU4#HeLEdgPmw!29A<40Zp```pFfCsB)Sng*a0Q0Qc z?ag2SA#syoxvT&LE3&LNHGlxTR;KGDebp=tb{}LI$aLNrBcaMPAO~b zOvvH+T-P@lq^lOUIa)@$?A^UqQsz)gxfO`^OD&V#xrFR7Zey{TMJ{oU$)+cvys(yj zRpgHxei3?qJ9TB2H4nbDk*l=SlXChgR&Z4X>%U8OzFeo}=~TWqODhFT*-3vTagnIL6s?igAQl5jXG;fX=8E6Xl% z?YT{>Lx5!w`Am=B_)MyPOJZFoqq8jQ+XOS`W<63LnVpi(#ibFe@z}*ALV7DnC!T$w z$ej(%Ovt-m>F228R8ai=CU<0(bpT;|3-;hO!OJqo=5`03fMakJGYnXb$+dc|oGD`T z*vomW?_R$S%cJo0t=Fv^v2ve!oS1+m(idBC>@`+hYFT5OwIzb1b>7Mu+fdD(eY(8> zG;>y_NB{r;000Uxu_FRj0U<}48G7O8Lx`9IMr|>J2r>);5Fkh}&|DIar=dWQ$aG(uq~N z({{eDU8kkSNb}m|9OWfQq?%b)eoY&2VsTB&FVWhZp4Dw**!&`wdZ(YatS(pw36nBF z*Zi%`NB)9BQ#o5f5EuXe0Rg3B12hMa1_=_lW^RY677}0x8FT`{fuzkkz;O_vAZQ1K zKqxtgV+T4U5+xyufPjwFpcRPN7mzS3nK&16SFE6O3!tD7^GjHgwe0Al8;re+=p7b1 z&DEKbJ4>Z{U3uHPPkU86p8T;ggVl3ixbqKLZlxssE>rR6A=GdeB(-oTF%`KnKp9kkf+lbiDl@eS$;L)+~ajWIC`|jHz~KeJ9oLsT&{2V zk0~(^k9;z7{@?$B018Fe=_G&v0GRw74rc0>n4%ym!=sv&GGzjOo`+3ADWNXlDFq^d z5R^SKMMcB|)yz0tSQJB#6&N8LK;w-PgHB|)X(1*Vi)KR9w=DDj`@jSyf+R{?+V5ci z0*)&SOza>4T4kYIjJ-3Bv(p_6D}$&{^Sqm@Zbsa8HH_O0!e<{qI*^iBS@ zf9B%8>#eSP>R;L_b*t#El@hU(L>HP-8l+OP4nxL>H8_DF05*|^V3@A8L4!mT_Zl0- z`K)HO4m|7e`gvVJ6w#pAvO(hoPZSo!5rf6-6hp}-1i}#p3kao{HN-R!3dl;kJ#3>K zRDA3$PNkUwnXKryGIi=@B@N~Ds;g)+-mZuCUn;hdR{TxF{_RzAJz{3vaqw-Hjnee4 z@M%?JNC_xdtzXt9ZWS(=G@)Ijclqtemz6B;Y9eb*W=QT4Dkvwo;{IKns}k zF4sY>uduiUSng9VrqsHNaq3RDNUS1Ti3@t6Ou2YZ7xl5EBl5{xGmMBaN4`A)ysbUA ziazQFvlxpcQVAZM^s5{Vfy~4<&cpSbTNCIJJUj|g`i^)@)ynidZVWQU!k0Oll+6Yz z5S@ZQPvaiR)xrS(J&@JOzM)2_luy;Dc#Nr{aoCXt#Z0goIxs=exf@{UpwR{g#HpDC zhbWMgqi9h+Y&ek|kXvia%J#Cv{f67EJk)!);u^?W!KzuZ8x6#>if(9Ms=3150001l z0}w3Cl*u#!R0~2}0pcl}2|$W)GkEg#Y!~?zdfdO=*S6%~{Vs^}OlAN3zyufo1_NT( zOAk!&#O!LwVT0xo33qL*B@fCItgUr}4@jlRbD5^D*+gU|5^Rc>)1|^PA!^mz1U1c7 zV|?W@lhT_diEa|YQO!c5A*f@=DDP7AZrwO0q?IEFum zc<<533&DQGtj5^W>noU?SCex%(kA0|n59xq#%spsUH3e7?9zW?O|mO-_s!c&Fg9)( zI6*2;Wz-i930-4fyL|vSfB+&XmaOQpL7bQ<0@{~QJPGcisCQ}jY-={ zDM(3&K+=3&4FJFtJG(^ z+`<~7d&?OBfoEvMg3Uxp_if1|?bSS{c%}_J?&s-twq{2mn;7sG=sA#nsxU z7DG*sAeop=r^?)Zp>?GeXKH&YI1epUjy5DQ?hbO_c?j zZvDl|R`q*4)DR4n^0%cQJ%$P;(95!f6V~9Y^Y)R@iIPZjohU|-7X6|I(UwDEzn<#G z21NnGp#dRmvty7k3R4(kGeQ6eKqn#egiSL4j~WF_wH{l}|E`)`fY8azgG#QJ)oXUXG6-jT6Y_sFNMIs^%VH!AQpkG+uhWNLk)BpRh1S$X| zU0>UK2}AIgjH^#z!`4-Gb75>S+R8Vp?Dd8r@ie&`HQhJ_3sMV|-AW8+vpjU4Q%!JG zLaf#BgbwO1HtH3ikimi--z6qDaiexwgx)5fh;=dV&% zdQQ@S;~kps`Mgr^nH#!D*2^wYiUK%IsWvjq?vBnHo<5DhLi6o3GNe$359PC3 z4e(WRgtbXi!Wha(M>Sk}*r<<(PgdkSfi*Q>2>%@zUlfqDuB02B~&H2>gA?nBC>kR*l@iiLzHi; zOmJFF0;}7hwU@uhC}CEv##n~HrQl$CgV?wjV3`SQYMMMiIe8>=O{_rW+9oMvz7;0E z)~S2q`rb62v+AODdO?J=x-&KKZyF`Eh((4cbNF!26IYr!16FWv0 ziRhZd7P^l#JFv?OhK?*t$qF=B1~$MLAp*{%-qCYJ2uVdqxQq-UWRYhfJ}V^u`>+He zfHbOES>p*a;D}4xJz*n$P~m-TtR!zq{H!d|gpK*N42RD!$}z;bA{kqcc25t@iR}7! z(i*xk*$^IUl?ACwp+!STnO%ca%k8w7-wXVPSuAbd-Sf0HDgJGV`%1~rY|{HAQVRit zgIgDL-uFddUmTJE001tCfLY}%NFy`*$?-QMjw2?4Kp%E$*1Pv@I zHlP@ApO!Y=CXUdGV6{x$$D(A*F{#m;T0MBg_wUuG9JHd!#O6lLMM;4g>=2(uf=#z7 zga{H=I9Vzt#WHD5&&`S0nx73}Yv&KqXkrTGu7p&xFmJ@ipJ#HeRoZ5d1ON-7l}>gp zoCyZS*3#%lwEY$fe6yg4ah=1Ljx+~|MRlabfu)Fsq@m1c_ne;{CdAMtU{c4)rbHoE z3>Zv8V9{=6oj_g*=2}fMiXSVFO z(pW?kV^D!Zi9;hD`LhOGkYlb+tinNef*ytA&>kA&9S}H(-jk~K25+b(jeY#tO#{Rs zdubBJk|HTeNWe72o00KJd8*nB6hbbX8=O$=Z7I83#?8TNtI7W^y5t<75yc!b87X># zUpq$qN2kE{{3^xYT54Xf^Hd{BSxhFnZRs*;1+73~r;zARXvu%nc$7}u?(ZulG?U*S1OVJC;=I!%Rw*UK} z1UG^Nd0biJ3^Q~)42aZlDwKV!ab_AS@le{cJIC7zOh z8e)FTW=3>cq?RR7hd_~{k`RCd09(t*m@K3rOXzsOYtNvnX~Bv`UOF-eOaA?eiA5x6 zo1&?PUX7sfpnh1ptFB=h?Jr3Pj5mreJ=v?4&E+>1P_b;+_XzHdY%Mr)C`s5}>uob! z9$M>OyfiN&IdnrXz~66|MPF63R-L(@!)tG%v76`Ide8T^j=a_RTxaOykmZlXQnh!n zNp;4+1;C*lz+8ez1_y*wQL*ADI#e^2^ta^BtQ_sj9qP7k^C?mplzdU*2$N&Wq;RPi zgesk=4h00jG~G6pIF=qXYA{)?1sW@=wIiu0k1|e<%Y0@i@Y}c`X#DBucLBPRu|qYs z2^E0~xKdz*TI!BM(5%`w1ulkGt*FPsc4PXCI~5eV(;k+Je#uQ)#8o+cunb8s00018 zc*s;?6Y zX8Qii*WUW|C;b1Q-Q1|$beRuVto5xg@-ch}=<~W*GgSlC009-0^&H3@tbk8O#6=SS z`@jSUfCdt0S3@i|Q09#qrD^7_Q9*lctfX_w955}lln!|v5|Q#ugrZPyKaHdldS6GJ z9P~@$Qiiz!G|4M)a^w%Jp4=wuNW$Aye5Na;C;@lP$DtI!c`@s+!Cf zU0>!A`!3Mu*V;3wW!?5`dsXnHqV4fEwi@;NuVH%-LEbUmGCP%zNTT1i+&B8sdSkAi znN6!|ga85ohIhuApz2a(SAzy5$Z<8iu^m820;rrCLiB@RN9~it?yEj!YJMc83D{l- zWjP61EDzCCIEZaSQ5{}6#K97GrxAj_P!dFRMG-g^!bV!M9VETm(&okx@YpFtwNy$G zV+a_!A&ur)IA1+ZGDdG61N|0<2*8t+!5=4wN$z`+g2F$}#5nCD7+9i1eGTfijI8dU zCsl3hhImMPWP{z^$_Krf8`)jAH%DrDc>QH)SfmN1K*nNZ5l&>~CIuIL1SK#fA4oa} zrdB5kEmx=(nVEQ*NLu^buEmv4gyIir9vhU+HGTj91Q&2tvLO?oKp?P*DgX_Y4G5~t zl_*$a40k21EO_wy&zYXR4346+fum zJzpBzjcwdzw_eltPs^j7-uA0*|8*C}P}_53JF1cVQHcg~>`iDCYEk&ziz>6+$XKDJ z!#t$T^?O5-^vO1zfB+=9xHj~GK|uh^QJ#PUVZ*{K5|JhqOcVi#MO)XhRg7Xcy>@`2 zg$EFU;D({_RB;DcWZM)c#>8_hwTR+di?h>NI@PQA&Rt^On#tB$<)}f69>&y0POYok z^>J1jneOC=bsK1Wyr^zLVV#)~NrSYNghNrYWrlcF1#?|2FxNsKtgSVM8EF<8AtR&qnnl}PYKcT4 z=eCAzYmOYFN#qNN$c+|M;L#wUVaB{h##C}UB6;W(Gi5!AV@@)fT8l*cJ1H}}epE8E z_Ad|jahKjCt%WhABeF$gz-`3W;J=u zFP>etTYG5pui!gBV&C1w^`7so9pW~#HP(ynW!_CR%YObLP^1Xzw-3YlQ@;Pu2|xe< z7|5fz5NH5$svmOSro3@V+Ch0%5k{F)I(#BuKGGt$;Z~^aw(^R2%lyij6DVd5MNrU8 zgYz@MWlQoYqRLpxJXYbUDh?Z{`XuH|Y`7CnkW zu@7C6oLZfHG!6z>D90P?A3!+d< zZ6IG>+9X(wbGXSGA9Zz`nHE2Xujks?RQ-LbjAyA5Hk_A;9ylZdrDUFyXeN_i&-#*c zyVL*zLYoN~w@tWR2LPxceU$95Hti8WGUZ=tT=TXD^^y)D0Sc_53COw&T&XK(5Y!eL zffrZEk0X7FvFb8uq)ABHxb?I2v_lp>f&QL~aj-9;}QHL>h z32RO>AaL4?5Wx%>FhHvEnE%N z5`i`9;wmn9@Z|A0v6kXZ1ywe=9x`*z#*vrRRdFEw2;=$co+0A4s&Hs^GBY>MFwne>5INaM|c^nW8xuH$;{K|?4XJVuF@3LwZ{vOy?M z4)yEKXyAyQso#b;g>bW!uGRi_E7N~joy)hKtN0~A=+oKme%>f^)<` zMPlWM$k^E$bvp5>sXLPh#-z+YdkXUVP0K6UOLLgF3M`Bh1t(=`yy;R!P{gfjwiJCE ziz?Ogdi3Z2`>+Hj00cW++3N-!(1{C6Eny?5RDE$>EIld0G%M_Nh86j#Xt|evi`Tbd zZ7}_!FAr1bl?dJJQqREL^ggtk`75vM8Pn4DPC@(z?D;M zkN^QWhYbKIkc0>Xg`xt17kowr#7d9Bd0Q{T*sNt+P>#X`)|CV-UBZyr8W1)HnKCFKP&sD$7;*l*UW@mh zG$AXM&yHrV+@b>H^U%vO6nI=&PUaB>05|`%wTVgy%+3 zCQQ48$P6q#O>{8`jkH6MReIbbV1UF^xRm0UYD4{1rZ{C6W)9L&#HTkhI)a6%R!h_jP-`jAeNiISIAzdg@Xv#;=eiXF1poj6z!#&U0}R)L9tHHzJ!r*~k8eWJtd>>B$`z=%(+7OPJ=Aa)_A0xt4fk}vxe?7>YWlPjJf8xHP~ zU|yg=1D9J3FaP_n1T6z4duG)Rb+gMJjPYh4VzEy5Wr>@|iCI7&E>>2ql+ zPW`QtsHKsilaTp?xILvLN~=6RypdOfhyPYcS0eUO2PXWZkbd62@HOY>9(@;ot{L)b zsXY04?=-(0&PFt}OxdY)JMBH~eD5EvD*YfD%7_2}0I5NPV+=qFVI?6zxZB(pTHS6m ztHs7`;g~ec$Z)jM<}fQRuQfwDZU7fW+w^f^lE>6Gyd!l+GQO96d>(%S`G%GCELSq0 zN7lf>lL8as$+8w2%whyD9miKx0vMQ>x2SH{%0yh4z070Oh3LMRm1NkoV)s{dOV&V7 z*XQUF_ftw0a)1CJ3;-%&)cG?GqBX;c;oLx*T3aj`mnaV9x2eUr-mQw$xjQV3ipC?w z>A1kfnjvUW@}Mv^SkVQkdBPl2IPTL6VwqOJyLSO{q)>*~Ur{bVuvw&Jl9W9#xQ-iW z2t=lyjw|521T{r;D53D_=&D=YlU5dVU7q^N?_U;-u6O#Kec0sYv^^@;R%O;GoTizk zp?|j3HdK;|7DSV-$5gss|4x%x&q&-UJ4DLKqJ21qK zdSQU7Rw=`b95f{8NU?WN%>@kcWA)NWJK<;OR<1zP>~wy$V$#dC`&%n$eU)pp_b$ev z&AUBH$(%(J>YhXp)E9y;WA7^cW8{+gAFWDo0eICbmY=Q*0!GCSXmb8N1FVARe6d>siP>?(=`<;C`DlRKF=8|x zoj#;2494DOKhhfi`>+He00dfJS!)S1(u?ccEnvus5gCJLtQc`hCbR7Ih8d6qt@%6S zEu5yr-#PNP#>B``*XfyV$d?Kg2}823CUy^3|4*L&)j8e2Z054N{m0gr%2i}B!<*Z- zOPbZ@UuSEa?3gZ7@aG6!tl0n(0(Y3s2pXz{Swh#rgeW@=v6lsbDMLzm<9_f(XJDFN zu5N<`sX#&Wa0EV0X@Ns~PKE>LRLWd!&SU_u+(DLa#BI?(yi<*9UhS$-G+6Z?uR`d1 ziAP1>b8t19;kl-{wHtb^#3UR(>AV|uL1=m~Uu%lOA`fmZByQDGh#-&peYCf}G+q+cb+EH0M z*<9pnw#N7P-{aZtx*=BDL;wIf2n;3^$#2quy>gN5FWnUihg=33z&1D?mWx zA0P86RNXMQtF-Ui^*cOG&HGK=cUL^JbfrhCN!-s#imITtfO)3T0Du8g4B1%)GF$R0 zzD@aL(4P9M>&r2;nq>7XNTiixp<)B#N>~TWS+X->#1lb<+nNJ3qNxg;QVScD8q22W ziaD#&EpAh$Ebn~r$7*spaFxoNxY+5Ak|2c~n}lY1ifRlO#Po`J4=`1|0TZW90ck{t zRbgY+oRnWsN|FYyj}76npk362^P5}+4M>0ipd1PW%Sb^Y3%)Et0Zjc0OZ*%nD()~= zUhTTsx{&PrrgsQTLE52#t--OjlCPD-Rxc{GKJhp2+%*=WauWISiNH|IMWHq5ve1)M zhuhgqW@1+9Dd}n80s-u(EQ7YoY9X=0C z6<}02ECWlw)Dj>70%WPC2r6k5h6EfKHkR)KRV64uO6ErhOOTbVJ_B*1@r$oJIf9!< zCE!&C;^kt%)cgpr$Y|K5k5qN~NS1dj&KYZ2zoLM3Sd5vmMxoZK11$|3hZFL6trqft zYLZ1^xSWc9A-hr+mB73=*b8zPYr{WO0}!#O6s6SiMH)>;12cXM7G?y4I+0fmdkQ(= zF(q`|o5c(^d-?WQWu91aOhF2=sH#nHob$})&gimbSxMQLyMA)lJ~GK`f*2sy4Oy26 z#@|P(QFcaHWFkQTDMU$C65p(Kx+G)*D-wD$5LB6ZQ2Ycf+(Fs$Eg`pFzIshbdU)y^LL*k7K3oT)WepC&2V~o8k!Yi+=b%qW& z&Xpw8+&+(7TT*{$$bw~=%bWVK&pxtwz20O>obdnv04GqT$pbwU*&vXB0!Jl)W+l>h z)+0-VL1|F!C?Y^wO?M9T>KUze40)-Ub-YUX=P)!2;e%qQbF0!n zRh}W8jX*{gS(-;FCKMC)Sqqp%{V>dXBW~@V=4Io?`P?l}>5JH}dB0zGGrQAmTQ!F( zmecDz(qVc`pV-`yMGb8L00wkLx+yUO3y#5BliOiM)qKe5QLK`h&pK6pcdRg(Zx$^x z*oebvC8TKm>;-fd*q(~krXl#YeL67VKAUNHE|VJa=FcvR1JIe$3&c#K+}spq9R-^@ z+bOPz6w3=XD?mDt&|G}Tw_0*Oi7F zm0H=deQ{kPvBOo=GsM& z;9=wh7SUpW1D^f}36a6>^Oq*3d$_JpVIB>JK-ruYbecju5YnV5Ubl?z>jh0H+G=G$ zf*oilBlr%|kD&ZSwRG}DGf@Bgzyt|`1+`sQBM(IId#l@DVIz7HC3R(tFmu94u57i2 z8M(Se>Z{?`W**8||3mTI;4MbC5)|2bs7#eA*WYMZb9Vp1k^hS0H8h* zj)rEFL;kL^e|i!dio>C>0RhYnD~cQ@!kF|ZC#PdTk-hjjt^EsKhM#cv6_M7Wqs0(L zw-sELANeI0)_OWQW^(54{f1HWfrOBO0GNV!0c$(N5-7}-Otg>RI~4WEj%(6PEtHQs znGq|O6paS0NW92n)?f3RpgQ`q7UeK+O7e(1sz4EBi=exPioVr)!bsvRjV|Y2 zwkZQE$a<19Fw<>P-Nt0RrApuCmjG!jmeVw8{RO&Ivr5F;^X4L2`$8?stiI{#>i@qZ zTGjQ}D_b~y8`%|N#@L=>*lb%$$L7T?=TNLyX@rAyE~$li>T_|$iYZG39c+H?Wy=m$ z{ma|VF)>m?^y*bb$OKS84Fm0qbBO&-=$^Ww!T=de$W`eaCDBohJhP4af}QCH6>O;h z?*W4)0YUhsI@>^Wx%O!m#RBpbV@hPIro}4+ z;|6PkB}b&n9^{?Wcu}6reM$Gh&h7efo*l9?HaEU&{r|GJ!#2FAGnoOhEna>;LvwWd z+pjw4u@i#?Ij-4JU)3n$ooE0fr9+z#88|4B5Tg>om!#@zDxzSnN1Y_ym1Z(9zoHS0 z%Eks5(rWUm&G;-4ZCLP5Wjn?wa7Y1rc%egjp|wJBh1MO=`seks*BL6gWsfUNc+$w~ z-(PCW@x*XiLRwS3>Rhrn>{}e0fN}*pN1ONa~w@XF@P4F@xv=A-F?S!pn0MV6+*K4YdQzmz;u=eQ! zVC*pVpn7(Vw$LV$?=dq8T&5)xBU@`h=fS(0JpgvqNXA=e?q|_sCRbR>mVK0f+G#NC zsJq-j@mn#yB=WP@Cq_TSmy@QX2u6lk96~z<3Uj(QQk=iP?w z*bo2!Vkli9LI?tMs32tn9)mwecHoT@N}Ag;%d^&=X{MPD(^+fm#q)_i(9^CJ!_0p6RUx={A*1c%n#?%ym>itcnyLWhNv=~$ zwp?A9({DjPCd|y@c6y^6Btp{-FR+G~_(;f>ZCaU1^+;omMd4u_o_=&veQM-si4<+; zlP>F)FI|7}&T)3-Df+nGo;~Lui7Wp{qubr=V%@b`ND%|X3k3lH+q)@a;|nK`uyZRj zAVu_f5D2`cL8Hr4TaX(2bQ0p@mDc5!R(HtNod^okKq} zFMZE{>MpNYNHHc@?xtU>KXl7DiGrd~@`VShcs%8-rrl@&09dMo0S;+<#je;H8eXJJ zSz?zG9uW2qKokQP5Mu`mCypv*;Vl*&w0z2>|NFoM7=i?!URmP|Ghl_t+dW}}ZdTQu zUo0@&0~arOpfmV>YHy_mksPcgnymZyiHig zvW+P~YVXm|jX2OC00Vg+Ld`@~D;hh{jo?D23rTM-Bs>W69Rbl92^?VIWbxHd_?Dr8 zEv0deXLA>}ojIe(@=S=^4OpUmttpT+_tMIw04fmFfCt7HFOR;?Evg23(T}}%XLO0> ztS2z(LwE?GTJhrG-4?VSz~DYI?3a_n08EsmS>|GOt#N+8j8Kx#NWt_4(CLvpb6PDta)+R zHZdEVT2T#+w5qgzCldp*S%DCLGO2A93u;yh#th+I*LR#kSZk+D7~@I|QVFG2BbEya zkf11QOQJ(FxE2%IaeNi#*pkWhpJkl8H>yN*YjM-x{(9evZ0`HCuY5b~S)wiqB$>NA zOW(Nrx!u3)TyFY66r3e^P}4Ut5G4Z)mbz37n3C1H3IL$1Wr7F+O6US6!XcGb+&dSb za9n1&G}cShv&8~?7&9q<9)fx%Mo@?(k3|etQD8A(Bu>-`%7vp4Ory1+K;{#~Eej?> zp^V~2OsRf{Y;qoKrPcwwxMx8)BN@~r69`Fmq^0e2nd~g^mL8;!=0e2UtW&8~if52$ zx)nVWVf0G0`U8Qe7+sgzDXfv`PcCwO`$*dRYB&5ncrUTfza_EtS#_81_l8MScxsJN z>M_dmAOHXWsCkqD1PTy zoS{3@h=ogYEHr}vwR<*+>8u<(VhIpIP4k|Bi^_uk`=A6V0t9YdTIuOCV2ukKU18=% z5z%L9tgy|(A|~xMq>cFo1QRBjcUH9JJf_U5hHpxnJoJFb)R1qFyZ_zF%qq3FyJYsw zt^Oih%__x?pkG^b^~JyVhADWx@>27 zGYA9)rkk$ZndT6hLY3fdZol1!vVVJg?)LAmf8#Vi?|!lCAX3W3KD2+Yx7W2)$V1O- z0h>DaiLqBK6(c1e0+ED?#KcE~5(&alxZ;(h(yFz#g7M2h>Xpb#j?!6~B^IdZsfuIc z5ywm|%tAPyA1k&UC#{X|SoMclT6$S=>F;7O#Sul?O_Nb1ktC@6XL*LIG9Q~g9G_nn zd34nx*nuSaah6MGYwBI*8uzwUdy?mIwH7aNyPJ5Qx3~XYB%uJ!GscRSTPI3-B$)sJ z0d}GY95W3bE)ZFP5QBJ>%`BMok0Z}3* z=`Ezv+g&wf6;PoRrB&@FE3AbMM-^r!MFug>s;zyP+8)ZHM8k+#D`i;+6L#y9qw)ze zJTo!ERU=A9Cw;@7By-7hl+#`myG5&in*VJIX=c=bO8@(?1OosB8C=_I1}tEQ%KKem zBa9R+pJA-A5yBLuZFPi=`6bFA5VMrU0w69YuyGwl@~sK#%v0e^C)-#V`&bx$CiSx9 z0BI1!$)~v#T32T&NmZD58+gseQFSae%#RvQ$djq>n$+e;Tei)194{?ZDrQMaiit9f z5D{?`rp-&3q%o!=s$Gnekd3_bb(sYP$vaAVqnXZtAx*XI=*R@Dvc>=*r+)@mOiBV+ z7(g44kROH;p$TfyQb8{zZR`y5x-<0hSjxy1Wb!rJ)nO#sn(H8EDe#)D$K)iHWTV~G z`G^9nx}%ufRy1j6z?db3C5+oZ7F%dapzIHZCN`xQBc{Znvt~XDbXH1~pmbrHK!O}8 zFhN9u@|Im;4=p21z~OWjDbfLnB}f1O0aO!VF;hTOfJCHuh8?w5Ve|<_0IL(E-a2>O zi1Z512+gA$Do8^rK#R!-A$aSIoT3w&I6_qFCJt_iHXx;ZSu(MTf;Zky*ldGuL&tlS1(JU z2vJ5V4K$e+6g)wqOZt_K3s0}1iYfZSddo5(vYVHMxdp^>B z3T^K!h=dYG$_)!IF0h28)@fk?UH~IC_K2n|xl_jg;iG~7`@jSd00bOdTWbk3Qsivv zP;UvI7Nv1n46zvkMl39Kgqh*xQv}TC&C?I8N|`dHW^`*PcjnSpe#kKYw!>w%POd9fZzT7L|L}`Pvh0nO9>au=>W*|Ns8l&-LTu z{oVXSv_TWilD*sSqZ>aKP%^axF>whJFftPy1`z@nh+=b+3m9FtZAzT!q;`6v)Ra1*L~8yh^nq)WHQ;@^u04GPoj1*2Ntc z^fzpIj!J#MPP~2LcN>D$W6ZIl*}zC7 zLddNM;&0f zt||*d4QBUfF=%+WaZ+-SzYf@qX0-<+n@)rh(3Gf}mw81ZdeFssHm>%F$`GV7f$YcJ zO+dtt0>eCEQ?COh#n9FcCuoUY>|9x>#!%Z&eEJZI)x?0g8=eL(Dvw1|}p- zFldmJHzRgbkYLF<1fPfwVe}f1B4N4=Vv=__^=U*}dABCiIcOZH!c2}8z68`dkHzHT zNbc!g=Nr-T*$?Z&d9Lj3Pg2q3M{M&aeak<37M=d;Xw-Pr;J6Hk0fMpqVJ5z+EUHr= z006oPi+VVv)?3u}2NB>vI<~Xe1`yA#fN=rn3kAd`7BY1-Gur?AumlwV1Up>WV+=E3 zlB@e2VTO1R!F6ryFw8;>uPt?h4!EEuDI};)=Qh0g_$tFTbYVqRvr=m!aT6Wb>$Gmk zru|cRY&_$4n%^}rW$6qw3x6o-y`)IDYCGf1R_|`vy7vvvcX!{dU*~=Qb9?s2?LS+8 zX0pD!6nf0vVlQ>c6-#6Q06@8oVlN3%jGP=4wgo}D7ab~B%fiJIdRDR8#j6$yg(em< zbybFQQYvg{_zAhtmeoMBL>`hUO@79fhEWhhfY~F-8cd$+-7ZZ5p|EcJJR5)h{d#gG z<@4EZPwyZ1Py5HoXy;{QJeK?oPf*d||D`!8lIyplGwHbU){!A`x1a9rLllCo0nz}g zrRYH=mSs}_ifGA1Jxg0E5{ypxVAKiQPeR_NGs>jqfJqRPOdzIkm?`5__ebe9lGrrM zR#`kjIl-tuM31l=Y6TP%cDvB$n9G#o8lD|(yMNw_a|v(H8~n|~Q6OE>VAyP+@gemmxUt@TnNUKwnk0_jSq1>dcV0s>NQlzvNQCS+pMr#<`OQ zuKM5Yn+nZ)F}@hb(S`1(^yW}4>bY~R>%Ket?|eRP+vabSn5G>Z^>r*Q?-n1ELZh8J zS8OsXU>Wt*Y1)#k0003>4uF`(8W%Ehs|a={y$}I>ytL>2ay#7VXO$o9d_wQx|Yy)T(yU@V&6(GLo+p40$6?jMC1LO}@|r z!05&$@OU0U6G~y(aI8B6ad>u456_Eb68PX*aM5b^2t&%!VBlm&X5px`;Oua)(*k!M zh`v5y((A3JmzCs5Z6xlrBN^2q&v789BwtMqXpnogWBp2TjjNRW1u6Y+=dS)P3()@ABd@5whF5GqxnhC-*g6%=kfJZhH(Ed@aGdZ0!AuJigtXHk zH75g!z@SD0?n~6HzlCC7X2m*tRB*PwN?>jdD1BX&26B`R) zM`HOgU~z2Ha5>S%#L^R1Q(km~c>zA$+>o&$CB(RWspFT?x@WO3Ae3wnj#M=whNw{V zH1ih=k0f0MS5#fw9$@GYhVB6d7`hvzySroPmKH?1ySux)OX=>CmTr(%Q1Rn=zqQT} z*lV4=@4SMkO3Wv#e?M$a#)D1jfFa|9cC>A^O*Ebcs+5z`2}FMr6Tem(3v;yJg`K20 zRGw};lt2Itwm+xk#kCcZ63W#D`>{DNv z#-KR}6zF!@T29t%LZl&5Ph<^pxh0}3URLm)f7}x1RRhOp;U1*axulLL+Su+% z2NzbluSk>_PNBtoml-?bP|uOKUa8rA!OD(OwpUb%FguRi?FCFtx(w!pZ z#k}-cX_T8Ar-WN!$~zZxRL1BVopWY2snxe}inA=sbxR$y3R_M_HeYuBtedEOOjg95 zG(0@|dRW}1d>P~toIId=a@oq!sqtE<&jQ5rQrz&9xlh=xW~u2n7ucZ#JWRjfEISIlUY zoFWw&2_7;tu94OmQswaVr14ootnG;_3Ue4}DDPISUYYIre$-$-{P0ojq%0J85-bOh;x1fc|D;F8 z$e&MFmm z?>bUAg^j#(iy@C+g?y^D>u{T-xeA(-tv7+fcT@UX%XwpBRKZ#NAqFHDiW>QBGIy7LXmqsR z&$MMDa)z>{5QdQP@6kev(X9)t6N7(TWi%CS&zBy9ZkOGys@P2vOK&e5bn+U~n>WrI zb4s_Y$2YRy|FoU2L*Ri0|KPI6Y|31pxqF%i8@g}e*D7S7ruHGk3!BBE_-4iaE+E1N zV58!K-@!xs5y(?fkdZKg(xnE14NO+n&N#70p3q zOL!o32D>+{lF{jjod??X%RY$y9~Ry2X(R-Pnzq!wb_4V9TJ)Pf?eiZVx=b(SN`i!N zA}VBLm&3+UOcN+}8rsum3Y0(b2c-3s%3$g;c169;7p`9RU)f3llexB^d`VN?^y2KK zxUU>8#I#(Y4?T$(%l0b)J?Vx!jrs8ws_8xUD=*FmiV6P7W9(gFf3N%gea$#Z@NB3! zGXClL(Z=t(ZTi}Q-q*u^6lv>>qX_hH(v@5cyXVWLPMrIC&ErlZo07Z?) zBi+E^Hdd-&O_Zo0n0eQeB%>d+0zAUwOd^}LXb>$v=F$?7gAz?l-HM{i7KZ&rWim~o zNQc7eH_KXMS@|7vk5M6X!;@$PWJ$4dMd5^y(nJyJW&YmwMfh5+mo25+;-1QZGdIDmOS=MzN* z+IR9q_Vyq02n}o2FyFDA(blB;DjPgvNG?(svCf%bNZ$uYDn=9)G*T<@j6GZwTb?OW zjM)=WWuQqQxm$c(Mo!-HnIYC z!jR@+nlnR5?1;C;i@GN|_o_DM-cGueW3U767hwkl>AWl`vs*kzl%3zZ(<;k#s6r@XW+qu0D-k76(!+TSAx&ifg)`@b{@1MrBBk4| zOeygduV8#CbGod=?y_>agnWqRV{!6(6X>j;J|A+%mH%kGPQ%4=A?M&~o9xL5=?~ww zb|oI=&ZvF$tDMT^_aZOzF8CSt;H=E6_B!_^naEF@vdZ_@<){gtKe@eYr88Bk8}v+} zLS7jMb&eR5o*?L;c#^3$uzbP$&rIf2EIWDLC-b6gclc>7AJ-Rc-Da!h-%g6P?|*0K z**KQlMlsj4XTER36I|e##ly1chb++viS33+;%9|Q(!BpxWlyDN^r5vPgL&Nr3ZSEh z!ulZt)?iLfcrzF+autOcAPNv}bruobpSVt0RBp0%)M{UwSWgoYV}*rkjG>|?6x>PF zuZMq^>r90rp9%-9FB+!RvCBJ0aZYtFm>D^27Zsi!2~%(Vz%(Jzk$=wVCc24lJ5oi} zMWSNSKL(^;JA~Jpq9kd)J!TL1RhaJY6e;C-7}iKju^5*pIrYAdaj<8k{pPTB$%fa5 z?5B`LrqY~Qa*y)+ZJ#v`X`;AsBZnhG$8DzS`rG3lOOqSg;Bpb-`&NvPAfOo%3UlJ+|+m?0R09%}$v|0sYEij25CrOUhS$ix3o z(mG%Yo~1{UQm>`axhB$2N-|ys@5tu*{`})$TEe9T)nrEmrlhtWTDgTnfkBu+8{>)Q z-rUq9?Md@X{yJ95gsD>XU!Rim2MQZ|lf*+)O0kg;um#NL#qq+@!|2b}t_QKf$L7d| zZaeJLE#G;A1!+e>q4ed+tbSheAaX|AUlj?Y{DZJKOoK^uUN>pXFgi41}#Roa%Mpu!N>bkcK`Jqb>Ezri8&a_x}lR0e~@P z8&@zee0YqZQ!N-^f}dugpAm>K&B^j#fmI;q_m$m}$c5VR%PPKQ{B*kYs#R-gddQa)t0(0b3eBv`Ob35&7Vb{sVPvMp=YWwpGA$` zQZ9~f&K*@%O0YKdtJ%$G2}*lw)L=MlK#_|P%{p2>82U_U+``v6r0e+n5w6oJ@|Q7*=tcB;Unv04k2 zSg>mSoCnN2K28$kyrvc58mx*~Kjy|mSGpcste_Zt<9nzy_S}rqe17w3SwK7`4cBbI zQbmGEXXPdSc8=M`8H)#k;X~_|NXqcSiq@oEq-sy{M~Y{PUI`mpn6hN4Nju^`2~=>A!pmh3O%u zjt%KT0|*dkFMGuuiE(&f?`@Ze2nTxfHcAXGCo-rC6pIFg5!P7=TRjLB_Q=JKW=LW< zvrC@#pTJg%*NWNitI(Dbepz8UFo`Gkpa2vm)N%CAEb*LS<`)x$TgPR$WIywov8 z*oPWYm+rap^o6rWAXn$TUK@Wv1BV^t&rVsNxl9fbXw&s$NB2$hDx957`mGeMDNAzv ztbToq-^*PQiF&car&UO2|Bbm)YMLQAbHwJb(GY6yd?eh_dHr|dT#j?51~));;}e>S z=2}i2=1BE{wYn%{Npb3eQAJA{3(KXA>z5?Lehn^)X7fLcr|yK@}C)scSDOW@j8&6zuvj^wu_$L`$Mj~TgrK=Vb}Qf=@;0E z_;sa$0C=sUfJQSW^8Go8D+gionHVbz;-bwD^dHh-z#s~lWISdKh_b&XYPTB8JydKh zlvOVHh<(5lUydxvfnYz%Vv@gtC!1J3+ci{#vqoa)@oD*fj^z7rZSBshsX^J4vY*iB zD=mN4yKnJ5Sw2fWB04{@vl;Hkwj@@>ZuC6wXR?j`hxGw)GxFt?YOYJMzm#YOWLbgk z1bE*4C}poYh|!Zd7)7bA`W74eqD_^&L8x{U_%e_4!ZaApH@-Lfo=Lr?aO||jiD^ZZ zL+ni&US2*M5vA&MnAQg@UX}YvN#zn@!G{pYWmPd!;xHS?5f2+%WCoWvFh#{DMY+v@ z$}8|3?N^#r6+-Q&Npua^AXzXC1}6@_5VW)^(`m-7@PT%_Xltmeq3hl)eN^M8#i&HC zl}_>T`Fw-=mwh|+jMh-sJaY@IkSM;$`Z#DmCenBkj<{j-bD^8wc6#Fu$7&K~aG=;c z_OfDq0dRtldP%JvWtKkGIEx<*xDDc_K^ws-)Yl-#n}l)d(k)61-$r`S(Ny5rOHUF# zyOn8Gr)8AA>*&wKn0HL%r$Po70k|sz$@alLmIHW^W@uT|q%xk3!HKa&N}GuDy-I-^ zL_yR_%}H=uG_HRRJc=2U@nT_?PsS7VbLX!Xs%#6b?X`b5Qn`)|+mn07R}pc?$xGYd z`T=lgzdmMS3hUnzTNwa`84SGBCpgC?Wf%X-tdr=AmF8a2Sq0|iVn!BmDC6QqCPjPa zq%7s8#X-20GE?H7{lV$;lb}+0?R6MHAOCw}oRq)8gVB4n95*Xr~0j!Ie};?hZQi>$;P3 zqVf@34%;>TVo^X5@Q_s~PNBzZOAhknpRc!R!-135_R!1SS;C5CO}Q9lB8hH4Y$LNl zlP0ZVjG(Kj851nc$4AH|yJ5iIb~;4?poA5YV*^iozqcN3jWK_*+n73Rkjr00yBvzd6NalO% zVp|?qKn9H{%{;^zta!ELG#@&_tT_IOZ_&C0_?|y3R(@;Xg;P|ndOc}tqGMp9Vb{V- zjc=)O>o-eUEs)EgN}zg7QjcWGZB2ou`j-r}<3k zC>*G}lZ=SxWDlrSdkP)L+_7E#dtJ28l^07rHLA9R7i_G*34$_xG@pH=X*6>2Sr)1Z z_#rkAZ00X)&>X|CW|!aZdveQ%pK(^p?UK^1x*@l0K_CVO$}%(wPo?L1L+sf^@nxcf zU-D~=-jQzWs968XQ@$wsqOGsulf~i`*QmbYOZeOH*ul5w`k()Y*KIQ8vyubqA7yOa zJBylCF!OYEkQnW92Z6fl2KqZ>Xmi<#0xcBAXj#91_X~tW?6?E6uo28m-@Q!7Hu@`N zuiGP)s(bY|&Y<}h@q&oGz`Ee7-KOzz47p3hrf96{n_Kas{+okM?Lb%;{91!t{L;nA zZTe*$MhBbC^(OrAgW60;*c0j zGf80M=`olo6OG3CZyVGNx)BpXja@DB-bmtRtr-CtL(D!w?L~-Qa$1FiP_Fwd{Z&C< z!;U9jt^|9C0!eGb-7fz+q$f67L~l5YG_xdGW+3s-B>Kk(lwNL9ZLWKft%Q!g|E{(m zJkZ$Sjj|{?_~z2245NuO>MPM@>Ejxb=Qtm!$T1@@ada|TJ;TI_&}Jd3Jz}g!vTG62 zU7(@UI(R!S<1QRknM=<|c(Y_|_o^VS*)e$Y>y>eT5HT~$w4XWjs->7PawJuvIi$7- zkIqO(hOb5vPXfjqkx1`djlmIEWg8d?0K z%=R^-q$fJ!6UJ$TD4m7pF(YR<`Pm@HoPyG{?LCL1Xdx#6a7=|^6^i6o49AJ3o?dBN zNE{jjMC93r&8tBR;eR3_wT>(Y+w7fG9x3RDloKcq%E>7uR+EgZrBO=`3WVko!kh_5 zpQS*qJxuy4v%-oFpgiFmQDk+0aB2S-eqKiR zX;dCLlEcU*^s2Q8ChX$R8?Ow*zy7LC&UnAmz|xRXmoW%^XjH0#rZ#piaN7TBZKd<9 zRb-`a;HX?w4K1lWJmxt&k7RU$RNDOs`W07}uJ*#4U3{es8pX@IP?1q>)NehW<@|Kg z^-~&vi?}um;Z0T&0($n^o8bX_hOE<_@LmNSgJ`>?8cxjr-7%cS?O~aUV=Kl zO>i>xqM5RPc*wFyGr{Q5MNYG5gfDZ8231DHgYb7iURqxz6PC&^7d{{c-5(DNI2|T; z826p+FSkA$GqF@192-41Aqh9AORt_Y8Tf5aefA2aT#%A=mX@K7;CuYK`V{%kQ|wuS zMYj9oRsnvD#4->LRgf|ChWQS6kRtkQYml&qSk7&^kuLnVxXTKLy#Ps+cAW5i3bv`d z8Fy_uR^nm3`E|<4tX^cQS#`9=;jrNGRUg(z&FO6__03A0NLGc^y;KEf&GYZjE_>K&`F!u|d=VGZ@^ld8665lz~H!{kH# zK1Pr4_s#UHExRcqi&=@LF#ml1@%ztT!<7nc#5Vt2RTwvth9|y-1oXh<)Idh|>+F6= zkX9QC^p61yHc|jBKIjxXL6&Vs&Fu@sZwvJds=s4 zbMNbxP4v*9HYr9TEF2;R9f~@t{A(dk%_2*7<}{(e$ihDv(hdFXaRC;n)z)OI+9ZiD zbx`b>+2)8}L`UhNn71mNlxxg2K=Lv74S6;N=!Lp5Dz$%d!P115hP~r3k~~XR<_#?AE<*YR7&i zXqk5?hH_g_8F5$IL0>CTRm*r`rnhNcBIAvZ{F_H+Ar*x78wC%zK>5YXzXJD1my6%j z?D=luXHLEzzOG0>Q>5Mo$dx9bc!o$Lz^{xVZfXVLsb$2~Ao6vlDmEv8ZWw{=f4fLr zcp$#P`UNWKe(;$h^Bb{CLp{Q#Ei4cXpXuu9O`Owawu8|2mLEUp@y%soijH-jAXkmj=A(C8J|m**WcMtFmTNIJFmXEI|v!e&X43Dz=R zZk1=^7vQPqq{LO1T>tc$&bM-nLn|2o2O33F3dIgIdpB-|oy90wBB`lM+-t+}?SL;; z*>S(-`g!xD`t#Z!#$po5);Pg7iIp?#8vK$|+b1F8z`wP6_sW#qKU&aL9EY#m@ZmV& zD*4?tZ|v5I{2rn|L3xYehIt=3ImiFa?VZ5)TWSd5z#VzhKVAL}?joKL#rV*U=Sqmm zvTF~BvVuJ30w0m-hJxVPsGSV3!G8M;= zq^XG2yGBz0S?TmOVM4D<@T5! zhOXUft*`|iE$eb+sUi6$$*LW!YwBGuwcnM&)z1-|)iVhTO(}|Xqiwk8hPgae#K}se zy+)<8)fZJ!KtW1!(1^+yf%jCJl+4zKb&3plEmEpAKod_3?-b)fe*oVi5KJ~b7Rx;X z42hva#$>|E3N*8tz(TPoqz5sHI#$I)cP(M5pl9= znEx9pFac03-xN9>0C31kIhbz>oj7434t=2jG-0+YzQ#Z}&sD@P5eR`Nb@CHonae+s z7__t}Y%!BEG!(0Lk2IW>TKK89Ld=kHM6wizFgowP-F=coUQv?&GtTB|+~WTeNGl!aHclhwsE$Kc-oB&uvK z@v3s~J&_x6wijwIMDkVM|BnHnB5hihRkY)n$wqPA$eR9>bE`RWLs*rJC^Tc7&RJu5 zPWNN(Rn14yHw?)jJeFb!L$eV|D3Foo3W$qLjYv+Q#(a8;4WfX@Kq49$%?=l!cCJN& z5TT$zso)0hF;GT=uM-x?=}Cm%YxSRVa3eJ$(G^8KVyi9ZK0U>uyXONFIHP{0F_NK)WA^;-_9z z5g}4$rxJ7sMP|Ru{O9RO*Gs3t@3#`(&yU0zAM!q=Ps6iqL1dTRSWfsol+mhXob0{un-WL+mwmH zx4yBi0cakc7A80%jDw)<$ubuA-L2dT9u1-ElxKpVAh*EIXbNbU1a_4xtnr2zq{mC> z;-bPj7S{x`1&Qs;b4&`3vNvI02q%zYP97(hGR`P-$b#%3wN=Gs_=Ii4UoY>u(DAHH zIluD7zUWp}J?1|j*&)CS za8p0U)?$UovUqTg6Ik$;XLP+O|EcI_)9&jW?xUP;tB|ecjjIIKmXXHRE0ZA4b70sg z7vUfOm&0k`5r*^)eBW|-WDFCrbv$n)=fm~C3>;DKje6@VUcUtV zIiS%DE1=exnqtzO`BkB)xg@;f5vB>nUW)u(veaBOMgV_nCbJBdcstwS0Dsm;l6XIi z+CgMmR5%Yo7Fdm_MkNIm2AY&*HZxVy(^gW1o9NHp$crTb|$ zGP>m)p?#>;l9L4#+do%EO*{{&Q}rH>R2$G<6e~o$h-hGIL77C$`R(@1`6(`8x}QQD z9I=dCMTFN$aBhCYuxvide;?)}V%Q?ST%A5vQ7tAhW6_t$XG+CSA+0gwRuwZ4fPn#O zDxfSI!ma>9s-9}lL%p_Jo9-cRbG9%Kt3v{}eZI9wT=!~bq2>ttq7=mKOL@BhUOWTA zh8w-D{?%cdF*!aPGVZOkfU2td%!*uHcEj9~S-D`gU<6YW+wrSse4$1u z{_c$-+jf2qnR|U}1q=7)kAKsDSC9w90C20Bf>->QDS*x9r}V}MkdG_JY3)@c7P~pK zS;K!h96K0-Y_z6`L3$U0w21)=w^bt!v8XL|iuzmc$P*fOb0v7jZMy2p;P|ZG>+9QH zK@(4=mSg!c(-8OLgEbPFd!D&q^R?9{OhwrlX|<{a%!J0EDkf}M5VeVwVL3kTrkll- zd36_PdXgvLl_I6X@J_>-?3^k%R-hZF_^a*BL_Q)u1Ba0L*C(?twW*f*hx)KUb}wABQRF;E@kuoKu!(S~s#ATtqy|Vl zH`cq=88)hYfxj%WDDQ_9vf_5&mb~M~qY7Me=}nQMKd8iXw(>UdPu_u4CI&sMT;0`Q zUIS()Q%48j1nt;~XoB%0z0XFw3#(GoV`m05?WD}0Vwmrm@nlhFh&ecf%ZjS0?HJUT z`NP}zh5Ozg{6UW3^TwMP)99Ku5JHFdBpIyaq~sD}qQ3hX9PaNoPPBmNPN6SU1`<0|uk&%JRX|tMwsIJdDXI zhX0ue@B{*#_20LaJGGb3 zX2-%SJ}gXxp5vU8$zA2m`h8QQ;1&Zws=~p%p=rTU7;3E-ET|OT2 zbV6jVh-YK7Ch!EcxY0ptwZXKw$l^GeA-5W|4zbv(ihsJ4@w3unO`?VlmPQRIC8?{H zB91`BdmEbf2=`hE6y;Ux+_}QZ3K3S)m%K&PYMI2+OC4A1DRXH&*cm6?9X7DM? zRmWWB<&ccJ*8(j6c6-vm%IHvRoK3c11=B=@AmWWTGe|h0DQ6A)VI%?wh&pq)HuXgr zQ87h9ZqoHny$k)uX-q9!+)d=4WVfagv&&H3xJupVnaN2V?)~eY@z3WX6Q;>`l zKtmdJkykoGfwO;%uuDk=Ny>7Hy7~9b?8R~Gw#_?%fZAppL+)P8Sw8(v7rg~t&cFeL z60%OOPk-+lJDJM`68mRm2gJ|fL-yd|7c0YzsfoOX97OnRu^?0u6e3~9b?T^x z>Zxs6oKhJ$Dz&0r4#;GV6cH14u2vJm zJ^QNc&7R?mGF)0peSZ~?+711_-ioO;7FA%Wk-4R~$NrO$*otBfgje1XKmiaI$>Qwx zUFH2Zj6n@V_{(K*!9c1Jz=)n;HWaJx=dQ-wxFf;NQr8w5FF>QM%#n)d#noAF8H_Jx z=`Dv@$?c+JfR>VLK5T^}QrrNvtO;%$X1p%9CNdU76XHjK+LEgeAQ4CKnFBGveC%2q zWF_iWJbDwznYOkoqFAQRN2kAnQR`I|3~G6PB)!)j-~~)SXY^R?{8%Gdq2a_1mehES z@Nx?dgJV+*1(YNJ#Gv~Y#RkSSkIr0(ju{L6A1}H6>yWD zG*N{KF<8&ncRzmzT*4uGiv@+vOUiV~8{ja#(*xZCQGlmruCOJYx1D2=RFH8}eMd8FTW#q9G3DF9mXP0KfG<|1|~#IGbkZb3mS4uy&dkExj0P(|r)0i~}llQe@c z9HzKtJ3!^oyYo|KkWqXl2ZSAeM5VZzOThTjWU{)2v3^F2kx{WV*Rk8t=q&eP6lW3< znS9^?(Hu$YH~}G5@Y<^9vKfzBKt&(nSpq?ub0uJkO&?z_XdEMH%lvDuCzzj$8uv}e ztt+W^{F`kn<9tY1wk8jkyT-F<7A|Cq%0->MQMCHX}Ne)VzO{6qdg%%cY}qJRzmfvMl=JEd(8yymNRLT5TsW=h+CJ1 ze(5jIoJL&I$Qj(#JVCZxYHTn#qp^NS|B(4j-*2bcsm6Epq;TdEqcaR7od&Hxa~$&uI4~dPJ1N7waYkRpdPTk+KqQ75x4X}gtWNR!t?ga!RIjw z)5zCD0|#j21VKp2wam(nErdb>%;^Tp*Gu~^y>kzVFX?2%;PG)kwR^M_h+vo`qndmP`1+kSyA~B;nu!eqqiI3y88GXRisx=G zw>3_|D&MHJnJ-Qfn2uU{>M*mWGAv1N76nFT&}c~ql1f5yJVLDn6M`eyA0rHIgfA)a zqB0A%+E6`<1g>1}6-)NmKXbVL5j9Z3$|TR>>WsI|Tp;!DjqJiyqN5Gd8o4__FUZyX z_4-y5U@*65aQ=ZY`j(HkJf$py-=a-$uo)ED*;z00o3i$NV%v6yYbXOl6q~V^DJM7Ncud;q z4E$e^BL-OVsBbthkeRo|W=~tu9O6((JJhmIPj)w7(1yQD>T}vy{;q zpQL_vH%kj+DZ9Cy(FS!`Plr2Sp(2LQn~rHb1D!@$x_W(i1PWn4UrPJR;$zjXs#zt? zkR)rjo#SR!rLHDNK`5iP4rUF8CcWd9Zbzy9m*_hYAFWQs7fX*fXZ|u+M{5e1kCjl9 zyFoESC%igdSvBuMZ~^zGR8UPH?sqJhuO|lK>zxd;}H& z`v*z}QE`jTVI_eoop<5oJxQb_nUru<%>x6`EhLYlnL}|{l*ozZ(dvw>8}fcvOayqJ zFymc3wb;v&q1!^dJ8-${y87g$;_T?R{REO@ZGn(1I;+kqr1UHDDw>TzBitXeh&(0V8OBMVEscTO|nsr7XlaBQl2JLpAjqr)sDT z8a)twewxlcyl=CN;=y9E@jLslqr1Y9JvBJ9hHg;qaSD2VHEudxy!J4%4MBErC`;zn zlj7{95Y$!wZk$4<$VIjo<9;3L;)waI$-!pj6%QkXuV-g!n+B_o!JX14G{%Zq`%2~pOH-((A8nX3(C8*14IrW`vX=AY!9SyCBl zxrfyBI3>xD=VcTF)Af;H#pMz5`ty;-D6o=2%&fxuEZkMyQb=>&_IPKAgh3x~W`my8 z$JAPI}(S&r_%*K zV#EJy*S3})_xUJVg}pmsi?c_w&P;$Bl%)<^0SwDTzGSZN1V84&K3A{k)zzIgRzKd0Bi3j$#>oq>2QRv^MPOh zpd~PKxP)USR)z5KgA55{I5u|=ZVyE*)OMtKfhv6Xy#61b zz(X#NNCTbD*tXIAM}q6z!NBomkB_lk5UzKTv`A`A6=r{~Ydp-0&b1ffO8T~@C!)!v z#Db86?0Le>?@A0_umPwE(|&ctSxBpJ!M6A+g0y^U!`(HVKz^SIxNtg5_(iQ5+xJs| z@ho2p*Fq%Dx+`_1m~042q59|DD3CK_qw~VwkNkrT43N2 zOOT)Ff9*FrJQB0vGLsS?bu=?6%iACZhg`^_mi@ydQ_U4mI91oX>U70j{n1qH5UU`& zn^bQTmi**|>Hhr(c%M62H{}JgGA#{$Q5s4@LxJPAC(8D&KQD8JHVLIiycL?m;s$8V zsY$Em$Xpja%+vGl2Mty8pSRDxbNNm6`59t7NPzh(Y(vg?3RS}1Bv%2rHAIL5Fi0_^ zy2(p(p`I|L+GI$lWQfKe>`p6*2zWqetz;aW&K1N$un_A{4UJqV9*;>JKybq3Up5QW zC;`%1(o_5Hd(^Ca_y`kqfkhhXcu$A|H{>)Xx^n!!W=;4I#ZIu@@hYEp`B$11B{?gj zEtYk{Lbg?C{Sy1$Axj0B$0?wBL;+}_+K$rif}$wU{;{~l6x&ZaM~+5Vhp>ilCX)`k zv60Vp1^};bv74 z_5n@y!>a5g*WX3^h$^3rTU%S&-SIS@T!t#=ke9TeuH3jZDe#MS27}E(oGp~EV>7k6 zQKH@q9(LQYo2WUH*t`4d`zLek~{J6!5J~fo?qFCM=6RH zD+o(v(qJkgjIK~MgWtYn>g%WIH6){>=Z&V>_~wqdvi%Ybv0(;BvTJKg5x^=bH|0eu=BWYUy-q`xL;Etj+8)++oNZr^9$A#%f%`pMxboKj|DA(W|e|WAbjZlE-8< zIFVO1oS#1g{LAV)Gh{l@rrDW!=Oz$mMu)i&IZI$|XA-7_DM1S$M2a7VA4`$|(BQD3 zZ&1VOEH>7k5KyXU|2nLF9IqFHr$k=!0Jwm~(q`c~lc50V&R{p%M~&|#r)bmDVN@av zY1X@2Qe_#ahzwA{tU)x1IZ$JMMri+Efsy_%<2!|B>V*kh&u{+Q)n!JuD8FhP<8LO* zZ3iohW=9K!X;YQpVPfp1>yH9BjGfK%UP4~W+q@UN9H#$t9k#E!C@*}zt%Yy(dJ^*( zPTF2o$~}ej^Y+*Nk&D^tOk`B5nO0U`f+{xGLR6Ib`X!*mn$)G@BVNVzNgRn(#P9?L z$g6bTNr?th$-Lb>L5+0?5g5@K^4Kh&KI%%eARb5k6i|T+(TL2f&)p_#>Y9w`Oy+`9 zPiX}uv#&o_O4G_o#-oI7DhL_mE?>S`{vi<(O*&XhxzGq{qzJ+WXNHSV#!e`f8LO^H zYytAl*WacYA>LVN;}!yid&r-cAZE5iMo-O0++KT_Jua8;x6i2W+4KSz!eSVAUD2T= zHrDiv=;{9jQ;I;~zUA9wiF>zADZ3YT?2p4kZ}n!sF!50TAJO~x)9p)z-1xF5QLW#Rt((owbiTZeS#^v~-BI;=+w|Ltx9u!z)50xRLc(%2SB;~nPs z6??Ja>R|kc-pM`UOb6UStsdE&5m+HXt6jeqig#|Xtwtocvk(DqTaHYE+ddfkN}z(P zsKS(_;YN=jWpeFt4s#-4*9TDn%OC<)+%N%aklJvD5 za^1gZMIlgrPyP+x)9H6h$9kR9hif4%vOBZ@fdGGte@`5ncQ2=>&Mk5s+uvhn?%it_ zk%(T?jpgayw!L*T^C;X-aQZAOFZ%t;Nrnb3D2h?&NqC+)fqI39B;sa82;s67>%7tM zA@X6%7)qIW+=tze0tODc?BJAm-rvG;ZV*~+W7&~x>2dhT^VThGn1p8)rM~LIhcEX0 zgMm``M4=UF;bi&cjo~HelX7ylcGv2`@)Bt)eBT#dy8oSSdi^T_- ze}fUk^Li~Lm5+A5yeIP^-Unza%xms`pfqpd`D`}4=1P!h=t49it$}e>rDBRjtbQ>geOZsR0_EFbK{eW z?0>2ejy_~W^v;%hBTxPiGp6I#W;7;@>;n`sGs5p6=?(5wWP5fEm9XQJB}whVF!tX= zco}f}8UMR+#PAS4!~bo-BbkI){%gOB46SO3KBB`_R8v)yucv;q?2nPDnrBPuE}Pn#Tm0v}>HhCMZ~6D>lADX(?WP%PM;V7>W&c}Pno%Cm zvq6mzh=xrlP+40Ccj!Pk{48IG%H&^h<{Edy0y^1fnG^n;TZbjG&yCH*+0zUK+@HZr z%)#`mGGbhKYOF9bbb%8VDo4G%RT`QH(>vq4M~I(clTzDP}(v0<2W}i z6h6xW%l3mUzE$P$l4k z;g`|UvXnuUsMg5VyI1c~0tNS0tE!UT%JfF~x67-Bn1l{x*Nknt=ZE-!06N_!SvX>5 z6Vth;rAF5H2>r3o7JX-U*D|^iSFFwSXmAngEJ0=W$VPMkft?_vfo|r|8+}GGsY(8C zbVEuyk@FnG4QQzlLtt(JoLtX4gg?=o^@fmo#@lXH$%l z1Oop{-}r$*ACt8=%*EYOte}+xsy{BiFRYe*M!~G^tryBVqYb5QWT#hq2V8&zBPo!H zaVB7sfEZ61x{$S!Dx=V%Q{B^kR!bao*n`3sq>A zb>>>oO8C7)WZjQ!G|r}5ju%bgG{VORWS=S+s`zNbPyoPzeNpxqT2As~&#ZPMB@>s9 zz{K*h#3VOxIW~MFDw2+M{2#(S`(#wyRr2?WujOWeH5_^{#$lXY>u+Wp(ZyxK;64_p zKAKs^0F`xRYe}WXN;c^5P0h_Sr`dCkYD91(lbcSPsd1q6#~X5fiRxb zZ7_5foBIwB_zo-$s*V;*)b7{eg}|v227)Vs@zZbYlv8X|dJOI@(@5RZJ)hGO`f655 z=1c^?x4YY$vK?Dr{uN~0dH6|1ne}6(bODCiO2}P|`M975SMtW>MAdWyq$RcFqDXl( z$axkZysvq+Pir0tiHE?pJ`~rG>*5(^K6`0C6ty&^+>WNZWmk!VCVLPX^6nV51=?8SmAYf}xM1O{GQ$KgcZEGC zi~oWtJv?yGNYCMI6&YJ2L?ROYNt46JqAeVNCQ?`H^#&(WBhmGI%3D3XBn_us(W}e~ zEgG^-|DRl)-{^d%3NB0A|NiQS!lFwXoBbSL<-8K&6}|H z#;35>jo&xe~GoM>yi>u9z(MS+z} zfTbMDmYuUrSXxJ$?C=)rVY) zG0uJ+bEhVs%^k2+AAQkyTG(`1|6D=%V$G%OA54-v>whh3lK;n)R_}#gvi)dDgm3S} zoRHGrs^ffdYh~K43HK|wji`yabdW>GG`)7x^n@isYU^7#Nw{Sr^Eal^V@p2EcDoX- zmCGf!zYYHe@OssLzV;K;MS;QWI2dRNrBFvAX$GVeB4(h@8k7jYfD-9lC|0RsAVrLz zfG{#2mCmLW&OGVKdPJ8Wl?X&QKd4V_isx+C+tR5Kgk6o$lAYd5sQR~_hWHqFDP$WM zb;XtFhw%|gw`-i7+k5H~&ItYizlxHSpne{Tye>I%?S$~xN zJLAaV-#@!H(trCw^GvJMVsA}+a;YP4=41a~6^R9dalR zB9t@~uqJ{V%Isqv4)v4-+>KET%v<1+>@C3K5IoNZa|F9-Nw(;<5=0kWW+W?Mv~SBw z$ozCo_83zT>C;?!8_u*52);jg4sTD@aN`smzj>yCiM@&)sQlaQ)Rq%QI*IKp{D@ zC?{%wgOZ$x250Ihm+6qHTX)r)s|-6qOo>Da5r>+YA{FAhXyRE`?aw_0i=L!996(tl zik~VgP}nE``>+He03=mgTWbk3(vAx2Oks$AQI&CRtR!>77%we#gpKhIChlh3uhAiNe+PPT)DYtwPdZyQOz8mooaXH1&`;wmw8l`EVO7Glbcd-h~Wh~ z7;vPXFitk1x>|a=`PSBFxUOoa8YYqBmv|6aqW2-w2YZlpSG} zo$61fK<&!qE)0e`7A7H59}$d_E-FNZ5k#7!k0pu3`p^*p-A3u8>9aFUtt!gthF278 zD+iziE(=eB5CxdQ4o72#A&Bt2fsCfJ!p3s9>4!xL{UY66Qf4V>O1t9P*mG&IcvfBM z`Jur^=~-rfy=fIA7=~3r001u@z^DZ%LIJFDD}lTVU~qxZN~*_FQ4b)E%BJGvtxkOH z#LSh6oqS%xnNcc%jX`N6m^_r^CJ0NXI@yZXNQ4nVD&BQ9?(97wRPk(YO<_e04BEDO4nY@RS)JU|DvneVhs=G15j;AuI#g!KvXjydZ zO(+{86lP!ki!~?_C)PS+LH7!+F| zt=lYN>KQcL))E^DO&VBl($zV>eH{^zq+q>7mL#g`mZyMc_I=<4pHo=2*R;m-lQ>xh zPle>})84Kf_4nWHljd4AzWuuK{(p%7eV@MOt3v2*-s>81GDn|u>dd+S*EQADkQ^Ap zY{<0fcvwJ00!JVX=R!oOKH|zn`V50Y1dlK)k(1KX%7~H&kc!v}9e_6nz?08EP9B|| zaU3f5O`?t}pwcyo%^vJhNM>d;W?tU6oFn3pGcQ^1U*pd2>|0BSd$#wIqp8{-0Anni z(_!A*=Xu-D^W$G_f1Y0(xe@pMxr^iFckSa+>Q_i*M`!|xL^)JgO34IbFfi!~88*8E zp_*+Ys+>wJ50dslmLs9I|NF266MzKMUEBK)Lh^hIJ6&NTd=l|B_3sQ%w<57vWHS4u~*)Om}Dt7 z9b$|;%B>`IHHrw!+jMv|4#x}{kTl`QkIhu$CvP1#KCuj})z(tkqi-91LbpUA@=!Mz zAO)a^T-VK{^zbWHJ6w?f000+6Vj8r#8Z??_z^cIvy#Q#WxRo)Cn?X7>XN>-IME+MZrFG{2 zVH|S)>EBc=-O~rYjxjej{+IU}WNr$JA4)1RJv72dhYpUWfB*vTuu>lwVAN~zyNhQ{Yv8`Co_KW~Wg?fQcqR{rn>^>dpw;Q1c3jr4(!;l87HZa%CQ#BeeEl)z zwJ6fWm#a;qEqj#p?|JLh+|>X3ummB11XNyH>j@n4r%Q_bVTQ;NRg-J1B@fCft}Qi& z8BoclCoi#<)Hmi^zE#WR!{%4)r79wpCmJZXmuIK7LG&$*9C1W#Im+?Vf{(%6bMMI| zk9><4eZ(1~#TOz`EanW`U&e$XHk zyK=j4jB;x2iF8IN`oC_ph6<5bhML!Dq%hk|Tr!zxW;z`T%Z*Yu?0Q)5FTPbI8WN6+ zLRtB3deqQW%vz$sf}LS2Sp!N~tU9Wy?zn#wkMZZ8Z?3sr-{uF&4hHL5gI5C9DYG_+f&d5ts@qyEG#CVtY{dna ztaqttFr|lcpO*?|Kow$USDcYDT~=Df;ewQLlFhJbeoHCLA)g@j5)Zk#mYaA>6~zx_ zG)X%Y!5I-Rtki7RGut)IKS|?0@%ph&kx;1Av-fl3jpypqSey9e7mhhdnB?xJp~7K| zutU7L(<8`Ed7+6jmL$53r%7o50R<~zs(z&i)o#axWTipjxQhzj#~qaH zxXqk9iRRKHy><_@9k{>GP^A_!@y{^aa&d|&0c@|kGL$m5VPGZIv!i4o47~VSbIt-b z0}h;bmJysJV0%Q!P*)|aSPn!038I346bQ0GBpv{PO$8gFu>cUUc(EvbTU@5nDZcp( zKVxA^vP+y!^zy13$3wvKKFtUzBrTxlQ?)3YO%RQt1{jr zmA|%SjP7qmbcd;>!k9kHzt#2NFH<+A194?Hu+!d7gBA5>7L1joTp`T_NjrqPZ(Xt|^a znyDDgCZg|^N-;o`8ch`?O?r+_Z5A0}K{=pZNrqIY7|>b^RS*>ns$|4O>MJ+r)64TZ z0_o30{vhO+&|sU5DUrd)BBRgTXri~UYGA*+f4WsUWp+alLWH+i*j8lMNwR7pqIs}H z?R^>oEU5^jIPg2vHKc>P2@Al%^w$6TumlzW1SDTu`w1KJgi9MeVS{>5eRFH97_-V7 zv8^?Pjqp#}1T7S5E-S0gC)#Tg+f}9HX=+ODHt|`O(V|mp%?cYSqD-tfUTTI)Gu}Zi z7Ka3euR}e9gac_(Lh@rRnSQ!hN2D%!DUUl-U)lWBv>`xHv<>3x84*H`Wi$W)028f@ zge(wI&?+9O1)A=&H3Xqs5jS=u&>cgwmBqq&)o%G*nDyRF1<*&>bGnPnSE+Rzuf1P( zFFZIvEDUu`f(L-Aaws4mU{eHdoD)kJQTaN7k@b}H?S_38YmECBb0}x2mRc!DzFCp+ z3o@sd`zi+vKuHhhg?p{49sFH&Gi{In1OnuwC_xC2T}|wX5w#(A#gZljo1&04JFf5R26vkk5OAG*_a)a`U8 zG4xwA4Yz0VLq(}2ifXS~AsfgxxrUUNA`oj5%}XO_jN;6!5LF(3*lc9_$NXDrCQ$%@ z050`qGGh}6R}vr#X_(Whl14smJSztFg8Bx9mqRBmxY?2-g9i(N)=!*}q1FgibEt*U z$XujXXtbqGNrqeslaa!LxE0h+ePXo6^GQ=?ga|vB8zsYb@- z!YVIp^@NT&K~Ti6PcXBk*VL~Wq=Q!puBB<6txc&E>L#>g9=zeN-~&R)(N*P&jY zojrkCHN~dy`jGMr@g=y6#p6|`*J2QSe6*2-uwmz6XFX{$Z7u~sU+4WM0~&vb3#m9!tQfeKut=-hLor`6!mj^D}xE@8p}h-UZiTx zZ~1z!^Q=Qm;Q_&IFG#`==8-8IH%_Ewiw_-ScBs(2@xz~~((*u(r^!o8wzLMX zM6|qMc8v1?#Rk${2RPtMP3)G^I>=U$*Ej$BpadlXBt%@<;|w!Uh|B9eVIz!DjcsF$ zF%7~MtgN+$4Y?uAwMosduKVT>rigZg^4RmPN(yR9Z`^K_XM(Ty?%(!&ef}TI#l$JI z&E(GPeVO;?#pEpseKb;sx|X7Pltpo*zyJVL&{2?b!XUKtU16o^U&>Zq2FR(~qon9Y zAPJA#;2({scs5da+4BX2!19e5I)OChOU+oS`bBci+DX1CMk&OLSe$EaskU2=7tI^6 z-o~Jaz(>rY)(cEV_mS5nU~lKKIU7Y97vm4*0mFevZ7Pnsy<6EDi6qY_)EImdq>eso z{}2^|NB|UQ3?!XRFzG?1s9`LcSjOJPyM#PeEs~BxhW1&qhRuoi(a?}s41$DWQzd63 zM3Sok=cu1B2sonvJAjeH zoy4$g8&tNxJb23c>)Ai&p_P2sGMW5GZa@^|ND?4Idn!<001N@C<~x6|NF2627n|oS=##s9l(dm8%<#*bW!b( zYpf*CiXts7HG>YZmXA&Vc31IBXkhVCyA?$}kl~W#Qz5WIsu5G(Pd0#4&X4 z<^hG7V=K74OvaH|2ws@oYH$Yf6nO}i| zt74>Fs>0nDWHA838PpLfb{XP+DXXagNPKW>duml={Cah#t3r|htipu*vVJ3PI z<%?<^o zd0R#=undID`5@+4>V=F-`h6%Jz%?ZBEg@G$Es6!UbEFBNQd3ICOhpB$hHlVKL<|^% z_biEsPhl^9D<2vWK*P~x6Q;Vvh=u?F0F=t8B2rM8MKp`-O;r)S3YtUC+C$P=>u+%A zSil}tHcqY#f{;Wc1CJai6MII`ht^P#H?6HJuB&Dmqv(|nW}E~?Ie%Kz#Yr|iMy_&y zf|{W$DT*gAdh^$^-(ogh|AtHF$j;yW)H56A=H|Qjn%bA|FO5&E%B=@AG8B9QU}Ghp zQce;e(M*7Xv;=R61i>nYh2SQ;X!4zG(XUb{{7tuRa=UT&qNu_F(_}3&NTeyyfaX0M zP3&tp5<{QDIM=m#qvaFz4+vLY`JDBY|CwES(@3<9sF7;|t6W)Vh|(R!!&hpPqbRD6 z`kg!E)o3F1K@nV{L&XJBE*=dSAtNiHN6J@d$f_SSf;%_@T!Mh3FS4RX_JWXc<%E3K z!*@X{>2Y6&w^FM&Tu{?XkFla)AcTk=0SFKh?vXAdBARFoG&E6U$_Zpylqe%broxd} zji+qWz486>O>-`O)VDFWBxx-cbjXvmOdcfhGVa?Wqun9$P%I$QF7gjY~IP#W+ zSmL4$!4U|NF263IYTOUfcTy9KeiATRmYW zdQmBRaqJ{<%0R8{HHI0frmPN;>F`_TN?%8v`Ik2NOJtH*z055VD8`}$Y#-I7Hjw}- z_RJod&#iq`SaoIVnI3RRf?@@_xOkn~m-3-5WZZ-~YTwvPpizjw;n?=~ub|-#Pue*o zFBCrs%w~{YMkxj`{d?%3-$)Us>1@9eNB{{X-20HJS0%B3z@RRau@M?B_zBu zONt{skYGFrtoC+AB{Uq>Bg8lhT>J zMU|%{qztHNWhP_I&L0IV*v2c$Bp+WsAD~aj7nyq$<8Z6&^ZKN{`5Q6T zYYCna9dm8$B+Y^!Ev+?%8IVXC6m8mjls%j?6s=*c2^xh6Ohx4kG_~GP7(&>a74+Z= z;-E0gnW$fnlI(7y2xwQ6vs}I~52oe8reQF{a){RKgf3f6CPhK;KhMZT!N`~zC{ZM` zkmU<9MC4tS#JK2Rj^4RyP*2kW%u10ev`9k4uM+cWv8h*$EZ7}p`>PM{xf06WtyX2B z+VL|nFmo5oYS#b$xXl-BT$O^T1jHg_1SIDte^3HSZ1Ao#Sqx{ObK?$B!X*j;Mg@EU zY%!UAC@TVyM`GKdbkTPgBkqW!Plybb3wq!g9(2kI?AJpK zlolM*#<3?E1g^_^)a904^?3)lQnobLRNa@tcRKpGamON9^|QE~6#r1b1I-&ze z3KAj`qg4v8lnsJ#@TDidu?kHCafB3th?Colj_$Dwgx1C_si^kj=PL5~SwB63hlQFo z2BfwkJwcHfkO|i6J`o0so^6?Bz>85u&DS{zN``i3B9O{t(+88L2T;A8W;{Hq1XQ(j z(GwPtAqX+lAM4z_SuJp@(Z@zW2dj`j`oJ&7(ZGe)#DEndY7MrXY*N zR&J`hL&uuF&e@HT4Lk4VF=~68OXqBdhe?^y5vLw?Q5yw7c=Z7j6=7N-Lz;F25L(NVjhZ%T zBhnq~#+`=7YCBtXF>X`$Z_93u_abd4HCXxfetU!ymSYS4>R+I(?ca2N)_iR3pZx!7 z?-~ED)aYu@0%lW27mLn4E&AI@0003gT(@PgYhufC(Wws~l!bx8qL#48CHAIzgd^*g zf@=ok2Q$=IfP^q3Cdu0FB3PE2v5-$e-<8D-$ePxV1bHYzAZ8e9Xv5&FIE+Q+F4ji!byxqP#k(wkxk&yrd09DSJt0_PL z!vIz+V<-asI7Rq>lzmuNT`G|YI}Tbf%5^{0A?lKcz*m$Ny5}?CFhz23du#R*{f`_Top$;|5gA0qDV=81Z=7^+!zE_+FVlhdM zEsTL6Jc_VLg$T{#5dCu{Hu!eI^ZU|=bGwCDlmGz4g#!@+n}F7!^9mHfFcVaSAfYa{ zD&ns9atDk@v%`0;#&D}lNd_x9Av#Q@h<9Buy*?A#dwEY)TN&`l1z7$95j?kxHJPC@ zxWC-3?_oxAe_cmn+^GMG)-+qWGDxmDU_OlwJV?(ZiZ_kPo)^|eyw`q6;YVh=xU$S+ zMA-9gw&X(*&!<`&2me%F7)BPR8XJiY6ey%TLhl&kRDZf9QE?yu00nUXMTmzrxHLw} zEX5Y0c$dOjs>YPzqmE@ObDFzNu^&BfR4U;wF}B8|3b)C3jgHu!tG8xSwpl%{PKhRo zg{0*WgrblymQJ);At0@|;ip{(a`w{4p-zFuIlAbZN=Gq1#5wNg+l`}+VKlyjv|~tF zG?DRn%?e*JTh9WFOWsN=rxMp>Q38wQ*Y`C5)&f8P02AUnk`*ui`@jSS0tKyKSYr=F z@P*6Ue_+C%Q%!YcEHN)a9WU+ulMZ;m=``_YEkq_hh)rzibq&TH$s0+GMw|?#Iprip zE0t!GVeDcq)aVhq%Aj_>tI{GBC!Adj?fG0~1y zE(ikYA(O~nWdcQ1)l4Y^!D^-H*CM@{sys?LB31@#aUBtOkR3}oT%tCo225b-Wz43r zO#5FOGwa@_oT)P7>G1uZvY0ZGQjNuxQPqx{J+lU$Rc_xiN>|m?c~xHtaa3e;P@}R= z@Mz{`J=&6nwS+-Jv=sANG6KwGFiIRC0W;d7qT4=P%9a~cP~RfXOXycWEuJhpq7CRd zK=U<(@G=%InOHm&&LvCbkZ>i1a?5cr{pqNxywx_E9B3a^6FREBRZ>)k8I?^FNvkfI zL`g-`C1y~9+UqpP*y_B<9&*_rH5pn}>83h$i*&TR?OpVgc2({*R}7*%|6us~zWkF1 z=h$L&oXD~(lLN^*P0f~7nTSCsl`kP29#E*Gr=Zz)MTTywW{YbaEDMUe+?CS0noMo= zf#uWxglU0-_sIBT$ExVLS&r}WE9#*ru)OJ?X*mSuLGd&+av`i9_2#Dh~Ja_m91U;@n-25yRM003Um zH9>)f3=s$zcpxi1=3)w3x}f=!qEJ>;NLdq;xdG2n;@U>&O-_2Lvc0bWo?LRpz7qo^ zCsax5_KZwrmmAZVxPnkYDU5=!NivRZ4-6^}J-W$E^A>-+B>%Lu0U#qVz zvwOUoWHC`R$&#fD@t%yJn=hxSRF3AMhWlFe= z@PYf97Ze-I%e0=uw=6q=0?fh;YE;PdMx&28_=4+7O8264G=WvjENz_rP0}Q$1$o^SkF~F{hC&{ zXv?aM)Lm3f2}2Jrb1LIj0_Z@Y)nfF0sui*17f{JB7OQZMY&>NSr-U+YIkGN9m+uAo z?KDr(Y>__&#iex*b4w#wp8>bghVM^+h49-{d6bq`GC^%gWTH?=aAE*d|NF262!I4t zTU`4ILqLv-`%Phnc2UWFZLAp)!l|z-nT8KoLSP9h0+?mgUulA*sNn#jAS!Lh5k$Kn zkuaP>zNCsMS&ds7OA|tsBSIS)ZseFk+`&@gtb@!BDhD}d)LDo^+GdDCsTP@KQE3S! z&4_Aylz&qWeG@ad;tOh;(Oz>>XYXesrco!D8>378Jbzad>S8IlwE>!OOl4|$Y-9jH zE@;WY!cH^DtSV$Q6^0P82$LNvR5AF;`E*xtShgxHs(`z9*O5_}qf(IkN#hJS_7F`+ zsG@^=HWE#Eqnv=_=-avY$Lx5-`4m0Y_%{#KpSoS(g+eUZDei1fIUK8&TLc6F6?h@cL;w+3 zdTt>)x@x4u2yq%@{B7`mC9dfZa%hx*A?)^&i1Q3iNu-FfC3HfGj(s)?S{Uht81YIN zhT`KT^|d&&)BOE|`m!-cS)zyhNIktz9kFJq@T*RSpI0+*=#I3P#LS8xlC_;U(HG)x ztvPq=Yb7jq1GUA_)rvThm3@bx00PJaK|uozvPE%al!5zKX^@&MMNON3Yf(lX@IMeM z=`j#Et^tx*Bif*VxHv|x!u zSxeZ1z%1b6Eh@tdEMIXlXK>T}p?l;gsk_60VZ(?!y(Cz5XHyhF1Svrh4g&xCzyt<> z1QlFc`z9Q4??AEIV{n#s0*0DpmoaR7FhwxtX!nVaAJ%JolDjhEe*7$c8w%uEGkizD+_DkH}ONywM@#z_2xN$($Km`a0g#iMj8Sdxp&t4l!2~Hf~GrPUc z$LooE$vRWN{AuljF)PlAIuyGU#qLC~ssjAg)&#YT7diRcl(g-IwJo#&B)2am!4$#E zt6_87h_I=Att$=HIz)%oRQzq{E;=%W8MvZc!bz1hLSS%F868m@N^5RkpN2~-6;4-O zsBEC2BC`AEFIRJ!;LZYO3WNmJQXHcrD^;JCe97F8GKJm0rWm}lI=7a#EE`m1KYnLO z@w4WT#zrB@6y}v0zQ6zhDMHC4ArX?gS`J}vTm=%chU^tWT<5$fPp+FpB=UFV@#vov zHxCk>Hr?5)%g~t|R9lj_korkd)FOhir((EF{kGQD+#*R@^a%MgRM- z1T6w2TU^=G3`25`shbU9=3ZDOlUafFO|YUf}cfY$Hgh_+tUdChwH+k1a5`}1B|>%BLcZJSJy z5ne~C4!+>_k=KySyzl(^`vAfSAOORXoZcCOnn9Rm7v-0MhG>Y~ha%sIKxS{zci4?1 zFTwnJ+VfeRYtSqqUc-t~>?hlHYzux7AGZy7f)B&v~0jWReO{(RKBK*M7YZm+f4{xF>z%DBcm|c3ERndNo2`% z0b+DVuM_s^+?>Lsw3q2gYk`Td{<924uTdnG?0?8>9_mwTqfbbJ=6s^)-u?btdiJ${ z?Dc@L1fl{@2#N~=PYn=tDL@q>S5mDs(H$z=e&-!nc5WZ0eW&Wo&+Lqt=)i#^z?!1K zX`*JsbSBcoYok!osI~E_uC@5ALYxmk!9_b+x8XK(&CRtp;~D2K^ryezab{etJ*=PIc>kCS#Yx#~U<`gT1CuRVUKm#z8Inf6oJQR3} zai!kWrE6+7nu{IPXKKM4&IO04op=gU3W>HzVWK+`*k!Qa+M2Z;VJdnbSi^K++Hcf(0X7*F!8GK!_`Q9btoRSv`AHtvwe)DJ-ougqhh6YpA1AAqPSsuyDB}W+#hE zr)XgUxD1msM(AB^`|5G7z}&M;iOyVN)%oXOJ(t@gr;PMVB$>NvL^YnUs0>FyMEGMo z?<#8n#B&EI;xUVC9<0O^k@tUoiWaA6Q6o#!|NX!cjX(eZ04an<7-*tZh`z}>o)Gj< zgsxdALJv-w!*&VD@oLQF$e)Msrtx*HxTMA%+ zXN;&+!=R%g+@O(wcNrhGn8B}AvxOsSbC0fPmibwg8!&wT#H~#RD(79a?ak4ZKU{JF(46jE{7s3s>@h}wbzAt zD}i8?5Ys?NrzC_rfh{P?StgzqQ+O*5adsG{fh-`c@JXUX$P^)ZEQmpY6)<2dE8V7x zH> zRJo#s3Wuk&!ylpPo^XQWowkQT<0extm(47Cd`Sv$$$5e#LktPsM55-a52DW$dId!W zh}*xZ1-R2}fCx!H(M^G*U?8Y*3=&$*N=63xjsUz%Q{LE3a_%Jz)9)Mp;VoQ71RE(4UA4jUJhX7E?ZDZ|!aOPE)B7J$eN9a=d#p@?2}VwXDNxHq zWB>cG1P1^Fa9!JL2{Yo2YWpo=gML-zm0e6dE5au)Z1seV`DA5L1D5lT9$Eq-RwZ*O zWi8pW(R&$jbOPiBWQJqn6xd`_rC{(_-^~cz3=|*Pk zz1tT+vrqHlTc=h^$IO4y)oI|$KTU5q+jUv*8^OOD&-1Hq{Q6e^%AN2_4`yHoDB3U^ z2&Nj07~LTJ<_WxEU;qFG%pw^BgS>;l<)=X?2nwypgsjLsrH$4y-$y1-1L4Hk>!L<- ztP{Hr(8ClknU_}}r*X4FRCgvV=Ay@!MDvNaSy0@e7Ja$C=iZ+lf@`6m5SET>9)y7f z!?c;uu#Q1bD#Ue{v?ye>9!8*)`47R};DxqXwL8ZmC~OOc5)kQ|eYN5*H@jvEpa1{> z7y$Bu1BR2rF{DDX4Jk&LYK*kO0xl*&{N!Xar68Oq6WhfaBw-`=K2j{Jgu=AzW@|&o zq|P#qRu)N#>B~i(IHUnqju0L;R1i>ZqP}*3ETLm*yZ9cb` z6;|D~s3J>6|NFoM1AruZUfXL4GxCg!+bv;;ZW<|*R7||p!V)iSHH3~h-j_lcja(og zVuOlEwgg+{)CPMIZ_@#pPO&!J(0o=CD@Zh}$>E6-fk;&aG>=-QV%PCah_l{|^rx_= zlZCiIP$*d`gMJ4gniR^#rK%sDhZz+yfcelKYym%_{9Hq->*9q?K)KJ zrk}~rCh001C4i?$b9F@-{1q&cr)VW;E<#L^XR z#v|Z;QGAqgJS2^)D=;mJ8(29Ehhfm=V()zCj!u;ATsW$xuIvjPsqVaDdlJYv2?>f4 zOja~pZavJ;nCxc!nqt*gLw@U&j^EP0HHf)RSZr}Ea~)SyH}AOG^{2i+cG+A1qh3 z&q$R4f@0fw2lke1&9D-8mlOpgZUT)q6Oo~+83IWlB|4$UIlXinoAoc%3`Ev(N@Ple zmMBD7#Nme2NgHh}r%TCgbfC)4d{T=2EB_{ce(plDqFNVN%PO3PzBroRVaEi=3d2Cp zMso~bu|lU)u#MEnw?h90MsJ_Jelr;<%3MDkFk3A0XEDpW0}@IhN&o->gc1=*7?6w+ zP25J7D4Yte_n}&Fvo{%>Mp}Pq-}uBaAI=!^zFw#p~c{0KLG?4jPEYBt)g zE!$5fk&PWu5%06#-d5w^=kNL5PkMp|7yxB%k&>tc0BMI&%)lfqROKK500l}iVg(kw zNQLu)MT)T@EDggh8jHU%DMR|xU%OYO^EADf!lS)!YfT0qi&92F#TMtFEY~Nsho^5m zo1dxfktUwG@7~FijfbXttcxcRWc#jPVIYP8auV=wWM&3DOcY|{MjlM4!oecN1*|Tbmop%sSa2v@ zDg0b3{d-ceLd!bK3dfK(A8RTDPO2;2hqIBOM}97{(Xm6Ka2Ntp6oZhEJO#*Vgy_4F zp@K6<+595JtQrCchz@b4W)ShJH_9N!1L)xu=xih~<`(e^UK6na97G&m#y%X+(ZUkL ze1e@PVBj1|vI=P@i3$?lUeU9s& zUQ_MQYEtKxRe7u_D4`S~hLD#&zB$fh=zcb7IP7ySy!EwXehoj$EY?2MsIetul{E1v zrTL9&;H7ge-{>YHl3^$(a0Y9n=0<1+8Zt1TNTQ37i-U$3dL5f5FrCc$3=7qfZ@1dUn%C@#{wuC#W);6xG+p1%%c|| z$wEgtm@b3}xB*#OKg3jw9A_KC>?A=AWhKV?8gR6wzNd!@h z6v&Gt2vRJ%n}qm$ohsnOTnuHj=~$9F)XZp1lCZ^^cBoc+wm0`- z!UU5et1S|x2<4je7Q_f5>4Bm}XY1Um%G=e;y!6+PIVdNlLK%%gcS47EQ~ifuRfnKZ z00Gt@7=^x9DZt_vRhPpH>EK-L-zqsZhos$XWU5tZ-T+%DPK2FN@fApscIZ|u7@VqD zsP5KTUtU;FaA!(C%31&WummE2BvVRR%M3H}jf^{8VTNc?RgZD37<0-WuWdDijrcpb z{YNF&KWi86uixSF;}5#%Bc)2V3r{5LZy@QX5qj$_-Fo=VjlKNjv|sMONB=P7(gra~ zf6-B7W3%2Mm}T#R9Z}LSt)eLa005Unz>~pHE>$3fg}Hu`RtQfP48q?iv2`fu2T9Q& ztAP&9!hB6~S}j7n{TV2LuwbAxl#$4wl;Zon^hlF`yJCNHwB1Ga`bFeSZ0pYMBDQwb z8@U^sdA9AI?``vS|7`u8@BJ%V>nnGctnp&Awrg(pt@)UlcIb9_vzkz7xoEUAt_3sC zE}pwRKqM5BnLn5Ms(?U5a6%WlbS{LsZi=Ay$*16$yIzOmR8Z|r@{tlm5MZU2Od}%m zoXDW|QRpvP4nhe#Mw8|cB1p2}doV`x9#QfxHi|y&x$#lE;PjG*3q5cKVzQqNv1Iv9 z6<*+rG?sCZ!AM1$tD5ddk(PdP<~53YV&-d2%d2t+3D0LB9QmSv0YQ)@5;mY2pQ%u= z+Uo3RsX!nTpwSl7aF9FekCO()0ri@(S~y`FBw&1@66pvYk@D#0T4!3hMv7e9sW$1L zSX^>SwQyJKNy%}@S`J|Xj*PA{4D}cgN~~oKP6Ud*d-TZu=2EfGE*MKR^J&;!BhcZ$ znP~9eu;NDeEMo%1M0ssK10~X<4AlNuc2Ac`;fKf4(1n&i4T-bU>9*HVy zPOiL;1JtXUJy69*J+07|RSlC5t0F3!me0xLl9V$0mm9s2K&kH*sQDiiDLc_oK1gK| zoJURNycjw-pyXFS;_{h4|NF26Gyo)lU0Ul5GV+m&TRmZeepK0aV=OTjLP4x7v4$bI zZrz=meLjDUt@}OF-Xq-BTRHzeML+7UUJH|1fRQGfUJEo=L)c-|lw3%b0000~3$$Pb z*Z_<$O^UU^CBPL!E^t9a(~ca|9=2HQ3E&exQnz zSpv9JW&};j$QDbX{j~EkK{!!?@mgPx4p+Lz%;HPdfB+0a6B@y!9U!q1Bxq8J6P%e$ zJtQcnm~&i#r0~PTX6y-mS3R5+B8Q{bne|rX0U<6pOk!?wt?Qjo4VA$~iwX%32$f{8 zVvWa47hVV1WS-(xC{lX+k(TI>W%IY*Lp?-sdqvZy1(=g1WSG5R91Y9o(M!qLDsQ;C zijn1{8&59n^iz3#W%ko`GANxwrL`iR5_{T1gMthS%1j7}sdwG|1Q$pJ0BjI2i=c^| zAmM*fjjq2Xk#v~LT!N?pGt(BD6em!fqw+~-PLqc8bb28sY%I+&1_;h`VXCK zxYGWGh0VOKAwcYUo{;5~Nsk&`kCPO5SXAL)oZF1xUXIk!u#D;wC#l zS}R#}H0aCXpp;bZ6|>Vk3>Y97iMEjgg@ezsb}@;`2WB-&GQeyUho>}Bw1eD>jp$pjLQo>VJ3P~4RvRXFwMdztL*iJ zjybERQZQ?ztj$#QcRI{<8&lB!CyKUJh8q>c_2-N#hD&lFkQSpFNIau@u4O+CB%V$p z0001;MRNQV46rFe$B_CyqRm0HS}dMK<;&X4Ew#eVF*{LEQI?`S$`H9kyzvP!GodXe zA|hZhM^pzmk7Uh88&5RU)00^>${wYuEAGeBsM<*VXx0r6-^zJ3&3&s-hpf5JZ{D4q zD(?;6Gki&H<98!1o0h%i$b)pmhyVa)xd{&)t)zh{`KqIx+RCgf_g`#S^*Zv2_P3s1y1o8fXqp!8DUXTFA@D!R1L;axNZ>* zXB)LWF^e{$2&Ablj2@)UO>{(LCJ`V-VRy=HxVmt4{acokj(w-|WY;HW`j~Q-7_-9G1)0sP|F#k@y&kVL& z|Ij2&EHu`%<O_&iz21E^1`pwYn$iqROnOL-tdh*~Fl$=FQq~eZ6&X>CJB@V(vg+xg;!`eyFv8klHo|CT&B}nsk7+L@HrHoVA;1gm+yC2guAlzJ?P84y zUZ&Mta`^6qk^yq|6as5V3LqU-C`14mLFT@ysqP{RBTkh(;6~Sj-fg5wXB{ zX=ej33B;Cp^2$}nIBck%dz>|(k?fd4T$-5l6QiKs(G;deC|L>wnuS;>n0uNgM;1h_ zOgvTMn{4C9Ff751k(kuSAEyi!ZLU^Q&BUGQq3#;Kj9;pe@1<}Q00B7imS{p0PE_Mm z4g&H*V@*IJiyd`x zVJtl_%0e@3b%dGV$QWuV=E(>ue!L+45gV{zl^uGRk3@}RcLwTufN*0dim{| zJ@+10O~?Ejy{Uy}FZ?_#2F+Z(4E5bL^_9%ujn z6C+211`w>Fos9wzbXA%mh;alVIP22Nk5j<0r+xH~#NyO&;~}~t%5#|YJyYc?0)Y&3 z94XZ5+Nm-^)pH*wI<)DWxhDF`Cnm?cVxy)QyOS6l6T~69nSb8Xl~o%2X?E;zt`!dIRF3yVFzKDip|#`JS{0uD+_d3kK!i0&eO{yy3m(D z@2Cx^wguAqF+hH~6yF9|jTNgrNtV7mfv!dM325UcTLr}ISv6bjI2t8c_ zJNm*;H(>~gW*qD;+iJxrM2wND7Zsys(Jo|!%)S@X^{!>hlN4II}B=gJ?u25mHT(9Uxs9ESC>1PNla%m1Dw4Ed0G=3mUU% znMJEg=XhTomkj;7W#iW2jL=b~<*d35`a4$*@W|~m>*G6Hm-^YCJJ*Zve9(HkUU#3b zG|iUwM|HbAGtPTibxn`I!)MuY>NNQ@$fN>6N}B)szyt(<1c6yw>j@lkoC~{uVJ40c z@pEnLF$~K=v+5Pcj_?M91F#nY=#M07hEgell&z)Ay`HDOB>*}OyDV_5l@aH-L@9#; zFtBBi8FFJfs_aW6)+TzD<>54opl%SS;Zz%=L^0oy%gM)veZach8cZjPqVF`_fs#iUKY+#rnF_$qS7clAM2=fgqrajWG%Y@fJbinKEd}vO8LO z=p!=Hb+o({Kz0*~^-*|Q**HKa92X=NiV=zl2-Ge>U0|q)L_&zmNMx>@UO@2FdWNrF z7GHNLv^I{mxnXg=<2EW1mwoN2`Hb8vVYcI6UN>#;7m&{#-#7BY? zaae_fF{sQ8)Q%OhyH{;Dko)%9hH-t;!KJCsXUcsHSw^pRff z-&av_6T~Kx!J6r)6AO(Z6xedEFq#`0rPcIJ2&IL)POR$0)MVg65> z(lTLQ(AcF;FgIyc5y_E_g~?YL4uK7_*LMCraS7!2%^u@bnNK4J#3%9ZVp!TW4C$f- zA&)E_u)?}2XvD1f5ISF>7Ya^Ukoc_ahysBC006{wOyDp>)gOaJ?@1Reqfg(;S3R17&rBDzG4GmBhlWsA7 z%S6Uft%#$fHo4FqD`tTbkx{*V73^9r`MInq7m`Wm> zJNAfi>lZ}=W#-TfDhc<2GVBojC+>wkG15d8-h1uL544u;{!wfc16NES6A ziH_%iQJ{ngnSg{w$K=JLQP4;R&Vc|BRT2kK*xae8ignGoWlgdKf0!}p6D?vno!I>Jepy%8 z#~@(SS~>QN#P3ZF{}qsc0wv14kN}p*emGY=0w!QwbXAD|`>+HI00a14TWbj`(2MH( zJz<7;Q-yPJ>@h5AK&&jih8dtDs(rtmfLT-m7bO}e5E5dOfwU+PArWOGLAr7-Q7ETV zK_%-@x`_w}(ObCW4~L4#ZJ5`U>`@D$N2L*NCTTo=XQmj^FhC{ESSn>MH!k3X<1$G|92n4fgSy=(|bb^7C%{X>Z?qmaB2jM$Mp;x(31N%L5K$N{%LNrG2ACN4<+KkjW+96P?uAU7L_llHB0ez& zSe@zuYC)9*bWb5dNg{{EDJj9o>L~~qDwfWr51UkRsn#!fb0S4Re4yzmBlDIUjPsE* zI9p8W=0#ACqVU|sZ9TWsOeZY)g_BM>mmI%2N_*w$bt+QJ)RooRVlfAqGZhg}9R(I| z;hX>|fiw{S042LgB23iEC?N5cF=&JwL?T@~1B6NH1{wkU%Gqas{zfy!ee5$ICe3je< z)bKPc#ERi%qhp$d2ylI;gy<6qR0?SyOTd7pCYoiK=xTMO761FN1Q!4VLtNZ@4>7`r zi`y+>D0~vFdu!|^55gm?to4MM@Nkz|=wq}q0f&6>qwL0mkSRN-Xh9)#ei>UikJ;j} z{>o}(7E!%rZu5wyNyY7Jc{|4D$C$3$`^UL2_wSpn4YA(5{I32VA3Hhqjh0Pz&X5`= z*#{UfyZ#D*D+ow{00B8sP|DP$MX_Khu=tP(1uDC|vf1o@ikb;@K_Wmf1D;h>*KiGb zMWxgqL(4K10ZHdnbzXVx%4dmbB+$hrn%T@YQb7NirG z-t!yorsu|YBSdLw;Mbl=nuo?^bqu$&_qSC~R}CCRwO2Qbbd%6TP~?bc0ECH`2-q?N zmL6cRnQ%Gm(H7CgSy@^V*SotXXKvdzp!t++f~lZVc$n~wM4NoxDJbhd zOhs)-S4HrFtT?WYVDpI#5zYc?uoTFO#~5s4B_Sdc2_tOuweHkV&z>Z(Y-elU8E==! z%~4h2S=W$gDt}uIXZN<7qSG4AJ*!_kvTv^$-*IX_ix`3%ns1xT&bH+Hif&@!j+WQPM zLYPa-KVgV$5lL@n>?IFMGOw(4h8eK7=j{7FBhI(R*QR8*B$TKA%{o(WSH3rWV>|lY zoc;aF>tVaE^E3aR`oDeIm(T)EcuAm`6MSzM1xNcLMs!AKKmY`}x*vg{(|}(Oadt(7 z{+H0SOc@%GlEH8j+ZYv3V-t^0lB0M+GE(8u4U-qzb|zOXZMaJ@y;x&g^}8JFG+>3m;jw$g;1m6WCTNKh_vM)LV!z^ zT)&{=w`8hJk1fQWxxYN+`=T;z6uc(u5*T1;mCUHP^=j zm8%i;@~--WN1|3#OwnSe-5X1NLX)WFrTfJiVlA0qZP)71oyxyYT~|@?WL&h}Siufr z2o@u9a{0Qsu8cvVsuBVc5;W103Uam3t5u(`Sq4hYudjVg$H0YGB`F;jN~#ayT420< zUeNY7{|FcsdP}^(0PLe^QLOewN4IJeikepYo^{z2zWk;t|GCy~(*OIg1Tg|6i)2}A z3^P)TtlK?dCUzOUkyfm|k-`_RthI!V@e;OVZS%b&nZKQzjlTY7|NiSO_LDq%`Z0P|m{s*@|r8}5pfB*qY%S4c6k^qHZLgP@S;OjAj;dR?fmfj~V zuNxLa2D@YIhtM=JBZ2V(Gmd#hfD##|lQ6nx`6SS-bjfCwuEoBd^YdS?{;&NRy3o;) z(8Ce=-ydMuXR^QhxqGTL4h*jk1xC5$KbGe*ncV+~9hjNv^I#r^rDph+i_7C} zNtgC3T9s*G=1u9LveVaVW8B+Dpc|M&NMzWCZR-s5=L1> zbU#(N?@7E8^f4|uIF6}ITK8zm&8BDGBp7PB_nfV(uXU@J`s3X1M>M^!n;TY0`K7+i zI@Cb! zbXOz@=}J(?^vtf8LpC6|k%XowGABrsqA*Zq22_J3;XpDPfgmM_eKU=?$NA^HZGNd; z^5{38bHEz5J!G7OpRpnkQD$a!0v9@Dfs6+Hbf&@rg z+ItBba*3-OJz!G#Kj|lK;e!Y zUzG+?49x%#0s*Rl$%29s-n(D&!0vww$t81|v6uh-_BlYS)eZ*AbW3*k4d>BgXeKVT zBmjT~%qZl{FJOSC0xSzOdkglDP7--F<$-7tXmbdyNxRj1$@$t_dCKe8fvwPX&vUyu z{g}M~KoC;&!T9Yo-U*76hXWzm0GP%ZDd-eXAoL3=Blt`1WFR;JOZi1CNrWvL_(AFi z@t0(~=ryvLYk%2{zMPez-1iBGrI#RVLyE;XRd(13PzeA72AU(}!9-#s%!E$?7_R_= zn!_s^Eudq=7Is%%$YrS5a$nhWx@tJXnzPcX%MuW#jJ3dfy57I88kx27Kw0%@4eLU9 zu??m$m1k?j^+qy`SZM{+V3Hs02LRVDM>!iv9Ea)3%H)0*Gxd=|a~e?<6=PN#R!}!3 zP(}QMyT?@w4ITKs=E4rG`Cl&6{uh| zR7`)qLvgH}4mZz@XOHeXv?Y6;A9EV-yS43&NZ0mO#t*k`zvCT|dsD948^u5HzrEn) zIe2d(-SrQ9u-PB(-g2=lH+c4=eSYUdML+-%RSJTJFw_iHq5`Tx#1hGUtN;7J1PcHL zBVAWR4>fRx>q~86D0ooOcXR9|4MIe(ZM}q<`3riXkMtPQ9tZMv>%H`Lov4&i{(&EZ z;hA`hnguCyRjZRNqCkDJqUJ^q&{~9qH_tQ}VBuCw4}`)Phay#s$E@a+)aU$CXu=go ziV(U*x3I*I8A{~>M7fgrVA&)O7^Of}ca1l?*UY4&6CI zftuHGBQh}7H8To(ed?@xnoq`pV~MQS9Ovfdoz>=&8cKMpRHF3PHIrmUe3?>Y+CK ztSHyOG7s^ZOvfJh^$Nyo% zH2?&AU0UM_L-2@7>rY_Ao>EzPX^cG0f-bD=^@N$}q@l_+IeVr_ohBwF*Qf5*r~ikI zIKF#JLkEeXUy_i(CgJ;vsm3O-YKlMr00Sv8-ZdQy3}GmAF8ZudRBl$~(2vjSXM6LU zcJ0LDT)%cyaH1;30|~&yk9Puemb@$Qqrx>dGqY{v7bdY1Da#&g64k8_HkZ3QS9X21 zWu2oGO`-AO^MO}=_z$ojm%kq_&5Q7~>aKJ#F%l2k_3M?EHQ-LMk4KS*-m3xDtFqAZ;L?vYPxc>V)}ajwEEAxd;U-VG8^3Z z$h_#*cGk!HuabE}qDqr&-xv6R#cb_CQ(AY2btck8IaAz5W;QZ%5h`VlM7iQ7C_?}H zumlYN1Y%p<`wuemfvOu_Wh0IiA!lK1JuS*cEA2Ihp?Mn*5FtD+#`(lx#6Pc;oM-*Q z(XP)jZH_#Yhbz@0x)*4B4OBy+MDS;d)KjCl*Ci+d-DWqGWyq!bJ3HJJ{%)U{_jkKw zde;5EK7x>EBRfj}7g4zI`kw#&6pqi!$e&vuH^jI4zR|w7^6(KTz5THI;GUae0H6R; zmIyIoevn3jtW2^Cr9sg)Ww=c;W`d^?mnHm}eW2|+c)7)C{jzjS{Ay4yVq{Wd7!R-K zk869b7J~Cul96t1xMQT9WTB;ge_38vAL((&KT6CjyPr53%@K>$FuEDc!h9jg74E|; zWPstbF%a=V=Gv1%=)-fB=om@6Su9x}-(p~`3kp)=-u(ur zI@n*lt1Hyj;1y@7DM7zi!+@-g#Ba8*$gWeW2vc)DA38=*nX)svC6$pBjjG^OWL!QJ zYrYXkgs3oT3ZjjXILsW%y)s0aL<<5-5lHA*K#>#Cv{}$t1!bzr7G?P;Qc}d6_^ta} z9+bWRKc4oko2vUsTzvfZB*dWH3Wh2Q?tQq$c)$4>{m&2q0uq)a7)Kz`L8Z%yu+x$) zG~`J%1_89d%uW!5a;1Gpr^Og!GHM&gklgEA$-Tmh9*`yM4)93?L~fDn z!d3&}&>^gn*Xoc#qME)oK-I#E<4A#5U|0&}o+Z1gG#bqb?voHByX@Ph=Gn znuwjf?M`xG8H8~mk@n`0Cy~i(@Mw`hMW&ApB2kVrwbtuXT+Q$-MIO2^beML z3X*d^IQw{6RhRVM{`rd0HR7xJsnvN9&PltrXyf9p;tRF-@0cK!V9CH+deW>PrxySK z0T#Rx1)vUq>ynKvBMPdbtKEbk^RC{!4ZD#jfZ(`&)z%Wa@(4Did8S;uVfX5K8v1Et z;|PmP$tkVHngoJRUV2!;aIcURS{e_K$7Cb{?J?NCkK|=?>&%~Ghn>zu(exb3yNU3b z5~4a{HfZtbWWjMI#pfE^LQvv@j|MiA#QG##*!en-v}V1U*AYq^ zD=FV5O4Qgk&2Q$YlLX?eQWO8zV$rz~K#~%;kRrx_#gz$Ag8j?T6s@fdeJlIVvskkH z2Lm;WonE37C=YL0PVv(!y^Fc9KSzJcisQAZM1Ly~@t>_>Znn4Ew%PZ&>ca@x{t4AsqT2q>5^K!hu9S!l3XBej;3S#*(Elyw4hXS7L z%?kL^J&P}SJ+}n;fpTh+IPjyvqYkc_>_Nh(-W9Ft8SXqivUUE}m;Lk5hW~G?OP@KS z^U+2O6lgTTLhIOS>#s6%&kInM;AMdg%vi*xR@IO&86SfKA%GZMFq%&zrn}jt95)TX zuxs+5>fz@`wYsb^Wr&anM&h9Z(!b~AF0$-qDx|&FB2PBW&G3k|$)!mbVQk&{W)7l( zxsBa5(o<#`ely9qL&?!FP%BHB4i`gwP09igU(3<5FU7zl2M|FFf&OEdpVDl}Vo{dbJ!Y?L?@z6SHQ6 z3q}-k(Ka}a;Y&Xy_UOGt?bE2$8CB8Qok;CACSdOKFm4=|lvyosr$torpY1Vf&tlZG z5X2bOV^uQ$_l7(oEs?B&A?7OcWY{Gm*$D z1~Nof6+l!lv#S65umlW%1aMv3YY8+kkgF?AVJ40eMRRGaB@s$JuI)X9jxk=Cij9}h z!4F!-ourJYLPQtB>A?zQglL3q63Y=R1elRzB>d2bDGWq$Bgl#)1WuG$&L5?1v334i zzPo4Nxfb}>Up~64c@}A}QPMrmKls0|`)gDfr;gVa``V*^Q#0XzTjb~cyVoBtrlkn0 zlNE;sl&T#K&0}Z)QA+M$XhDczBRIPgm5<;f8}fpv4`C1jf1(?|8Eq^?q#zu&5t)gW z1IQNz0}D8f8*(6t(sgi9pS!-3XbE$QVj#B~S5MW=I!|`kly#whvTbaf;Qg!2d@Q%^ zroOKoyZ8Osj15=aZ(40r`K7Ns#^xFKNVFB0U7Omi4_P@5sF4pdc^9rYO4cO8Pvevz z00<4y76+7_AVP#S(g#df45=KKdsAk}_~gHhJ)|}Wq`D$ZAwVEt5tDE(yyA4k&(U&l z)e=dB*^a*MiTY-gg0lG+3>t$)sTlWt<|cdCWLXbGh)BI^ZlHMiYe=Yw8x%aMbLv`| zZQc)AN@>rNk>PrFthB$V$UVjCnN zF$&Hw08rg@0H-;1SVBKCR?6l^pvVQ5=M@N_SX6j@3KZT#6kt5Mo(d$5nWIV(2sFnb zL`Bi8OpP?tH2KKB)D^qCocAiiAE2x%!f<6M;0k2ISxk|k6^K~zu79EWk?_ksTPXDP zItmBeM0}Cs7(@;o_)>ZpK*R7Lc5Q#FZB+mqAOHXXFm&Ncfv$xj7OgspfG9jDX`m>e zQf>;GrmZ1cQ!SE6|NFoM69NW~V%B3XOz?|qJ3V0|j8S28YwRTv0tBzEbo7m|T)VcUQjU@vSLb+=qkmX7pA(CmXl;>8O zkWZoMqlzwR2@400b9uc?y`)5rBtDrWUE&Q9|$|nN$hz%AwWuJrQr8$`^Qz z5gG!fS1aq*Hc*y3WF=Rc?_%UG#?;8FA4?I*Rj*TDeUdS#5JNOWP7#&^ zxU+<8pf02&1_n(OArU4F2$&WW2Upt~FktC3b9`P#FR3WXZc`E55d~`sJSQ;$4AAoP zj;9$cur~KekqW~D8jz=4!?;J%ay`uIAJ23@imB!fPa+g$tERQfrkO)#Bztg zG~0Sr1lAY;001DEFy!-O$k-4Utbhsb_qCOBra@rK7>On2DU}xvRxs&Ys2fm9NpX^J zY+Ev0`l05Bdk*YLNl%&jr!`TJdbCF`xP0(fxU9w#?@Of^<2Z z6K>qE%l}hwzyA2|xrh8vYL0aYO=uF2Hfqms9>Q@|ECC`FfB*mj=?@FEWjYZd3l%_e zur?%5OcDXI7!sYGvj^xdOa+}RYZb**T!9cS(X>>l+9f0+Dd&x-`6%KTY5S?*u>tgH z)~sn4+Lc36tiTKzz-%heG_c}f>ZVyHD{g`>azBKJhneLMrfs|kW_NVQtCLeWSy}9) zx89QxL6Q#CTT6XcRTy2@7)-IHJ^ohh&JjC@D9@_9-w4mDh@akL#n#Y^o zUy#z+H3F)$O7&IRlJVOs`uX?nI~Bj?Hl3+|j~?5{_|E0*L9!|%LL?D7R%TfG$>Pgbb<3>o1BVWSV`QjTa!H;TQB+1^b}Pu$sfTwuj3`+0 z*rXvuQD}iw)LWL_B5H78&YVV9;QL^VD)Y?S@?Ls1^PE2ay55rC8LG)4qc$RmA~}Y$ ziv|k}sLhD{Y29tA5-CwLLl6Q;x6ndFWsn#Z?P&&!XwcTuyJT!8C4+?$mc{NsG~lwB z1j51qPzn-2=u2TpC3?glssH=11RQ__QeNA821H_sOWPV@gMLzFlWXiS%|a@x?KJe6 z;lv;5AWFNKJfv)!&8XldYomg2qUp@8DR|n)nD-eX6hv9MdG77|QH>>s)|1O)r3vmL z8|x}L@1?u{|E+M&=hNP>W5!fE zhkxcMCIyVb1c}@^F6#6|03cxyb75$P-f- z8LQ0{&;Jy@Da&beB6%cJF+_xle7=N&K#_HcizqKERWkqpT_+j3N$8g)77If{Q*U!bB&uzlNGh zMOjHIHCZ460dsKr0N@�R%-Z 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 |p6G8McCc9nlh;7DQML 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μ!Qd_?%ll_LUCe3 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

    2~*B{ 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

    <-Z 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 z zQL*XqUDhT6eAfazj0|(Ff0tWSU5CqrXTJ4o=K|9~U!tLJ=F~x@2C{p*jW>W$Z8x^R z_-;LI__Rt&|BqMYLD;hOYS7VYcQ6*{CydHi z?e3h?DBjk)8bJyB7uRqKig-|XLfT86+`FF;hWC?4DZR;&7KChKn*U}m7k7&l&wne>n z##ryf%1u{X~E9BR&h>m;Ilo?#~uh`9n!fnTh;rbaHg=XfVFpTs zF8?=LrAgQ&#?~Xt${q%S-{P^b1x4>|P9W&Pfb8KQ7=#(tgC*P1fGY60S%{$hBJ+Zx zakMrlDiz*xBNSriy%?TyNLj7T6b(VbEW1n*Cc+tssCdGu&m$X$VxNCxr!R{~gYFgPw!k&z5ai6kP0 zwVKSSa`Bt+PT=ld-DjDc&l;QV=5|%OA=zra1tA|RwnIlY6CHAaH4EI1g;rYb#Irz0 zR(t?^&bu5IirG2fMxSc9lv`h7FZUPEAy|U?YDQ^JHhQn%7Q#Z}(-9Ho2wpS3m!n@d z!x*t)I7u<4kPw^(H2WYL)t8U>V&EBC4h6sDA0bPt4cyS?5oatx=|2Crdzk>4R>8Io zNo&l~=>_n) zB<1yN7!NOSvLcXSA%2nqDm=Ex&hwVNNuB_L*1qNeXK$=knat=04xWpSB^Ql&e7?s1 zqSk-@n42_DdMyWFO83Zcw_SO36p9bE-Y_p?JRCx|lE30=`X$NGi9L{?GNnefy%TjE z77I`mf2u6pN#rxmM;rzjiP&(7+E_=}pt!+=5L^Y?dOZX3?Hs43;=4M*mCFbOg%LCk z3=OYg2~*)Dfi%S$&5kSTdA{T^18Mpu58j}OCgCEqXN9;;q|=5PZ#v6p-#dQc2;fLA z_oy!pXZd_jcPH;;(MpQmFfX>?O-thiY?sT2ccAeRf!%Kdk#sEzN9X@2={%gt4E&qo z1ox-j{}7eVo!d*`V(meG44UYK`mrjhhuJ;c0ZT z!Qkx)YS~)=D_>q1y&?IlRHpfbxTPx|NR0}22n0g24*M|)-$nw0gafYpFA}sSmg=yi zKZamuO?hk_)1T;UKY9BOZ>eaCvdg~ED^h_S7@b&IjC zbgxF|gZyXrc@2~H57J%sAD1YJhUboTROBgu=5CG~tYH zSf_fFCCmVf486x{4>#+V)QI?G#3;9D9$IEWYWn=d9~nknO7ViV_WJ(j(Vyi*k!TNo zC}@r#b_6}8XM+P>v7}=zX>xV8k4(=I$SKp31zJA-)9=LW3TNcfxC^PlT z&=NjoO(Jig@8sIu(!ZxG<>&<;o90SGZs`h7;{9`$-C!Ss^o&5@C${T7g)0MyC`nV4 zBuIFP1&M^bS^AvYLt6BfSD$`u%_sUB-`(_YxulurXF=C!}-B#Df%KA-0ka_vAg>)K83aAgO?3m z?ZTc+5rP@5IkN|jk#ljCi7}tv;MS8a>Wu?6YC%4rK;U=A8RmRR9Piq>+cA&;oDUia z^j*G-v7?1+lI+ob-_T?JaB_o8JDf3yd`KJ*{ff>XNig@0Km4S9Q0*|5a>+!rF1;ZD zm-Jn8Hk=BN5%Wv&2OAac`!AFl9e2?+eWwe_;g17l2U;wktq3A4C}KOAP}y7@2u%V6 z=F+Q&9^p*nA-&E6!pRy7RBZglA{y{RJSJ15-~oh@(8^ype3?Iiva7X(+X1A-WAhzb z7|tW~Jb|4}<2Z;pRCd`+Qmaun_FkBA;+F{xOLVh`_cHP%f_27ut!mC@%}sZ7sNg#2J-=>tS2gR}`!L(yps-eH zj@>t!Mf%Ll(t6ND4V+s+(Gx6oe^NVxNQIYeThUa3{tE#p2NYHzdi_zPBot(dfGH-R z!4Ro}OaELds~&YX7UK6TX+oOs9b$3d2>#dny||24(L9eZ0t&CS9y7qx>u*TjPmlV` z+U7)=zEvOi{$*Zw|AQKPk{o<>hjsP+9itfATkH|X!+9Y;bURw*1>t`Oft{#=$hgZe z+*E<$mhPA+^g;PNM#e<*Epx73KlS*c+Lbx+C$XlCN0CK_VG;xVeu=-<1}BC}Gt@V|&9vsq*5lK;tHv$Xm~q@pP9vBcda{2Vb7toR_`4X14NU85 zzoa9bxpe|&VkdTWdcu*yrxE)C(%qFok`}BYh+j4cR%!(I9mMK01mcnNEId%&Fa>QW zI?=C4NYCEHc}_gs1y+(K+REOs7tJeK?MMzP9vsoSg3y0 zH@$^~S$;hr#-(*73dbj8X{$uD+TVJ@<0u?anSZPxTIvmc80?{?zFq&^#b8g)?U21- zm#{tMVe)RGQC^t3koS-rz0ka-npZ;!r3~ZnpCpCPtyy@|V=_VAn6SwR0!3?euwsn^ zS1kY=u=!74s3V;|CHVLk=C;iGe$p~P#`*6cvc0)-_}Z^%@WIVXevYo91S2}{ib#(- zU zs0Y&4A7Mw~5A>4bJ4jm+K2d}dkaJ=QZVrG!#`#qrVE*srq@NX)fp=x_J@^(2KjWiV z{+!cSYYeC~R*k0+g8sDeuwRvk?wuO%VEc zeSuIGG2ZAM?_Unjl>@_>n|!bN_Mg$Mhn^ya(gWrUuaNwzS!akZRz^YDGp*Qf^T=mFSwcbBaYA!?xZ8rpfA>p*va@b zP&3?Ml3)tRCKi~QDN7Vjl8)1#)plq$Nm@tiixw9XNXr`Hx>AEaY>*dXQmOBF6p@r z=_pK!KL7x8^<|&K4QJJO33r)5X@0}iu_o2R<(k3o_)XIKF!k6vOP2Y;0d}+%@>rLD ztza|{d%1Wt*!v*@G02>S=;-S7mvo5;2_k$(jsdPcah0pNkmZZW^Y09pKExx;s$Gh2(9b-3xa*4v)NpALt=Ny@W#?iit@;)d zm9ltaJ_rc+Pf6Gj*-CD!5mFKpOwO;*)y;;PZ&Jc2XygW8fF-aTe*(a{H_+bfdfEQ? zuz2{eq*PlsQrNUGTTjH@DusEUMyDKNn_`{7;5@L0B}G6o!UqDK&JgrHNqa9*w-ud+ zo0ow501eV~ro;=vVZq0CqegwlmcfRAR#z1bi4pcZ*tnfo-sGThqJb_dMIEXu6@P8A zk$%hnl$mfsZn>^yR^cEzN)Q-}n*a6yie%7NY|WSA!8|J#zAgQu4m4LlI7}`vx3_a& zJIg|k6E0S8_D4P7YI->8s+(dZr18zFNK9M!vNxkBqNBjeBF}L5vN%j?3EF<;>8Cvb zG^Yx28r2vi{a8$;(tOWPvo(OG{Q|RSC3sCo$l~Aql8hYq0V2H*+}f22A#-KW7$UWD`!YD)R%fT-;%w{p5^R;7lAXt-Ei z^z`3;mFnH}s`ra~wqHyU@%YWBiI=i86`hu{I*jFiVtT5V0VDSa#V49U1>OOo#l@oojUej3{G4YjKtM=Cvs&Z@nx;f7|0~Z3VL>dKrz;?%dLi0 zC)bXLJMA}oK+~IzgCBp?@{UsueAnSAhk07iLuDj@snA+aW-_`qS@$iM;uUmw=!z}{ zO4fud+|Rk#6(@-F0kD2$|m1gA$+<`GQxoXH3o-%)%DmJm3KGkW=d&CoOq zU)?R6=?DCF%rYJ=0U76QX8N*a?G_V?KB>K*Kk6*{6dVw!EUUo5mp)rbjpWlsZdB~t zA<6Ba<%U>Jh)0Y^DXYDAkTU!=)lcSPKBT1s>p&y~LaduJ{ znmB~I`NtVF)G4f3Ws(eCa4l-0qQ{?CN$Qtb4N}!b_oX@LEu0y4eim=jP|m?@QgEaM zwrwAZkaf4lejO(D1pdN1?(SxPS2Qe=tFm{?!{QF-3C{c$j*A^Ae7fhNt&kjS!s!y# zx5;>aAb5gTn-v>5q*W8si1P~tdQzJ1x_EI34BP;iB!nBt^!rg_t|_i@>R3g0WWSz{ z@s-p2W9{P!#}d~XEFz^)KDzoM{kHSvn1V`39wn9l69vpWsIeZ-dEZ{a|D8t;j@-=c zJvPpYHGZ-ncFK-5;~qYAoiJIH4XOx=!;tP0boh_-I`{lLQ47X7lpoP)P+2uDhrhbb z6SNEjoGiu%pEv#Ugf8*}uXhMdcGF-Q&{{_`h!PgBRPjFOo-oKc*#F}jW`}cJ>Hx?x zJ~7u9-N2~85nJ9iDdY>RAsq0-Fj2v^=!OXvm}N0t=0h6vHxZkCwiwr3y(S6!uC0D$ zW~12}n+x;~1I&hIi-V}OsKDTasI;lYDcc}s=J&TJSInIZyj$t54ODKdLwHw(IZ3a4 z|DZYx-{O;#6!6#w7`;mC0D-cO`!ik53T;kBuJnLwKHwU;k{F;jPKCpA@3l->JC74k ze$xhAdjb1Te4A9(A&X{kJqMvlrZ?*O>JE9d+%v>OtRYEqRFo+WGLk8x{OC0;Z(y_b z?o;}Kd<#0PGF0CS=H!=zGC zU!?h)$t^FKSRKpspZJ;5?`=q)C30Gmg(1hW`ME3eVBeN1t9pB@@}mYEyZpp08KX0qkxLqvVbsMG7E|#vcxqeRF-ZW zlz<@{tqbu}4aE1D2HBt=OZ3ZS^)goGNJ-s#91AWkzWPX7ip(#avIfiyckF&jl8D;o zk3seSJT6>=Pnz07SjkYbVJ~G_^H_HpVMe;AMS&%Hsa|n1k~q$4`qeO!O*LMKefk^W z+x3^7vC1oWvk&>&ty)KXb``>Csolb8p1f9ju7FJX_Oc&g{zACBKVU*zR~#HFy5wI{ zBKIymcS?doQmj`7wc|`{*$)y6-?Oxua!T^l*Vp%{RYVit@!)95+j8I8A0FNZ0CQmK z^~!<|GiU5hg6Eq!(Q-yMW;#MhiBHB)j^Kckt9Esa2_K;)sIR00UyGjIPm5WWDo zC=PTMdk>l{wzdT#rq&<@trO2CYr3vNVl8@@u~5I1=5VOZ^|QX zJRHN*3)YCIUb;n6tXG8{|DFn_&Jzzy30n87W@}xKF64-O7;OM~rMy}4G{Ycn`)bh$ zI%&Ttqn$5)mfRE*l+up3Hc84M;q28{-j}wx1gjT72zN^_uJs2A9e(i9#(CpJj>Q^} z1%iQyE=qe>fUAG35X1Y4BMaVNlEmw_!;h6ss0Y)BhXK9K8-qrZ*1x{RwXf?9X4P)E zXl=)JbM-aD90lu?@)UDS6}eyw_?=*Q0ty3dVBknfCRkk*+dO%K01JfeWUO?6OA`%} zEC#>V*L~ho(Se|bmD(rgWB1;A9BnYoyt$^1hI)s=SivpEQ3?4gsJ7A!%7|e+F7@yI z#J7?-V#Du9sp{^DazOCcnTf&7!K>s&U7S4LxKK(lQsIcakEVq4Q3s7q1;)9f&k3<% zukM$JR^fAE2f*Lo?>ZMX846m2?<=$fHnjgVGVQ;Z`Wq*Gp8uPqP9d5tsNl7m*XYoQ zgxcfap$26I14-|YU%HBe1Kmy&fAv@ zd+s@sEQ&+(Bd?&+V9+6L9g$q*@B#?5*E~LE=skRRV+;V>7zgD^Qodi}+-S^bpZq+- z(hbi{WgnQ8!z5T|Pu&8O&~^N&X*63?DaC5iv6gOC&)_O-G_lel@geSuV*V0e?NJ2x z>RTmeR8vO3;tf5-r?I>u#i4PPk_}|0D=md{Tscq}ls=*N6}%DJdn3_Gcf~U=qa``( z^Yl3$1zLF`TZGVpfU4*jIoLm(sBVx}&i?%IxbA`>GSl9}ewgRrttdz76QNQhg8gw> zEF`VAO0P$)-ogBrc2i~gbU81tzz9BGh^c`P=DeX}r$NJMJ1x*OT7@e98A<=gF5JsB zT==zPwc%-HqG6deP!4C&_gUO{7>20%2B=8>n zeQdq_6~FkiybpF*WF-6TA`w?G1n^5b&gpRHU~a~jD3E*^pDuazm|Bh?O~C?fLO(2))Bw#SMY8 zCu&P}p0g!?3#_K}r1CRTjgZO{aCS0+;`=|_$1lzL^mX>B_Z*T1Td7ITodVu$@$Uwk zdH8LJ;j@~GoO<|sTjCp?2^>OOq`Nlo~9NqSsj)mv7nT6pj(S72qZ$r*v z=Re!u2qL}SNzZ^lXIGjg=tD#EwtGL8PQJj`rQeki&Gp;&Qz>j~=UZb~)id@p`{4ft6hLu2rJDriwvfW(0?1G<8hQQe?W zgkJhyrLZE3d`y6Xg4RonT{7u0ibcBuKe{YnQywo!Zr(4Sg4~L)glcwG)GtH+qu!VC z?4X?MVe`MQYD!t$V2W=uo__TCJ#0?SEE!J|5~1#`_)1pnN73;W8N4r<31U<6M;GjrQ z*Tg`sz%Mi%x^*q~Jn#I4rhJz{b;{k~IjJHp5DY9o#2OtX%*f{Z1q|gs`-^)7GpDI zUlsn+6AfZE81mTU4r#MCzbQ@v&aYZmfWP(EvWcd&?*tM?H}`|yJU1U}yNm>mst*@( zOLKRov_Dp~(l}rf3B>2T68ZQxn67TUyPKK2v8VUTJ_|WM1F~1FPhTXyD1VoJ z=(5Ztk@5|8*BTbNY78-eJ>Lw>0zSMmaVEi(sK!iKTts zBz;=_la^tJsRz?@C3|8?2?$77MPU3KxdNR1`vn(_C@R{2j={D3a8we-o{1cf1Gkmr zX&-Xo=1E&M2Xc?pED`;*PKjNUf-9wg9?pM6lNV2$2gSVy0+qH2*yG#$u{(O~zbEQ3 zYQwo0VyNE`a-{J4tBS{a+D#=NIr3ng)qn&==VHRYds=&-yA^!5p1=@HwP~WofJqZH zNE?utr2!fvKN&SPMk(?CN+GbX^v4+19w#*P##p|W+-p#0=gQY?ZrEk}Zgd-2Z%_X| z#q4L+NRp9bq3W7$7oQJX6)e=zQb+>irMfShkJ663sA+c~DhMlr;4r22^6Lcak|}a9 z^Cm0AMlF30B0Aws$W-md&BDc8G}-~eVwwKwy_u=7i{yg`sK2T7J{tiAWgI|mwcoZSfpgE+yyFwAf#IRd65}QSW8b7(ZNBXp zBrMMk=qZ$w4j0Wz4&iK+P-w{_)ZFod2O9}EWM~|8R6{sB*h4Vw7au2DcrW}-u9w<` zuv9?SBSE6rD2^`)BW7=T6OVf*$tbD7l?`?9slb1WL;*N##@dd2GOG_s8$Ln6b+nKD zBr%vU=pgpb6ZG(3Py|%GxU;S;)ra_PDbVlrw8yuW;E}3aVK~La#+!=5nTb20$Bl%F zba3h*hmLp`#7Ejt+0IVX+Tyj^D3#>Uk56ZHO=aih;o%|v5d!vT`8?O|Q<_TM4@DY) zHv^ZaYw^kG@_6Sae}Y~UIUX%RI=oyD1d+UL({2Mu4J2}=ZC3;M&o24$-#<4QNYvG# zcVqs@rCWoG&xr-?q15VZ>CiX#a;|I&dnmcUi6g+HOoIBr*-?PbVb?;;X0CNG1xal^ z@Fk7$Sd>2VNg6sNB7CPzEa?)f+Nl$*$zEniM0$@Rm*C(tR}eC{rlGm)Vlkn`rMDnI zf`V~A;m+eXx^>$1L>GCy-)q(yxfiM>;%aJYYM&lVbVlPp?udNR@TZ4h<*erTIycGK z>|>k)*R_%JTNLcn$#EZfS>Iai_j=!K%I1OlIQ@czc2{Bx_mW?q8p;Ot^X#VdDr%6Y zEgD1_>|`8&?tNAL0%!#QA)p*kT|e9P4Yej88ktahPy6YU2H!Yv+%C~}6=Ys?$#4_h zr6#Y^S@@@r{)PLNVq}CkF4{I)@T>aWC#be6I0C(s(@l;kG!{=a1t5@+PAO_@7y%D1 zSOt35lU1}rk=J{EikG)cZ68$&{g;mf<49pj2MwVr^)d`5u(vVf`3t|=5#FDFf_e@|*1L_}o zF|IH6$ls#7OQ^QgRA1y|w*FlH&YaI5yR&v=*{J(B22ZkrkW*oom1aX972I9zcC~ci zdaEcyyvJ^QU*tf5jh;;4mz$hZo#n+FLV*TB0T|AG1c>x#`kTTnd}abiPp|TZfm!pX zO`9fTAGZH>Yj4JHbYzjpOFtRLl9%r$LkB~Q%4VNa1kP%~`a%TxPsuH9DaaY2BJiE; zWR6t--R5Naak@q-P%Y(1XP2s`rYyZJ81!8)2n7K#^+;O4)YRr-oovA)f+R#>@(`}o z3Mp|4!Dq0|sG`xJq1?Opv=S?mXF|H5dDj~dW4B?Kpn%lRQ7s+T-bXm|fy@QI-#_6}&*Q6KM6UT876zXmPp63QQ{ zn+vu!w?uIS3(r>sKSBntPbOg5ncvbG1k19Noumr@;e#+{@R|e^ij{cRG9Mx-1cmxs zV5mOX@;2|0{uC=daS}|l-OLYc`qjW+s4{y{J0PHtjJQ*E#(u1#QWndaRT-B}Wkub$ zuBbw<+E?v_CtJ$%uUN%}eAA!Y*LYl|MOtv{ag>jYl@A`1V2agscT6n=Pxw*b(2*=i z;R-W&ZSkmBC?tLs82nhH=kri|(>vnk#P_1IzVy4B{HO21xP7@_&&03K1a^HlzxH}Q zCV1nWqgwX)gX0gQwV3!$-V<`rXQ$WC`?rq)NQ&=1Fbu4=spv`6`@CyA-gOK)wMg>Z z2L4&_hb z$Kx&eNUrKf#gL-fcp)v1!Hx=ELgnbnj5!6bwzSKv9u(nh@Cx+rIxhTB@=)8 zysPWWzgvf397?lE9YtD%));1%FTY3cjTCUQ9`EE4!$3mLUk(%(^cNeWSwv73?}5$B zb+hI4*}Z)3$|M;w*e?%|&6n-Bua=#{D_X~|SxUa%seL}YRMp}@j7#{2SJ`F~iq`wm zv{)CRl;7e4_qz-N!NqWBL>b+F&b3v|*GSwf|@B~c>YM3!91){2XMQd^aBc_DLviivq|mQ`k==!#mSb5sxAt zM6qBdXxk3(nFBaAIzEotm6_K&X{eL?Ks|7{a4J}`sMBxT*E~E>m-D7I?x>{McFui+ znnoq&)5_uZNYn_qY}iP3+K0h+j&lG2474;Sngc86!w(65pWD1!@VG|aR{H#mg4{FL zzWp*y#-gu26@8Xba&hq}Ic4q_V3HrujSI_S1!2t9jGELEP5EA+QgT{)6D4V2iJXdb z#_w(0Ja;wTcJXfu)2uacce;nNK2Q^oCK3I?K~0m~VKu^(QzytwPSVp%n4hxmUGq;B z`2m<(-D1*F^**__I;KP^9HVLVms7Lk>A1KJLbRHHr|#G}-xD~`$J_?XWpIs&mIqZ7%d4(rIKUR4%n zozsZBy`fTd(0voNAwbdF&!Fjl*W?L3IRi&k%qKMkRdN-@I2J?#A(e@L2{hm%ma$J2 z3zMXbEFzRGB znnzL2(r;di2WlZ>aS^rK3g|P-kYil_{n$Cvzfmp36n@qIuu35(%PF1yE}00SJJ#Up z9-+26rHXnx4ZcPKySD53F>PeI?&(v{!0!<&%}yinB>U^Bg?Xp-!1hAX&ondh<(FxR z!;j@`>BCy-s{&Y!R@)q-&~i>QsC$~AW>kAG59Xoo&h{~9*XFN))61nx41^S{*qKrl zT!`Nt$kXB^yK7B8!c1)0#k@|ewE>GEbkT}%5km<>Z= zd3|>usie)-d>wBoL$|n5-XBy&8Dfny&&;7=GCu{Z#fMWG*om+m2MYTBsT~GDMvTAg zbKirhkTzsO9<<$wanLAvOdaG2nQ*}~h|wGle}~I-%i7cHm@4l159cpFF^L7| z<~Ve_&~JUr=r`2&u(fFJQ-tNA@*W-iUIxamFz@09LT z&&Dp}RmRY+qd+33%PH%VPg_Y`p$j&FwgP?fm0P1jN6+_(tmb{e;9t)H%AbuD~+n{9> z2tQ|%)fFY&QPNZtvC0Zze33#nMZ!s$Px-~`D=sLD$+3~h)Rdh_*rvq)3VA;$&=D=8 zAeoa>*D_uf|MR{+p3Q};nHT|Ur0O?Y*6Yp~Iz|H39sP{f$NwpO^y-^W?8}K%DXTX` z-jbPOxyYzdz4NDOT#EpGMu^=Evgs_GWm4!WC3?U57UZ*3GVp+L4{ac|qs^ED?qq?m z7%9s<*tZhb_cJ^53kS>a z99x$fI@3CYk=w;3mKZ+r4g>Sl*~-#=Ga(iKnr;Oe6MI@w_hfXbC1D>NkgIrR^PHvm zv9muc#WzLSgn0(BQAmjI1&ys23Qo=E<0Y-$=S?W#a(0?jm|5|pd-KNZtZSNi|LXVn zY+k*N$%zNiy{M5h&hv%S@&R}_R65y+blP$Y_8m1z>#)ClYza9YhMV}&J3wI-V1BEL zGAdEsY8<(@j@T#=xc%QUoh&kD=Sr6B@q|v-ytTu(xR_($+SDiMWbb}{Qlqkf9h>(H z6_cJsIiV>urL9AfDSZizx0h3H5Vz?3q9px)i6IMl8kF6W22@$`j?J{a(vP3jyK7 z>N`N-OQ7%^2;T&5%+GIwV4hiVit6h?W^{%%DurR;KACyhHFAHt^>FWp>8mA2$zQFDoEHulCYDQ~KoF z$G|4;1Y}GQKG0@Sej%hM`0n_12q?Z4YmB(`(#HZvawiBZEmkfj!%7dk7dUVtRfbv3 zQC5h1_9Y_vBl@7rf|sqPg;@jc(4FTTVrHWw;Uj?`BXXrfI)=}^>v|FMPTuHxXf7dU z_xL9YZNcfQZGN;p8q0LOxA6fQG4PCEw)dCjh)~WxeVl*mH->SI@eKbB;7(sL=EWKp z?H3}Gt`l3YmLH4nUNRMa1`e<1N^7~#9+^bBHaBDid;E{3tBh+p+`=0<27{4~keoQW zkq`x>y9ETP(Vc>dj1-WTRxTke-6;dSo>v=~c z`?l$!5);m#Xh!os@i5usb5p)YtBhnK|Jz+qFLLr{sS=f)H@=*(^{?G*6n&-ngsiF9 zfwthkwk=Hlc6W5_g@)8+@;h*_#TWK@`K$fSiNvprP4~W@b_F(b$FBp?U+c$=IICJ* zF0O%#pB~Sj3x&+jWS)l1H+=Bmu4bKtmsF4VW`Cje^dRtrgGlEbHp-5HGY_i}oONsi zfGR5>`CFRy==mt)3LpdkfY^EGlZnJy?WUiP5aXMh90+ImBDZgYb?nC)!#>)Dg#pCe zED+X}I6?{!c`@FaP4d?=bQGzg{DVZSGDH+$#B+>|d}svL8pMLc&{)##3+bnFWZRUh zdkwudE9Yk6mjP#KVigj(wF6Z?qKogMq*?+4Yv04f4fl)*@@lX>Ve75@5}4AZK4%IM z!6l!Im-D~%=uqixsCde@Qc7FT^UG&t%aU#9UrIi91uCtE8PFIaoTnqTQ>Qe)m<+A7 zxD}NyzI7Miln~M!{)mDSs6hqlazYMA`ph_;OKYl(HT&6+TkEz6mp4o(R1$lssI1cr zxat|)%?pcpDTJ1BQOsDlSUAYN2m!uZU0VTtBjH&+4cAOJq>tY8TU`RcS5H95gZZ%U z_vw=t6qem&Tk?@KJuN|ZoKN2~W$zg2eY$6wk;y6PRtW-~oEe1{Itn1X${Y})B)bB7 z2$tr425w%cRyxTIhrDlo+|YEctte}voL<)oRBAL*txyUdqcBqv$Li=X2R`^_B#84E z)&H{6Yoc`Asjz1<|Ju93ur$h!gz>Wse;Ri0)~(8LDKxVx0B@-;oUG{7a4vXt9d_C{G+h-7I=?s>A?U zG}>MI?$)d(*F7R(n1|p*`$`;Iu1z*T-!gXI*?NO(fLz_iJc)jAn~<6nkDc9F8Eh zb6`=lm*?h(Tjx9VazMFNM5qlRMDk28*4>0eozzc6dQ5LJ{1W&t8;Y z${s;6hXXHeuT&Ob^`kOj0--hvBzE~xl)UDt6wstBMudfzpJ^bwaNH0`k!Y@^z2Zz9 zN`xIzv-&Myn8|>G8*x0yVcLEPTOl=m5-UKaNZ9Z%Mu}Q~{$RX4Q0%}Wp~VW%>R6^N8pBq~VD#t1So+Hh zCqCULS3^9$6g>&qXTCGfzg|@4GB;$&^f?MV{Jay%l)=l|2%H^zBXU;Uta_xOBXn`^ zX5Iq}CPq$51R1#Zix<_JU2J6q99LhC0M%{NTdCm;$O-N##E!;@yr2fv<@K{i z8>btcY2(7L)HSKsyG?G6XvefNocL9z>^~)?WfOJ^WrwdysQ=XaBcVhV^5RVtkrdG* zYVyp6OjK#Kn>?o|=cA-P!#fJM2t-2ZltEA|gNr%l-p#f4Q zA}%ar623?9v$!NsK;>hVh!qWHCr!)$n2GsVy-E5JIC<;!NKvaw_657Eu$}pjGni5A zOuty|(}kT6Q8&RZub&N3#8nJA4#z7b{M6w&`K2Cb52dpoI4F1rDKF%R0`-!&M)TbD zf4$O{NBYlw;h}fkVAEarr}z>z%L4?o;e-kA{H@`)ea~Hmb}Ec2l=1$~t)*gT8zql% z8nWh0T4(otkA#yj$qB&pc>3O1zsEuvly$*V1eC0W&lz@lq=f6VVtf<}VtL;R)DT;I z7#m>K$_EWl40r=11oZ|;->_karwkvQeLrNJ1^_IR;j$hdHATjTUTxOL$&`G?&kVl?!7wH{+=uu?H_I$CSrHN|&yTjpkir-k!7A zyrk*ml>pdA{hu6O4>F zTJ4(}W(ge5hM)*V-3e@g(C{G<{9X}QC(C&XaH&f(H~<`7P()m1zcsC;w-%bIml`Sw ztEL38P;YXlgz+P4a*we7v`r97VWKLgX1;*z%kqu@D~@)_({72r6xU%^u%jf{SKSM<*#Z`AcPldc8^M?6kp~s8zYMxLgx+zyS`!Aubq&xsk7;=mhv`ULt(T%jvYMZW?bxZ-`8c-2Qw_KW4a0 znW(Y)^IZs?y79vX!iy!&7lE#pt&iNRyo*TmCbo@LOjVR2cR`?AKFwkVB^7KtLRTz{ zR)-6~;Wb5*W>b$sR@~Nla=J8wp#TrtE*^Ybxei%4Hj_r@H&>N$+L<~#&n%ch(X%DD zpT}|BGSO2BP5&mT^PQiQBX^C9<~B!b5f+=D;`LGx22asq4ImGVyGI4NOGPl=2-c!V zre};OqVV8XvO9 zERD@)gRw~{roac*dWw4BFt1d(yZ2}ck|nIBv5|gm+<%(IXT&T|It)2`9?wgCIzI^# zH_fY&!V;1ivAi3i1b`E>t-OBNXmrgN7m82RYvSt{Pn{KGf zr!MaIAC1&4pr_nNQl4tg8B=pA#pD(0I|um)lEHj^7o?cD{$n>?9-9uWwN+vtlf%vI zfNMrTO%;E=<>Cl;I5n8FM8B!)wB+CdPb%xzNDuT-s9M`9zLaU_3gp`SdG87nCg(O~ za-Kt+aXAI70P|gf_WC1mgG`fJU>gyaU0QlARA%1$zM^u7hgM*O%CW99GxN}40 z@%PB@L$8EqDNU(@D>VddIT(MIcTa>nc#Qv67sLD(2{5I|j2?7haYozsyJRj9eAn!c z=N7qR5uvK`(jmZN?$KWt&~C9TOslU5snEUe}#OLqP_X-LaDhkkFh9MTlss>Z6vj(SjDaMjxTF}J-aTu zfcrq>#gs(ni>h|H6Qh02MnkJ(t1b6EVDsv}{S@82jxQl3N;YQ^&iPW~+PYB;c{;ab_EGR*!Y6Zo#&EypHFY_G|yDduFu}6E7s53%iwG zEV0NWxL4?XoV6jKXdMIJdPg7oS)V}sX#oky`bYTrm75K&>YYJc2iIT_=qhu4n)r3; zS=agNhRcUn%|LN_>|G=X=@s!hXFcQo*)5kI7bprI3vx97kWVi zhN>pI1IUdldi{;_>#nnF;0k#5*v0?+>6Ij~^-tsTDJSo{R=Pkj9dB}IY`~~1l@+Bru@$h$-mZX z)aU+E)J##DpC0jSj~r(X+4Iox?x?y_e^sI8kOxgk#F?{v+Ma;u1YpSXMLH4PE(VmA zu9kZ5gVhBt`*?m9vU6B+NVzDUX4hp2nLLEHQukQ%%mUE2+dFhGtx3?EX21+SyNEtMF+I+fX}B3CAmjeA-JFTae97a9pYc-M~yk*tCR46=Yj+PkzB!5qAG^ww3pby z6vbplS7(}6LDzV+)_&vo;`Zi;i(7khSNGF=clM6DaDR4h-1TiA$xWlx?zp^Ax(DR# zl@`+v#~Z1e{FBq>$&2Y}Vajy!l+;4c?Ce7!u|9*dgemc_+G7jqr($d}e5{+_)nYs?lkp z;KY@X*~PmoD%{MEuU|NjpQV=HFIP2wXBIW}_xos-jRTJ&Jd{*tjB+(JpP~B|8-Wv? ztul_vy_Y}=X&OdbAxe2~Rol1%;zdR%kJ&8bh#>CAhN>7b>AT?<8~55OG7cD0i00j= zY^fw7_ze@sEwy4KhCrJX5CseYjLmke7F%GT+;{ z$lIIu%MFXS#_5eYxEbaL$Fk18fpQF@=AlbukeZ9c=9SBCB3rL*NFX649=ROh=u+s@!Py4@e4R_PfkZ+zkMvGinA%thL7%3g0Pe{?Dl5M zm%vrX9ByJO)4(IX>*_t**VkSDs3=wi$N9ky4?N2KeCqS*5#L7ZQ!7N6Nm$_9AbxoJ zZrn}&ywcy~Fw?o`-`xv_B2e@ywJws$3u_Zpl)eP`#iqs(TCoopQi)+?by`-42pV8T zwai*boFcCbz7=^HVYWmp)k5b_!W1S32@R9Tn2O5g=O4+2+C^T$r1ZB9p|PTS{x28j zX}#%^g|~W@sE2Wk z?zy=B?tYo;5l~VLlmL4t_(-bq=ABss#Rxf^Aiw`Pk6}e>1C6Nt-~0AX$`Mj)_?s;)Z@Q=w&m4 zN~RJx=)MN<>4?n_E9mB9;L(*tNPs7Bh0jZDG(2_>*?LprBEi>ICu&Mi1} z4P~+Gv2|fE1~EpsK?#ham%Ni^@ec|qh|rL&e}+mUPv7GovxV|_fl*6XAFLpQHzR-5 zeu|nHtR_UtQIOt=9#$$g%mde!nt zfk8~)trpAof(n&_3yd=6=l!`ZQoP&-33kIqkLT^p@68Af##Z|~YGfa^eO=nb zCj?xLk39FDhU^@5bwqvId8!%gF;k$^XXED8o-pI;ROi}31ma%z<Nn2{F5R2H+sS zgSCf`p5&fxlqb_wzD>FA!1w>RxVn6<{6+G2%K&2#%20Z+$Z}b@VO`*j!`oi6iu*O0 zN~Fr+Qv$?)K@)rNIoykS`3&AsG>_MU8Ei{4BH1#-QO002yIVk@>D|nyl3DDQ|0zQ= zapi9yP(#q$QdxH@e9@ZRC|M$T?6PBDxz`5f=SO+EB*`gFI#XqPnf9cjVPF%m?AFYv z{iwxgP9U<{gTc(Ouj8+s6o@vM1!vq?ItE==q!bOBemcujfvzHjD$G{3YK5rs%HRyAncQ!I7|ICBX3sdD+`tI7@IYZo(# z63JYda+@w5rQ;pK(e-yW!ptcO1_~OA{-2;+fnb8r&&+Dh(S2ZZ60&M`AIy!I$WpQw z58ItaI8Z0ENJUU9(_nNVQBAND>cE~;F^ZqvK|FzP*4~&u+doAqn~SHY^Ipc>Ot)&cq-Rwn78R|jk8w+HSsvYirjIP!oSv@#4Z#_* zzpjWW|?IPCIjHWG(CUkl>`64W$C9pjked$8B%8 zB_`%&EDge2Y7X2h-&q;QoG3rfsuzB1NlMMQ*7$XrcBZmurowhJoF!E;G)#q5Ja*qT zGA5?#C4RAQg#NI^EjF20je#IOm;aaIGUTQf(o;SKWETg5fDRC0JZgEtER~5b;6XE3 zq}J=mKaBb`*k9rDsy;Rg6$O)0`M$djzi0frI+ zqO!jZX$6350|3A|rNEBLw&!#^GIr=GV)%TKcWDW*!iAdmW#0L>OxJXmJMs`IlHO1l z$QBQa)8%}?Wl=j#ax|3hrbLBP;~655KWTu$ThPg10at<9+m#Qum%=5Q8saeWA1q+u zRIgIl#hncvByZP#sAQK>b@-YE8_Z_&_@gXZMp!>?z9>fl6A#iaU{3mrjkav+uZ$9^ zd}W7ga@Nc#{zpaP&ONEAOiGND#c1^Z3eZ~#vcuxgvL09X9ziKtKIBqn@BGCj{RxSN zX$Hz6->fGpl33`cpHRgh^?RLob82ho)Ep=Y5b`j}jxx9t8f^@-j=Sp@85Zq~=Tb3X z2>tG>8j{gY8tG)>VQ`%WPev^{ez3{^7`7s&<+j+YxgRd4E3LE9jmnl!Z$AEz zzS3y;b!5s3*YSmzfq{#5D~-9dMyH&_xuGWj92d^|tBUc=>4e7GXNA4}nMzyk zoSDd=ih|c+8ZxH*+zZfbx7=8|i9nsnHQbt1w-M-`QP1eNZ;QHYgz5qqQCO>twZ(gC zDtvlT1hrCVy#$J;R~4g{oQkGz|3hpZ1hKVWGAC4AwGFjNt*h@TR-t+m|18-?W|BN7 zR|CR;QYI*ckc0pi4tsVAwY_lfSDYgn>5^O|gKvomUYKn*LFL#%pb=yF!?lMv_fQD9 z*GC0Z18n307FRrl%5bSD~E9Z0l1n2y1pLGnjC!RFLXD^Fsjp3HrXyLD*Zxd z?lgPzld$t`NpGge4C&rww6*^ueTp8qm!4A8NLjDoG&rnWExm-63co>=IA4~vznwx1 zuD{>nj(db)slhk3MEDi7{ztU6V09WyN>+>^)>9Ma7>Ff6dCdx}=Ne^I9+;dKJ4{tj z(7`({C>d-NUet1kZHr3@^2mE(R@13^f*5Ol0l?OmpDc~hnoQ3FKNi53mJnaJ`Dv!| zL7?I%uBo$^*ApYSFFC9`+qt|B`Rdb`ICLu4a^|Ndl#&|)T;~3|YCgHjt(Vna8mE}a zyrL`2ei}BVFz@^`t4@QDk)4>8grboSC$kZ&>hdQekND@mzCXT;0TN{y}(-4fmLsJt}h^xnq zu8EFz2AP3fK+_sd^nTHy8lOer-)au>ms4|{iz8qSX6T5F|7{TAUDiQYDp4uDeSEO7 zO(ng6*o}A=$|r*-oJiG=vG^C#Y={dR5_7ed^uDfHPrpfcn4vtbrh;B`bwp1v$jsI9 zCP7Kf*aNYXq4VcSmcy{i8yyjCUHMqvzN8vj_JjRAV&Iv8MWXP>dz)Z!w=o(F0&knmsq2^@0RNgo z+y^eZEHd+XDoZYabQ3DvXX65e7guXPew59+blG!n)GdD2X+k)yd1|H{sq-o-S=fjY zF~sC6)ED-=-X$y+4kfF<9}gF`@8=7fCl!Yi+WlmYMp?I2Q?r5%aK?T8AONIYbvnQ3DiPTUMmO%qHJ$nX z+a`axj#hZA+4gpXbp(#NAyl=bf!ruW9WY(Z+@TcxPq#4~Nl1L7AqG^CAR@_C04dVQ z;rb|T23^|5Zx970-1VlKQ=ppD1IoXhI8_}g{RPCHur6l24W~LxR&!s7**wQaqW}tl z=q+*Z<|~;iWfxQA*()<3OjB_-q&fd{^VJC+PQ$lpF?MW9D=3;=GfUP|{IY)#DXJ4jhiD|SB|sAT z#Sk_rCGqT2i3)sJRggbD^A|vloqprj;X5Lz&>ZJdyGUw()mYr_ondXM+b#v!Qo?&= z%$OeuB5JM_%%(UzB_96<{dQ#2x;y+W9fXX-<*Uxh;=c?pt>nHDly)BZ2I1}IiOs$ifXcxteLki0#XAx{YeIuST*#o+ZtX0|!5HpDbvQleN+a z@4Bj|k~D;aUn5CHs{t$%#|CEVUhC}+e-kw!O)eABk&-|gXiaJSM6EJ9WceyY)t3Z` zoB~@PV$_R#hiG2W-JlOtk|~|E0`TM0l2cJCL04U8833F;aHK*YX}Fyx{nLVJi@6MM zkYIf5?cl5&InLmvH$E56|Q6LYz- z$y2nyMtRYEoL%jQi@Hjhqs6326>lRF%90_dv@ZM|OqazS)L@@f?2*1x1rH~n{mvdv1+KCyq6(#XOh*M1 zZQ?d|B!piXOKT(g@u9N$*HSOhcS9X&N4-4OEH;K=A}lC=tk9tz|7P#Jwqc-1W@M zomt5%s-+*L(gWqla&yrr4s#$}o!|`z_qwxd5%b!5U^4uolbu;1Tb%3!j41^@)X3zr zPh|`Th!U~cvg}b-NpW%MgNuW}90A9h7N(Afm?Os0KWbaAnU_1bd+h0n7Rxl8vC+p! zTX|AXhMd-LOn*=NK826b?N%0F<14<~J{;e|Nt4a3mVgT{B1zDXgqwq|{9-K+J*99b zVViO^7zg%@V>3W#Tp&a=V^U~4>u45`K2{Zt0mIUG=AfbNwn`cZMt z=e-mF9RM8Z;v3d4bOjh28r)K5GYXngL6zFIC7N`sbx?9Boi1f55tMyM<_@lN&brr) zeLsTJ353n7^vC{3@(Z&b?ZcF3`KI4Sa`ho2-?_pfNZqr)S+b*QMo8vpk|25a2)V?K zi^Cg>{bX4ocg=n^n}wj}ybg&I^1UkqdUV*6@@64~27ZK?*4bLUNS(mq7exS|-O{P> zpkUK1BUX@9(AsRDf<%|>yBYlcKeL&RWIW#TLjTM#A0q_y+|R{-f&Vzzl_$nlqIYE)#G<3H!lD zA*`L(gy9;**{dv&(tVC(8%pCGx7)l**~-*rw?*qF4{gVI5;@7ZAJsWl!(YY_6cqTc z!TTgog)}$B>4Z%`(n*C62q!7j=>}RR8Yi4w-LI;wUG-wgj`(}TpB+;wjI!v}(o+58 z(<~7IA{Cvgic3v+y72A(4Lpo|F#(`&x0lKcDYr&%&J@2)t~PP7DoVS#AM+yjGjMux z(seCZ@`dj8jr$CU2({At1g|*+W2eZ{Zu3^Uloo$foJDaEqKP3R9NhBtL(~+TsnI=j z@e=EG1Stu(|N3V^>2LTDnK>ow^@F0<94sVToxpwZtai6v2E=)=RIh}_N3n`}kg~o{ zeHV_Qn-nRs3(g#!ah*A>TdMAqbgfUXdbK^YtbO!9$o_O{u)b4l@L|EQ%5+?CYx3e^ zxw){<^#8)o`C6q)4XLmP32bye)wXYa0pMbJ7E3#Llju{UcBmd9go@KCvs4{KY|ZyZ z31SyWAkPE-#wCwdRPaG59ocYv48+?w7>4kT@ ze^wtyHc_M0Pi0?un+9%p+&ozgh;jZzW!|EtW>>W}N#od$r7*SURhiRnlmUS_3*K%B z&W;`?U;h27Ia&l<0be`k{ysVEFEn7;N3WaOI#|{ZpIM1mje9IAz5*+^OXcla?gA|PA%TQl&VhB@g948gl7Z%Iz&zX^O=9`hJf5sTf zEIvcC?YOH5Ut$(`3FOLd>{_gT&53wo{v@qdNUtZ4eN#Lt%tO6a6_W@6$0q|inwi

    hfJvH12ImhnzjR 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 z zC<2%XAqmLQRtV-~(qBjAu({s3bA7vH7s3XfKLx`JXqGCDO(|V1Ve~}e?3@_cjLJvF zBZ81vY6_wPf~mM@$T+A8-=l1C5jC+*crkI}q~qNL6pnnJlurowi0&AfEi6QTf5ltN zo!dLs8qv>`SA`KWJR14M;!s8`KdBgZ*d#%`oI?^NTa|*q)6i>>-`Ey|zPV3nB1V0O zW&*=wR`6a+z~wkztqGH_rChy)UAhoKMOaX-t=)rpqZY2_|C|+A>8PgBYMzUrK|n|5!qV7Hyx%mIdl^)m(|J z^TU~{m40z1ONUM|IH{0GD%bLcr&IDqmwe=VnNRaXBEs{+B7yWkXybp@fWc*NPSVxo z%l`r476vDcN2(h9D$|AEG#2onN9ib7?;E|A=!VzX__xaCP*y%cT*n75D(x9()-%wZ z|94Z}V+%(RBUH`+wq1bQ&QAJV)3E~&XL}{5)N=<$M3RpuJ!|+{DuEbtFNa2i(c=~r zk2>5Ri^@=y3^$PLN+5k0P;kh^kk4Sop&yAx!=XmJ$}&5JbFai%dn%@QkG_!d#)emr z)u1x+Sl|p=B(S3+E5yjl7-=aR&eRe+P+Bc(=2ENOXG(DJ2QHe<0@#5-AltQJ(UhJ`!`-ic3BR_C#ade_ zE~LPdIWc)L=W&-$8vu`wwx&D)z+>z~UYYf~uQ8U0-_M4<=A&9W8wlxzU6h(jY@B8i zn%6()%h9Q4Fgyj!cEjOhRXd|xP~akhk-%~2zY@T~QT=XBT^D#tQ zJtNKoITbFLAgfv0&m*2uM?&}8^cpT_w&98I)-VoGX`;;V6Xmgh9!ZUiP*4Gg3( z^yGHiP}FMF6#4A6wHv9r(Y>!ci8>vBnFF3?e!4qP7+m?(H|WZ@VY4?(>Uy9X+Bju5 zJm1GuX&0!-P$i?o#b$;WEL0h`bcq+-EU`J+z>#0P$X`EP01wi9FjOk9q$02TEzKbg znjQ+Tf?rV4x?tVHe(P)g>%WbisT%_q zaFUAiPaU^dZSvS1j`H&rvm2ojJXAAt?i7b4S||H|EbkiJW|}j!ELC<($^Do&l_JoQ zGq`to&oi^^ai7;wAsly6gB5n5i!UyU*kp-b03Y?}b06=nRvW%4_ zQ)8uVY=(NEX+HDCL6I%cY<^&D_QI@sCVsOQcyQ4HfXZ8^t1e5s(g6td;6tsp!5s0+ z^YORgMPson881SXbX*God( zeOlLSZ*6Ov zKvpPl2RwMcq2Yl4x@}8>U+xu1_*7CGV7R(PszdyJlbtLPELg;X<>rAE<)2J;p`l16 zo{7dC|jpSCU52n|rS>u}Xq28SZ?*$P` z=gA`0%hL@@hlk58>>DKw-+6>SOe%_Z1Qt=JDSODF?Tk{h4H^hV}~?_TUWaVS`LNig{sF3JR?m^b@H4bi=XS8)To;b>{7?y;a2`D*gR*g9>cr}DI1G^*UIPs@gOJS1l z1KF5ikmw7OV8e3uN@hK_+Xe3=UU#kYv#Q_ELp&e`q_#o|AxFB+OuRa$g9+me#-}+h z`0x>O@`8X+0c3lOluC@8dhwgRIuU3RcWxa&n&ytM!~3t_{)7 z1J9Mwo|Ok`<&Kr^3fASAUX@#NRy93cy!-DWCz$Q^cNa9WP2~yICXm8EL}PQ5M=U;Z zYTb|MWrU2>Idt4qdaP&6z!(NhCOQMX_sg-iZOUE^dtGY+R!f5)B{Mj-Z6j(x=xJD{ z>L-Q-;(w}KY88zdf9N`JRg4cp@y!JHjO8^eZhTrF5avpuK%-TNijOH|uiDoMK0`yL zkfNgCL^qi&X2j3&butWZeh7WmN}3zBEtU|KVT6dMhN9z%+?aYRc*w#LKYUd=Y2SYX zBa6`O1&4k!1n%GYWW1W%jT8Uro0A~p`fwxW=20!}Bd^)mw>z0>NuQY~A~Wb5{%hX*4w+YN@}Fcl+Ceckggp5F1p5bFG)k ziwHJ{z46PlEzY3*hhE_R!JIWczDay-^(4@v(t^Gx^KY?|zZWy^&aNPa`5bcztbXug z@Zm~ulgs*j&P1q^L=)jFM+a|&T$JoPK0Xo1|5}y=`||=eVcXFho<)l9_8EUzjw?~Jq*__@W#R{$2Gf%hLkB~LYLWZq z{e(Kba+bYh=+sxzJ{#R*WvUMu2T{y=8F2OJLTF{j>mOF^4e2GfAFJiXGcWFM@79(e z-`)rfDf$P0-0c(}o9U#+oa#zx~~TfX|I2oLH|S_03-E03bDTo`AzX=hFVxBHN3N_j!4Zb5m5wMSi-_JL=av zW2PVCojT3JKp@G>G@e8(2GFQN*f~)}YHYkKcCA1ut_e*=@0Q!|4sfyvY3z9tEdqlf zPBQPUl)VL1RBiYFJ#>SFbPLig2+|;pNH-$g-3~XQRu=vX%W8d98XP@tBz9 zr|W@o;i}WlW;c)CM`b^Xahg5(I7j> zohkVoMQ0tew)q3++mHz5-BxKgzeG2<<^PwQ7X(gESp9&+4&ZPT6*qJ ztw%(n-yiSraH)Q?VYY%rf@R{=RvB^|3$yY?yq|=V;_BH^|o{HDZNT)mL!U zX#Mh(62>%-MdxVj2jj~naD@YV~Ji)|tY~V&k2*F`8MjO=t{v z_|ijrSMx|^s&O*kGv=*k%8+}@uLTmN@1Nk7P>hlNe2pnw@;vr4W9PeekKLoJkaY7_-dYqtCe3HMW9)tT zAU5E)qRj*!4f52=H2V@Q-The~QXoOr-|~5$nx%kb*uTHv`gcm&9le1J7L>&te#}g% z$mCa2t@fGJ!*!{o30JOKQD~3cU7IO8+u5D0Ow1DfqWrz*6VqBI5A|^{-_!f79(yeE z7%%Z@XNacnXdBj9M{nm96($s5GVAnzJo#`Jgk4U{VxqeS;-9N*iR}B4;hrGKQ>n-u zo4;44N6VDj4!n0;eYMC(XyBSitBFBO1>04dkaKUgra%ravy=_F^DhQ=U)LPZBeO(* z8VcqceJG~CVzz7LaG`BUXq73}kRd2na9~;ab5?_El@$AC=}RujSLD(cq5}mcv~rCD9t|ys=4y1%nTlMirh_gT_ZHhqoR(QGgmVHikI10{LenwOt}xJs;;h z!|t?uw?|?4>x=1=`CP5XeD@#Ng${0*J=Qn8Zc~j%jJ9B-ov7%U%qonIlep3P8M}om zAn-tXCETX1B%@mZ_o!2T)EvLSF=MA((QF&!*5DKvB_Bg3_vubW&IQqFcV|l#2L3Z@ zLKA|xOa&$XVV7HXl(Tqt6;s({92>XXo^ETW)3y`6z;qkDO-PRMWv z>C|)&6Zh@Yj#WtdNe8s>6EzD3neY$Z_8duVcMYww-bM{XE!AN=$fw6SlECz#$#c=r zd#l=gudV)NbPuchB%(eBWIeY6H!m=Okjny`Ml1zT)wqEmN9~84zbmd^pKR5RV$G!qAF6oM7#i@ zZY)s&VMX{?r>EGQggl0fLn66R&$QSS1n&3z>|On$D)s5fQlLwsE?@EX+(~0Cs&Pd} zWa;rl<&ghUAjP+bVs|8UnlexPv0C%)d=mTAKr^={iK4Jn;pnKFUQwJRxr-|9JS~sG zs=_!GOL{AUY-1KN901ImfJ!`&H$zOj?kwiqxrdrlYzI7B-FM7DEik5&?xUG^uAhi z%#)k+xH2u|7ffo#ubWx6xyk9}EtzjwAguq%6#0{34Ou|-Owd!ubfews$0r-fmKyGv zB&0Re%$R7SQEO&DQ$ccfYBQc~5B4e=Ch!~UPUA{1l~0%R5aMh5GGzlVsAvBg=+Y!t zIsav2LXBxpp!<-aSO50cX#(M(v`km7K!PfJB$iVqTGh;6qr9vP_aS+m^*7!6itaBT zsqecky{+oj7RG7r716b0Zg(Ety;tK|CZEkRV4nYupN??rc-IvDDhTc7+XF@%eX6!C zDnh;(KTYmfbVZ@} zsea5Bj2iRY$`%25B*QBeH|+#bhL_}pgH$3)j`kLGpZhsk%byG@quCAko?bMmI*EVN zaFbqcb}K$5Yb&Suo~X*E5rSEhj`g#^{N4TDoMKI!_LOb)c;Cm7nEN|tWs~Ds);(f% z9@Yi!rIN1$(CC$tS`5Ta8c;Dl>xeEaib_!RNwP=T#Aa$~aW&h9_%PHAk>uf(YE z^$)fKL%R`ye~=DvI?(q9?pqCet3KKDCKF@>v8Fax7+pJ4doEO*pira z6u&t(FZ8KOJ*UKqt?K*0^O3Q8v6~xn?(2Jp$iD85`7UouEbr2=ERyy#l5LcE>ajeS=hd@zbnc^4Zs(DOQXuFr(SCW>)lV!)GRRriF=Z#!>>mE2@Eq{_Sl zRB(<-#3O+Gs^3s4-7!7)hP&PRTu7O9bX%#Vj;nb6;m3Igoy|BW zj@L4tJ4xT)eiklH z_mMQruXl`^`o(t?*1TJl^ncsYnYg#&y4vt$0 zSP=4cMb_NR`$9b}$@|(3)#gp%&-xnlyGZw~Ym-$Cbj`3v1}+3BG=F?Ud-u9~seJCR zE6<~~`lpp=1ONLgUmvWVeJQVs_o}uT&ewLNw2^vwYy{Oy zui>v}C6RsmRHn6qBoM#cI>++!X=B_$Qv~7jP_mxl_#aZf+?hE`vix417M57E44(!y z6<8bvBlf~y+EpZO+8Na;qb&+Ws~g<5NqKL@x<4eoSfD6OsWmB;T_N>wuB4gqqe@WY zDzWC>yUYd$R`{B-&!-5-Bh;n7j)?6YYeqf(S*?<_qVCn+6zV^FA*Iq5q4YcQM}U0) zFPE85Q44LO58I@ue4>YMcy5z-yhvr6;p+GhkM`^q=e~QVMriT}mXdj6+9y+a&X31h zcv9SqgM#nrzWC5UILTbx;{Mhjv+vcq)!-LS3gg0-x3T?H?_Z_=j0_Etb42q6){S#G z?%xa0eC}k--Pt})tHge)iYY=T*?*s9=mA5qUq>Nv!I(X%yEX|nahhVA_2V7p`>Okb zHEC0cueCWRUbNJy{hFQp7S)V-MtHEswt3IX@Vj^7gHaA6Uvzx@HMW@+bJ3Wq=QHKu zA<3BP-nG|*TD{{vn8kCQqA6$Vh3~MX-sZT|GJ3zMDqd?h z*38}McX&d8#X-M;0*xL;m$RZosa3^r%(RWokDa20qS2Lx3 zj2HMtGa2}lU$o~-R>RZBH?tn|JFOhf)Xq}sYqU1GFw~YI;1++)Hr<7}&UZL7>c&|> zOhVXo-D$dNvaUQ?8uhL9Y>^k6+Gi*Dtg@Ohv~f47&?mw(n7{k87pmz7uXCs%O)z>e z-0DQ7KX#J*e5!SI7rE*5n+iu#8bRVSJfzGRNObR=iGCP|3FfhgYxjN0fH0(Nd9mQ*x`CO_R&olSO%vFL^-87x! z48HVe_!7=>6ehS_ulQ$W%up~=g`eBC-Maed(5_I}zl~e|trML|(Ti0NGd0nyt&;vk zdZcb&iv68CEU`t&A1rukm5+DGbhyghixoH5MBK*%Q>Lt+*toybbWRt4Vm0>a5bw0C zl7XxD>8a6bfCZ97#Ayx>Hcv5O5cM?9FPj7*&q}N5u6pCnDK=ipR3?v~h9)=K#5M)* z^3Oan>`juo&aJQWfJzI8bM@)QhMgtN()a*XYR`|Gz`yj;eT)LyMu{M!VYdF{`J=n^ zCe7`-x_SzK5$mhQ4=nRA@~=KK8TEe3EKQ#lcs{-+lQZc1A*{^w)3HPPn{DqQ`!V9N zv$d&UGg(V~r37z3S#jO3f+e`G7buRb23@Oe_w_cP_N1@Nx$f|}4!ezw$TfZAZD4EC zut*eJXni|7qI0GeKyy5f`dK0PenptA7+2L!;zf7ZX0~wunb^~5m1Kble+LvAD-z8Q zMvu~aCw^b0jncS7hNhRF9(%NOJFRjQOL;Tyr|hRUD%nT=9g%Mwl^ayzNRpizCEf(j zI_(h9ryC|B?Y={vn>cV7Exfyl@ir*lv6O?Rc(wOz!sruG!K{8-AVsKc(MERjaL3j)Y`u`(`HD%5 zGOXz*=*5+9Xz?uVHJYE|2>VkM%j8LE2wg8vqc`Bek99?v8z>X9PpW!G_t=qF+3{7Z zuxXAspZ8hTa%EI`v;+&+XHVp&oUq&S+t+}%;tfq5Tb{g#vh7{CZ%1K@ZZtC?IN_yE zl_GD(Zt>KRTK>mAdpP&2e8*g8zqR~IQhj2%Rad{dRP&cKQztd}}NC zC?0*);e}&Cgy*{1*Ss%ip!z1YDrysX5LeO3LDNl2mwBIRhu10J4J^@0f80<~e)_U@ z&NF(Kr-E8$uF+wZ$mZwvPcn@A5()RuQrZ0-YFDX4&<*n3rAf07tOV}fQq|mbj?6&5 z#8E$b{KVlS1rWe@w1`U;SAhw}Qj5_md% zyxC^BH^@}n`Ru2aW`czq+mC9Rl5ZPhb(?&7mGaK>=QX|u4(P8A>^Hdr4xK>iwfw$I z#x)`rna43rnkp4Kho@*Kgo8C zzVq1@g))s|r}EZ6r|mDu3Fw;t)#eZ!{;-%Y#(tJ|oc2e?ku6_7-@4vFwRWmv=4#W@ zeWd^~lwUplRlW&Wl^XU8DW-gfK^ak3G@C=dQ}Jw!);jW<>l9=z^~NqMoVe&PJ#*mJ z;hez|J-8{6i8{?&{SqaiM)`FS-@R{CG10@TEWXi?_;Vh4l3@|P(j#Kg%vZuEz^3$S zJ}Vx~mIwYG?2xwsXx2Oo zUEq>Dp5wPj^&yJtNF1+`y)QRd`O)&GR5sp~3PX3EP*mP|R|d|k=SGZI`lI{$w0e;G zO-Llo-{yQqvfHF9dVy+c{2}dlo^)Yix>+}$*Q&o`!!?6en=C~46cjR+B&??%O8D9ACOFp-3mN&1Tj=cRld*w5eJ&m=C7k^FS zm!ar!VKvSXMb3#~?*8A0-cq-RdksXUEtPkQkWD{taU^fu?Msr7z?S7Ry-s7N=oR!T z^Zu*H7hy3-YfD5W(Ib5|m5gzT&y)l2>Iz9QB@WhK+m`zX`jUg;o6$q7Cl~wxyZEO& zV{M;cY^x@D-hJg@g=6tIYNgTBhE1VHJL6HhPrju$C%BQ_tTH#Y5LHh9T*@>m>qTW| zzv?88FWPovH#aDFHT=iqD=#v=G_g%g`(NJZ-n|Ob_~%Iy!h6@xTUQ$+hptC`JPefS zcDDPP6!wZ*X#Doeu0WG;v?#rXlOO3+^-J}gPu>Ua9K?abD-=%`pOqDlX?Cfvu-NZ5 zB8T&$S6GN8@$G8LW%g?nN|8^;%w{tsG?qP6Z3<`F-86C3vU}}|*CeSnP`xPmS`&2A zw2R%Q$XRyGTKI{ahClpZUP1n#^7}yPi)A_40;x4QhjOqyTPiV_q*`Kb7$h zj(dhOvHA>bhYnZiP@WA4t(BaJhimsA{*E3K)R3uIZ)wIIM_LehM!+vRNu=n-#2gdz zu$|uVeah*r`!a69HxHS+JbVi#2TJj0le-JDvdzfm%Nf)z!j?Hy`=8@vN;*7JiQFs8 zPxpDUd3VN0`=Ljx4~JUUuNtegXzvWxi^mRMZY37qY^;A+rt5d{>xHc_t*;hK%|&Vz z7D)ceZ}o}Z>2E3ATPD$EX&;JiC*QyxI=V(>@s9j%;^s)NZWjZozSLmr7_KWZFM-v{ zx%}gRr&b?z^3;t+UIeh2%2|fhil*AmX{`^_I8%sQ3;wUfJ-YdC%~_1jDm2!G4bIr<{Sk6vDk>(@E{j+OTyh6T?& zoL_X(pMU$6K)P0VTdkCLp)B3#gO2SBIy20dxTlZqIX4}vrHNFPNwAmXu&VXV3w=@rzQScgkk;X2@jve6m3#NX%_9UkQlJc)clE zTZ!jQdyr@_^{u#ib%rT#3iGhYuCwyDGgd7uQP247%8oXtB^bWH<86Jl;m3{Yr}Whi zMmWwF^Lh1eZl=DUb`tn7yxFz4M~8OKxJ6_Y5xU2?%I9ujaU;HNQ_%HWiL64nik;NF z+CtUuU-IuXByne1F;G7;U)NwB+tTXKd?qNgqddgHeu^n{WI+A(2j;JXQ_G$$Ufj>JO{+spbJz#YpjM6LJnnS9@}|eYx$4^~4$sUL~H1 zoJigqw9bw8ptu=!{@TH&3jO>iXY+aXLZRea^3i)^tEy= z$JxP}f|u&YD&f+x@j}o+3!SIf1=EP)O_`8LdA^PJH)cb1M4zcTQMT3TNT>EB&eS9f z)irTCA6YpRC<)s>@#Jia{w!$1oA|BGoqypy6OF`P^7u#tsY=?lbmJN{hRJ68y0jN; zRNM-deIxHWR`2nb9<|?93TXOyzbFGVL5{L{TYxjf=H~!U6hmBTlv`b{+rdmv(!BV+ zTI^-=Q699H1dit69VAJa_ivk3JPK3Y5DX322;>+KcjvO#0?dYFWU7tfw7=kMaPdl|FgHLx^v%JiU#_b1*! z-hEpfE)nM}YVWot$wN)EkFQCQ^xBu7bpP~}>vMj;fqgtd+#LF$MP9QCe*o6jP5WpA z?-{GOkXi?(B|?kQ6QZ+$dJVUr?R+`u`x+x54U)-T!tD>z>OFtNl-U0W#~BN_H%~a? zm;pM8Aj{dPXni_G-qj+YhutXoqKI)^m^m^~u3*f3P{qi~G+1jzha>NG14wprx9khE zaS%Fb)lsjCBvKKFz*1CZo!6I~>z=);phbx}l!%F`CuIRjY7ZDb)m9Zr8#}&!VK38M z+EMJP^25SyM@7^AgOP7_d)m5Y>Q%EsKKkm6hHF{5(0b;Y*HX>o2o88MXd_oX^&Ml#cz;3+&W|lnHf}S4(WiOE%eL+82plVTDOD zw3JjDjiqXM4+V(yd@AH0#YaC>|M9E1G(SHqqebDuiXrvXr!$DhHSwOm9`+d(fmPV% z@X~J8Wn3nr2>!!={zDF^nX4<0hr0!j zlbM|}kGquzkGGkl7a)H>6;llVDZ2mtDJ~yjeqKx0KOe>fJt+}au%g6WIR-xDhy(($ z{l7nKY3F3+?7{8p1UW$XA z0t-}3GNsD7N$&j@)@#Ct}M0_#1^u1RSC5Rrq4cXSP zL{;Gmc-=`$(m<;oOs14K_P0r$~>xBQ_ss8n0lvN6_N8 z#O@Sr2-D;I#xCjp>Wn5yQ^fK^gygv~Ia|t?Jme$N`gCPH{BlB;hq-N*)hzn65+~U0 zPn>7wr1uifGgZHaSsGVnSJD|ZMIgn;wXo_ zS6`49DkELvOFaFCeK2{3(Nxz#ThcdUoJyrRx+NEzYC&t|@% z_GEOU4_11mz1C!$7-}7!7EwXqE|qA0^T|+*M%|s6&+kT153t&2(3Me-h}e|qW9p8n zFdlN7`T82GtO*(%t#jV;IGm}D8`-+iRj8;jJwAz`s*j7 z){wy6`2b&H*M!a*p)n88j(B2;Zj~O7{yl~}z7LQLW_<Qh;cx>VZf zQt_X!>nBP$Ix%IFK32&-d;5xG$3B0GW=PGe+1tsrYlLEEf+>y_t2$Np`ETPyzfWe; zYD1O$#NN&`7EHFsE$7_(b*{9P-%%{?(9-=VIvhOf@vL9FtNVfGIC1%-wf}RpkW>FP zUffo}Za1tvqVf2*3kjkHO~l7z?B!A6#cvgZQzrvR+C4i)Y+hyjZOXK{L+wMYo?c1NAfd08zI^0f7kr{1CURyNj!pyQiI%$4gBUhZ(6Wfdng(oIeWgSg`Tk z!9tfL$v8rZK~bA&eO}|tY~oL6zV{*ebgRYZH4X7E?JMgJHqO@G^7~S|6lJ`-$+v&V z$k?OCGqBG5SUTH2b3|SE>a&mkq%icOZh{t(E`##wyzG%;@PL5JGj$Q8vg<_3m|RVh zwSoPrULzb8T~5y;Kej5`n)y_zFPIhB_bFOY}=Il9k_wj7JYMpzJZ+{9OzBBlG?=<&aGmZlA>i_B>JJC1C=NW>}z9&Do z3F_9W?OK-}vgaAI@mL7qmf~f{^ZO7^^EvK-hi$m}Q=IYRc`~fiN!n%P<4G*+(rCk{ z^URJk-$Qpb&eR0LDb~qHJNfzzZx4NV6es-nTcTeR@Jr!a1j(+Q{u(MtP3{3Vuf@6x)g_4mJ{?u^NRTS!vxQk3{-L z%1x9)4O!}MIj&p zVp4f(?STZ6*CNIAgoh;8-H<hkT@F>!!zLSRqc4V-pMJd*GWHtQ#Sl~3?B5odY@zOuyyIBCeNkeyi`@v_aM)RZGMXq)J_j#B(Jwf^ zGgc;GGd-yLIPkY!=9l1n>PEDk`4<5g__x~X9y*sfEe@-aM)Ka!?`Rkg7ab<}>1JxJ zp`G?of~g(pqbzBj?e|FnIhm29!Ih)3eajx+l*k%UU%pG zG>sk~oP^w|sC-?0+>=tSTjacmjV*cz`~&M<^Vh19^N!*@!`69-gt88M+nbN;PBNL_ zl%&6eH9&Dx6At z#(?j2BUZh+T6;T2V<=o}j*-4HCluf{YOP=!H+wkKvByL)bWZRN4E3Od$-@y>H%b|r?Jc(>F@`nn!yef)UX^{Q_IiGX^}hT4_FIh|C) zd7`^dXu;=hgS=5dW|o|JxXEzPBdo7_GL>Fr#=i-~}xQH;-%1^OdY63TG)f(I-1pNk7C1Q{IV^{`F zneG*5B=(!m=Q=HPfH-kEEYfMzQ+Q*^Zr!VHmG73PN;Z_wVf?N^jzQ;HJ{ei8UwDf? z7lYkpl4LgZk>3-;M-u}qohU_OgwmWG$suoKyBxdrqNGYu6ckS0xyf>&u3`#?RJ?D0 zYSyY=XLs#gey^D<%kL5`bazRLAxSVM7J z$#?s{<_T&FwN=vZeB5M`+Cjd%n)#lbQlt} zNo}RyFX+6s$>y67!P(sOBdnbuOcrSUOrH4aL5_5daQAxYTR0L--p0M^m!Tj$5@RQ<(l@< zAWjhx&zr7lNpXqDb-ME%o@xo3com#0BWF^69o7wKSbIxY4Cbdi>Ty%qYvF;X)TX5S<1x8DIVcnyqtf?Z8S1RYo zR=EM%O>Ora9h^6FYy5*ZdYeqjCqO(|*l9f6W4x7T*x?4ol{xp$xwLBB`Svgib|3goEXvshJY$!x+p3^xgaJ~JW(1?lS!O>5)4&vv!;`-;GEF?13 zPj4Pds1Vh+hOV+jFQEx($Cek0MY}3TY0ZvYdp&@!!~RJ%{)$rJo=~DH`Y#j0<^KMf z9lz3BeMQMj92ybW_w+)fa&8+VMd+UAB{VrtTFLEOUyJaa`xRKPU)A>W*Bg)7Az_it zsSRY740BGl4w;QASWkQAFFb@b@9p6Ou=8F!{w_J?$KOTW>U z?$Xk{?|4sx*l>q+JL>H_D`{rqRr`nwT&lDx>0MimqX79@x$OYyFCvxi0(Zjl2fox1 zc5^{4gA6%ty|V-PuUh%$X#-p8Jk>VZ0Be) zBYO&37Q1Es*qpzz7WWrupT>D(zkz<$DvC64Tn;_8S=-+DE3U+$VJE+F2YIGB4~{a^ zn0j-5Gr5ynT{_#$+Jl+|{(|^gCib}vaniRW#S$)#id$95-9wW?a%SzgUiWm>6Vj)t z&Q+(>^n6@*w%+2L?P>2x{5s+G@U9X?yLLl-MKf&T*!7zrdaBnA;256SUV{f3&mS zgtiTibeZ8*m33G2?US(vqB%WuFR15E1c~!`8uEj09WqlvFFE<|!T~rI6j7D%s zmqueZP&cmb6BF+AK5=9X$YWSnviPwOZ@HlBd+6NXYUKBjk8CC5z|{r86{}d-_s?e~)M^5W7*S`MrH8}^y;;(J|ZbPhXyx|kt0e2fIwXddU zS#d=U!v=d9eOd$L%8eyYZcm5V*5#w$I_9``8cJWNL|{B;@>k8nXql<-^Ba9zj8m219(pN&r&hR_-ximF%W!AesZ^yIw8ls-Qp5OI*=p*{N zMZq|$T_kp$nS7GM`s;~J{b<*%qR<#@96ztCO`o4>nve*3j~i6w2~Liai!49KP0*)U zy4Nz+^=MHz*HYFX_6N@Aoh6GV1G6(>!}o<)^I2a#X7BQu#3pR4sOmERzLKgFDQwC) zu{LR#-*o4sTZx;0zMP;J-@<#uBP<_(BxNxdX&8y*nX*D+;;hxST%Z6gzEDAoCg$y- zWQ8vClIKIVdOw%d_Z0e#4f~lt^gfj1_uF{ct5lsRs=es>;Q2&hwZay`_Oob5?v1V5 z^XEn^i7Vd27jN4;bEfH8ByZ@x1|eiD9naBAyjbx7#^#l!4(p4qJP@`dpAX4ORLdqnfynT-1#D^m~7&5!R( zM$oo9t&+}v4H|i#BrD1q>s&Nw`(nlJwX&ws?ZCvW)eBzpB`lKBJZIeHZ23>?Z`Q9k zSbfRU(I=Z#cl9wDk6-e%aU^L7(Er}Fx7V<^(tMBUck|4qbfPu@eOJkQ` z|2aeD!3NQTzefU*15XNXAJ^!OAVF2#3G)5_Wf>RF@^u)?{Mh;<^Q;E zN;vE42-ZE#JRGEflP_yC3r`O?*7F8=uqRN3G9jKoLfim6FLA%e6?*xQ?x!=eYi ziv%ucj4nNaXF-lN|DL?TM$wg=y6N=SFj6j-9QYof3d`OQ~)~&>zE&4H%qVO6lg)9%M0g^U3%a}TQQhXzh4Me{#--` z2*Lnp(61|h7?**W1E`R|Sh%?Qx!c*;dcuWB+Pnm88LFY`5aQp^L%f*Tzc-=`*i!{A z=05~_;5!^3YKR1&&a44{JWT&|00hU(BTC`0P&_R5GUMd^p5uW4Bn!BR;jn3cuvX3% zE|$<|L$J|H!-xQ<|5fN?IE95o0+6s@<2V#RF4}-t{f*wGZ*r(m-yj_fF+cbFaUNdQ zKuW+XlL$j<_;W+!{tXT{~7q+p$aW!SRXD4;rYI_ zNr1gM;G%&GRP%o!SeUt6n!5o1L3GHS3WB=`jR#|)iiivRxv(4uphkg<91a%+JQ#zN z!(WGhKY<_I!6xVNegd3hPzPa25y09E)htH)a_DFSJrEy`bO%^6KuAt@9u|n6ghrp_ z;{rV;S1c1;Y47|HQv+Fp%uh0NR|8(?0R=z^XP*Ti{>Q$Hr58}mh=?hzNU#fpClz2s zeC>Zn#LZltUjh&}05_=M5a__R8iH{5a+Y;*wzjkJayRp|bAdeLhK*Olt7tH+Xchv6 zDr~$i+l{1M(aQh;mJeKba4-hoaU=xhZSjvUAHyI%@VJ(PeeoApLa1a+(0gDGFjlxd zCd&fMKg`Go1G4{*c^?;d2M<>>3oFEcSvO$+vf@lXh~|sE^qQ5tH844a{UQw9F!CQ z4*Pq2KRAUA`zOHo{3sp~H&8-y|MZY!VaP3mA9DU@f`%pd*3^w(_K>g*$ZbRQF98Hv zt%iU248J~!dRAe zwsd!~v*dPyo4T8;GX0c*yC?Vpu?^L~cMo~^(}qElL;%Ew4d9UeNhv*$(of=l?_S!~ z)zQuZJOB_lYud}SX9M^Ate2H%Y4fQk2yc@Nji*%cm<5&o9<3y|#UpAZC8VG-_T;))Bc2g)Qsp&tL! z?-C7Q5SMQ@TpskndZ8E4!XF19<`s&-Ie;oG;_{sy{id;^=Rjt$00jJ`J#L7Aumqm< z!)Jo!`WiSBbSV%BR1qQ9w{Hm<11~8xx+8`v+vqRE!pzmw%-aqg5tI%=2(Lg8P=z3X z%mQDRenk4nz2pM^e0jlVgTwP*1YE)!uB?N-2<9&ahYG5QUSO$R_rAvj0!gPKA|enF zE;cssUVM8DK_rGk5Ku)#I1dH(8Ur3w{o@4*kR)hLT?XnB0q2D*;|AD^&JPd-R1p!i z(yp>{z`#ZV1|EE%vS1OGW?q(dF7OED;Y~2&H+2a(P*6og+&D<^^#uAy5wMzpM-ab+ z@xs#7*~`%pK2Wi#5HF}4APA@;BG?}|9Ve53Kuh|FWm^v{KmP>E($vG&%-zZo9s)9g z_@UYafk5>iNW31#BfyU@Kof!YBd`_*V(n-Kyz2ztY6EGvz@d7KQ3?(fRACXkSqTdE zvFA?XKsO3LMO@DEG{7Jn?W~+V;ggY4NTvNjWCSTw2SR`v2lcxSqsA(_{UgK(gV$Vm$tnLGfT z*#QO#{3I)1^*=ap{xI=wgZ*)>gK(gV$dT|n^K&NxR{y}%4PV5Lui!YAR!%PPu9&}v zAfBU?gF^;YM1)CJ;Y%D~j9dX$$YgLOhSv*^@B>~O^Y!#{N0>*drFX!-^lLysP(=ip zvU)n%12J0x3IHB-=k5Oj!3FKO9s>H21pz@77DQdbthh-V$~1i!1nN;oLO2K5eg_A# zb9VLegpb;JbC%+{!Uz)cE`$M9ScV}mWSDl>t3T?1Ko#0Z2#GnSK!zEZrk8K@!Xr93 zO2sY*jG9;lI5AL#MVJ7HYjxQ@qTV1-niMjE8%Hj12v;+A4}_ekjOI&SGSZ?U45-2~ z-e)^2$hi9P6*>Y7QW|80IyU`^$ndnYxZIk-t>&t+qxQ(?Mv$5&Asnc}a$-wU6j*~8 z1;3bpKw7{kgdhAOS}3sL^008XvO);hUdv&^Z?O?1P5w%7z@Q2Xx$H3JOwyI8K!H{N z(_xff{Wl0)ap9SL16T1w0|*4Fh!BTkRLl-C5Xc0WyWkI*LSDl`yn#b9gdu4(4q=oR zK^Ra)WCU&A9tsAABt0-B;Tg^Y|AhhP$8(hfupjR}Kp0SkWjFxU#bJ=Zat9wc#^3>g zDBy-Y^~Zl1roh31nYRyo@*U%a)h>&SfTjwZ7pTIbWB?RZQlSG2u)ir-LtM&d&%vOa z5GMMEawznd=2;vd=AjB}{xaU;6UjlK+HoG z(LA|?!3R{}?$^W-OLw0E#{7SuPhJF`fFZ$OAP}e`LbNCzwb}#g;rGCH1b%!l8~-;5 zoF`wtK_Cg-)!;lp6&7*}$iv4tG1b#j2>96c3Q(ioSYD+#l1KMipx}V z20{o>g(YwUgjuHj*m+>Ox&usC@C5h5e+Y0su$8W0UlNA%AOxtw5-yW{WRMpX4I~?# z25~|RZh|E^11lm6_;RiH{Rz$m@&N<^RYXMj3Gga7&_W*nvv9oG^DhF^|W-?$m)JRyE-WlA;X+0aaMUWuWl$ zWElj3RpVzM9q=oMbxO3qqXIbpx%gd^ z1!@+aAlv^B0nUfU2M~f<5QG3#M8c0YW+&hu>IN0sA)ap=48Rb)&D`Nf91-0G*n_!DD zU{LO6KJX0}H5X!kRiqA_8>qtCX9K3!KGf-~BEStrV22C8N|??4Yya}Z(#g!z0^#8G zTIoLOgCI0!uvt@8qO=|we0JvdZQg|&X^Ma*s? zTO`m*t^qv}-Z~4=VW3A$hzBP3wo$?NKF1BQ4pl_!hEcmK>Q>f->Inc&a9leFN?!e=Vu;%d3w=2ArvDx(*}Z@;%nl$7s3J0y-G!1#fP+e1AP4XVBwuXc8P+b&p8s+z zL`pEjmd+lK_APwGg=Y^s=AU6<<7jGm*`(kWo*B|uU`Hr9 zAPA_!A{c;i-F(aJDC`jusF(~3Ve`5u3x{z3_h@9x^y9AuU~~)kK^RblWn7N#he^@L zO2Qz};Td8DC%naib;I4m%iS8@k3LHrupgHF5C&8c8Qy)!sfk)3P|zq6=qlXm76%C% zmhqoMF@#3Niv+2zEV?FeMxcs_Su@nEodpgp_<)l{_*KIQ@E{)AsBE3g5Oy;yTM+vz zcOmwnifBLO!6fNC&{W?840!ufx(N2+DhkaE4;&`KOo)A`!rBi5UL_+qQ-7nu4+8xt zN3_4J2V>s_aXoSuA9wTeg|b_H5c^PtwND0=Q{dGe5pLixPfZ{3Fz$x*lh4pN^U1OQb; zz)r$e@;jiRI|BzU@H?e}3q$~17WP^pfZYNJ0IG-pB`*JkG+=$+D37=@=tRZ&Q$=78 zOkJH3o^SE-6N0@!AA&%jiUo0X(pS0HBHpNNR7Dy?hn+GvEdMxGtfA1$er6 zTe(|1x*)98HtmVP!HRwg!9W!eGpJckl?L>3gNKOYB7*KO#@^KmAsII?h{5(V)*<$x zifG@Ns^(h@kPLx;`i6=Wf_=C!xd%e*zawY`=K-p)_6dP;mr+nr<{XaV281Qfp~V%9rV|}qwVGL1AaCBKIg9SBL<(7&%Tt0M#xK08|kH z=~zEh)_~qU+=aM!s;q$l*qK{+xg$L4?e`=D`_R`0K|mD|5suZsKmiQr$AAy;$56dr z|3$!gfw~DnVB@xf!vs}Cgws>{%@tDM8JRyK0(bK-0@xAR0*Bb}6NH{AIoJz20SE%B zhzOT2yPsHyfx~iHL5e7j(6%mmpaDqJ!RMVFW#OCTn0*7$7 z^ZmztBn4At$OdRmqrO*&E!m3F?6^3Bt>;+#?BOBV_7r~@oX@M238Nz|J z-x4IN0BRodp9hA;0uU$oRoTuof_=FAe_q#}d~iODM2Xo6ju2E~?O%4+fFxUzmq2t# z{y8Z)nTNISVe95)<%O`SX$__ZCt5)l0)Z+bBq=xM2`4aYry}j9+0O!10iy4e;O)jxlS%40a^*0K$MOECUIc>j)%{ zggqTWp!t4ege5`mCIZ9M%+byaVals*^O?Au@&={4z)68BEaoyP6ce)Zl0d>A0*?>j zR~`;}cz?Udr7QozzrZvt*HfH7Je-Qb`>6%oVeFn$sW zv@9!f#J2_r%@Hw{u1=T1gD--%DhMdl4+4TJBFH0l@!e;jlJS8<7x-#^jqZGBj|G8rW)UCibGaiz{@WW?-y*O+U)Hm|ID`XLSk7fV-|pJ58w1W>gz6E` zc%EGR4-Q-j%#~dO2Mxy;!htFxhm=g$FCO@-Fjb0(oFq;HgrEV>QS1<3bmU-Q0&~h= zLpV@Ho2n&L5}$ud?%w>$>{>_{SAEB3vm>6x5#saNq#< z0u(iI6plp32SgbkKTM^PGIQlO6*Vy>a)7yVE13&3&5Z-M{xrXiZ(3Qd%Jh5gy&m58 zoX-d4%j1DB`R6|Gx#!+<$NP>2isM-3d+8rk&Z&54OXw7+1lbS^=th{6-8g6BgxGl4 zctI;dRz(%pc6L@ER1TVVDWt(oFlH7ET|CJW#;3gqC?sK=ImQg@xgnu(FiA`_!_)_; zaI6Gks@V#BvJ~XiqpmE_gvpAJ%K7_7p3FQ2YY$P-Nl^Z-KK~=16!hqAieLMr;-hl@ z{#%0_%&(hF1@J9{9^ty&w}kuzzPz2&qMo#UPo@3R$*7#2+4FR!FI}?5&S=} ziQT6rD)vNw#YW}qD%Zjvz*2^(DzIskSv^c++ut~4j5U3onHaGL?IS3|SH0Ow17Yz{~Ga-s^A1S<~5YfjJ0+k~U{ayERU$8mx$+iNU_S$ip1R-_AYZr+r^b{&7aOabES9h9y>)d2-7d;|JlPIvklwvTL` z$IIz%M+Qh{!>zP&nad^y7nFi`;G|~vRwx}I8uwonX02ZYhZHP3_~P+v?+`>{JZuQ2 zo!r<WsS(qsrEpG_n3m9a>$xW{YQ?6dcnM}rEbXVwi2i>*<5xuQ7 zlvU)8yA|vDL&ZYntWR1WeL53XGuuqzL({(>Ggf?LB%B3iZF0_t*3zcuJr7CupmI)! zE+&s%(1$dHMo(kcw~ke`Isp6UV=Z)0+9*%Ot`>6@0+l2F$iI17T>tS6^d)rhCie{k zF+OpE1-25AI=1U;Wkl~hML^|*UpJ3(o(t2(MnSwq?y9U2#1~=s@JtzH>$i~w73p(W z78I(^XtKUzfXAbM4#TwV2Eor$jCXln|G%HaEPzs`)#E9R8bf`dC}k> z<=pjN3tJqYjpv2*c{?L{D|~H+qwJ)RstoKP4VXGwrHrZ*?m*az?!Po2mKsfm!4U@Ls+q^yE zH&6NE@>7LDRT!A2!;iqo|GfBzemY+ns$<~TzeUV%s7sLYi`xfEA%LIRi#oGu|?c35C>=RsWI6ty`}d%Whx9R$2ipK_lG!# z(G|Qy1Ei}($G}R2JdaH(@v#pSWY``BLFJGt^;ezV41U=TRg6N~CfI|J0&{(!AjwWg zrCU%rq|j->``;J9U8f(FW%amLq7H$DjtKacM-0in(pHw%jJAq_${GG2cDm*U!>!L? zGZAeoPJUI3qM}tCR}&0k$A1R5lZ@??6$6zsYQkyg$Ccn_9tbFOxD^^m7~>{TBbxlE z0QU+M0F?vI7Pj)L4GRHlVKPj;F(sG)vr5 zSPI7JkfJ>kq^!1WQj}V*$E43ub;?4BT~6m4>`d(mb8Ej+Z1w!#$p$4MjPK;EI(k;P zh+945RQjlT`XZp*sdS?t0$N8O=%VQA{Pb^G`Xv9i3w>lMC4HyTN9E~<9-r~x6f6KO zg;hY>1-k6i(pN`e2*IG3K~;dTkiKPaMjP@X9w331-+5%(|#)x0MlxgB1al6NaSy-D-Rr zlc`%bz5^%ql16|=XSRk!#U!wW->0iP%CdTpqcEr(Q!{1XkVY`6Z326uXvnSOT&<{e zi?$7zF*caD13F2}54RKsm18P*K4p3rhE{be^T?jqQNzSVz#5!7|4(Aoni~r9htmn^ z7F3RLFIZMK1Qtp^_Tf{WvOOrqcKen4%Ffc1vh5TDl{21YMf5F%o};-dkB1pE>@Z06 z`k)s)3<&#>+kUJVsGQ-RpZnPnh=(Ve@fw`DfHBOhM?aFM5D)e#1S&^dS=+RGLl{&) zhYdZos*?KoMM=F-j+k72(;~5Sy`U|3`oA|ZM0|uLCW&?DLzXLy zuTOz=Ix5FF1kc&(1_5gy1Ql9^bNAcF5TDF-=_aiSpQ8U_d7)1 zTd?zlB1Zi`MWlo#Q@1B(D@0`blhPlk9O04kT4o)v;tLxqCjG}2L9EzSy@#~I!Kx6b z9C35dgOjQ7@nv-`Z-a;K>Imq~;}Y2x$hsR9Bjp>#K;?{#f9<&I4n4?0FoTYJtS;4! z$OvbxB!k%DYw9WO$Szb2RL*#_+2rZNAS~{NRzk-;Kh)9~@ky|;mH_50R)Fr6Pf1^( za=@*Frq16(M?TbMt*l=I4IoE7QM@m#+)Em9Jy0=FIb+D-f_-_&B)`2Bj936smzGkE_8dS;>0FOK5)igS0Z?_oWwFve@=DM@ z(XgW(4g%BB;mwXZ02hBq-?ZQH)OsrFd253Qj-}6nQ;U$N}!X`ypqs*%m z;?n|!K;?+f>;9TPVF)bm!p2~VND3kd%NV}J@7_FrX~oX^XQVGsIb!YQd8R=P;p@#T zZbjW3f=Gf(UxHt5whkEik)1PN3 z#NNkx=g2^5O79AV(iy0nGOXqA`CXt(nhCQrI_I$bY)}%%Sk0j<(DvA@2%cezfXWHo zmwho_Eb6(zrVx5l-KBe+5Mp^jB5`DL(|*#H5z`e3m6M)0?Ok>YY#9o!p|i-3AdW=v)=~J-AS5M5cCgut=N;BxB9=T;2vm+( zWt~?i5sK@XO)z}!RimhlBZ64*!C8ga*yybEIjW9W2SGi+GsE`|jG-Sl;;mz;w}F6* z3TPquUhk47!uf9rDtS~r`Ls3O0j2l!THy~X3Vos1qodBP-AVHHXEeut{%HE4!3Cx2 z<|_=Uj>!WnCWYTf7fZQm@F|@x@3kCCG4|R=HJAKp!WfS`ih`|{m}?wd z&*%J8b99QCts%J#nXy2mKR-OX!4=RE?axV{=;@2T&)I*$yVRY5-|~x}Y_!0GW=mn0FkREBIKTi*jE`geX;h1H*}}gorl|B$ z_4I{*+w2eWy9)-Kh0jhj{oELqKFPmd#voZhtJbLWQF;0|n&Ds)yE3$ZpitOH z#O|Tqv8llQI#evwce^T@qClj8pGdd|RQ~71KW@aXzQs`B+gvQHA;FNu?3tKKE*31v zm{d*N3tFetfrbK(YM7=jk*s;}`l2dO)2c#Y)+5lF#X`lMs-EGIQF`6jQemX5b;+}o zai|6lPM9zwjf-1FQJ$Y@zbMsrDN<7=Haq>LFb*~MqF$oVF5#YNIStY7t!PM$tCIFo znE$|jyg(mMQU;zW-B;EXRKq|=Q&1Kh-JX5#`N-pN+W7)6(3SIxVOnBBVQ=nO3n|dE zRqnoZ3~XFoZR<#(@1Bjne*tzv7(Cl%Y)sunfp#;y$aq@x-0axUWO|u*^DmVxsLxW= z-!EerAxSVSb{SAFiN8kPQ|Y22Pv>lhmJJCO{TMec3(oRlIT6+{vpJIBIy(H5Cz>@X zVs%_&Ru>x-RS$u?`YPP`WGg||IP%^R(acbTs|CthVjxxQy7>3<&8wmJE)C7TO%c)+ zko6+%c}tY!3kwCZySVMKXJ|}}IDzab{HeFWuPfA(;Vdgm!BKf8oOhplQqK`CoQHL> z)+7_P#+D!xz2Z~iV&X$1hQQ7HHhEaSy}r!DiS;TEsCphm*}HBJycyUSjud>u^Dxa? zf;{wx&ZB#HVsvtJ;sl#K+<#v=W9GFq>6Aa8*>{Hj=?e!xhN3?RzpY3)xMh|g5Ae;u zSXX$ZHk8HS-@l)%2dH{6h`!9B+TPR+fQReqOf5(j9+fZ)em&l@DS-0l+$6o+G(|_{ z^tU&x%n(D3Lohq>BJ}%%`U2lVL&XRUZm%y(`iGmw+7GJtAiz+_5ZMY}v>Z9=rb zON&_s#9P^VWp6QO+x`pC;!ttapd&V~_9ZdJn5+s!#U*wS^5iTfeR%c8%5;dlTy+wE zzm<}@+atwwAaS_zNuP2pxA*;&{9hG0av9a9P zvwmBov8d~w*f(}(R-a%u*pDTCsj-=_!j-^Sq@%vfSYsq88p>;DiZ?dZ#TW#-l|!V7a7zfp^hn?&e&QIS(^?Y;Rx z*^9a*NBzz1oil9DXJeA#uPIPa%fBv>pe%s_pQ4P zrt+w7M+LF*s_pE;Fin);h~h~eDIHq3jIfZhT)1P91fc#Br2aNcQ(c?6R;3${Ao&;= zme8(k;j4iW(XnRRXFl2ojh0;-qER_Idg)j{F&sPxzjU^EW_IzVYM*KOK`|$9QRRxN zGuy!U@4d&r%oqo}Jou$^{>(YWGZPZwJ1krx$olX(OD?*Ld5`H-AL-onWq29GcEd2* zEa;n0z2|l{$wxJa?>cUKZ^>s+9Z|~!4`!7``R=bKzkMr)B?rKF^eV1sOxMn19e1aP zO7|S7@%clsx`b*Jm2Ix+BFwA|%r$(SHd|w1KRKLiql361SCkE?Xv@nev=`i63?;&x z>LH&3BV~pht_IK1bQ_kI-fTB$zIe(?oat#oV#nXFNx4x(nM&$|9=Xv#ny}v9wIx9& z9@2E7tiY&7;-f9iyDzKNs7n^N;qRNc_vdGSaY2` M9==0BGA7f10rsVYOaK4? literal 0 HcmV?d00001 diff --git a/app/src/main/assets/splash.jpg b/app/src/main/assets/splash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..205b6aebfa271f15ed7e446cbb6063f04bd74b9d GIT binary patch literal 55971 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 { + + private Context context; + private ProgressDialog pd; + + public boolean please_abort = false; + + private String sdcard = Environment.getExternalStorageDirectory().getPath(); + + private String url = "https://www.dropbox.com/s/cgd8ynsvp8aen5v/quake106.zip?dl=1"; + private String demofile = sdcard + "/Q4C/quake106.zip"; + private String pakfile = sdcard + "/Q4C/id1/pak0.pak"; + + public DownloadTask set_context(Context context){ + this.context = context; + return this; + } + + @Override + protected void onPreExecute (){ + + pd = new ProgressDialog(context); + + pd.setTitle("Downloading data file ..."); + pd.setMessage("starting"); + pd.setIndeterminate(true); + pd.setCancelable(true); + + pd.setOnDismissListener( new DialogInterface.OnDismissListener(){ + public void onDismiss(DialogInterface dialog) { + Log.i( "DownloadTask.java", "onDismiss"); + please_abort = true; + } + }); + + pd.setOnCancelListener( new DialogInterface.OnCancelListener(){ + public void onCancel(DialogInterface dialog) { + Log.i( "DownloadTask.java", "onCancel"); + please_abort = true; + } + }); + + + pd.setButton(ProgressDialog.BUTTON_POSITIVE, "Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + pd.dismiss(); + please_abort = true; + } + }); + + pd.show(); + + } + + + public static String printSize( int size ){ + + if ( size >= (1<<20) ) + return String.format("%.1f MB", size * (1.0/(1<<20))); + + if ( size >= (1<<10) ) + return String.format("%.1f KB", size * (1.0/(1<<10))); + + return String.format("%d bytes", size); + + } + + + private void download_demo() throws Exception{ + + Log.i( "DownloadTask.java", "starting to download "+ url); + + if (new File(demofile).exists()){ + Log.i( "DownloadTask.java", demofile + " already there. skipping."); + return; + } + + /// setup output directory + new File(sdcard + "/Q4C/id1").mkdirs(); + + InputStream is = null; + FileOutputStream fos = null; + + is = new URL(url).openStream(); + fos = new FileOutputStream ( demofile+".part"); + + byte[] buffer = new byte [4096]; + + int totalcount =0; + + long tprint = SystemClock.uptimeMillis(); + int partialcount = 0; + + while(true){ + + if (please_abort) + throw new Exception("aborting") ; + + + int count = is.read (buffer); + //Log.i( "DownloadTask.java", "received " + count + " bytes"); + + if ( count<=0 ) break; + fos.write (buffer, 0, count); + + totalcount += count; + partialcount += count; + + long tnow = SystemClock.uptimeMillis(); + if ( (tnow-tprint)> 1000) { + + float size_MB = totalcount * (1.0f/(1<<20)); + float speed_KB = partialcount * (1.0f/(1<<10)) * ((tnow-tprint)/1000.0f); + + publishProgress( String.format("downloaded %.1f MB (%.1f KB/sec)", + size_MB, speed_KB)); + + tprint = tnow; + partialcount = 0; + + } + + + } + + is.close(); + fos.close(); + + + new File(demofile+".part" ) + .renameTo(new File(demofile)); + + // done + publishProgress("download done" ); + + SystemClock.sleep(2000); + + } + + private void extract_data() throws Exception{ + Log.i("DownloadTask.java", "extracting PAK data"); + + ZipFile file = new ZipFile (demofile); + extract_file( file, "ID1/PAK0.PAK", pakfile); + + file.close(); + + // done + publishProgress("extract done" ); + + pd.getButton(ProgressDialog.BUTTON_POSITIVE).setText("Done"); + + SystemClock.sleep(1000); + + } + + private void extract_file( ZipFile file, String entry_name, String output_name ) throws Exception{ + + Log.i( "DownloadTask.java", "extracting " + entry_name + " to " + output_name); + + String short_name = new File(output_name).getName(); + + // create output directory + new File(output_name).getParentFile().mkdirs(); + + ZipEntry entry = file.getEntry(entry_name); + + if ( entry.isDirectory() ){ + Log.i( "DownloadTask.java", entry_name + " is a directory"); + new File(output_name).mkdir(); + return; + } + + + InputStream is = null; + FileOutputStream fos = null; + + is = file.getInputStream(entry); + + fos = new FileOutputStream ( output_name+".part" ); + + byte[] buffer = new byte [4096]; + + int totalcount =0; + + long tprint = SystemClock.uptimeMillis(); + + while(true){ + + if (please_abort) + throw new Exception("aborting") ; + + + int count = is.read (buffer); + //Log.i( "DownloadTask.java", "extracted " + count + " bytes"); + + if ( count<=0 ) break; + fos.write (buffer, 0, count); + + totalcount += count; + + long tnow = SystemClock.uptimeMillis(); + if ( (tnow-tprint)> 1000) { + + float size_MB = totalcount * (1.0f/(1<<20)); + + publishProgress( String.format("%s : extracted %.1f MB", + short_name, size_MB)); + + tprint = tnow; + } + } + + is.close(); + fos.close(); + + /// rename part file + + new File(output_name+".part" ) + .renameTo(new File(output_name)); + + // done + publishProgress( String.format("%s : done.", + short_name)); + } + + @Override + protected Void doInBackground(Void... unused) { + + try { + + //Inform game we are now downloading + QVRJNILib.setDownloadStatus(2); + + long t = SystemClock.uptimeMillis(); + + download_demo(); + + extract_data(); + + t = SystemClock.uptimeMillis() - t; + + Log.i( "DownloadTask.java", "done in " + t + " ms"); + + } catch (Exception e) { + + e.printStackTrace(); + + QVRJNILib.setDownloadStatus(0); + publishProgress("Error: " + e ); + } + + return(null); + } + + @Override + protected void onProgressUpdate(String... progress) { + Log.i( "DownloadTask.java", progress[0]); + pd.setMessage( progress[0]); + } + + @Override + protected void onPostExecute(Void unused) { + File f = new File(sdcard + "/Q4C/id1/pak0.pak"); + if (f.exists()) { + QVRJNILib.setDownloadStatus(1); + } else + { + QVRJNILib.setDownloadStatus(0); + } + pd.hide(); + } +} diff --git a/app/src/main/java/com/drbeef/qvr/MainActivity.java b/app/src/main/java/com/drbeef/qvr/MainActivity.java new file mode 100644 index 0000000..438f6b9 --- /dev/null +++ b/app/src/main/java/com/drbeef/qvr/MainActivity.java @@ -0,0 +1,1195 @@ +package com.drbeef.qvr; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.ActivityInfo; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaPlayer; +import android.opengl.GLES11Ext; +import android.opengl.GLES20; +import android.opengl.GLUtils; +import android.opengl.Matrix; +import android.os.Bundle; +import android.os.Environment; +import android.os.Vibrator; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.InputDevice; +import android.view.Window; +import android.view.WindowManager; + +import com.google.vrtoolkit.cardboard.CardboardActivity; +import com.google.vrtoolkit.cardboard.CardboardDeviceParams; +import com.google.vrtoolkit.cardboard.CardboardView; +import com.google.vrtoolkit.cardboard.Eye; +import com.google.vrtoolkit.cardboard.HeadTransform; +import com.google.vrtoolkit.cardboard.ScreenParams; +import com.google.vrtoolkit.cardboard.Viewport; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + +import javax.microedition.khronos.egl.EGLConfig; + + +public class MainActivity + extends CardboardActivity + implements CardboardView.StereoRenderer, QVRCallback +{ + private static final String TAG = "QVR"; + + private static final int GL_RGBA8 = 0x8058; + + private int[] currentFBO = new int[1]; + private int fboEyeResolution = 0; + //This is set when the user opts to use a different resolution to the one picked as the default + private int desiredEyeBufferResolution = -1; + + //Head orientation + private float[] eulerAngles = new float[3]; + + private int MONO = 0; + private int STEREO = 1; + + private int mStereoMode = STEREO; + private int eyeID = 0; + + /** + * 0 = no big screen (in game) + * 1 = big screen whilst menu or console active + * 2 = big screen all the time + */ + private int bigScreen = 1; + + //-1 means start button isn't pressed + private long startButtonDownCounter = -1; + //Don't allow the trigger to fire more than once per 200ms + private long triggerTimeout = 0; + + private Vibrator vibrator; + private float M_PI = 3.14159265358979323846f; + public static AudioCallback mAudio; + //Read these from a file and pass through + String commandLineParams = new String(""); + + private CardboardView cardboardView; + + private FloatBuffer screenVertices; + private FloatBuffer splashScreenVertices; + + private int positionParam; + private int texCoordParam; + private int samplerParam; + private int modelViewProjectionParam; + + private float[] modelScreen; + private float[] camera; + private float[] view; + private float[] modelViewProjection; + private float[] modelView; + + private float screenDistance = 8f; + private float screenScale = 4f; + + public static final String vs_Image = + "uniform mat4 u_MVPMatrix;" + + "attribute vec4 a_Position;" + + "attribute vec2 a_texCoord;" + + "varying vec2 v_texCoord;" + + "void main() {" + + " gl_Position = u_MVPMatrix * a_Position;" + + " v_texCoord = a_texCoord;" + + "}"; + + + public static final String fs_Image = + "precision mediump float;" + + "varying vec2 v_texCoord;" + + "uniform sampler2D s_texture;" + + "void main() {" + + " gl_FragColor = texture2D( s_texture, v_texCoord );" + + "}"; + + public static int loadShader(int type, String shaderCode){ + int shader = GLES20.glCreateShader(type); + GLES20.glShaderSource(shader, shaderCode); + GLES20.glCompileShader(shader); + return shader; + } + + //FBO render eye buffer + private QVRFBO fbo; + + // Geometric variables + public static float vertices[]; + public static final short[] indices = new short[] {0, 1, 2, 0, 2, 3}; + public static final float uvs[] = new float[] { + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f + }; + + public static final float[] SCREEN_COORDS = new float[] { + -1.3f, 1.0f, 1.0f, + -1.3f, -1.0f, 1.0f, + 1.3f, -1.0f, 1.0f, + 1.3f, 1.0f, 1.0f + }; + + public static final float[] SPLASH_SCREEN_COORDS = new float[] { + -1.3f, -1.0f, 0.0f, + -1.3f, 1.0f, 0.0f, + 1.3f, 1.0f, 0.0f, + 1.3f, -1.0f, 0.0f + }; + + public FloatBuffer vertexBuffer; + public ShortBuffer listBuffer; + public FloatBuffer uvBuffer; + + //Shader Program + public static int sp_Image; + + private String sdcard = Environment.getExternalStorageDirectory().getPath(); + + private DownloadTask mDownloadTask = null; + + public static boolean mQVRInitialised = false; + public static boolean mVRModeChanged = true; + public static int mVRMode = 2; + public static boolean sideBySide = false; + //Can't rebuild eye buffers until surface changed flag recorded + public static boolean mSurfaceChanged = false; + + private int VRMODE_OFF = 0; + private int VRMODE_SIDEBYSIDE = 1; + private int VRMODE_CARDBOARD = 2; + + private boolean mShowingSpashScreen = true; + private int[] splashTexture = new int[1]; + private MediaPlayer mPlayer; + + + static { + try { + Log.i("JNI", "Trying to load libqvr.so"); + System.loadLibrary("qvr"); + } catch (UnsatisfiedLinkError ule) { + Log.e("JNI", "WARNING: Could not load libqvr.so"); + } + } + + public void copy_asset(String name, String folder) { + File f = new File(sdcard + folder + name); + if (!f.exists() || + //If file was somehow corrupted, copy the back-up + f.length() < 500) { + + //Ensure we have an appropriate folder + new File(sdcard + folder).mkdirs(); + _copy_asset(name, sdcard + folder + name); + } + } + + public void _copy_asset(String name_in, String name_out) { + AssetManager assets = this.getAssets(); + + try { + InputStream in = assets.open(name_in); + OutputStream out = new FileOutputStream(name_out); + + copy_stream(in, out); + + out.close(); + in.close(); + + } catch (Exception e) { + + e.printStackTrace(); + } + + } + + public static void copy_stream(InputStream in, OutputStream out) + throws IOException { + byte[] buf = new byte[512]; + while (true) { + int count = in.read(buf); + if (count <= 0) + break; + out.write(buf, 0, count); + } + } + + static boolean CreateFBO( QVRFBO fbo, int offset, int width, int height) + { + Log.d(TAG, "CreateFBO"); + // Create the color buffer texture. + GLES20.glGenTextures(1, fbo.ColorTexture, 0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0]); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + + // Create depth buffer. + GLES20.glGenRenderbuffers(1, fbo.DepthBuffer, 0); + GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]); + GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES11Ext.GL_DEPTH_COMPONENT24_OES, width, height); + GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0); + + // Create the frame buffer. + GLES20.glGenFramebuffers(1, fbo.FrameBuffer, 0); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo.FrameBuffer[0]); + GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, fbo.DepthBuffer[0]); + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0], 0); + int renderFramebufferStatus = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + if ( renderFramebufferStatus != GLES20.GL_FRAMEBUFFER_COMPLETE ) + { + Log.d(TAG, "Incomplete frame buffer object!!"); + return false; + } + + fbo.width = width; + fbo.height = height; + + return true; + } + + static void DestroyFBO( QVRFBO fbo ) + { + GLES20.glDeleteFramebuffers( 1, fbo.FrameBuffer, 0 ); + fbo.FrameBuffer[0] = 0; + GLES20.glDeleteRenderbuffers( 1, fbo.DepthBuffer, 0 ); + fbo.DepthBuffer[0] = 0; + GLES20.glDeleteTextures( 1, fbo.ColorTexture, 0 ); + fbo.ColorTexture[0] = 0; + fbo.width = 0; + fbo.height = 0; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + requestWindowFeature(Window.FEATURE_NO_TITLE); + + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + cardboardView = (CardboardView) findViewById(R.id.cardboard_view); + cardboardView.setEGLConfigChooser(5, 6, 5, 0, 16, 0); + cardboardView.setLowLatencyModeEnabled(true); + cardboardView.setRenderer(this); + setCardboardView(cardboardView); + + modelScreen = new float[16]; + camera = new float[16]; + view = new float[16]; + modelViewProjection = new float[16]; + modelView = new float[16]; + + vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); + + //At the very least ensure we have a directory containing a config file + copy_asset("config.cfg", "/QVR/id1/"); + copy_asset("commandline.txt", "/QVR/"); + + //See if user is trying to use command line params + BufferedReader br; + try { + br = new BufferedReader(new FileReader(sdcard + "/QVR/commandline.txt")); + String s; + StringBuilder sb=new StringBuilder(0); + while ((s=br.readLine())!=null) + sb.append(s + " "); + br.close(); + + commandLineParams = new String(sb.toString()); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (commandLineParams.contains("-game")) + { + //No need to download, user is playing something else + } + else + { + File f = new File(sdcard + "/QVR/id1/pak0.pak"); + if (!f.exists()) { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( + this); + + // set title + alertDialogBuilder.setTitle("No game assets found"); + + // set dialog message + alertDialogBuilder + .setMessage("Would you like to download the shareware version of Quake (8MB)?\n\nIf you own or purchase the full game (On Steam: http://store.steampowered.com/app/2310/) you can click \'Cancel\' and copy the pak files to the folder:\n\n{phonememory}/QVR/id1") + .setCancelable(false) + .setPositiveButton("Download", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + MainActivity.this.startDownload(); + } + }) + .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + + // create alert dialog + AlertDialog alertDialog = alertDialogBuilder.create(); + + // show it + alertDialog.show(); + } + } + + //Create the FBOs + fbo = new QVRFBO(); + + if (mAudio==null) + { + mAudio = new AudioCallback(); + } + + QVRJNILib.setCallbackObjects(mAudio, this); + + } + + public void startDownload() + { + mDownloadTask = new DownloadTask(); + mDownloadTask.set_context(MainActivity.this); + mDownloadTask.execute(); + } + + @Override + public void onRendererShutdown() { + Log.i(TAG, "onRendererShutdown"); + } + + @Override + public void onSurfaceChanged(int width, int height) + { + Log.d(TAG, "onSurfaceChanged width = " + width + " height = " + height); + mSurfaceChanged = true; + } + + @Override + public void onSurfaceCreated(EGLConfig config) { + Log.i(TAG, "onSurfaceCreated"); + + ByteBuffer bbVertices = ByteBuffer.allocateDirect(SCREEN_COORDS.length * 4); + bbVertices.order(ByteOrder.nativeOrder()); + screenVertices = bbVertices.asFloatBuffer(); + screenVertices.put(SCREEN_COORDS); + screenVertices.position(0); + + bbVertices = ByteBuffer.allocateDirect(SPLASH_SCREEN_COORDS.length * 4); + bbVertices.order(ByteOrder.nativeOrder()); + splashScreenVertices = bbVertices.asFloatBuffer(); + splashScreenVertices.put(SPLASH_SCREEN_COORDS); + splashScreenVertices.position(0); + + // initialize byte buffer for the draw list + ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2); + dlb.order(ByteOrder.nativeOrder()); + listBuffer = dlb.asShortBuffer(); + listBuffer.put(indices); + listBuffer.position(0); + + // Create the shaders, images + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vs_Image); + int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fs_Image); + + sp_Image = GLES20.glCreateProgram(); // create empty OpenGL ES Program + GLES20.glAttachShader(sp_Image, vertexShader); // add the vertex shader to program + GLES20.glAttachShader(sp_Image, fragmentShader); // add the fragment shader to program + GLES20.glLinkProgram(sp_Image); // creates OpenGL ES program executable + + positionParam = GLES20.glGetAttribLocation(sp_Image, "a_Position"); + texCoordParam = GLES20.glGetAttribLocation(sp_Image, "a_texCoord"); + modelViewProjectionParam = GLES20.glGetUniformLocation(sp_Image, "u_MVPMatrix"); + samplerParam = GLES20.glGetUniformLocation(sp_Image, "s_texture"); + + + GLES20.glEnableVertexAttribArray(positionParam); + GLES20.glEnableVertexAttribArray(texCoordParam); + + // Build the camera matrix + Matrix.setLookAtM(camera, 0, 0.0f, 0.0f, 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); + + //Start intro music + mPlayer = MediaPlayer.create(this, R.raw.m010912339); + mPlayer.start(); + + //Load bitmap for splash screen + splashTexture[0] = 0; + GLES20.glGenTextures(1, splashTexture, 0); + + Bitmap bmp = null; + try { + AssetManager assets = this.getAssets(); + InputStream in = assets.open("splash.jpg"); + bmp = BitmapFactory.decodeStream(in); + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + // Bind texture to texturename + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, splashTexture[0]); + + // Set filtering + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + + // Set wrapping mode + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + + // Load the bitmap into the bound texture. + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0); + + //unbind + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); + + // We are done using the bitmap so we should recycle it. + //bmp.recycle(); + + } + + public void BigScreenMode(int mode) + { + if (mode == -1) + bigScreen = 1; + else if (bigScreen != 2) + bigScreen = mode; + } + + public void SwitchStereoMode(int stereo_mode) + { + mStereoMode = stereo_mode; + } + + int getDesiredfboEyeResolution(int viewportWidth) { + + desiredEyeBufferResolution = QVRJNILib.getEyeBufferResolution(); + if (desiredEyeBufferResolution != 0) + return desiredEyeBufferResolution; + + //Select based on viewport width + if (viewportWidth > 1024) + desiredEyeBufferResolution = 1024; + else if (viewportWidth > 512) + desiredEyeBufferResolution = 512; + else + desiredEyeBufferResolution = 256; + + return desiredEyeBufferResolution; + } + + @Override + public void onNewFrame(HeadTransform headTransform) { + if (mQVRInitialised) { + headTransform.getEulerAngles(eulerAngles, 0); + QVRJNILib.onNewFrame(-eulerAngles[0] / (M_PI / 180.0f), eulerAngles[1] / (M_PI / 180.0f), -eulerAngles[2] / (M_PI / 180.0f)); + + //Check to see if we should update the eye buffer resolution + int checkRes = QVRJNILib.getEyeBufferResolution(); + if (checkRes != 0 && checkRes != desiredEyeBufferResolution) + mVRModeChanged = true; + } + } + + @Override + public void onDrawEye(Eye eye) { + if (mVRModeChanged) + { + if (!mSurfaceChanged) + return; + + Log.i(TAG, "mVRModeChanged"); + if (fbo.FrameBuffer[0] != 0) + DestroyFBO(fbo); + + if (mVRMode == VRMODE_SIDEBYSIDE) { + CreateFBO(fbo, 0, eye.getViewport().width / 2, eye.getViewport().height); + QVRJNILib.setResolution(eye.getViewport().width / 2, eye.getViewport().height); + } + else if (mVRMode == VRMODE_CARDBOARD) { + fboEyeResolution = getDesiredfboEyeResolution(eye.getViewport().width); + CreateFBO(fbo, 0, fboEyeResolution, fboEyeResolution); + QVRJNILib.setResolution(fboEyeResolution, fboEyeResolution); + } + else // VRMODE_OFF + { + CreateFBO(fbo, 0, eye.getViewport().width, eye.getViewport().height); + QVRJNILib.setResolution(eye.getViewport().width, eye.getViewport().height); + } + + SetupUVCoords(); + + //Reset our orientation + cardboardView.resetHeadTracker(); + + mVRModeChanged = false; + } + + if (!mQVRInitialised && !mShowingSpashScreen) + { + QVRJNILib.initialise(sdcard + "/QVR", commandLineParams); + + //Now calculate the auto lens centre correction + CardboardDeviceParams device = cardboardView.getHeadMountedDisplay().getCardboardDeviceParams(); + ScreenParams scr = cardboardView.getScreenParams(); + Display display = getWindowManager().getDefaultDisplay(); + DisplayMetrics met = new DisplayMetrics(); + display.getMetrics(met); + float dpmil = (met.xdpi / 25.4f); + float qscreen = (scr.getWidthMeters() * 1000.0f) / 4.0f; + float halflens = (device.getInterLensDistance() * 1000.0f) / 2.0f; + //Multiply by small fudge factor (20%) + float lensCentreOffset = ((halflens - qscreen) * dpmil) * 1.2f; + + if (mVRMode == VRMODE_CARDBOARD) { + //Viewport size is not the same as screen resolution, so convert + lensCentreOffset = (lensCentreOffset / (scr.getWidth() / 2.0f)) * eye.getViewport().width; + } + else if (mVRMode == VRMODE_SIDEBYSIDE) { + //do nothing, no correction needed + } + else + { + //No offset required + lensCentreOffset = 0; + } + + QVRJNILib.setCentreOffset((int)lensCentreOffset); + + mQVRInitialised = true; + } + + if (mQVRInitialised || mShowingSpashScreen) { + + //Record the curent fbo + GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, currentFBO, 0); + + for (int i = 0; i < 2; ++i) { + + if (mShowingSpashScreen) { + GLES20.glEnable(GLES20.GL_SCISSOR_TEST); + GLES20.glScissor(eye.getViewport().x, eye.getViewport().y, + eye.getViewport().width, eye.getViewport().height); + GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); + } + else if (mStereoMode == STEREO || + (mStereoMode == MONO && eye.getType() < 2)) { + //Bind our special fbo + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo.FrameBuffer[0]); + GLES20.glEnable(GLES20.GL_DEPTH_TEST); + GLES20.glDepthFunc(GLES20.GL_LEQUAL); + GLES20.glEnable(GLES20.GL_SCISSOR_TEST); + + if (mVRMode == VRMODE_SIDEBYSIDE) { + GLES20.glScissor(0, 0, eye.getViewport().width / 2, eye.getViewport().height); + } else if (mVRMode == VRMODE_CARDBOARD) { + GLES20.glScissor(0, 0, fboEyeResolution, fboEyeResolution); + } else { + GLES20.glScissor(0, 0, eye.getViewport().width, eye.getViewport().height); + } + + GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); + + //Decide which eye we are drawing + if (mStereoMode == MONO) + eyeID = 0; + else if (mVRMode == 0) + eyeID = 0; + else if (mVRMode == VRMODE_SIDEBYSIDE) + eyeID = i; + else // mStereoMode == StereoMode.STEREO - Default behaviour for VR mode + eyeID = eye.getType() - 1; + + //We only draw from QVR if we arent showing the splash + if (!mShowingSpashScreen) + QVRJNILib.onDrawEye(eyeID, 0, 0); + + //Finished rendering to our frame buffer, now draw this to the target framebuffer + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, currentFBO[0]); + } + + GLES20.glDisable(GLES20.GL_SCISSOR_TEST); + + if (mVRMode == VRMODE_SIDEBYSIDE) { + GLES20.glViewport(eye.getViewport().x + ((eye.getViewport().width/2) * i), + eye.getViewport().y, + eye.getViewport().width/2, + eye.getViewport().height); + } + else + { + GLES20.glViewport(eye.getViewport().x, + eye.getViewport().y, + eye.getViewport().width, + eye.getViewport().height); + } + + GLES20.glUseProgram(sp_Image); + + if ((bigScreen != 0) && mVRMode > 0) { + // Apply the eye transformation to the camera. + Matrix.multiplyMM(view, 0, eye.getEyeView(), 0, camera, 0); + + // Build the ModelView and ModelViewProjection matrices + // for calculating screen position. + float[] perspective = eye.getPerspective(0.1f, 100.0f); + + float scale = screenScale; + if (mShowingSpashScreen) + scale /= 2; + + // Object first appears directly in front of user. + Matrix.setIdentityM(modelScreen, 0); + Matrix.translateM(modelScreen, 0, 0, 0, -screenDistance); + Matrix.scaleM(modelScreen, 0, scale, scale, 1.0f); + + // Set the position of the screen + if (mShowingSpashScreen) { + float mAngle = 360.0f * (float)((System.currentTimeMillis() % 3000) / 3000.0f); + Matrix.rotateM(modelScreen, 0, mAngle, 0.0f, 1.0f, 0.0f); + Matrix.multiplyMM(modelView, 0, view, 0, modelScreen, 0); + Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0); + GLES20.glVertexAttribPointer(positionParam, 3, GLES20.GL_FLOAT, false, 0, splashScreenVertices); + } + else { + Matrix.multiplyMM(modelView, 0, view, 0, modelScreen, 0); + Matrix.multiplyMM(modelViewProjection, 0, perspective, 0, modelView, 0); + GLES20.glVertexAttribPointer(positionParam, 3, GLES20.GL_FLOAT, false, 0, screenVertices); + } + + } else { + + // Create the triangles for orthographic projection (if required) + int offset = 0; + + if (mVRMode == VRMODE_CARDBOARD) + offset = QVRJNILib.getCentreOffset(); + + if (eye.getType() == 1 || i == 1) + offset *= -1; + + int w = (int) eye.getViewport().width; + int h = (int) eye.getViewport().height; + int x = (int) 0; + int y = (int) 0; + if (mVRMode == VRMODE_CARDBOARD) + { + //This assumes that height > width for an eye + w = (int) eye.getViewport().width; + h = (int) eye.getViewport().width; + x = 0; + y = (eye.getViewport().height - eye.getViewport().width) / 2; + } + + SetupTriangle(offset + x, y, w, h); + + // Calculate the projection and view transformation + Matrix.orthoM(view, 0, 0, eye.getViewport().width, 0, eye.getViewport().height, 0, 50); + Matrix.multiplyMM(modelViewProjection, 0, view, 0, camera, 0); + + // Prepare the triangle coordinate data + GLES20.glVertexAttribPointer(positionParam, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer); + } + + // Prepare the texturecoordinates + GLES20.glVertexAttribPointer(texCoordParam, 2, GLES20.GL_FLOAT, false, 0, uvBuffer); + + // Apply the projection and view transformation + GLES20.glUniformMatrix4fv(modelViewProjectionParam, 1, false, modelViewProjection, 0); + + // Bind texture to fbo's color texture + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + IntBuffer activeTex0 = IntBuffer.allocate(2); + GLES20.glGetIntegerv(GLES20.GL_TEXTURE_BINDING_2D, activeTex0); + + if (mShowingSpashScreen) + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, splashTexture[0]); + else + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.ColorTexture[0]); + + // Set the sampler texture unit to our fbo's color texture + GLES20.glUniform1i(samplerParam, 0); + + // Draw the triangles + GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, listBuffer); + + int error = GLES20.glGetError(); + if (error != GLES20.GL_NO_ERROR) + Log.d(TAG, "GLES20 Error = " + error); + + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, activeTex0.get(0)); + + //Only loop round again for side by side + if (mVRMode != VRMODE_SIDEBYSIDE && i == 0) + break; + } + } + } + + @Override + public void onFinishFrame(Viewport viewport) { + if (mQVRInitialised) { + QVRJNILib.onFinishFrame(); + } + } + + /** + * Called when the Cardboard trigger is pulled. + */ + //@Override + public void onCardboardTrigger() { + Log.i(TAG, "onCardboardTrigger"); + + if (System.currentTimeMillis() - triggerTimeout > 200) { + + QVRJNILib.onKeyEvent(K_ENTER, KeyEvent.ACTION_DOWN, 0); + + cardboardView.resetHeadTracker(); + + dismissSplashScreen(); + + triggerTimeout = System.currentTimeMillis(); + } + } + + + public int getCharacter(int keyCode, KeyEvent event) + { + if (keyCode==KeyEvent.KEYCODE_DEL) return '\b'; + return event.getUnicodeChar(); + } + + private void dismissSplashScreen() + { + if (mShowingSpashScreen) { + mPlayer.stop(); + mPlayer.release(); + mShowingSpashScreen = false; + } + } + + @Override public boolean dispatchKeyEvent( KeyEvent event ) + { + int keyCode = event.getKeyCode(); + int action = event.getAction(); + int character = 0; + + if ( action != KeyEvent.ACTION_DOWN && action != KeyEvent.ACTION_UP ) + { + return super.dispatchKeyEvent( event ); + } + if ( action == KeyEvent.ACTION_UP ) + { + dismissSplashScreen(); + Log.v( TAG, "GLES3JNIActivity::dispatchKeyEvent( " + keyCode + ", " + action + " )" ); + } + + //Allow user to switch vr mode by holding the start button down + if (keyCode == KeyEvent.KEYCODE_BUTTON_START) + { + if (action == KeyEvent.ACTION_DOWN && + startButtonDownCounter == -1) + { + startButtonDownCounter = System.currentTimeMillis(); + + } + else if (action == KeyEvent.ACTION_UP) + { + startButtonDownCounter = -1; + } + } + + if (startButtonDownCounter != -1) + { + if ((System.currentTimeMillis() - startButtonDownCounter) > 2000) + { + //Switch VR mode + startButtonDownCounter = -1; + SwitchVRMode(); + //Now make sure qvr is aware! + QVRJNILib.onSwitchVRMode(mVRMode); + } + } + + //Following buttons must not be handled here + if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || + keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || + keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL + ) + return false; + + //Convert to QVR keys + character = getCharacter(keyCode, event); + int qKeyCode = convertKeyCode(keyCode, event); + + //Don't hijack all keys (volume etc) + if (qKeyCode != -1) + keyCode = qKeyCode; + + if (keyCode == K_ESCAPE) + cardboardView.resetHeadTracker(); + + QVRJNILib.onKeyEvent( keyCode, action, character ); + return true; + } + + private static float getCenteredAxis(MotionEvent event, + int axis) { + final InputDevice.MotionRange range = event.getDevice().getMotionRange(axis, event.getSource()); + if (range != null) { + final float flat = range.getFlat(); + final float value = event.getAxisValue(axis); + if (Math.abs(value) > flat) { + return value; + } + } + return 0; + } + + + //Save the game pad type once known: + // 1 - Generic BT gamepad + // 2 - Samsung gamepad that uses different axes for right stick + int gamepadType = 0; + + int lTrigAction = KeyEvent.ACTION_UP; + int rTrigAction = KeyEvent.ACTION_UP; + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + int source = event.getSource(); + int action = event.getAction(); + if ((source==InputDevice.SOURCE_JOYSTICK)||(event.getSource()==InputDevice.SOURCE_GAMEPAD)) + { + if (event.getAction() == MotionEvent.ACTION_MOVE) + { + float x = getCenteredAxis(event, MotionEvent.AXIS_X); + float y = -getCenteredAxis(event, MotionEvent.AXIS_Y); + QVRJNILib.onTouchEvent( source, action, x, y ); + + float z = getCenteredAxis(event, MotionEvent.AXIS_Z); + float rz = -getCenteredAxis(event, MotionEvent.AXIS_RZ); + //For the samsung game pad (uses different axes for the second stick) + float rx = getCenteredAxis(event, MotionEvent.AXIS_RX); + float ry = -getCenteredAxis(event, MotionEvent.AXIS_RY); + + //let's figure it out + if (gamepadType == 0) + { + if (z != 0.0f || rz != 0.0f) + gamepadType = 1; + else if (rx != 0.0f || ry != 0.0f) + gamepadType = 2; + } + + switch (gamepadType) + { + case 0: + break; + case 1: + QVRJNILib.onMotionEvent( source, action, z, rz ); + break; + case 2: + QVRJNILib.onMotionEvent( source, action, rx, ry ); + break; + } + + //Fire weapon using shoulder trigger + float axisRTrigger = max(event.getAxisValue(MotionEvent.AXIS_RTRIGGER), + event.getAxisValue(MotionEvent.AXIS_GAS)); + int newRTrig = axisRTrigger > 0.6 ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; + if (rTrigAction != newRTrig) + { + QVRJNILib.onKeyEvent( K_MOUSE1, newRTrig, 0); + rTrigAction = newRTrig; + } + + //Run using L shoulder + float axisLTrigger = max(event.getAxisValue(MotionEvent.AXIS_LTRIGGER), + event.getAxisValue(MotionEvent.AXIS_BRAKE)); + int newLTrig = axisLTrigger > 0.6 ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; + if (lTrigAction != newLTrig) + { + QVRJNILib.onKeyEvent( K_SHIFT, newLTrig, 0); + lTrigAction = newLTrig; + } + } + } + return false; + } + + private float max(float axisValue, float axisValue2) { + return (axisValue > axisValue2) ? axisValue : axisValue2; + } + + public static final int K_TAB = 9; + public static final int K_ENTER = 13; + public static final int K_ESCAPE = 27; + public static final int K_SPACE = 32; + public static final int K_BACKSPACE = 127; + public static final int K_UPARROW = 128; + public static final int K_DOWNARROW = 129; + public static final int K_LEFTARROW = 130; + public static final int K_RIGHTARROW = 131; + public static final int K_ALT = 132; + public static final int K_CTRL = 133; + public static final int K_SHIFT = 134; + public static final int K_F1 = 135; + public static final int K_F2 = 136; + public static final int K_F3 = 137; + public static final int K_F4 = 138; + public static final int K_F5 = 139; + public static final int K_F6 = 140; + public static final int K_F7 = 141; + public static final int K_F8 = 142; + public static final int K_F9 = 143; + public static final int K_F10 = 144; + public static final int K_F11 = 145; + public static final int K_F12 = 146; + public static final int K_INS = 147; + public static final int K_DEL = 148; + public static final int K_PGDN = 149; + public static final int K_PGUP = 150; + public static final int K_HOME = 151; + public static final int K_END = 152; + public static final int K_PAUSE = 153; + public static final int K_NUMLOCK = 154; + public static final int K_CAPSLOCK = 155; + public static final int K_SCROLLOCK = 156; + public static final int K_MOUSE1 = 512; + public static final int K_MOUSE2 = 513; + public static final int K_MOUSE3 = 514; + public static final int K_MWHEELUP = 515; + public static final int K_MWHEELDOWN = 516; + public static final int K_MOUSE4 = 517; + public static final int K_MOUSE5 = 518; + + public static int convertKeyCode(int keyCode, KeyEvent event) + { + switch(keyCode) + { + case KeyEvent.KEYCODE_FOCUS: + return K_F1; + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_W: + return K_UPARROW; + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_S: + return K_DOWNARROW; + case KeyEvent.KEYCODE_DPAD_LEFT: + return 'a'; + case KeyEvent.KEYCODE_DPAD_RIGHT: + return 'd'; + case KeyEvent.KEYCODE_DPAD_CENTER: + return K_CTRL; + case KeyEvent.KEYCODE_ENTER: + return K_ENTER; + case KeyEvent.KEYCODE_BACK: + return K_ESCAPE; + case KeyEvent.KEYCODE_APOSTROPHE: + return K_ESCAPE; + case KeyEvent.KEYCODE_DEL: + return K_BACKSPACE; + case KeyEvent.KEYCODE_ALT_LEFT: + case KeyEvent.KEYCODE_ALT_RIGHT: + return K_ALT; + case KeyEvent.KEYCODE_SHIFT_LEFT: + case KeyEvent.KEYCODE_SHIFT_RIGHT: + return K_SHIFT; + case KeyEvent.KEYCODE_CTRL_LEFT: + case KeyEvent.KEYCODE_CTRL_RIGHT: + return K_CTRL; + case KeyEvent.KEYCODE_INSERT: + return K_INS; + case 122: + return K_HOME; + case KeyEvent.KEYCODE_FORWARD_DEL: + return K_DEL; + case 123: + return K_END; + case KeyEvent.KEYCODE_ESCAPE: + return K_ESCAPE; + case KeyEvent.KEYCODE_TAB: + return K_TAB; + case KeyEvent.KEYCODE_F1: + return K_F1; + case KeyEvent.KEYCODE_F2: + return K_F2; + case KeyEvent.KEYCODE_F3: + return K_F3; + case KeyEvent.KEYCODE_F4: + return K_F4; + case KeyEvent.KEYCODE_F5: + return K_F5; + case KeyEvent.KEYCODE_F6: + return K_F6; + case KeyEvent.KEYCODE_F7: + return K_F7; + case KeyEvent.KEYCODE_F8: + return K_F8; + case KeyEvent.KEYCODE_F9: + return K_F9; + case KeyEvent.KEYCODE_F10: + return K_F10; + case KeyEvent.KEYCODE_F11: + return K_F11; + case KeyEvent.KEYCODE_F12: + return K_F12; + case KeyEvent.KEYCODE_CAPS_LOCK: + return K_CAPSLOCK; + case KeyEvent.KEYCODE_PAGE_DOWN: + return K_PGDN; + case KeyEvent.KEYCODE_PAGE_UP: + return K_PGUP; + case KeyEvent.KEYCODE_BUTTON_A: + return K_ENTER; + case KeyEvent.KEYCODE_BUTTON_B: + return K_MOUSE1; + case KeyEvent.KEYCODE_BUTTON_X: + return '#'; //prev weapon, set in the config.txt as impulse 12 + case KeyEvent.KEYCODE_BUTTON_Y: + return '/';//Next weapon, set in the config.txt as impulse 10 + //These buttons are not so popular + case KeyEvent.KEYCODE_BUTTON_C: + return 'a';//That's why here is a, nobody cares. + case KeyEvent.KEYCODE_BUTTON_Z: + return 'z'; + //-------------------------------- + case KeyEvent.KEYCODE_BUTTON_START: + return K_ESCAPE; + case KeyEvent.KEYCODE_BUTTON_SELECT: + return K_ENTER; + case KeyEvent.KEYCODE_MENU: + return K_ESCAPE; + + //Both shoulder buttons will "fire" + case KeyEvent.KEYCODE_BUTTON_R1: + case KeyEvent.KEYCODE_BUTTON_R2: + return K_MOUSE1; + + //enables "run" + case KeyEvent.KEYCODE_BUTTON_L1: + case KeyEvent.KEYCODE_BUTTON_L2: + return K_SHIFT; + case KeyEvent.KEYCODE_BUTTON_THUMBL: + return -1; + } + int uchar = event.getUnicodeChar(0); + if((uchar < 127)&&(uchar!=0)) + return uchar; + return keyCode%95+32;//Magic + } + + + public void SetupUVCoords() + { + // The texture buffer + ByteBuffer bb = ByteBuffer.allocateDirect(uvs.length * 4); + bb.order(ByteOrder.nativeOrder()); + uvBuffer = bb.asFloatBuffer(); + uvBuffer.put(uvs); + uvBuffer.position(0); + } + + public void SetupTriangle(int x, int y, int width, int height) + { + // We have to create the vertices of our triangle. + vertices = new float[] + { + x, y + height, 0.0f, + x, y, 0.0f, + x + width, y, 0.0f, + x + width, y + height, 0.0f, + }; + + // The vertex buffer. + ByteBuffer bb = ByteBuffer.allocateDirect(vertices.length * 4); + bb.order(ByteOrder.nativeOrder()); + vertexBuffer = bb.asFloatBuffer(); + vertexBuffer.put(vertices); + vertexBuffer.position(0); + } + + public void SwitchVRMode() { + mVRMode = (mVRMode + 1) % 3; + SwitchVRMode(mVRMode); + } + + @Override + public void SwitchVRMode(int vrMode) { + mVRMode = vrMode; + if (mVRMode == 0) { + cardboardView.setVRModeEnabled(false); + mSurfaceChanged = false; + sideBySide = false; + } + if (mVRMode == 1) { + cardboardView.setVRModeEnabled(false); + mSurfaceChanged = true; + sideBySide = true; + } + if (mVRMode == 2) { + cardboardView.setVRModeEnabled(true); + mSurfaceChanged = false; + sideBySide = false; + } + mVRModeChanged = true; + } + + @Override + public void Exit() { + mAudio.terminateAudio(); + try { + Thread.sleep(1000); + } + catch (InterruptedException ie){ + } + System.exit(0); + } + + +} diff --git a/app/src/main/java/com/drbeef/qvr/QVRCallback.java b/app/src/main/java/com/drbeef/qvr/QVRCallback.java new file mode 100644 index 0000000..24a0836 --- /dev/null +++ b/app/src/main/java/com/drbeef/qvr/QVRCallback.java @@ -0,0 +1,10 @@ +package com.drbeef.qvr; + + +public interface QVRCallback { + + void SwitchVRMode(int vrMode); + void BigScreenMode(int mode); + void SwitchStereoMode(int stereo_mode); + void Exit(); +} diff --git a/app/src/main/java/com/drbeef/qvr/QVRFBO.java b/app/src/main/java/com/drbeef/qvr/QVRFBO.java new file mode 100644 index 0000000..c19dccf --- /dev/null +++ b/app/src/main/java/com/drbeef/qvr/QVRFBO.java @@ -0,0 +1,20 @@ +package com.drbeef.qvr; + +public class QVRFBO { + + public int[] FrameBuffer; + public int[] DepthBuffer; + public int[] ColorTexture; + public int height; + public int width; + + public QVRFBO() + { + this.FrameBuffer = new int[1]; + this.FrameBuffer[0] = 0; + this.DepthBuffer = new int[1]; + this.DepthBuffer[0] = 0; + this.ColorTexture = new int[1]; + this.ColorTexture[0] = 0; + } +} diff --git a/app/src/main/java/com/drbeef/qvr/QVRJNILib.java b/app/src/main/java/com/drbeef/qvr/QVRJNILib.java new file mode 100644 index 0000000..86ae90a --- /dev/null +++ b/app/src/main/java/com/drbeef/qvr/QVRJNILib.java @@ -0,0 +1,26 @@ +package com.drbeef.qvr; + +public class QVRJNILib { + + // Input + public static native void onKeyEvent( int keyCode, int action, int character ); + public static native void onTouchEvent( int source, int action, float x, float y ); + public static native void onMotionEvent( int source, int action, float x, float y ); + + //Rendering and lifecycle + public static native void setResolution( int width, int height ); + public static native void initialise( String gameFolder, String commandLineParams ); + public static native void onNewFrame( float pitch, float yaw, float roll ); + public static native void onDrawEye( int eye, int x, int y ); + public static native void onFinishFrame( ); + public static native void onSwitchVRMode( int vrMode ); + public static native void onBigScreenMode( int mode ); + public static native int getCentreOffset( ); + public static native void setCentreOffset( int offset ); + public static native void setDownloadStatus( int status ); + public static native int getEyeBufferResolution( ); + + //Audio + public static native void requestAudioData(); + public static native void setCallbackObjects(Object obj1, Object obj2); +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..77369f8 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3eec333cb3adfe60df14b1da54b187b79480d622 GIT binary patch literal 8993 zcmV++Bi`JJP)t_w2~LQ^^pN4cm}YS=bX1mGeXHelNhY~`P8ISMt)MmS<177jrV1`yVC z)NF-qV?`7zRk$u-XhC#jQ;5e5L_#4%4FlP965ZV$h-cDh>7IAOHbK*ED#ZD+97@hZ75a zS+kS?M}P=Kp;CkAdWc8EVpSvt*L4Lvf?c(FkD!3B2ZJzl4P7l6Oqtw`J!j8GGMhs< zmc)(?Z(!rvHE>=3+M#erz~ie{EhB&cblm`gK~zgcW9wVnR$s96=|g$DcaHg;bn&+U z(gT5j`sj?@F=1VMIB7=gu%Q`ri*zC?7E`WSVoe-u$k1f=9mhq*vSl#2bR6ZXB?An= z6X1fuAhe(lP$0-#2T-IdShOfdz$ZAo4qsJEfs;aO<2~Vd0ul$>l!{@mnNu)x_H2Zr zQ3Qh;cD(f_-rTqewrwMmN+O%wDZ*pOi0Tei=4nREi3U7ZMp3=9nn z3ZLIia6&2KUefCLTzkSY}IcISK-m3-SguT1^Q?XE=840PHrF3#i!wo8y zPn>+nV#Pw$vJoXiO$^Eje+oO1UCLZpPwBH8rDa);ze%R$JG+qPHD<>cjz}1%>rMUo>neL)UeJ zLE;=5FUi0yCX0+V%yA?Ndy?nSilQO9T1Wuni|*OTf5<5uU@n_NOD+qmW?^)^fZ?$` z#)?%87vAB9bv`TAEa5)7a3*dFcuXbu;?HrD78F9YW+5C7K?`cgWYcJAYl9JvKsQ2A zRt>qHJ%BG;x5Ap3~kR)&hM@MKn#*IdI!n7%5czOgI>gt-u(DVc~N9ygIpCNMlQhH9lMt`rG}F=hHRztRYyLr0Lgyj$iY2x91RzgptW+uybG#hA3)fQ!*gud zmIX7Fh3h&>kHmDXd%uYTbmG1}0#K=HDMJtHj6|GSS^)v-nKT(Eo%uz~IpAPKV=?HV zD7LSE4Yz#vs~Ft2MG`i?$vezZNaS=8gG6hZ=&7=w%;$xe zUAu}GpZo>3ul)<6(J(5NDi{H2N#v18IE0kANl+?p4oY}K)8x&vpja$o$Bsda7Rnea zmW6DYh;m{$Kynp7W6nh@$|Ov*x8#sWm?)Ji;_{hHT3nI*lg>6F-O?&i&8k!o%Vbm} zp4RorADTEohfU8hlkU^CpsLwQ=iszJ5Z%4K`22Za!+wVyjcRcm4=%Y8FFv~hcC{)4 zo;qU|K61?RP_ZzaFG-HYq_H{WhxJ%Aggv@i(bd&1X+x=8hM^m1>+Hnjx%)yh z!YB>zkX$UNX)q#jWkjR92hjdqiGEwzea!ypV!UxvHjRtEe>LVGb}a6`{z@$U@eRT& z95j=@WGv#7uo=P35AK8JjvoAO$7D+lK9A?Q}EQiw_)>+Q6XI6F(W7uin$R7#zEy$aY^#p+FQ}m z(t`2PQ4|UV6bePZc{VsIZbri9d9)gGP?4@yZwN~{5;D-;n#H8kXimlDce)h+ee8r!V$+&evHp!UQmB$-Gs&1FnS)~mX@{iZ5wv7d zNF`&)H8-It*CcIHTG!anAgYxLhDSy*GMbkt*NCE}iiHAmp8CCtRZF@7J*^qEH)qk= z)sAda6O?76xvLwIcoNl030fe4;@GGPMNPf=z)wybpp*9P=`U8QeWQhnkTiQMKlqQk zux`!kxbo7A{7xd<4u&TAis!mW$4%+`&_Yu2DE68+51mu?#2=o00;N(#fFTgfiMH$< zhNWC7A4uA~R&y?kj?OlOqcNnL+u%3~uH>&tvn(4Hz36hh_P>RGxgsQm0C*s!1Wt z>b|2nEf$WI{@3$x)kWvw-k;npe89TMl;2HpGgkL)O=;wsvzU9(;dtTk2Qi*63i+}P zAvF?fIQTs!hHfc#V^K6WHzA!)qpiDFLUfQ^qw5&hx&>P|Z$hb1Mx|Pn+Re~8F&>7- zi_-gMON3=ib5jPnrnGP!8)ogjlMzd0P|4?^83y@Fi;#%Yh{@mM|L0eNw@{m+2Ar*Dolv!Bw$Ct2W z>-Ku@$3r4+B9Th_MQ*hU$Ery5A@TCFL_97o(%RN8zc+PsVR+{bY+CmQ^5X@#2tx5~ zS*VqZl0GoMVjjixD#Lq6BT^eO!=5y2E;{!7pd_n&6$ZAb(H(E;+1;tdSgZyEZeO`( zsqXF`eeuorAezkLtEc@7e*2pjg>30&jg|&Wk7+oiPWm{^}__|H%FIvVvU!OI&X19zD|6A!xmG_JbBl;&+e#6oWel z&^F}*n0Lg9*!apzc;7?D`lwiIMUe+!r_QmPwxlzL8f<4xJqHm zUw)&utoe&R^_VYA+=3QP%k~FZi+P^<@WF@Z-@fr~DMByqI|-{+K2vXyX$S^_lGb;2 zb|9Thh-H<=MiB5Esgd^kr(^KzCmuqvR0cbRbS=8o!ABg6(=WOLZ@ly@?!5A1D4UhI zA(c4YHrJFvwkacdQP+&UQ7z`N;nm-xSSTQ#Yr~=ouEtAGJbEjoj zpkMUEJK)$gTyoYY@$`zPWucF0KHD0{pYmBOIQ(ctV+mQUc=gvS@zhV3AfyHGfqf6e z(BMvN-LOW8lsOT@dpw!Kr8nJ;)}F~&a@o1q@aLD2h?&y(Vs$RiTuD8bnY7b_SqRRl!Gb#Ut0=i<1} ze;KPESc+B4mr9;QWZGJrrO8z;m9fX%`7pv!y!`AFs8wqc37a~4aOU@J!P5`ih1JV% zmzD?13-Vz!8o?nad>XSpbT}UT0i!LDNTg)p&`hQ~iHLktld&tBh5_w31U-;&wm^1%F;u_U*8QIo0yu9Ke zJok%xP#7D-LC2qr`~Txc3CXObnCS7`Nt1eU?)QHL!wBIgS6qnkp&?kdEd)NL zA8`Wy^z0MZynY?V3tUcCXrD9%7hLxfJh5ykR{v}Xx;xt>Vda__SG5oS%$JaE?ZVRU zeg#n@fbK~>0utSgp}tZqsC=QQAMp9_P8^_~c(7k7w=WQc(gFef@+A6wVIj^`eE0Q($t7_PbWA|Yt5 zliBrV7~2=eo$@)Hc+Q1*;?A4!v!t;+lh(f6>=>x4S+u4gt zZeE5b@4pkPmfebUDv4ymlr_5<^AE;?kADU$?z%rXm?otM+bSbN1LP!S zD@Q-*>?XhGk(Z8^4YT8BHY{x(LpZ;|%xoC6NQfs0PZ)-|u- zkvng~z_zUtKqmEep{utSuA{JV{RWJW7gV`o>7Tjc&WQtLYCb^WAe0B_P9T7*F24k) zo%3Y`f*LNn;EPyt$K42UNjS(wzW|b^Ar?ihBC4PL+-dm2;;XUgFMq(d&OHaOtyu>% z%;J{91((a@QtY1ptxNIGpFIb6Ty-&4Jh)7n^|ZQVO9z(S{$n&HW3uecCK?w9CQaKD zm)^1rufDh%ORoGj0?I;rYZF>KIxu4KAO?c_$SFv{OIz)8HDg`@; zOdMxS+XLrbbSY-eTYz$56wj}G690C|B`A!Kip8;-XI;e1_sFA;!sR#LgI9jN64zby zWf)oj$DMK-o?Y=2)~|g-vU8RqTw>z2r_Gp&Z}i`b$M3rx4=ug1zOrG$G$WGLw@;ag z!%sOIfBwyLc;db#NSJ;SDQ((l1fJun(LzZ-^V<7%A0S3s0>mtoF43AvV8+zRIO(KC zIN?*DM!8bO`Zcd1=()(Yw#x%Lj)QbEj#7RMkNx837~Hu7C!KZ%HoWmVet6ZD*t&g( zkhI^f@X(se;`$|bVaDF`an0BM6+_#$V8Oz}aPN}aq?BN?$U>Lr@EIstxcJ9E70!BS zNxyv0+ON^8<~7^)*b_&ce1`O--gs%XbV3>B=-!cVm|U(ey7-p=GXRCC9jHrF8tdp> zb~*dZ&)~Ct=b*J~l5mjcIvC!$4eQpd!84CMfag}O#9Ldo3uxUvUHH=ZUy%pA@rOUa zrZ+ds6>D@g0H=QDRD9#AAK{hfS7PVZx3GHEN~~V_lyDl)ksc76@c^dJnvJXOd=Njo z<5n!c^*YI`GI3vdLN{W=p4aZ3x+e}l;bgq@=)D*j9+3c0s#IYZhBBjJ{fG;9BM+jB z1?nzlGFSzG5dF;ost#beKs;jL_>Ucoj~;m>QmGWmX3{wNxZ^Q(`ZWAx$r8N2W~~r9kNwIwzlBrJIS;p7{asvt?GL1N(ujJr9sMpwHw#g=9F%Q}qab;Jo&SynJXyZ zGf>dw>j3D({JF8hJ6@_P<+}O}KYwoG0Ckzc{)mn~Ef`S2U_hq@NYtq-Hu6=4s`6E? z;%+X4KrN9uRk^0-$)w-@_=^(W+}6EamEa0AGUSNpqYtHBxqD#>IrWim3s~ zND!G=SZ0gh(2B@C4Ch>dV4}^Gfc(@@0RTH0KGB&u{+3HAEG>hR=O|QpoH2!cj)bfd9P8Q5D3zDUDdjkNLkCT=q-9hsN5VW`bPEzQ-|;ZTn*K^hL-4?3=n8yj4vIug-6Cg~&Gv@i zlK{~7syn+a z?WjV{(^vg|Hvn2NDb*j*f_=($l;e0hTNRugJ}{SnX;G5mhz0otD?5n3c#516@q09N z-7|@qAW2jqnNv1L#fVKVvt@t`KO7iC^*99zU}*QFULz8*()YUo)Mxw3`>|40GU#Z? zm;1`w7v0HXBf%+G{Z$mcN;Rdb3i^tdb^{=;tj0omU#V78rK+v-CJdt@rQ@LM(%nYk z$>n#5w4Y zY1#g8FwmzQSCy)kxEMQjRF82sNT!s-aCNgG3HCwq`^vs+_<0k-;UXh{X@JuxFGOHf zH-AY$Yql>Wr;@fFqRD4;Nr`UC5g{jCn3F_6eD$oKd@|bRD>eC!R@WeWPOd2X#S=VL zwv_(x3%lWBN6%^PSGLnvEL+M_N~e!g{7v4VH8m8gBuxsrU9K$DNtKaCHl#2YQA*Cq z);WjkXEb}6b;+Sz+40j*koroK zY|fMVi77uNz%+OA5u08d0I%V1oAURK`8$4m-e?S{;j*$Brp_a8FHws^L=(V$39&DV z;AHr@7>OS1Nx`3E!^c`Knv7GDlTyr7v6c^2A+i(cWGCnM952BXEYkS#f=iQ5H4=-_W_;w<|S#ZU5l z7xT*kCYJuTC{Ox4v_{|J{QOCjB=uyFwHRf_Jca->0?HNz>3KW8mb>1G@J>&-{ML+_`h$|u zlWb6V$1XtW;u*T=3>)T7B|a@j_M5T=!p2p-Uo67#`il=ueyUmZQiLK;{%&*MM$MPD zcz)*1^ZYFgtl|7N23?4j#cZ9=#H5jtjaJ9(oLtG^PM7BdFrx8VoW$WmSq+Yr^rcU} zc*oqibI+I%K>s|q{oliS@Z3Z+tcn#&=b&p8G)X^!8MEI8<;>7RI6I73tf9z1Je~z3 zNt~?-S_C_fJfC5_kqOgf2?nDWoBjNqJ|x$X0008qNklC+`Rw(`+spl03AG~ z>EyO_^p1oXR^_U#Q?qP2K9Ms2@oOaCud~URU+0UN`!g+jzAWY^LD?agPQ+yJTs~%K z=FC$yFS!%1Rp%D++s={v+gmb4dtLACgeiUs2BePbXv>LWpS!9lTxi^%mZj^uq$HH= z@%qwctt;H}BHgPg%XaiLF1z8JQ%*VM)@Po11`8K1{JS^QaZ@il2F)Lx(fmkfQ*vI& z(9}qwB>f$lv!4a~=1%@;O2p(rLTm`Z-{nKHZR9l6ASM%Wk@b$`i^2oRxQTQ!=4Zmx z8rBOTE`9W6`lNuZN)%7cNCJav$M zKEzkA2Ui4#{KKG(> zt*X(&WJ!?|3-T?&56PaGv)^RbL?_hJoDqE?rFc}A8bPgUVf&6j6iO9|NSuK2 zV)^Z@;#@lBgEo@S7;7MF^M;DmKP+CnIKO!D;=lUG6W;X?3mkdmk>ST4dyEqGmTRuL=E#{dXU>jBqhZ%| zJ%8Qlf4|xzA@yo9MG(}*+f(4NmUU(rzZ8$ByzPS3guJ@1dIVX*TmGA26%5T}SrTUHq zng8+py8=i~IP}m%^-85;dY)(4w*6mC=N|!*cRZtE7~~o|8jY4$ty=XzNcq1H=kEgO zJy_g73S14b>n@-7y#ln$3;zFh!21C0Vn*Kw=zV~8&*}dcj@52;LpfKp00000NkvXX Hu0mjfN0WLB literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..968be2e7d164599a401d9b354f4b6514a2059feb GIT binary patch literal 4643 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 Q+l2s1a_X=;8H=$00U)_m?EnA( literal 0 HcmV?d00001 diff --git a/app/src/main/res/raw/m010912339 b/app/src/main/res/raw/m010912339 new file mode 100644 index 0000000000000000000000000000000000000000..31b148ae5ae93c5d9050b0772540e743625a0e71 GIT binary patch literal 2379942 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 z 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

    l2r?f3uA4XxidsG^0z2E8KB7A$Q0oeDl& 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

    FBnO|)%&jJszEcKL)_^S~oaPYfR z7t)m4Tpmp0qDh{D4QG{>n&5`!7j;bvWG(udG1x=grnpWDGA8uugz7nZQV*nj-1KgG zJcFt_uRpbKtW_78k||E?zx(F#8myPC+jsia=*vqT-m@y-Dd4Q%^I+9A&<+3q09fbr z#e^ZU_>^*HN=TBxB^(BULP9Q}!J-Qcs_Xt#xL9lA!&+TMAp;iy+*6fs;y3QX{h^Y! z%ms?58dt{UGg1b@eW%aMqOr%)Y1E80)uO@O2uvLqp_`GsK0>stuxy6UAeRm~dBTV8 zyhmIh6VQ(g4k0sK083K@06Knq##9#E%7>of!L_L(N4At(r88&zxHYxE=qxI{mn`zq z+i%N8U*;o?XI4L3LW&8sd>aE9_jE8dNPqy2-!&u%2>_5Xa{iS@%1jGm68XUaA#;){ zD;R3g9fiNw#HZZk98l9(>FGUUsI$o9CQwnf#r1 zt&V(0UiEjEKIiHFSHCypcYphIj@RKb%XRJaii?pF009*4EKUk&Fa;`GC`lCtD$|yu zG*WHi(6IJJDU=pOA4##KLm2ufF4K{ep}r?p}eh~arw zta7}4xf}#8w~f{6yfZ5`g);beJi(pHD(rNkPjGHC;U8P@U*YoeiF;r0b$5FoLYX08 z#x+Qf43$}g0;-up1-!6;sf7lBWQ5Kxr&g6?w7KTrSLSRV6M|}(RfnQ7Oi;>`52zs} zFBKPGC8S)PNbXw8J#`d$%$I`dv9FvLh?r|NEc>H~=JCUD;y^8}N%vI{jsXeo@_LVGN|rLOimo>6Q)o!t6Er z#>ET}a7rX1yCH&15G+MvMcf!Dzgv3%2||bf00Jr%oKmd*Q9vL;37|S3L59^^mh#kQ{U`&6!AXdKlqZ`=sL>∋2(> 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�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�WdFrIv(qjb`k8+X#hK_M1bVRopSE6a8m`g{|M1C zD|d9G>s#`)FpAGk%m{{1%sxE%?EgG(>~UgG5)uxWecW@}$2xC+XP%V|w6-xal0WjZ z(aH50SKt}EyJ~nA&fOu=Z%uP|xlgJT4lO|jurLs)FU6zxou8dhADgx+deMKFaDLT% zI{C10JFPo0A zWv-WhHId;Ffx9q=*mRli>Ocja?n#-36^*A!*Ra`liiOFEOq&rSooIP&^v4D|fHpVJ zycK`EK|}=v!FVflxLC_7EUK#(_oc;n`H^llc(%8!piGPUeUn?Q4Ur{ig6!tKlVE{@ zU>O;zg|_tM#ew0#;)$#3L+1d1l)zG@6)NsN@_2=!SQez2-D@7cgCm}nc!`{axyyy> z!tMxUBMc2HqSZ7a7GAc-f>nXj61*#YCiUkVt$eqAbDx{<;3cY^3~u=$!Ke#O+BB3G zjTN%bz8ED!8sHW|oa^LBMrHD@;={^&f-(FH3X1;sq&Is916mnNV7we-5nKVD>H#y{ z7Hu<$*nfya1Hh+2b#N?_?h!N0LC|f0R#>K4BFB0>F^ltmH;lNhM+#kbjoZvQ#e~Ix zgexM%c(zetQ4Pw0n#?+NYTqUwXeF4>+isSs&A3|@I`R9lnh-ILPSHXuR_wLmrBP3# zqopF1ooP|1>R(WxC{fy3}hnj+K46~AB=de-F9y1C!)vTqN_0{jez1_I^YsHPE!*mf0MESDKw z{QGw^HfY=nDzvin_O44)79Us>LXbY)l9VCtZEe+3{vQA=LDRnU2nIk20000SI0~rr zTNt1d#RXbac(^F$DwSeoQTPXL?K}&9dd#|pJxH;oR1@IHeL4|A12V|e>XQK-YU28H zv^2@fM`jKaMI-6@Hbdg^Vy8@&mf)OCbqkcrX|xXE^Qr8$9av8=*y^WHQWc+TK>5&lNmomWd{cSIJDNxj_wh@sFMAXDFh$`3gqmP)9&EfFDC(>RSfa%_lbWdYPp;=KSW z*-~h zesV8H(jNQRy6(AYB1@&&QSu@ZLLjc0+j6r1Fcws^+NzI8E+9mRhK|-Gu>=V5|ggG9ZciNU6Z9^<(ta$)OA zaZeFPL-OhLqm*Z@N8?hQ)=P(i!3c6AQyxnLQkF^?m{7a2_SbXrZY4`=R>Y7>QDP(V zxZUPyWk@7iQO!yjNg9s~CXe3L+>sy0Ev-bZm#hQ;00E<|P{)}IB?uM>4j=-Ifj|+& zLUIvZh%$yL14Wq(BAPHR$#GN!rL`T5l9w=!s^jJ0h0yi zs*B&Rg}W19rjofTsxmcIlA(IlaRLZLxlm3n ziFF({N(3k>8atpQ1PakpIC+OFmm(Z8+Ms}Z$|Q0-7}v53?% z^1)pu(M}&&VHBNqMmWto5N!=uTrp7SZ859H3A>WA005OQK{-7PRAoZQ8xl>t1&n|WK4A~CvDDEaeq%`mVO3c@^Si3E@ROb@16VLn3&YYDdG8H7V4avrd zk*U=vF;gZgDqmsOYRkgZT8vCYvKCvbTMaTJWTg8RT(G)%>|5^DP~n%Cq0#V-mkH|* ze`*`)KmZ2GCo~INprF!4K@w>U7z?J)RK;Ax<``@{Qdi4R6?+r0mgr1bBnqCiOzj!Ty>kEipaePsBwbxuODP=ijtg5aWg~u41$AYNFwKH6Eo^m`4f(JE zkCrI}C;c;X%Ph-KV+0VfbC*5uV4w-Zfr*d+006p4iL?wz7&8(AfSn^i078X(h@WmG zJv#9-p#Yot=9 z3Y;lX%r?h{0~I`mW$-oXA71c9~!J6I1P>oKy<81y7*0s zrA%_Cb5|NF265YU0eGPGN6pB`(I%rj8X-2X{;p=N;ogAeT0sA zRs~`^Y%{P~gNhggx%OGdq6APOS($dp-d<^yoyvOlvKyj`!m?P#_9iFAmA_KdD{{5| zy%KPr+Hc#kF5G(g+DDYQ1BQ#de0Bc zkt8V*nF;_BrRq!w!5Goq4^a#t1VLE9!7p?xOBi|!WsUR!IX?ARY)pY<#)*k$!Cd@Ypr`AYmF~8yQpOWV_wfYO%*;R_Nu4_GJK~QuB~W_r zS!HyRFxYdZdMn1>3_C`p0=JcAbl)X6CUTu5uu`9-Clybk@+vfAbZV00 z?Ucf)Rph0%x|kMMx>~N-sxbDKsQzuHM59NJ(@xYz5k{OP6(2Kk7Z)o<54}kF`%510 zBw9fJ-r{4@T}fvRLJ%0 z3Y=_*;F9*36-mb zy&DepqXf=onZ$F1vZo!z(=nL&c+8|&tMR!bG&|?n%(C;y{nld52aO>%>#2JPu)({0 z|2mAFPpa1~{Kzq6hBm|PG4-zsX6fdh;MF~@R?tAqmV)B?3_T00QnUz7n zb`TZAI*3`7MoG-OXGk%i-Vp!$uml}~C3;*|!!I=Oh3fk)VS{c_30q~1B+bGmC@j5( z8L8y~NTtGMMvfG$sg@MVhFER~JBj%1wHH^&OgT-)2J;o|;AT6Ed?)wY>qD8kRoa>n zgz|T{RV|bU9$y4yTW@z_v2fNzUH1x=)H3Rf(qO^&)87GOgQC(gE*?T}V&_;`%_FFDh}05%^?l-7Gq0wR$ zR9C)^O*%`*#1O&g+qBEuzJC$fmd#m}tlqwDZnNrn(6g;A_5aD5fcz#IT30-uyq1S#a@lc;S_)s>q}X%`fs~^>|NF26Api!}WYoiNO>l@T8!BNVj#0^xYwRS>!VazN zJ%bK#zpe;DmRFdNiThHCxey$}>YZa2a{eZ5s7v%9Pl}`6yy+*TiIO^X zsOH;UwCBa6#UeQ?ZpTu4eo$hzM&MiunoCrfw5?aOBbJ_TTN2#YR_s(ykqv@HrS+Y0(rX)b@i0P(X2C|AGBnsG?YWvcBo$T5Oz8uEX`STRWg(mO5@qMRVZ0JAC{=fa}f6DK_8;fsH z3_}U-qIy($R{rG#=Ck(oq@#BLf^N@=eY+DUl%rJ>r(_xh?%=@GThzIQ7y zZL&~DRwOFQwGG>qHt!3H=g#oU^@_G5^5^DHN)kFn6$1clqN<98qw2O+Uv7*N zN@dI{05H@T6(y!D!5Z5{+IiIc8m<5PumlZ&1X5dDYX(GOfeedHV8fUf!GTz;Fx=8K zux&krndxcYxE2av(w8$jKrkdqS*V!$DKJQvS=w15(7_3T#OZjH6zf4V(sn<9X@0Qu z=?2Vc#dIH`r9*ZqY~_3}P#lA9g(Qns`9_B)7Ku@$1#O-i?g zZbjUZCM9{x{(L10|4J8WA^-qMcNd8R$`1P~$2geR7drq>gf?dg^Dc0skJTiu0H%kj zY*s|nfo#Ofb{ z`I~1yub(B`)w;vgu1T??leqylmW0<78bA$Q){$kJtd)F-F!}<304p+LhKyPaz&xXq ze$Ym}6cJ9@QXj{egmGR$u*I%T^a39wh z?O|*2v(7>(-A+WGc8LPJtl6~Gvd!>Ns7y2-xR$ui)po(};uGQ))njbo%bOvW8eOh6z3PVi7cAP@w3h`!VqafArSx_Yx!BdY5{ z+&N0e$bn^A!M04DnZ{a&5iJyHi2;_?w4sGXn4ZFvq{^Es3y1jR>oVGHuU^oo*4Wl4 z-tfK;M!7R8W_@jJ^S8I3^S=9UWm@YAGq8k=D{o-Ko)F1XbF4gT z$~~@Z^@bU-R3l8esw`@0!-$%b2cl``_<=-Ps1( z{co?nOuavcDP{W0|HGEj7?Ljej`2-=r5CUa;n`hCkx3ZuPsl)oNL~(+dPb;{Pa01; zt5I7XM%`S%lpg)nm&B~_q9n(8gvs%~raA)L;%VyeK z@7vD|-g>hrB}A6KVpKU84Fp+nK&Y{U5TgxQ_6d5$rD!Q3k5~s9fM0FGhiHC8bxWk?t&NQD9EdK01 z9i@26{wr*Bi12%hGpiAh9ST<5bHm9qZGu5D>oby13vW^&1PV&O(wLNXZl= zkYYE?#21S~0O7o?n4TuhTie=@ALaEJ%rD($f8hl8FJIgJt$fdJO|kPXBR5ZUzk1es zoOXx3vyR1UUq|)nDE#n@UMei{_I5`sL;wH)x+oDDQ$z(c3qb4W#K`L->_P=-%>l-n zb0}Cu&80ii7$03^goMNjTovl4t)W?Av1$MNuml`}6i{E=YY9Wpg3HT2VIz)IC4*<| zF>}HPFYNJzjyPpvU@mL!0?)PhvRaA2F1~s+Z_Nw%F?bv%utfa<`X)A7}&~BVjZt2 zrhaxekNMumqbsB26P{k}^$>YcG-K%m2&*H}pD+7Bwn_qRTim;dFZ$c-t^B%2|~ ziT9}y9Nqd@&^?Pgx>*R05e)zUCM_^xRS|U+R9TI1h(bY5gbA>#?lRqsS$$p!$o!_| zz1BB_OoPvOm-bx;~hI2LzpJ)`fw>Zb(AY)zNyM*40Cr^r8uSoZRVc zKta7nCfx@6Qar&!^SvrUqQ#NH_|Z+2|6sEm`a_f^$hyOWx)yY`nF; za^)ptwQw{N)sZ|DD_@6hMceX0Uol$?mKh$v=hizjE!44UO`Rp2-i0YVg;Gr%a1sFl zIWmI^GKV%GEfnly$vF2bjNAGd*n|T2P+5}NqMeR-@58hwh7hR23{yQ}PUcclZ41y% z-oDmda|xUdPdD5llav35vo=V|xB0pqaK$62|NEc>D}V$iU0dr0M9_-bI}=Ci=04%V{$9I&1E( ziR#*(oqKw#UKpvacDp&GnMY)x_M!eO8?>XADo&Jx?qIIVM~fxpv2AN{rhotqt6^-1 zfWrnz4p`tE_2(K;_4c!)^g(q&ff5sk;{i;`h}dU%+yP`Z^@>dr*DSUO4|EAl8K<9V za%#CJT+@GUX-q$ojhidI5NL>Nqv zl#MPftSG7tbDB?Ms+PT>Oj!K(fV91(T zfty;aJ(0pIuPyzAnb=n&MUcWT#^xgMWx^~y$pNf8Xqr6)nZ!^WqIT_A!zPqSwDisyZ4OBX54X)n%AiHwMGP)xX+)~5pJX%sZfur1TvSZ5?MM3o>Z{zgj;nx0< z6}&^GO!1pFJx;Pw*3>vq4S~ZGKc@BTez-tPtdPhAk^y@aK=(8CZxDf3k4b+lGSg3X zAo(YpI@jnR8AGQH#UHtx?@FkYEh9i;O4fcLt?UyRXR-Fc$T?(ofQl4>1Y{n%&1am8;4<`EG0N_ z#Uh#@+7^suk@P6y{4%%n?L{nnjr`a zz+ww`8X*aXh=Xy&T78qnpHpWt*DRb?fL~;b5dKej_(_3i4pelXV|A1eyUA86G*T)J z$D{Ic^b?a+^0fTg>Iz0j>u64SgjYtcbo014*&4~R&HwwL1TO$2?p)Z*3^VYJ%KIH* zBaTnKD|PH7al$AwY;}eTcv0h00wtwsrIqYVrT%ltTPHjKihDz0~7fGZ1Z*&iPPqQMYyAbzj=8Pmd*G0M?>LJl#Z%Z6{z z9QjOQ+B4Dn$RRUzzxAkG0(_8|Ci2-7zW5E8i=?szRUoxsT z!(54EG9OYUHx)N)AiYl9lNw^Qvhnx*&0oL6aV${3x|}U7>ax7aCw{uAA)0rTli1eh zyvmt#gh7CW9(I?LScTIlhxzU>)-`N6S+|QgS#2CxIOA9SEDsojkOGPtLS!*fA%HHC z6BI4FF+|pen*3h}P6@k({G;=8Szk(pJYwUKVa8EROkEtuRHgLc@xPrN^l??F^A+_vc@dh zm}Tjn6>W203_Xp)y00qXr=oaKK;x})Y6w)zkQSm!PAx5!)@H{6wnXG{K9HHsBX;4u zq}1UBj&7H`5v1ETh>|Ye#3}X$qtxwAIyB7NlhDKxg4#heE(`zMmUb5xt)=D%+G?dewTxk`5y(a{YI%m z#T3Ms7uI6Y>g?80Cy_)!JZ?i$pi^sjVX7iCnlakd&j>__Xpo=AO1!{TolR);k(Bj) zDsChfD5Y`Dge6$<;o##Qr~A9Hw5uwO0g<95tybnnPLf9f`cYW0Njj}(b*VYyqtx7|J= zmmv^ZOQz0CLOvPYzeBCJ%c6RQ5@y#GYK-7uYB^phnBFg3o5EMKtJDP5QyHS}X~yRi z@o<7@VlRpYwuMC4dX-{GSEe{8DWZhvX-$qfcU#V$ql@nI>Q6^LUn_%>aW;`MwWwM- z)Hqc84PNinhIh7ktE$THbW_eZ*Bv~rjzS^kST zR${lQSy^03qM=BFFREP8GVKFwKRK9c@l0v5&X2j-BTBuIJYqQ@-!mA^q;BfQj@ror z$u;$3Q;drH$7pScs%3Yy|9zll#!tkSb=LJG**wMg4o^!y)}ds0RSkdHHws32yqM$s@JJ>9MK@LmBjSlrilOhumlbQ1#Vo|BMdd* ze2Y6xJtcZojdfovJ&nQtEA0J)4e&5on6srOZumK^f-Q2yMv?|q2nri_Vn!rD;Isy? zD0<3E1Fc8#fgLf>;GlL``lO|i*)aQZNPmqft0xPeE2c7B`P4AN;xP>TnXwqQOpWD6 z3svFrXipUrA030}R#p0+9q}35M!VVnihmowS#%UQ{OOZ5yQPKa=-gwX^vjgK?~8vv z{Tnv^}^+i>Y^av*w)z4d#3fXF?Vu&YM$#V-2WD=uerABls1s=0VCp@TQZ?m4e zX|k)csx38fVSa^YNUULAtdGW`uA=)~;+sZor8o7Z90Py_sE8JT!FQ>MwFe7KoY10S zvAWU4Ib~uVZE=h>lR>HJ=@lCJ9Tk|^WK+gEU!@Ohla=S#O*gwd#UZT#n~te`-Dz>RXt8#zT={vCBWUe)^Y!bCtS&%P6Rod$apLm(yh?!KxHd2;s8>XY zowF}>&M$tgBD64U|KI)FJuusB!vq7lOx zF%Xgn0m?$6Ru`xW<1t%DbMsns_We%N-Rf3d=aWGsSg|WOr+Kxp`UaPPq z^@`J=oXNC!K)h;Z`PLHZi>V0``KZW&@7!AwXW}58C_gz`BORYNEO?G>3_{3oLFS7A z8N?&jF_!;DNIQ(7f-y&^FJa83O7Tf&X@Ef?%JUQji>HIIJQQ7D|NFoM34jDPU0Z7m zL!jX-+GTC#*p?Z4S}ZXd!a6bR^@pJG)olQI*(KKu~{WEWt(- zotVReuQgWpNLCo(?An>j7d}dpVUt0_wszaFK^=iBRQdBAP{#_o882xLf zibFN*e0<5&;v_wdDz1N;d3ZthQ*&1~6V;^%#vDC~PS8F?KmY~T0D+nExuYwbIO121 zf)0TpM6hrmy@n0~Bq-I}J1D5-E7tC(nH`tex~ED!tz~R%v87n>wW9B(d$7eR-BnRw z^o&_qoTdsu6aWQ(mrKT-DV%ko3~EO9R4^r=XrYi-BG|ivkyo0Fv`|YDZoxbj`bG_4 zgs+!I#w1}a6s0@U#SUDPBQ#QHKF9)bnFtm3gQO-_pt7Hbn*xOKT@)&KSBB}a^m%Zn zn$lH1w5_}MyKu9Sq>}?R2Nn-ix=?&YAjes!o_pb_ms9g=-XmN4-q-!M>-qGNm5-~l zH~`BBOzeV2R3ZS!0#LH#P9*&jB)4e=6-D~p z-D4|dusgGivKq;I)6dz)GXj_|2*m2JNsQ@Otgk}btYQ@GJ*+eQRpzWg`F9< zUPN`dX8G@-XbXhH^RjH05RTtZ|5Yn$@~x1GPUa{gIVl4K2BT*#)IbJg_$ExS_E;`t zne)KyZOMiwnpUY71Jw@{_lXpqpQMx_Kyq5Pcx`@jSd00xR- zRYNaL(6j66sb%S&5jk^ftT7FW4KJ+qgBE$b&~&zj9AJVX{V72*VT% zh6qW5K$?W&gHD8Wzo&znB(!;yCoN4li^pqGIAIM`H{+G@fE=oZwBmmUueuVBQ8PZB z^%)!B7gN1fSrP?VklgiLC&n~bsq!A;PS3(K1hBF_nhLG~bjgN`ZOJ{PG-3>#VHku$ zg2smWJL}1`05cAP5j8n|HbiAR7L@tHVq>BoO#OsactgWVRfc=GzMznX)H_jwR~lLwm;MZmAJ+P2D#?M6bHS7@vr#e-WAM z#i%E1^7`lY#@rCRx=o$e-$1z+OE#-r!;4Qj$iFKU%0Z7JNmQGWVTRWn%Yb6NV^ z7}OnsT>o#@UxYNB=4%9btBC1qc9MVqkljhq8rgXwMot2eQH5hln5u9zNEJh2@@@^w zuZs2TaSn_7N`B#-TWDQf#;hOBnYTmk=N|`7%9Uzb4OAvsgZ3t*hNJC|?vm(z3eRX{ zKI7An=4z7W-=rMSkx4e&R*-r%aW%;HWm)Kp(slUs_pSv;L`8(7$BIzK6DCpDw;t!= z68O0)ND>mcM^Ho#V7!CG`8*3{y-JqN8CMPFFdWUB@;oAT=W9d`LCf@+V0V(ewIv|I zryCeF%XIfL=bvln&C$kvHQ7m$-`_g}ytVcC!~UiA4BWF_(R^Q-eRfN!G&?@7$#Cgh zO=2b(RTxsKj0jh&zQ&rTv&4~IKf~1HUory_QjcvE`bbZGaAW;q(N(g0`wIzUINR*V(00gFH zpwz3OriNjrfZ(eIQZUjwxQljGM}RL!>Vx zeh{eeTL{i12tHl~+6B{4wxK?>$*6kHF^(vs@nFfWIeQRgF%{-4TEr#$rR;ADNcv6faSevt@~f1A%;Bl^s3IAnGbCxN6m7>W;>gBme*a%KVm1 zg^f(N$?}8fvRwtX{IP-j3EK*S&psSfqeA2BLf%BmQ-iVreh0NEo~=}xNmNFk|NFoM z9fAa5W7=yBGT?`d+YezQd>L(#SgbuU%ONi6<(HaxjSA`6%46l+Ibi#)Lzisb5_$Ib z|Gqyg{ms2)*YyhAsa|}$-1uTUufDS}`$lDEe*KCUeIy8{GKTH_|4$oDQH_%3<^7jt zyVd{SbFn}f6c_~|l9+)Y028kA2nbX*0K+Nr+^3`PhXg}bMkRX7Eq-L#ZMYiSlGa%RRtl?jx@n=W{8kJ*@Vzb3D!`K zcJeYPPYOdWZBB4i@m<>r$R|$Q*mzE%wvW$m?{@Fe#6Jla0nh*d0F3m>q8%*V6s8m; zC1W8|BttH0Yb*WqfLuq_|7!{e%O#b}r=+Yy@VPI*5Dn2wM4n{qT-0TeIB+0^ ziQ#`NV}a|5BSMPSSLr0G?Y+@|QWnG^5QZ)!ErJk9;;^UDan-4&v0!Bz=30>8h{UTd z1JGCy0|4+L1Q50!XocF1Z{|s7Yi?jUBF1cB+_N6o)bPj>gdkvod1s0`t^5##5c<{S zyR`eQy^YDdfGT$VKGBYlj9f0;l3xTU5J%T?DhF@?004#xp0S1;LzacboCbhGTv1ap zl@ELoRpWr(c5692+sOM#H2guWq+Hh1|>IHSW8JBFpO&(U1cMVSix~w4LuXmAgt}Zh9Nisq(>1`&S-2>Scn!22@1Yq zlg<)^PbOfnY42EwL<0qgLoQvE+1DWfs0|7Y8NkG_qsP_^M@c00%LwWugsQ6TbDwAS zGc{6DtCrXl48kB(6$L{{HW@t+4&VRMQqrW5000Y^a1-=EP)Y`<)6f(WIVk&cTaFwS z{<9e~m6lO?eIY6Zh^NW9FggJuU@E>4;WPp@AfDiGW0tO&3E!qwmpM~B>h6+d#dlqE5am7_{V5bf(Lc1uVOxU{^ zBIu!TBm%-ZhwvlJkxEDzqDpoTF^XHoVua2;!5oE~r%Aw=cs)r*3X`I_m3kpPLfySm zo#k?mW<)hqgyGEi%YwcR+u|82mp80RClh?@aEPf_Lt2cSa4&~qm7H!C_^DT`m(02m z#)RZFju*Xz1U3Y%64EDTR$D`w7mJC9ex>&;dQ1>Stdu35ai^Fl85Aand@d&#-{-`Y zqDYK@xws+&`b~#`SfZmY>uB_YrZj@1$a)7uqOK}lcoPfVTvmXadiEDrFH}eUV%Z85 zCI^R!0u#gPQGnAHB<6#Q7_h@wzqWV&-XR{*@72?KaVc)5mH-wB5eou7> z4eX1?AF;@KqYPFVP2{k)k+S-J7$+%2V<-oaG9@SCjPn7+=rSDK$a(mEs|ykC!Z??Z zq&(VwbTBt4TM_R`yK^hmA-eXjo7W9bB`%0fR?U^tu<3bs%tqt*OY=q{CzM8_>?jvY zC|f4tqJl7e09ZbLS!k1n(F2f^m50+d#l6M9DH`R>`jR@P4H|yq$4$ul7avIn3pMA< ziKRcWLD{d7000He##Ifk0r3E?kLXyx)5Sy7aEQplmoQrGcBdz$**jG7*{Q3H9#N#u zB9c;rK_Wm}W)KDnA#Rdnw&97<=BTpio*Q1K`yY3S)xANlEYBX;m?K{d6<1!bgSD=yZYO5-x{ChYr)YjFjxXbm zRLPmSO2!O6MSy^Q9)|-51l0Urm;H5L-Hno6<3kx~ZUjRPB7lX6Uy{JalM-0%;wIBt zmbJqC5LktE#88n8BBh!Jh)vo*iUuV1d-b$pt4xb23|oVom!<)UaViYe^E41v%OeU9 zk%g+45Hp-Iu1H|%mh}~j7jKhr!a3x(KF+a~A=K%a8VNTg4-l1A#hLyK{f>_mq?W1Qau(N27dNT$)_>2{8W`nth^EmE6&W4 zEsZ2{f((^FH>qVXJ&5(Yk;NK@s>m6rjG?mwfi+?Q%csT#uq5po>cL5V+=6b!ZEBZHH3}%FNu|LVbo2YS`R!l zDiT+wCYi5&ejtllPLo-8Z;=Cym|O_rKlW$a%MH`MDU)!rP+^ASi)N>e;T3 ztf_3bLI4D%a<&)Y0Y&};Ei{Ef`=W~jY$@24($soFOg{Hqf1|Rv8h(F$ zL5=UpPgLJCI}^j7;cn>dLJ?DyF486t$z6f$f_L(vmWdnuEMJ4E0aw6jC~6a)S@kte z5@AZ2^Kz6Y<9i=n$^z=U@|tSWNIr9P(B!@XmPO?d{HexkF^Co|C7qaHa_6F^6z$Dt z(nsfL9vB)Fm=UZal2|`5LucEuy0eU6^(C&gq2ah-El->4M>+LZSUJGU1c@}2`w6A1OV7n_gh^T~- zX!cg}IHhYKWll>jc;RpBw-~=Jja%IX%;OX`Elx(Z5XEl!t>quN z*_&EbZT(bKweRKaZDL7g-`T)93ZkYfnzB5yD%;UW%vMFZqP?rn#d{ft#R3vk|NR9m zw!i=YB<>K5nT4i6DnKErgeu`Ji?F>J!?8lU+-83Js5}A0YUeqsv_%u>qRsI7IDnUW4`GO zek}t-WmG4!9h{TgTEgofT8L~?GLuxrKma+WBosguCrOW|MI~Wr%$%wwWWGyVTb%Lp zA9TFWQytQZ(@xoJgS_nHPpC>J3=LT*|0q&Y1~T>=(+utpZ1Ir8+HL>RM{=_sW>ZeB$tqRPtZw02qF z+jo@j8>=VRY_C~mM`r(|tzCrVxp*WO;#T;~2r~?1ZOu22^1o~CC0s^TL=r$qxtL<& zPL$;@0M)_B|NF263IGI0WZZiULqdhin|)xztQF;vUyLx#OD7Y}!SOfR zbrxQ+7aR9$Vjz^0y)8$yxl2YZB)1G=*JsQTCRdMDba9VAv5DDZ^&E=hZW*-eO6uM% z;5~;VzoW~tH4u1Dw2?cUktZ0c+nLZb8x54_!eR$}ZOr5qlXI_!ft3@R_HmyZ-`$_% znf_AKEy@=k`x%6?5GaJa+L32SvnxmDZ-ZwR2}>Ubita!V(f|Me0EUh|6u}^{FiSLc zYn4<|LC`@QQJgEcR@PByMR)R-b|X@EX2cx+Tz;Ahg32Bx%(P!Kp_rB;IwTr_)s!n8 zmD)2ZoG&nV{IE_Nm@5bjYCoLSbV}A8oUd(r_owO0@V`x5a`GZok6Nb0*;=%4?Zd}8 zq=T6ult3abjLwPD-AEsf>z!{GiQ{VJ{NsE7yE1#M+is6S%iY4aX5f3n(`w+}8d$j~ zuchU@ZXie`r*K|rQVudnCj$ajM5HeQK{UpYu<8K*!SDC3aAXJv+L0k;k2hp5axoC7 zQQIyABWhOX-18bz+Bm{dKxHQ0k~E^r+OJWs0R%K+<%HD(oF7(&XfUomj}94WUUq+e=jPj7&hzx+_vrsFZ~mxuI>U zxaGF6kH{f}awu$NQ5wk^g!Yj9j{xLoVANQov$yqf>KdH$XII5ww2^Hym6Nm1{p4o` zeH4eNjG|F-8b+OVE`mDA_1Vl8EXuLLo~QaF2$qt zveH;!77G_EVX|TLa1n{ZYvh{KPGJWqi6y163Ihd4pCg z0?7IT8Lc!*NO^doz|cNDcnYi1SNQGibz`T&x|4>m6_AU-Nt^n}kuxalaf;r}xn63eVKA0!l^9LqXxC z`mzx$kVAl>7$Og*|NF263;+aVU0Z7mGa`!1J6&NWc2Oa7YpgKLN);&WHG>X0nog^X zuofJaSX^XVX%LX(kEkGM7$G2|aom*>NG8ut#+o0NPjeP)*F4hDtCmMlNW!Gw+IMnK zzWp}4#Qw4B?8Mr*8|Cbv^ADyQm{V_w`z-Al@xGmo{L75`-fjxr{$pdt!~6u8!pXU@ znKZ$Q-8Jnn@Ftn~$N?0kv`l1Mi-RZe))i~OLwT~nM-z(-b5Xi~Qrv+;Jh3D4o z+ggb3Gv;po(b^Rq?rEPZGs}0##Yz=c}fff6FTX0EkY2 zgi(brE?R__;5q4T6@pbJnolc*HgG^A<&bDdC&VKGk26X1!;KY*@X2Q;SBYVy^FpKL zojd&(QHjDP$n3bzkv55cZRCR2B=I8>`&*Ho(f!xkys>vFU$4IZZ+{)D&Tol5{}Jw9!*JDkD0}^w*OO(M$(J^hgf;!?RJJultcgl+zK#o!7s#Oco%P7g88s$DStTfNn6m`*MVtm+_!(X9a>tn@mO3NxOdZ% z6itbxNb-?9n9`u81@Qm-zyu%yBsW}H;|49@gbVvUVIzK11$AMJF)f3KEos%an_`6} z+EI4H@Rq!ztIsZj!xWZMM(R$6m!2d16LeWffq$G}@Z}-MB!fPYyo%LtG=bUe4OY}m zx}g|otFFmsFCcXGut0$KQUtX(2mk;KdR#;m5i3w}3m_z!g%4{C72$ZG7%8(%;9TR! zwWUrL9aS8N#bBdSF8hidScL?s36>OTj3!?)v-?9Ox55x&IceEvL!BZRne=lr&M~;J zMcX%XHM@+!0+0IHD!YjmmpEVB{%VP3opR*7e0#0ZK}d27ONc-~VGefVE&-LYhyaKT z2{6lxoLWW}43cS=3%^5bl6** zz6JrTai1hG{YsrGbo&7ZQYP6^Y1gq8X<|&A3b%|*igY0jJ0})1bb-pPhRCH-!G~#_ zpSw;())#T6)0OJ_>7&WA1J?p{j)PD~stZhd%nE3%IR+zW%*6BM(jssbBy+or7Q9e;dY6wr!nkTPItmmTlW! zw%u~;WE;y~HnzODTH0!@=lq`jgFdhO+}~T*_4b?7=5&-zn%a8B9=v0a8;R~k&`R36 zV2<>-fq%ie9I{&bf=~%*#)wNORs3QJ@F@Nq!5CSNm|WT=K-%X$^y?f98y@#No-bOi z7}(LimuYb4YJy|00I%AJTnAL4bgR!O?fXIR>ci!AySn15I{7ZZGrUASyB8l1VS*PT z_#$E8Cffr}kW)$x=@*4;ou}O`zI*n$XBK_Vk9kOPPBdqlpFsY4w5&|{ z@Ub$=LVT(f*?n#}y?TbW1k-<&9St7;{GqnHvTpb2rAo#XWV0HT`{Z zX-_V*TES+_^6RcLZg{u9ChdPo4(dq6Ww3RLBD0+0WMl^Amy`Bn>L!Z|Msn9d<-Yk_ zXyrgQJwcTU`h;{D&I7&VPldbQtNV($1Om?;_ugL5Asy^_nO3!y`vs5WvS3$o?XlFg z@tn+BcEUq-$UlcON(npf!@Gc%Z$(OLaWkV=gGsMOXsk;wyn4~r+Su64 zecQt=)Ij`xsq&{>u~OMeB^zFjr4R!durM={6uc3Vo~&g96&bmf6Sl;`$D7|24=u-w zSt@a`i1P5xEiPZJLlAx;pM48Tvnq;LIR$f*Rgq?U7k!kqRZ{kMt1tX38s_%AKIrAt zfAFV2Q|4^aujw1+`;}mSvg$sSNk28%q+ZOXo6`gUf~H~sEMG;qPO`d}H97!#-5*Yh z8pky3OOl}{QTuhx=-Fke@zOD)y(JI)VfA*jbPBKMi<|ed&c%sNPUeJED)NqHN70fN z(P}Uuyx6p$nWU9o3FL4yPG|FWeS^v4C9KAPD5+hGrI(mnkCu6#==Y6?N!41Mqru1` z>0-8HzAG+_yxC_=0$j@d({7ysb-tz!oDMQpZ)T{NA{33R;E+xfb=7EURo&_42IF+a zD+6Vc9AbV=-AUsyT^Ok_+s5qDkh<{mt57YX><`eV^IYatGV=0TsN+r6$;E`4MJaIt zkcO0i38-v5uwD>St7DsO`kT|4@H@winUPc4sq;eeiMj-+8@D55`PbC@|X<2#}E$b%p>lxsC z*Rlf5z`k`lIG>zZcLw&DZ7gbws+9++Xd}>wCr=pv6d3SyYVp*!6z-MiYtpwj^z!Of zf|;A|iS@l=uTP8Q!As5sg7W@flH&ycJ*}Y%C_Ye};tsn-jI-9G9~4%+pv=kR!XHE9 z5%e|evE!%Y>s#2f!25e^+dGQi7vvaeUx$&K442&umV3@t?Udl(rzp4+notW4b;j_! z9aICtZ1&*_RRmY%jh4b%zf%erCDpA+o|e~(;4BL+Oke>k6utC;!)F+B|MATGN9g!g zP$jT+Kkifd;c|K?(?(9PT5k`V3jeD;{sqI5Aiw@X2`PF?((d0+^CmZjpD6DNxpuo4 z2d+>ef~M`{AnZndI3fCOQ|yI9|H?D8nWUhOv1K5x!#{OK8R1#*eQZ7J?aR9zaUEpj zFfdr{#E4p*_6Gb4@RoehIGQ{?d=@NxuNJ{<60bkBb!$Vhadp}H+CBK)1T+-)4|Cg_5Z|~ZFuC7;NHcnfk z1dKX%&fkYwC^i9RW(YIGimDvrXZ)pX21s>++_sGa;>IUd=u03Gy*Bp(~e;Hmephp&C8Ne zc>PVf5K>y#vx|P!4yuDRx)pr(HXx`iv5nJm5EGLyUuq)QdB=AX`{n4Rf2Jhh3)TX} zEA~u~kpVuFJA8zt0n|=4cYlQauXn%z0Q=31UX{o_;}eabld=>ojBKZRddwLSc9)JE zk{W6niF{ctd^7)kvD?w++S5hA*1SZT?2A_>~8DC*$ zZfc(CX-*@)8*4N5* z^QuP6a3ec8qOqw_fVmzGoOrf8b2FdVS;Q<+r9ETMjp>B`nK}5Y?VQ(@k7mvNlHROD=1e}O?M0`>TwcZLOmi7DZ=4(WWQKpDa%pExtV6_9*EboakDJ;dRXk9kSON;Ds?83|w(G zv9`14JmY=d+rPTne|lRLpWjvOR8tA#c}7PoI2T0YNf+&DFz{UoR4{->Q&4#Q1<@7L z67eq13B9LFd7%MF+nurBZ|Ou+r<2!#S-s-3u80>*|wgW!i+}CLMZS6Ko1RJ!i3FWvtnbiO^=f2_qz5V zT);Gp`A#Oe$x>cn6=R5#rVu-Ub%O((ucCK=f}WzOU;qk7BcjwI^)-W*uwG7Fa}j;j z<{%-VE=YH=jR?OS=!>hfr|Msmd7=ODwg4B`aL&6MV%eVgXE8>eR11^BtMRK>a=+1* z)r1zXm|cKH$R-D_n0%^Ui*TILzNBh3K{ms&rzA~bJ6t? zBKOV;CMrpC-{_Or+rA(&Pdhlm&l1ObACE#=OHq|VygdT9&~4EEwy)8MnV;#d9*Q2cWW{zG%+LhO)>8-C?DGW|HB$z=+=8)-n)eF%?wT9%MbBAPPm}9m<93Z? zjAKApET4S(@r;Tz!>7NrlYYtQ^2+(Z)eoza;>c=s9uTNj`0$^+k-WB3W%>B+?WzE=6*;x@ zs=rF+horT6(FSG(ite4d(f8+uoJ#0)8+z-aH zMq$C$;mFVxDVSfAZc!g0myk@s4+e&v)D##P(g%I(2*_QiQzUCNjct}}n@&WFhaE8j zX^tZ>!7+amB)+(Cu)wrM9H`Bci}$q%n5yIuq?|WEX-@k`Ky;{EY#ky;*k~daGJhRB zQdDr~BB;lI5#%Plr?|=h)gfrs7|RigSszy3Nyi#WB|FmV;ztJM8&<0Lf=QC3Wz$Wh z*Lo=A;DO^93DuEzWj?jn4NG(O!c0W=JmL*Jd3oEngEAWSGr~f9ybNLrTFQZkO5E1g z$@20#I%eI*^^-C3T0Eb2)VT;Ew4c(6Eqj+g2jy7Vys6v0dNtgy&j~K)klrpHX<50R zlc`oPkfAhIzIp3i%xi?%oMZ=(3B4o=oN~f9!P)EZK|4EmMkOA;BVOXXG!QZlK7DCC zqs3DYnY5U|+~Ez%5*M5Tf$V>+0|6|2l<_uHj&iuJM%v|a)rqU-VUxs-F@n?3@b(eY zL5EScY>n1-La}siT~LU61vwdqqWwuzw@5}1y!+C{&nD+hz9Y@RtZGzXA+uNgX*@`U zb?`hrsikJM@{?}*(A=a;=z``7Y1WTyuSx~TGw7O+n_;6G&sja)>HiR+55OII)G;px85Lrg5%5`cv%<`9lR6d_GId%`4h`ZLO7r4=lf9*3~JxZ1s z^-E-|^~Y;I4Td4)1=j}kVT(Qf)a97`sh|0HozL4{DqQ-!pv;%DP10xLI&4)ROC*v? zZI$eyI~=5v1}Hi`PA1jE>hz<}da&)m^(w(OtW-)7P9z{-F_jzu`IOyUS$O2lDiHx1ZIdMqW;?q1v!5Skq z9XdejRV^xEZ2z(Me?G3U#>Hm%+3vp{y}ZgfwKE?1yJi@dYBhn!iuy0nF-oXKbu4peIx_S;F&5=8{@I2`6XXDoGBc#bn6;A3vPdt;T_ zU3)St4R#p{5Dht3En8%qme@kvaATy_Y~MXY_(Q3yJ+>N5Dtn;!i!To)vR%IL_%E9+ zZjV*$k1CxZ{TfK%=ug0+h&4rct(2&F}3uO1^Q;mF!)pgT}!33@p zAr@>p_h4PC$x-J`vlu5?Yj1w98b|p~j8h;#lZLJ@2oLuoSt%YY`SL=l7T!Bjm zZNIOsuzy#Uf|c0i^d%68#5M#L zeynQ638_W4K=|t!#lG~n?i)>!*vv4W940-la|22_eVU9v$#>Yov2H3r0RnLp0Udq_ z0w9xc6MiX&^KDID)zzn@;gBCa)033GA=2aiMVz z$JkQjMPw^(%ds>Mx&j2}{PIxH!o$os@_94F06&3=DqY7*M2&dawzX?mv6LQbYN`trXed#Em?&@8DraD=ZBx?0U| z5td8ez3h~LAEV@+RI3H0|9C1wU%yF5T1z3*!H8>|uMH7*&?UE)`|Gr~q4jQsEV0dG zSGwfdo_e%DV`->k-4Q|_!di+x*vwem(U`vujhx~yW9aZ~AAxY#j>OcQ+r&T+@~wTU zO5W_j>4gA0_gb8L4p66(DUYl=Gj|o#QR1|MVz?yR(SXq90M_ZhV{M<~=yw{);fRt~ zV@^gNjfVk*LyO_v&KRr9?wa}!bhC^mWRrR6;O+!w#U!%L4mD-^(Wm~QQ2ItU+HajM zQsJf0gbIrq?93PIkv@C)NaviSFT3HLlg@?CZB*>LgATE2nBgT$mGW6RSut1J`<5ku zi2f?DNOsN^_S1^3fisdO`+z;NxOrh$^0K2_nl*F zflLRIuOv9@ygTFmBDmHv_+imA`HWPwFU_#EB_k2$i3&G@Qi721gJCR!jkIgW)Z-^> z1ExpZ%kg3U$A0l&AKrNo-u-oyNTLA98lGj?X=#qNEcn*g5hxlo-q<0Y)fr`>QY)xw z2Nr1;QDaWU(iybWN`+mAwH&SXNmB>Yv&E89bjs)HAnKca|S5Xss)Yak)w|jN`K%Irykc-Fkw1^}8 zZ&V}{63a}`x9c{tkch)=RVn&R|3wGPP!Va@L_bg99^MSK$uh)6!*b>~`k;<%@4jiO zGl2g)V*uAQ0a??6L+JV_`M=yl0}C`WHMoR2Hh*OOKTQwE#>0jUIG+H=di4lx9o)P= zUv6+yETZd=YU^>djgYooIif{Igy$)i?*0%_iQ*!y#4Y66lubOun!#1{`{sT2X^cW) zhK9jspPXwm%uo6AL1Y&=Cm}uyzX2C|f{E&bBJ;rB-3A8q)_9P@At^*}K5-$ddg8uq zTf5+BQ`T92j3Tz=r9=Fh1@hDdSx7~AdI!{>&dYd=&$ss@Z+fF}%XUb_I*BMQKx)uY ztJS=usO4G3Z)D|@)p&q|0czTvdXNh_cFEvs2ej%f&>zKjU%jT?Nsd>D$|c%oO){E7 z6wU%amO2cOS5%dXJdDLGr1%g(jBh>+{{f$t5@7-XCDWXeCXW3U$@e{Vek$bhemKJ^W)(kV%zM)CYAd#I6&2#G>#kVN%Rr89$nnLnKLW$-=NC}T9 zUCC3Ao`{cdoM?+#SBb&-pza^D)J`p8vcZ0;Bmxo7W`KIinv8S{J2&$*X7kCq#hjx+ z-QEdvq)fAte~~UXTmPVzL|if1#W<_xLUGk@2-G57p;iNBb-8F@v+QPaZ-SmAJ^?)n z$K~I$bprN*^1&Ufh#m8S&4O40X>yBqnTo~RHJ^loIRhAcFM0iUUgq~No~hsKzVj|k z6)!LVWOkHNWMcY5JQ3)D&lh;aNJJd#byh6Z+a#wxXcOtFQ|x61T|kWxHr(*X=G9l2 zMQahmN#HAa<`jBrcN%}Ul3zY`oaw&fB9)g>J-&@B0A<19N`2cAqQtIW929?)r+e;9Gn1q{cLx-K&3vUhUG1;LSG% z-3y&_-Osf)WOKcg(d;cGh6$S0qc)2aJdr@o3=d|*PCnVet6meKZ7lvARw^>T2}Wf9 zoBh!S@kH(-%W3YP*IWO-)$VKng@>MW#D}^;@LA7%aysw}GMcHl{JHZ>8z7&$ z5N@Nogy9C#eY3mvG?DS0|MU0#wNGz9z-9j1iZt91NH*<+x-?w`z+9J_MhZrWj&n_ zTxBh7Lp*og+x5b~?KCAIB<)jd?Ff&ox$TcKEHY^_xO5g_)d!Dtv&^K=2g_g3g{qq{ z{oSXIbsEhht?{J&CQ($hn6#hn z8gJC!=Qou&F1@{;B{Uow%;f&TlC(X^UR=LP{LQp@XP&Ka2x+i~h0@*u3p`d4#t3~F zsK)lP#pN{ESM1I(F-)|7+WQ!*u#T9VoYi@*J9OvsFsW0}5%Iv;u>IGf`-Efh-WEI~ zdfHggyc@6=(YwdA2rXHYx?leLtTKl)pqsA!cLLt6(LS9H)i0@dNr-O!j()9L<&F3C2)}a9s|QYzhy5cTn9D zt253{%<&V8R%8eYQ8hbDyTGDcrtoSWi)8`r)_J<&s}2EQ1cV;8O#_52O@375G^dY~ z8c?D0FAX-!h7TJ6z-v!)!|{McByL~8E;C<+kY@Z1N1KoD;D!P^y^mC-?W#v*qOqdp z&zKlB7^S|$$fk8uPqsCoPymgP4P`xwSg+?p$H8{fg(nH}1wkBoI#~)+@?UZYm~@c^<%EY*tJT9)dKL)z_2dFyc%*@`OsG|H zifG+2ndaAy$hRQr3}Ho~qRe|7hV~kRYt)+O{B`9$rN)`vK{M5d+f5|7yK<$A;}vZu zmxBoX*t+~g9!t?xKU>4^=v@+BO~d8y8eb!dXe3eQ0TB zVAxb!DDor>b{2MgTK%)M}F*1k~n#{@uEdRK=F#y}@^wiNU=5+PbS*SYD=#As*SHy(rNP-3O?^qJQ@- zb&{5sE`zIqCC-@i@Xv(-%q9{34jq_z55tijsf znj!2fmKbe0h6m*;vwFFZ>0X^Lw{^OZnIsy1x*~la{8j4h%}=f*H-4AGT0xL%V~H|D z!gi*RR%&aeFPS56hoY`Z5HF1TO(DL%-&;^|mC?R&Y8=MIXT>4^X`y>#Zl`bj$Zg-T z@K}9-_q|bvb+P_~t>;mwkG>rB6~wx}BCIr%N2wGhn`N@V6cV{EXkPRE5i@qRd+xc+_CWxf6*v59#9HFJr9 z(R=)?gOO!p*0(m-^M_Quc+PKqsZ4ZDVf8k|19F76WI|x#Rm&z-Y)_$w=|x(4OM(h% zlc|w~#0=o6BkDf@>?Jj=lruwVBo*MF8Hz;$o-C6o;ZcNG9t}+}i5A!cj}RSE6BZc3 ztprOHuj>pV)s4hiw%PJX%0y1cbH!#La)Gn?V}6$qAfu;5P(UPy#Xx~%G&PBXDA_z( z%eludJ+!c(-4T{9I5T$6{{Wf&yQQ2HCBG3y#0eFrjPY=+RWzbCv`y*Y007(<=51HQ zw}9Gat!(_V+%9Va*Cs<|sYWrE9rjq3D!p3K%-SXAA~T+hk7WW4s&P#1d2>wGmVwle zV~68t632Vl@-roO#62V>BPsXrP%U+Va^)&A#+f0E zfHBTYr~hS=xKjj5&C?FWcj@`;B&|#5n(8su$vI~YlZ(QE;BTgao%gAFUEBNQcJU}F zw>ezn%KIIa`T^gnhN`$Jg9vFuqYdh6%8Ra`wSG1aIjO#8oMEmiiCL>0HH5kyhqjV$ zo(B6T;u5xEdb&|AwN$~!7-veD}Tpe^`(*;&n&(vHA8bjZt7*?Ee# z+`pdCqNDGE{Wy0gNpfz}R4)1U+tG(G$LGD^x_8$w*7en}*!$d_hH1A@J!PTwJ|% zlzs+{>S)mr#ew5TtjhV|$Rj^o^A>)x@82cHyKTYWCruWu+ViHA{~$JJ%wQyqC~%)z z5x1Cs)Vprb$wfA`%sS*YDr?w$Kjd=Zj1`0yCr7&Thb`U$7(>-n^(XR#dm9n3>mt#- z`+9BoA*4wR8@`Sh9C8z2jWI#y>ly8v1KjRF4dBlMBZ!g&9+9}3Y5R4R{>gh#c1-Em zc4n-+o_~pG%bqZg$2=1FRIG8tz9t^1!YkedZ$qA}b7LlF1P1@!u6@>+IAgBYoZ^9~ zu#K`v0bom|puNL?e|SJ{4<2-MCfINSOGk}i>+1CHwYd0S#XieOeNhBb6HaNmPZLIw zx6%+sH`4IaeyP#0{iKaEnFop$Dlm+T8Op?q$BbhE*N#6KC8E=bjwLrxDD0o0e^BLe zP%7jM!X_?5!CfKuudMQ2BZnVjuIx?1Y2uO}x#-wNk^q=*P!h>i^D3<6i+d*yhqX^n z{Me=AR?1gJ!p)qiJKXIf2|nt7F|g`iH9MEtQ)9ixFW|K!HTo7!Paof#jv{%G-2)c2 zO!yo4DUo%rPEVAVEn!(>xXZMb36s0t!SkxtXERsXN#VBi&B^a!_ptFKAp=tH(I=kc z*97e11;)TaA3zElo4Xx4V*Cz|6po~7v+e5e9dMqMs5aLRAk|GZ3CRtIooQlYZ2kfR zz~{0WD}c4hRpA9R$Dr&V(cSpmW$kJ%K z#8QUs7B@KUpSi8a#5TsiJ~Mbitio{SUr8h3CIVgb?*=*%JsX`Px_9RCtM)`qAf!7c&acVl80C4DXS2!B%YpfmcxO>;xZY~0Ga`}!Ev z0o!sM>>~Axod4XuG5i;w*o(mVKLbkb&Vcw6IJoonp??Gt`f{3F^JYi%SzrSR8hhPL6>cv#6CT`@KgU7x@`EGX_aVWyAx|oVxHLjU z9e62?+YRzst?e?9oH#iJ!U^(+2@P5t^h&Oiq(}E&oypKTJ5^u4p#v-)2o+KhKwh3&n!$S?4UTsC&YcpI$c%)Wh@p zO0e`Hket`i!49mz0)3)XDh*0EgX%#aWsUl?4dTyn>1&4j&e{v!{38GWlsIv?VBj0c zLygVnPU|Vfp&y0GgTv`p?&w`a8yCBY5p$^_^_!H07OvX%OAFtR90c?dyhH@L@3JAy zo;t!*DA9-dXmF&ABa+CMx%6TqkQZ*2pZ&3R$cmg*lA-o3TAMj5)3vQJQ9(EAB zLgR}ceJ2y-xxA8g<(7r$exE~VXTSa1DKQyZA(Z3IstXHRb_=*@=?ZPp=xZmd0pBHt=0gZQ(F-xkGxHd1P@8Skljk0pY9JAWS9dSjdhVsc;vdd zHIWqoC>gb+C{eP+!4s@08A8aiI%yNjCMfpFB6~+}YhC;&L%4l6?O9Sf8KV`N)l=*C z=21P?%=e6T1gJ0;sM5POE z*ZmZ2WYKLJM3uAv1lY8%)ur@`C^f{;F**LMZZoH#00Q(%qb4%h;JP55K0fi{Zodt0 ziaGC7xz0evlU|in=+;h)#ijqqk54XzBpeAGn!dD2yZMJrz6Dh3EHSiCG>HQvaIq-P zvd9VhwdPBfGXao6zQd#1l81nyySrek`znZJL8Xn54Kk1W{dYO6h0Grc+T(0U_*%VN z03z6N+1plpHhg(}KBOwSokCo90(A=0hc*tT24S|Zbqhwawx9Xx=ht3Vu;hcQOh237 zF*C$|<>2VgKO=ZH~)j_?^z> zEe4|{Poeb$e3Z*>I%hymVPNJLkVhq)$n)5u6-3+vquq;2N*7n2)M8IUShKYN3fn1W0y)rg_R+)6xL+ z>d2+=ZD9~w85Q>$ob4+9IcCu+vkp*61h ztqs-fyQ5b6?Ls>* zt{m`}Omft*{X*gnW(GCl=h&l#!)25xb3rmtWOBWOnvb3EmB`rgWU)_@cnXEDNlIj) zCTMOd8^e&*B8TMr3O))`rh*+}SE-d~lvK@2>}m$xDk&h`9dk0J|TWP@20)r84GF#SahDP<= zP0WxK--eATCW`F4f~t+`QVLhU*0?P*+&h|WT;xhR>WcWu^I^l2rO+oh5GXQrYGMjm zq~Y+SJ4hVY$x>F@3g)U3h#oOzC*AjjQM5#U5H>D9!kdL9muHz=l7b{QQTEiH7Ib!S zR64i9X(&bnnhqF-VHfz}86<71RQxvs<_HI78}E2Qmwib!(EU@4t2VQj!yGr-2y315 z!$XQNQ&yCGj~14UR(+`U1VL}Tt)LN0puuaq;M&9E9(?ihue*?~{l9|G8lH}hfmkAO zT%2aw*V1L%wbam8ljSxYZp#R!Wnz6kf^S zs9qc}msh{8HZy;H7nJ>HwwnaR#3Mo*1WP}t?r3YN=Kopy+rQ^6{Fki>Jtb@@0K#yc zOm9$tN8l3f}(X03iK|E`M{ZFCV$-Xc5liR`WS z^$bXDWv1cT>%;oS+UF;-Cdk6IUCBv88wHplmPJ3m=!z zDpj%pavCA7B8+};`c-IP!s@T2AZs3>c_CM=gsx#+tReC?bFn`rKHjNnJzYJ}pJ7e6 z4?!R|u?ffGCWOizce9s-r2yDKs4?Cbc&O7`*oTc#bV2HDl|m@LF-dzk+2ac8<;2Wz z%?||!aMoa3;Ikbr`QZ)rcw@W7wEIS_n~s%i8Xb;-dFr`F?7m+e+?q1S4j z_nD+g<4*NUvzBSI1nDv!bX`ZO&Fp6a}4f$dl(PqhTVa%SnJpw1@3+B?S6=)|^r)op#8W1&a#D zB%M;sjfI#IQDSu=ARpFOGOk3_!k> zOgm%Z=KFXJz0Jtbih=4#tbyS3Zcq!!a-JhIL-9jZH~2h{&DTAl@d0-67YrL&s;zm3 z?4jezdL2g@P{g#MI>|?-yXq_RP(E7V+@G}R09hpSwQFqcT&b+^8(xOm3-iNr{|3#W{;~qUV2*vLZ*zn!XODHF9(i)F{tB4$#z9YDh&9c zknu_T@Y>-Qo?<%4!;m(%0*NROBM;dEb(GFLR)Hb2A zH{aVPlDM%`%C%Irh8y3mHYM-=mc6%T`8kiNZbW;^i2P&bu=m<1AapDWAdadkqlWJx zwz#vF+lqYmp<27=C-gtBbQH}3n;rZ)t6ewiZ)Vz`tU)RjbfH97u$25EE!tH2aZ9W`%Q+(Dd(FN(i|gDVzmB-GQVVbt)Vqmvt>LZe;s+%pO? z=A~^daQ|ptsO4t#epQ=&)syse`IdP_53x7YycHy^KN5G+UI2EIOghg- z5pz4d8?Sr~YM5J6EF#lZpLMu>$*5hKLx~$?{bzz);@nEV*Oa72FBUsKQn(%5JMY$M z2JY1x_*G%(W2@3=kswy~_gNCvZ&_7Yzcr@W5bP-E92DdOK?~V2zBs1fW!}0;(9`B) zoW_n;?M!NZiR}3NFL4CUZ=>_hqPzndn{RLw{wYb0H@c~ja+Ki&>50D_DxU@qq zvXaFwe>|o=Dg|czD-3Pc78~p?g8SCnyMH{+nzGQESVh$+r07t!q)3*{8=&93u-#(^kU6|HZ zv1LR703zh+CUl50ike`q$PD3Jt~HFvf~1J}d9hYu_}4Pwg>Lg%mdu1CoKj=ai)=*A z^DK7rkM2sy_!4=$;)f0o#tr-kM^GjPR52e3G&J2hLLtA6b#hV@rwhd)@N!53dd<*t zTs=G_{|UCm*DP3~Rw6y=21ZgCBUF7ob`3GZQDo`M}Z{mGZ-TdXZ(-usjB><7MKXv$`NEE~$DX!^bx_NfV zvGWdx65bzkYI)3hTob%#=bEg@1C`YkP+pd*Dx(&xXrUT*33$A5Eqk3W09Htv47a{# znAC9`&Kd|Khil@%#S(C8*q<^+9bsMD-sc5L&;JxHz_Ve>3xMd0LmxdDN~x#0i2bUXF+c^sF==_z@pY7O#y4H`(D6cwZX_F7VJWMuN~m0_11EeJi4@x)S=kBlUC+Tc8wmw*pGMw7ayk(85Pkt-`c{JL-`3~Du0X~Q@QKk*0-Y`H>#imVg?uD z8Mf&gPyO$1pRL3sY{rWAra9?`Xk-WkTLcewHVVeBD%SCFAW0)Zs5UmH#Oxmk^Pp)M~ zf+RSslu?fC<}8Sa_<1_%WZ|Uz@Em`lzC{IQWWqJjM6SBO_z z8PdANF-j>Cwg?N6?vXM#Ih`7=!R;*Y*MAX58VLlM8bYrn7h|0+O`z6Cn%7Y0LT(IL z$_D7z0;6SXo)+Iw8^vOYL37EH=9^YQ!xq8fY#!;`ssizD0Ls%R3GkWcXqNPg%5C`v ztyMb}v2D|hp?+P>4?+nJRUUHDV}QT7RsWndLLZwW>r!>_}Fn^2h_m zO-DF>s@%LcI1Ar4e@ouAybY>pJskxzm=$k2I5|2@HWRkveOK2Z%}|V{Rz{ z5O*zJ>XwKW``GvA)aRTgnV#ce$7)~I-CT1XM9KVc$H~E8^(T-rG_E- zC!AoggK{tY+d?6;JSs^NX${w}g9vuWSy|KCo}&&AbkhmwVO8~5sS#pj(x$hrTRAp* z++N)I_`#VQ$^C`;k4zc->}?yfvh0^Oi-UV53APk$gzl-cQFjEN3XK$SZ;Bdl2gu=2ZSZ`MD8qq~`t$ zdy=U9hPSaV$1X=QFTg57>U?fmLbmhdgTXube3Xoz+fu) zwEy;H62&jYbDR97ieEBqj;aMe5M&wPe^4n_}FK!L#5y`UN>3QQvQ@C#)gS7jt^98}2;Wr2mm7g}#aj~KP%oS;XHOmSMnPEKc~ zy)#fX%G*am|L@kL*)*3Ue7^3-fYLlJdYTSKm10Pl2@T8{U53DnA^wh0)_59z^``xu zvuD-`#Hjh6jMl8>vxye6gpW!t4B*SiOu zV-jmmqGY(sLTsI13v~vFz2dyt1iiH#6%>yPa|?VS(H33Hs=>GQ*?Y@;JRF}_KrfyJ z8+hPya+*B*pBW~h3&oobYXryu^Kuhb0NyaNwmFWqCI=>VF9Yl+ld>(A@av4sV9Z{P@XLIF51p~wCq*YWdCM<;}eesIt*fZi66YrnWBC_ zNs@K5K--)$M2@Sk{5qXx0r(nc0^{*j(WYOCD0(!hX;R zv6i4FA!2i72-d4Hl)=kX<7NhUDxT%~yu~eycy>xC`mzZq>R%GqQMmGj189rqvA=+v zO2ZS;rTUpQbLI#`qD0YgiuyF>oaM!+fY{8d>ALG~OtYG_^d>VkOEfwBlreVn1nNEs zVj)G-@CRjHsX8iJl?k~-B>Xvx{7jCX#FXvQgMI0Ks%bxQjE6Y>cJS@&e13DxUa?*s zsvRfUQ=53$W%m}c{h@dN!OKm+-rm#tKQ%b~lRbT6t|n>Zu7I_N@;w*Y;!y7Ldpu`6 zC29t&OphBKc6y02eKOJ}c54W34ZQvLyJ;bJ*kKzkcOg7rI``LMcE)x>z6b9q^!D|f zjd>M@osr`FIrToVN|Wq3Bk=*30YcM*`E5~^P6v&KJ}z68y~5(7PzhNH_@Iw}sC1*H zsgIS69?p7AJ+5~5=Dii36*85~q2i9fFnE3Pm}E|6T}2F5v7nPgk6NizYHZYx2VSf= zaX*^1BCgD#q)vBwzE{^7Rryov-H4s+tSBuJX-&%g7>=g?@e&h;PW#96`}acn-_|?x zT~UyRszHTD$*{Mr_rdFIsyD~tY5LDiWMLOO_5;3|K{}Utauf?kS9sTdj*DyC>EaYFN+}Y1#O>L9Hbt zSsLmeq4c>Ko9V3PPr^v?OsyeUR($iv{DWSRQ`$KO*SxrVznLwjmg|hD9H+6L35GMm zxX%A-6-~o*NEI45fO$B+>GtttrN0-NTM@5bt#_gO%S9y zQOw%qJ5v6XAe*YHZi7k?zmr1|nm~XxmrO6V|EbiMv}U?pG%wT<#-YdnRdEUs}LNW-_N{nYPMzb>w%1}@YIEc+r7RxwYFCXpg2r79ML zBF|#|UyZl|dcd?ABc#CuFmZIry+<$+&^mK%R5}3?l+tC?dw4O9?un z4lI&NErlsd<^6`CtxZeMRC}+KYAJf_y&d3NO=d>SHVsxOE-<;i2KqV_#63lxY*jf! zv*X;_zI-w#sy0k4BSKBvUgj5b$1Cr8QLVo2j*oo!FFPs>XczZk5_nmQ=SnFTjcB@+ zgj*z+mB(Y`s7LlQWkQowqw3;Tsjvo84x)!1vD5$^@KE-Op`fsUPOZvRH)L^J&)fl7 zmm>j7&sp0vf;Y7_mBLHqW|1OA7J;Q1?(v`Eh(oBf!0B@coUM^(`NC%B#;UbmURTsO zVKo20i1b@<))9K_tm`W%AcWIu3~+3}tNxNlxz#Jq+&8)J9a@R*?!Z7Q$e-qErh4GH zc*r#1p4aE>K`WXpQfvfHI(Ryqz(*b1r9tKAUF^IK@1bw$Tm`>4FjFBVq@(!D@UHSZ zaWl?u954%VsWm^-2=gH=`{;jeQ1R7G{Pk(@X+WksGhygh{iBj^|0}1Yd}y|SIDK`O zHz~M1WaM79rzs`cy4-eWU?YD>ht6`>c%`o3n(HpUFVp4kFJH)0uTNRI73LC6v)t{` z4iYP}$NljAntuW9lKcr|L#_jN{l^wj#oeUT3ug9-qKb zp&CxVT88aRU2CqqhG((}raU^<-{tAzE4jVovc?GGN!35AV3(2GU24n-#q?XCX#n5bw794?hY>x%W>$Ba$>c{6kKB--3{J>tuIjrNWzBL69lD}=hhSXTj!>vux@rIJ~cvD&+f!<^9U zNLX|IT@>ms{~{akW$asZ!V)HB#Cpi%dGOP*Y?A$7Gr9;e;~H!wLEY1I&kn@D<-Gdk zlUClWBJo-8LbF@+NH!`zLdK?gk6Y4YBqYrxh(D6RXm9X?5si??d@~bR!RJKRZ;sgW zNmmDoz>bTHfqU0D@|Bu&jEXKTK?!=}NJqQhT6hE5JG}#{dOQBg9cJY&)4x;8>Dbg5 zC(9-ANCuwc1ZJKq_TfZuD)D&!YplobjB(iOn%>zQxKsS%pHy7+XD%!8r3-6b1LZ^V zGtc0drM{O{bz^#um5(@7Q&&?G8X%}&xxgM-jt)OCW7QF%Y6(&U_d`H9>kOmrGe6>H zrc*O!x4Qhi|2#DQ#9{wwG~p=XuWr=Zv+#=?xvwH6zHeE}6w-(L3(!JLtS&w;<}DuqGcpYo=Oq4rA%MR6Q|RnUq>!3~X{IAQNndnk*#5xMS9lVt6g z-s&%FfG$fs23$A?l>wW(Z36`p*S5KiHNxSPOBpXlp_O&P_vT_@+4b1c#HmHx=pN)! zuS_aad~%wgl#XT_DRka&`qi}&B9XRSJtd{tnHJ|$L+EHjPUwQ^Zq1ueV@FcrdHoOo z(CC*JYaUhh6~9We*K9u*cS=JtC4qD6nzEab&1>kd%yN}np&$ZmyVh|6nK{i|dUj6* z%mM8Anz31I)g;;$&P2$HL|N+Kd-ZR>TTDaZ(P2sWyc!-cr$SQedi6l%-+NGz$6ft@ z!~YnCyV_WuYG#*K=w{&8wU!|&0ccT$AXNOaAXt(m;tem+N}b7X0YU)!JnP&53d(7V zp#jxdiA9~1ON3=dlFRJh?19-0g^b|bJ#6FUQbgL6=aXZ-jK(_6A%i+(MWPg)1o{zJ zvNMD*Vy00VIuv;O^Y!32zEJqD1(`?a~vLLxqs{+HcUeD!~{N(u}-{h|Eu2_0~dR<|Ap9xb&$!vq5ppeMrhy>3`zk`~p1tbYsGTJ{ulL^Odx^ucG68K3|IQKfW9f zeeIc1;k{vRb4Bv{w)!@eTb|@L&oLyVNtQ+cfbbuQ7Kcxuzo|!heJXeKBHmf)YM9jf z>!2K8y+tF9df(6m|EP`&*mYQvgmJ6H(1Y%rCG)XT-6p*dR_l@vW3yxaBZM%PZpjx%ohnW_3uK|#pVLJlvJd!29yY~XL?fS-R5Jo?5=B@piK3_% zS~GMe7}dyW#A1b+UIUl;)k`_mzNu;rF0*$ys+l$9wjN8UBVV-i7q@XYQ!ioc; z8)FP59QEHx+H;PYxG!6&EK+uN@6?{4X!f_$zrfu1JPFKy&Aq7i5b0aI-T84cNZHCs zgUXKYIh%!{u+b)fEU!uhnd*0YgctChyR>X3ry5eG=HfF}$1RgU-HT85V=KP~9+OS~ zGWMWhm_jXqw7ai~)*jj}9pPtByHkHSvVtWUi_8i%Ry;6a?fRz+O(fH#GB~U#Q6u09 zUS zY2uj92HVhItfiX71XeO`GTTs@^QvA|nRGk>c-!~-s;RF9Ym8kK-%aqRzKKAghZfMa zgn5l;cRK_v3s7=@_ScD{HQQy|D5El2}X;|rlhDRdnOBl52tQoI)r5)uYPVI5wJuHL5zc3M_x^QX^3Nf%L5)W@43nUQwO_Gc( zi%SbLTd~J%o0Hjv(y%I&IOFwWWsHVoYrfBt>H@K-7E7C)Py%NZr3?l^qAX&Aa*b-W ziY9gQqH$pAoE1U2tm4n23*}Oo4XuHJ8$IKH+bTOGm5-6$0|K#W90TEh!PS}r9%f9` z_>j1*OyEWCN7k;vY05tfInXPO1UxURcka}T`X`yH9sz>BjFcG{2Q}jhKN0Q=pWD6i zAR}?=L=4!ElKUO8Va!!d5-ayuLbGwMzhRzh1H+;kB$YD#fF1GnGjm0Yqh+r_ms9^; zLlEWg)bX^GAH1*MDTMZ1@Dw3%o7R=-r&M7TL3@gl@SJ7ZhmA2H$NsG;cV2aISf?*d ziml;M_0i$ww&O0F9d)j+PxDu3pZPc34#`~mCOUXS*vtQRfGY;IL>3VVMw45JqsInY z*K8{A>9}FnLO1AKJlgFgDo!_7Cv@rLIp?MJ^f;I6)++5Qc$F!*NoA{ zL*#%;%%EeG5<_~&PRMnKA;tj88YlJ|!OV-y9=Kb@Dz&~2U{j~F*TRC6YcL|C1{^Cg49mZCtBKANK;s#ST$g!Gf)3S&}e<;Wm} zLzYen#6Xo@wu|-jVQF}|BNDU&VO>)dxX>Wjfkh40>nHTsaW{c8tf?dQqD%A?bbqBv zZLP)3CuSrnoe_NIa-S9{TA!O}tFkY?WdOh*j%u9cic)wi3?Eqy9JSWBuhvXlyr;2) zKDQb+XeL2TS`)ehhXL-isbjvmj-)8Fwf16*kCjI1+u1+Niz=?hCxVg7R`O3KDW4bP zQK2+D6nOe@>aPVY+HkdLDzh!{?%Pbnd;e1$cNn#TiO$h~@dSu(C}xpKT2BE6$j$%7 z6Etvx7gJ-224!kVL3%C$DFp+NYQ%nmhg<;Y^n|r@;cTzSo4bL2D-YKB-G1?s@oKPg z=UEbYa}*HGb)UmQx_|R71e{d_KMf4Lwpt4lnq6%9il$udPeT?P?B1q7EF7D~-K_9y zMhwhz#OW?4F^5X5L6$c#3mPj{@v@Blv=^-iv@^2F*6Je`|Kk4? zt8xAeYtrO!5(cRAfagc1@ln*RSu0~~JFaY7bN=v9tQatsHlPsJONCyHk)X?jA-o=p z|8l4s9RiaQ9?59|V_aDl-h?3b&Aw17w_j+R5IMJ3`m|w*-wojccm3JTmPCQg!^H4X zEp4UmMj>vS_F-Qiq>rsn5Z|lT z*PiO{;|0vvCP^ibLQMwDL`jYHt9ptMJFf{Cl7>E|8_^>ENJNN(Cn|?2KsNjPbu(Y} zVpKOxcn|qNU6?oFM=SRL>|8b~%#2mMT z)tZ0uDdJ&f65XXExV{mjlk7$^J&KD}R8=BS&o)|h($YGpMqNf_9}|{%T`fmEDXjB| z&nvomQKFM0N`^2!bIuWflXz)7VnECIPjM8G&;~}};4Dswc%%SuZgr71M5a*!+v*5z zD>L}Q(-$f2v5>!@nAbfRJKI@1F_8W|v46A|IgDZPeM1VW)Y=r=0wU*xHC~GaIBqrS}-E7F&`Ar34A?8tF~nus!zV`)JY?;s$C~kYbc{U z>ROqoK(+C!M3Co++h)0h*0Mp52UI}LT`_~XNQD-$R8+3!M9|#JmQ3xU8%4AVLH%jx%znD@t@(a}g8H{+LK^%k znCsXz{9*n08+}VEgoS_^K0-E4G6VoWD^?SM;)#WlDN$crG0*9d@cmWBuJCV(NXQqU z^rWRZNEKx z9Oc1JqNzuWPdN^>R|}+rrfR2yb*cxOHBY ztux#%VMJM44^xV_dFf2<%y^bRX0YQhmQLAoy1)~KAERSn&jsFv+Q=|@41kb`Q>32} z86Bw(nYuJb5CJ5BiE(E;DnS{HNLxnrkDZs)#j~KgP?-IJv!(wQksV0{-kt)a@(hcs zus9d!`BO`J)7vrx0HGkk!4AX|zyzvdQPWgApk~Ls-d9Ov^l@ZMWw7YN)5xnzl)bKBkoH^)Nf>G4 zmFF{g&-fh;;}OwpuU>)q5iTOlSol8%P^o|vhN2r+v5+&_g})?fj5ydiB2>VkjQNyOIb&5!l4Dl-9}*SeuP#75wKdc2a_$GG^C4kATmb1@Dtp;d1tm-wZUhP z!?W{$hE0;!_6kqEK1SUZfwbo8ZaBpSEr{aGP~a zv+X8aYRm7`uS^yN-&qAzWZ>kw6-w3=Y{yiI`k^`4Bi zx7hKao^e(s>zFcHjZrJ3-FJ)I=cuO#VQw%koLp!*s=-iAGFu1~V_zT_{Mvg#P|071 zDC=&3X>LY8zG75H(zF8;7w1IR{u5lHfQLE&(Bh`xi&e1V6dZ)jXoA(*wZQF>-sPu+Uw3-qY*W% zC5Xu1rs^HlExos$)*s!1Ly9*LzW`%J^_F?B2pYZZcNC$hF0W=s2>=lG+>K54yD$yo z>$jh+C(%YO908S=NPa(4eKBF^;-e^WR>l8D=oFfJA`_H5Hl+OI^swqtP~kistJ|$C z6y)Ko8<3-gcPe85H)aAB*z@&V>Q;Up^#x_^PkmIjm3*{KOh|eRI(=St(uJ!X(d4X@ z(@>b`n_H9WeeJ}VFH069b^3CfH_-J01W5}w#mGbYt^;c|Gi&(8YUG!)E~5O{bgyul zj=3RgSHr#t5H#lo!*)P37fJMJUK8fjj`>3x~{OX(A) ztSpKfmhK#bZ+NPlJIeA!`O!#gbB8><^Usy9icgS}>>K`K*^%7Hn>s!C+1w8gi}%K$ z$8**r&Z~)kU^D!jnUVo-UfDH(IJ#ft6c#Y3c=mJ9wo}@RnKNBO4-Ka+GFw4rvK;@X|r6r#I$Sg{PSbXLS6ntt+v+jVE|kul|J}p+Cn|MuFV|iI$5> zz;)GED)p#gdg_!ivOzvLb3?bNzJ~h$YaD<|QgsI$fO?;Vgkg#7;r zYA@LCN@@Zo0&uJ%R}1tX;3iw?eiUbd<57<7sf~28+V7<>IN}>nLcW6vQz=FdMizO1 zI(*p@p6^DKiF9cD=zi$mA6e=(QCC&q--_#=2{TbFL7ttWTPH=dW2xsBe>DbVU{}i) zD7lbN>6wX>m4$aKbax|ng{O1R^8{+c7DXs3Qv#FOw59wBd8cCGchK`p?U~$vwW`J> zCBauBZWqVH^OM7)%XT9_d|`U#LVrxIT)F1M4$Yl&YdT!c>5d^%Ff5!zQO5J($jrk5 z@dlT3{ffJq3K65L^+=i8#t)h2UeN0oPzXroB; z;Y?8m4j9}hD)GN$XJJq??`Is!qzC6lqSDjk+p%YJbXYS!W+TAs-Z87LF&S1PAXdxA zx&AerwN+Xnzbh+Htm*K;_UbzT6IwVG;Ms%KnEzs!YJD$I`wM>(b2Do#1^KmIPqs1u zMRzDhoezF1WBZT8u*UsaJtiwxhO`oTduez=^C*tC`a za;6q`j7~ec7v(nVRLjhRU?9H`B}@#wWW*vBj=Ka?RSoq3YJ-E^re_iA4kAs|jj=qc zq!w%tu2|v>z63Ng@I1VWr_DyUsjfDN06ZBBsClBXh=`}a?gDPYtQFMNE!gQq3O=AGz;^9Wqp~Y+dQyeEGbc_)gqb&J5@$%9Lj8WF^@G(vhS{)H&aT)-} zOufdK9XZgD_`lX2Xc&BuQ!n$##hh2he5jb*sA=lfbYkJ6qCbZX8$c7^K2E-yf~$l9 z=v?JcQaL@>_O_hlKfaiy7p63A*(fzwy>gfBQ?VC6PnV@^hy;U zw*M8+I4*xRIj`YKS(Y^7@q$#Bll;~QW2OMhRa{@nevpRoL_v1JBQ368E_tbLRct0zC?3q&(5){5D^V7$zay-8s1r6K7fPHCyGnt@wCEz6ZD zjH|QLV{=qAZ5R>p=Bi?<%PCjSKpVN%^0d_bzrtKwr+SSIRMhtP0_48Z>FL;2J&@lA zMrUir<*vzPZzoYBpjsd*rk;V}>&1fvX{5~uo)brMIAqH%p=btEf^9MYr`3zx zFD!y;H|K^7R%2eRi(I+@$5#RU#O)yC9_|7cj$PI{whyhCS$$*{ZeXS}kxla3kP<_- z#y6D>|B~2c=3H>0S=pkzvpw*i;^-i$!%VyJ8L{JW2QY_eAUME7>r{)O_>SH9;@9^M3LrEv- z^NEEZbAm!5B8iK>pkdMkyIdLQYS))xen(OF52v$B{q>EDuw4)2)EJ{5>e!RszsPPB zo7p%^+<8*kp{+Qe+^t~XKRck`6prSu?Qr%t1y)5sl}M-;vbkfdxo(=f%~Tx>`}c(u zfxO?9had&bGvDoZAqCx=mm6sGJm2|Bb`7@BW8-kOyta!8q_kpqY2F;Z+JD7l8r^~J zXW$#^DN=_!=WtSN>UhyPwDVEog2>cQU6d2*n||OpIS#{zcYaO2ukT)5e|y+7$eixq)#Dee!`#ShI(piUfz6Zpu5FlXYK%pHV)~O)sUq zA+$&`@bOC=naAmpAgiRx>>m^^@VI2bzUxeBGs!8I8Ygt(Sg+(E2DX$HkBA zGGDou?1Bc2h-{_Q2`wort&n}A^{I@u6jw13NlFY^hi&wOwFyH_KjF_ z*tLA0REx%U^OsZrfV^FV3==x&*HU+E(jylantijNu9@o?hTEouBLnF#e=I!9vRLFi zzGN(8dQQC7F@5yTf%BkJnTlzg(doK5+&jX#1_950>2el{%%6f+ML|%oKJMcwyS08R z`-%O5pNA{?>}T)xueb7+N4-B)V-f-;3cWx7$!bVMNm~85p~5iv8~*};Lh%mD9l8QAIN;y-V{PSruG<_@=B)%`IwM3&fu8U z1H@T&fjysKK|UMv&e_#mdNd@qKLRa;xYjJdGx(lYVj^-U!WTSgN@_7`p<^MVoFY2O zvniK9^%9!jo9VvGl#N1BF?F(JZ*8X1*?V3DmhllhNOih?uUvB(n6=uK+DQbl$@UoL zcS%Qm(Oae?M|t;3ReX=rQ9`AQ1z@!D`LW=3)G#b`1H_Vms$)NG&J;-H3J>0pqQ8jcAtwAYTr_=<;j0!(!T|^M|elVy;Qkts) z-$N!%`N{F`aIuVaet0%`xazq?omP8vNF5)rn@cwb@?q3Ux1i=`$d;1L{<11Q2^62v z%n+IjS3Huauls3!;weC6_3AUP&4voG`ev_*9izob27t!3M=$WCc94F>t^w)(T`Gfl zwRRe>52b~wQR5?xJ)VhgJ*W;6Kl@MGxFKA;hPwd>oMIz&uN`2!e9Dgimn*jUaJDx4 z(&#F_8%YI>-t&SOHF2dlhr_LRqj`$;WIX%zL%|zKM$Ulep!}e(kBbl7N$k*b(eWV~vJkZ4amV98XaE}P{VWaqaFD*- zJQ>6~bH0^!kE6JDo9uqOp3>2Stf&djUsr9hHdW;VGNm7Wd4+ z)?4C7cL=cjz90!Zu+a(OK<_o>#mRvyi6=OnjfaryzF5yIkE03{}r!&a!u z%_M3Oe`BBkEh(gZqdU=8_%eYVTZ%o<$e6M}RyeIuS`j(okxs+;7!Z#Ng5aspp{+S9 z`$^+pSRym1e%5xVlgUd73+;HxNEbB7r*|IR{hqo9Kyt_fP*Y;QO_l2MZm=+lOsUpZ zCJ>uLTT|6t(CGA!xC_HGO@@8o0x_-GV>y4W%et^mR5v&7Kcz*jzvy&pe-3^^K()80u+`OMT~3dK|AX%8hb` zpYT1B61y-Z2oH;(B&^EWlGe3(<0uccMdIh2!tq+SFl1Q1m)&Hl9%bPyAof zE_UT6QD(g<^LF6&EfHAa3`t3rW- zfsx_1%|St(2eeE@bpE-tGFz`lMbyHhlrf`>R#nu=__N^HTQ8_lUNx{27=`nNIVM6m zaMW5`7+RIshHdSZ<1K(65%;C0%wyp+yyW<_dp|d1-sn}C`tX>%8j%bD(NqxRa^^_;bqdl4Whsk*Q;{IRVPYO!SputoOYq3kC`9m0w*fD)c2)1MWqE! z;uzUXDvUK|kwy9fEqgk@GFc2OZq67ue$}_f{d+^pEjlZqA((b={8Wch3db6}koy3gK~h{uAc zk41)o_hFn+i4~(hXM9cw-5i}LY82@`QgcZNr2K~Kg$%!f6`wnn3 z`~W~k{7CLMCd08Z|V~!Fr z+Gj@R`NA2d>tt2_>wR7a(-Y2dx&&6%|0z0185Ynn>qwD%>>gLS*pd~5>cN8*hOlnK zvNFhlzCQSGJ6#D$ax(9(@b#GU8&;QjIrvm7_i-~B+1H^-L;O6Po^ z3BfU6?=`}#mx-<{n_ZW?z3Im6aN5&CBr51P;f*7^E($V21F{vIyD95qZ2~-9&~r$p zwen;E2+5tuT2UR>=`!>L%Okjye9^~ z`E~zEi@+P+GN-uGjf-+ofqXTk0<(ZrCCnRR8W$d`ry3n0p=hH#6nGFhB4@Hu6#{P@ z2M-Od%pe^3qw;~*fyblo!kw2vuc@n4=@KPq+SD;6&Qd%|>m41y6=_cusx|+@9#)5i zp9#xONd+e|U*n?GwUqZYydI(vo`o2Oj|zJRYl&gX-qRuE#yt&?QX~EgsU<=Q{@y%; zxl|^V43z%Q88}QrO%=xWmkawhf@u)}ialp0F1~huk4zzRT$Tq=a{aZKiTMn2U}}{C z6RC^#JgP0#&?O^H+FlfO9e*lPyfi1VuS=<+66@Z-O;wP;dvZ|E4x)I%GMQiUSp{8j zRfajyFDmKwMI8VY_6t@Ff^rnDq`YrlZRkW68ZZfS&agE& zgFB2wUPwnqKyJv>yH(%H@O)xCOz6-HNQj)uzuw$H<}SF-f2y-K`W|)7+sq47PznK% zuWq1gE8D?kG}gmEF9|Q%w;}^nlTtU!c^@QyDBWxO2LqF{>dFn}4PJtA_wd25R&EM{ zD;*^aMVvco(iC7EEhYaJQ_zE>B*fc~Vl6=B^W7y_vX9Pt1BkX79Oe zT%1L>c>Z|(e?YCqBBqFYAdY1Pk6W8HsnbZvT5 zWRt`=6MW^#MuQ#}i;*0k2GsE&-QBj+v(4?86`{=4TKE%r0I%(NILZ2(46`yB!cjS} zes;@9OA}n@*!l@nD@3OnY}1C6o0_fuqcdGH9Z6VZ-(Fd+G9-UT>O0M-@E??_pagYS z6D#6;kSKz3J$36rR?lfn0|D(HYiDg=TN_m09jnqD7-#wEs>o?+3lAnwX0EplOrC^! z_WD}-N6CQVRK1I0WeOPh>83eh5UBKDD`z0F<nA#r{&R@tkgRBHI_`e-z1OXMhgM}H38YJE)E~Igh7x- zSsN2VfM3&q^e>CaZOy`+HvM`CS#MzQZ*0z&G;`Al4>-ABD$_kEDp&!SI+#QDkXw$J z%|56Pfd>{Ucr(~RO2-QL4RKP8Ir3QlpDkntz)~8n*Ryi{PMi@0LrxskroHUI`CJk# z4a~w(_@xC!!t2Z&TJnuywH9H$9{q55&aQ^*chW5+UqNI)aOu_TXau?plN8LDcxlWd zh6FY8Lsl`NAUPnWhQ|^tAUo`0XfIGf?Q;~z7U>!nrd=PhBiYze)oa_~)CK4Wu2Vn4 zP9u-Tp!ts&bL)=`{fPWmZPBr5zeNyRYI&GFS&?=!2W*C`}yz z2sw^PCu{qSmqOfe6;6j}i_!;h%{t~q^f$jl4EYJP_${zhQ#)nGMnaz}`p>UUnPx2% z8XI$73Xthw@z_=-7SHBS0V7hCuHv|reXUlhGxH??=ehwQs4ugqB5D_132w@iu36O)B%NLhQN7uAxQ}oKip*R&wkIA3=k=AGxnYp~E z9dnlO-GRVtc|?Jt45p|8%Zv~|iXf)#{~i$%02P>fE zduft6Gb))vxVJ0Vea$Y!eSyo+&K8y0tXkmRKHk!<6a1$cEr~78Hi2_0+QiId@PT=} zunMsB@x8m_l%}a{IFwOT1XvTgS{@TB4va2X4OET%s zi_M(j{s?I_yr;MLXkIRYs8U51o5p(7PX70AjnYj`T3LQ^q=rd&tMj&}i=b9AiKPiN z#kfNuOa)Z{I{*Ns16+caPAt(2&S_!9^W9Y!8o1CMHW*j0wdc9*_qaZK^J|%`R9!X9 z6qm0M@Qx~<-|J?=iFilP$hdQouTge)+PCY6aQWgbp;uTF@4MwZk-q(IcojXZY@Qb#$EGrZIdE=1A0u$ zEGhc3l`*?paC##@&&uz=Rme3ld;EhDLqb8|4C%1=wg0|DzkTw$e-Urw@QjO zv%%$#g39?pS1#4Ucc{+xs$1l_aoF2w$J9y23KfyC(-@aJCL(jHN>vBAN5lZOTUq)E z*@jF6aLuLF$LX(mT%XL>P4964`|fIS{26wt&Q7{oUPOJnQpYe&fq~lbUCi_+#mCYG zS*+=nd&oWaeaD_;ZPgk|;IBP9aJ4|^F&oZ_?@55@SiVUBrF{@lGMeFFD&+MQ6bdpx z=S|<#w;Vj54f9B+=cLqe%pk|rn%n-{zKHOq@7f&)0v#0Ts_C;AV}%2 z*WejOKL&&yaw4)&b|$D5=wrW23cHw|gFi-?8S#&QKK6GtCEtSttlKocR_1a0>Pv4+ z)fxVlN`s$EEIz**k+PW3p`uvjRUb@9JT02|jMvG<-hOxl)Gomy&l0A47amJBX?7@@ zjUfZRRWWuzprYsSVUwh5`7+pG{47#BlanXR)uZnra*IfD0fh5NY&N{|fSL3bCm{(-W_c`;4$tc>4xRtkoE7lHeGz-czFlZUa?QwDH zj#_=aYgW?y{g-Z_eX0A-C=rbUpM;2pD}CaR5dZ`U0O*%N0Y({``O@%bnY0a&*^ryb z60}f+;NQeGGFo*Z^9VD(T9Ztl62`A%JEFUr^E1U(bhAgDj_x3LI2$L3{JP0DQ1a!- zk{PpXcx4rvvMHW+ES-))luhrb^5@Ph5}?kLuR*l@r77}#FrVOlIB@+*p*td`bN?|b zxVcFmkh@j=;$TR<%V(!PK4Ux(l8nt# zsVSUT)AV$)DNvJlc+SnGeB7G@9Xw#spTf`%QW<$|n%HU&g^-%K$*SkxE-EltTggSH zkrm#vJx3U!X3E4j{pQy{V(zX%Kl7sQb&@`I+B-#W_e814%wK6>!cdh+0l^ZeotdX( z#!Mc-+!^(ikyg84l{#wjXs8V>w-!em7o2pJ!6vB%sb-sttFPrFYamX>%NFIJBWp#D zO=cD~q_KYeYcC=MJl%r^r({UE^HmHHNoK9(!9^>PaXTQ8_$#LD7*-VfQA&I34M)m# z`-FpWopi(3i23oH3g6GjvfWR`ajVYKxBsedN=Rr~(9R_?r+ZAifw0i%20lirQGzh% z2xWtlR}}uX*%Az0!p>rNuebhyx2(a2&fBvBZGf7sv3koOFTLK85{yuuku@(`ai?;;OT3m?)@9 z20$A8UNd`HLo8CI6a!F>2q|G$ zZZ?&Lh-Ba9vdA2T3`GYQ6`KVo2b(8f=J}uE@ItUkj10gCjo;C;VEa?Jvl^Jg*ihjy zgTs357M<(+eWtbMtNgqt&6Zhn>23!>9IiMfhhg1fjVMn{;xOXX3};c^Cu^DbPhw{7 zc=dW%$p>>3Y$kP|d_1YkVDV# zUJJd9=lUL<7=RA;mUWJTshRinB2w zWwSF1-Xjr8kX={}snOd?X;wu=wdTgf+pX-+wS1MQUiW$EVM!MQKtmrd0m)45b|SWB zAP>jGHKO6$oqvw--Fnze$e}6DugnI}ozh4A&V?FVj`l2T#kG3KYd0eXBPCVC+{}fk z+^LnAGaR@z7#u4vpLDhixWfJjzi;b~T#dbD^e_6;$zbeM|EY2>6un|r52To%mfz2` zewWWF8I$4TLk_I+I_x@Uw$@Hl{nbT>4ks-pC8ycWPzuZ91x1nVwt*I5?CkA6;2pId zhAb+4TM1V`?)+2z*sbY$q(E=!Xdy{ANnC;d6vq%o9cHv;05;quJN#$3bHwli1Ebg$ z!Jz?HPg$sbHnwJg7o7TEmHaFdi3fY!-4n+894_8Ob@&-eMI(B^1IlAX_}mV4;E}p4 zFo`I?!kp}d|17_YCy=#6!2k2s+vX{Mn(NEq*;AdMcMus~0keY$$cSp&qxRLTX>XSd z0MHQ@TTSEw#a5Z5fT*l?wczGolyI&#Aj-$H%pKdkdt)=1NOfdiY#SbGnJF$>Y6X(Iv_Xv&Ru-h?2jb&F0_IcSw6nQ|?ku*>xl`OZZ=><*C<`~U9lI=m0$ zuvl9JzP&f1(QCDuPa3J=3JPuzxNepRE29g?U&3SY7gmgNg*HK(=YHAgWEVWAsk#k57?9n}?IO_r`4RprMB=Z&p!D zv%;hi?~}A@nP`1m*nR65H=+~61aQ{6qX)DlECsXx6rIFjYqn+gobYCpq3;^v$t=sk z2&=^(W9m!BmRiA)LIZ)RO}Yvfxws$h)kTI!1M-tzqAk00oq|uCSeA4OTm3X9t0-Ai z)`Xim4FY*{HYOPfP<_~+*@7+vt+C6>eh5cSzP^FCH$at%3lAyv~^Q+QBvRw)|F&di~Q z6-_sio=>*5KiU6KFfxT1Rdx1~w2&E5f=codwBZm>+R8Y-sJ4WuyK71g|AS@GY>2R? zfwgTY<5q6;O3#pWH|kmv+ae&{2@1~E9(yt3H6gF3uHzKF)ZjA0}n7%luG-gU2-J~`zv_vAGdI+ zYFfV$ny0KvPpVBi5sJ44T#<()t_uBS+G((w#gP>Zv zjtj%}y+Xg>8@k`bSga}rKR0axYKa6v;Z;y}yi%qNwfHSyh3w77WlcZep!M_4`sSe| zlRx-LsYzeA(b1OLxYbMhv%}i>=I!9{eN$aY8nzPaL-a}Z&x(UQVyGBIFCY7qI9XV@ z)a;s@-g<2quh>@{DXM$EG>mKzkRI7Q7db(nvo!V@$8EtK2dGKKgETw zcBi+3#{w(+>M9&v;P^5`nk!);ngQ3O zSXa};aR4&!XJ?RuTy}7(MwK_(g<$qy{leZks1=$JEG>GCmbGYoM{s$JZJ)>tfqY`R z#K-0o31Jon%A6{;Tl(EhOB^odde@F9<|vPcO(%vH3N2B(0(+oFmmxEQxGoNJ{DX%g zEX&Re{=Ak!Sdb@R(grYNpPxpfAU9=Q`jEBPy|DVct51H#eJlFf)&FIa^oz?~>7nSO z2Fc%N>n~x{@w|ckrj(lt!S>?ibe<-Bl(K6e2>yxSEw{YTdfA0=6V30SBr==?S%ua1bCfBz}yV3DLR_$$$M zTZo;y(xa0YsTek=IUCmWM^rJg!Hi%8pfLWsCLp|3Sd$Dy=?w?u}LM}PI# zgB_oI8!auw+qs_b2o_R z*a_opzJfNz0{1oFjKzGp>cu@ml81Z}v}Wsa+QyHczVMX5($VmCovDEPF0gp2E#Waz zNQBW+^p2L|dma+G19biC>mSTcbhg?ev%lvD?HuxK{Nf>?rh~(ErBT|Z#Q|azUBpMh%!g*MQ z@l5UJm`a1nlddqeU(?6v9Lk`gw9t3cOFr{r9)i%}O1FJvL*z1h)dz0HS|(eQmBK=R z$;whEN?F9__pB%*7itDQ0i3E%ph&8lVITY(pZOtvu}+_ZMYV62tdRu2#>+i@%4iKX zL0XzAg%CRsN(+m);G4-t3#(`Sh_hDv20Db zhIvIeG{yQ+DmPACs&xeLiPNRs{Ooz4bIgAghZ6$NVzhmUDSnW}B5Z0-U#N8)XzIk# zGtAq<8W@h@3;OMZ%?8B(GQd>K!-`h-D|8VHD0*$q52XQMlCj?1H!}aZ9^82f+RYVY zUgE-N^9o&{DTLcfJHN_{E{c?bcr|qH`FFj5HR!Xt{BtiD{qfkW(C0#a$NYJe8ZEA~ zX_f<E4Qc8e459E{!Pl(;+~sA8Q6^wJ4RqGnd9HhfQ_ZoKqmnq(5;Ooy zjx<#0Vq76Pv35D_l^2T2s2M)&J)8b?D#{Jx>ne&P4?e#mZ9dNbvyqld3>ZslC?5M_ zv9c}LnG%+Ad|AY+S9sNzrQCe;_$OAK`hsHIkdLW@v0+8SEQ0GqMMIC>z`ndzEUQMoN@FhS-!Cfj%d6qOqX9mG zKjBUYzZp1y)6oFnx? zecZz$oKWGfr0eOO?~?OUXwV7xZ6)7|1Z`c5pX(S zE@QC;WqyPdEYnt-Amn0HTcvPe8$W3&k9GCn>4;Gh64Nr^!Gy`^Y4zIvg^F-ee@WCv zV@h9@OR|~;g{1U(MV4%w6*}2HMj%wI$=VK8UJ(>MO+!*(I*7b_HAe@7X-j^O|4w@a z!@Ne>6<61SHf_`IoZ@ji)Q#$F8aTZQF8u~2g+T!Kl|r%+H#RPikQ0#*xp*jM>z)Fa>1San|c*Cv$o06 zI^BkYO#3!LBrBgbmWQdxnb41{mTJHSN6Hol76E_Itbt^}G;v>hnsi2v&uNkNM^)D! z00*~rb?G*sdhL`TfO{~T60_@hj{T~1+ZIf%!RE4|5GOf44s2T$OPzLCbJoj=z!*9d zao1}ZwonI8Tm6p3ZV#JHkrvv(!S%Zswr5^yk$0s0n)YMGlSm#G>rfXOG^5jS;Xs9# zf}N@-fCb-<NCi;DwoDDjYFP~BM<)e(Tr@KYv(870OvLXHDVFGQ(>s=1ZKm|I-( zKqL;%g*KEaxOdfmcN@9PdvY(}Uh{h#nhduy}t2Tk&4l*1qBVqc<`w6Ezb zbnFJ7<%&0o=u33aBIhyhU8=`M{{3W|^h*6Ebp2^tdrw$-|6c*~!l; zAGm`j&74iob4{N0rlL&J)_Cmib^Ot^0qrZ*pZ1Trn62^^vYveDUW+lEW4DUEHg;Ldp*TqGraq<-?C*FoR1a%TQJ9 z(@9C?2azc83yz&jWTN?Nbo8Qn{t{o})Ou%O)%`{e6OPLTDeNOXu6(lkX4ZUf$k;E3 zgz~1eMIv=pq%kdymV=Nr(C%`C`l#=H;ePN@l&6QRGN4WNy76)E^s3+Ww9uZ_%>Gw#v;cTR!%gT6qeWJH+$VGT4qfX& z{rIMUVX8(arYH;n-<+?mRfqrBiE|MPo`|C~FaeNY0Xr1??^<8OgZgb_>OPl!;`RMo zPKNs3Bxv?weH$!UR6yPbIgsVPStrU= ze(&%m%iH67k~u=_>q6@3?cDo6+2)`lv5*MpjSKYcuVnK$fKd~4UlMu7p7uDJ^%}5E z_v{C21LVca3|A>` z>}9AiLZ2L2?i_%qfPsy-rh??4vd_HAuOHXLpEf5gsL0RC7h6HshA9FDe><=VQ1o2t zj7H~hTb+lyH2HmY-@UdtIFg1_$E@Wo{j~e8%Fm{|P-5s%@|Vm=XTUrPH$j_zo+Bj) z=V=Ka>^_9y-JhR z(IgA};CU@5zNj?h2gG~5jwoqawiw^&Vy>Xynpc_#@=4flYb3(g%D*7I(X5Va%(Hp+ zL}io*_nkDb!z`#i=<_DH{<+z6KgZZxAKGn?7xQ=>ef`e5r~1*eK(^eQ?Y-i*=CyUu zCi5SCx%V0XKK-^tii%KTh8f{w1dabvNmuh2P&Oml@iAp>#f$I44n_Z*1yLJqUY%0N zGO3Fwew)Wp;Ww(4@$J_gmR`Tp*!RB0W8;_2UlW}%ytU`#d9#i-y%p|qgqfed-xhqm zv;S}yeE82Y_%N7vVZ2%O(kQrYEq8A{aX%O(cRuLJwC1nOuU-4PU}8&0_%Z%M3yWAl zF;EtOA|}QN4+jI78iUJ1s)R+L>*BH$LaUjH50Q~;(44JtOHUOW8U9zy_|&a;fD5bU)PS&!5EJWJ@#Y;!o&MXNV0*Jf_u%*7hhon)|!C1GV8Yj<@`=l7elm2NZqQLEopDFTNR8 zR%ShD+tq8nvu=J@xy&E&_J4l;yW5-D>wIwe{J--7GXKW&i;P7KWK-H|GTY=C~64HCU++npDS14XU$#L&VLrPWOS4fb;OkWRIdoJy3tp2+J!vbhQvPQ1f0N9wROQS0g zz`(o6IKGd4gqNGeH>*MbAV()aK)KvCV;&2L23B;2(2Aq@6o;zqpMEbMt?i|3!$S<^ zIOC%pMxu^ZfXy`z^P8k}!d8zY6omRz=mUPjpGDJnRItvX4C#yTp}ehUUU5HP(`dm3$^vKvX|k6 ztKtd`+YJ1cunO?iBfIVKr%0I$nQV}Y&s-Qp&0>|zM_~2N;YZ*V@da&^$e4hUDndG~ zsPXX!l|}_N;5;eksOo^xinzi{o_S?S<^0ofm*`bbmDAb)E+>-I)C{KDbw@{sUV)4!JNIW${OF_B& zJ57m05U_`#Fd1h|Y}zLmcGo@CGJV#HLb@cxt>lk~I@p&}gF$}!iz_ZHN0AO+(Zr=g zA7=a{Yvq3O)10Vjj)N*5QegV!(Ru$u>KW`Hyn%%lH8#FX1l1#wRK&0dg-kpSBDHZV z%mIgz7V2CSg4IbZykU%lA$Jmlg;KqP;X5|ptQ~lmCe65qxtCGOQ9z&C@(W)AmPVQ_ zMoXj?7C(dZjfKBY-!FSR1CdPC>XTNV*=0&t8|ZIBj?HPmYy11PX$=Mkl@CFQ7%*t( z!PY}lEwN@sR3KEh8M(1WjN6ii!)LL~BDZ=rP1_6Gb&eu>yqCa#+M17ROnRuz`$MLP9q~Xr z4rL4!P!fAs`rg{Lx@z_J(-~^)Wjp_B)fRNk4S-#Rv@JgxDP{W>v7nAX-#fXujd~Q!Y5^`QFVCym;^e?@ilH#~y zOH}{%Ss#9h>v_xHfl75u`iAs9b24PLbOHd0R?yc0iyyXET2e&im`6 zqZMN_CUca4ztLdH>W_|1(s%Tak?jwUT)77BrALoi1(@=d{)!oSIy(k(ilkUBpP1jEuMcIONx6{k(dU{0E(eA zpKNE$Vz*dm*Lc5KeZ+8u$*8fdSv!=bH%7Y~8!F|WqYHlB-5Xs}882~7nq{Q@Fp6IG zP&NuKI?XnM8GYy7Kv-m^o{+1xrlTS^q#TE9Cq6o4FP| z+|-bXD@T}eRbP|m0x}t?12d+xEtIw0X6i1hPw;cpNE)XORBe?L1jNslP7j5gbuSmV z+C*U5Qv+PVGHCwaSa2&<(}k+zKyhWG;?d1Ar?|1oQkAwxIL*wfRM~&&jo}9CK7!i` zTE2hfjAegu&{tG+-t;Y|d&Sq*T|{uNh>kvuC*A1T#&jrqN`_F6c%y4)ZN}kGy6HPV8!nY>Ja{Ib(8W6$%?Gebp44Pc%7oo-quz`+SG) z+1kpNW9Ic!(6;ZF{#$*zkByIn6>VOhLLwaE7&W7>Ri?e1fdG!B;S6ixlAXe@dFY&a7JCWQ=wM{SqoX*{8gxO$zOL zyJI;3U}qAH^jXSHJ!_hkzK4v%L8Z5;6LK4GUEdHv!cbWt=qNR1-XW`25qt08C}-}e zf&p5gvp_(y77keIIFzwftR(JW-Zoxw;EhL{-7FQ>02#{tPmyDVrFAvlI)r-p;W3vY zPz_ki*b}vacdwKbn9r3`loCZ*`!lxS+qlEgl>(he|LYgH>x`xR`K#_@LKMJ)CwHRE=5aN*Z z%k(ctJ2r455=RIOM)HU{tsDIo9Ns;|kIBaNd0fO_EO+$?4XaV!bOybpcq5sH1~FB0Wa?be5w5K=+Sx zjM|jiAORO;b}B-uIJUxo-R}r_S41|#CttrSH|Qr=OZce}8ER*f%o~dfi>gRbs4)u~9oJqM zAS3Xf+Ue6e9J@ZuHds3hol>Ub;2iojKFzu^m9e6=?{eA|;uKo?uwWvXbG9ZT@ta7YB~$WIRNAdLY~} zc*>;WO0mqWWhD*tKx@_9z8mY~<}p?@b>^1IiA|40TC8j4o_s5#yIiFV_UA7iaWL( zf=qtTS@;wG5K0}^xb^oSrJjo4188f@5rJ4`5i9{kNaA7_Kf;ToaZf-THjY-XDI;)0C=8St8m!r>Nrl1iW(fW)cnU5`)hsB!Z8VTUal?lWg*KYiR)JODM(3aZj`)sHaIr#4bXasc>e! zS^-Z9>A)`)arb?6=XGG{XRXkwUJ2S0>dbT5=34j3{8h=Hlek`~S=`?+VbWr!T#L)| z`VM&?eGvCyiZu9+bXktCVM7B1&@mO1@}q#kF=9J1>4jBp(MFd}p|9%eLvdrz^!411 zuVl#zt(852X?T0$kfjL})rg%W3Sld`-_mDamrKE{{tPt=J6@>o1Kw7uc#Htv z$vWl}DE_+@mzq#r=_FFw*r$>)z)bgp@ICl3oSFEu?*CkeaQFlxeM2r#>#1n0w-Xa6)el%YOQSL>)qleHV%?rlWbU833ZuHplUZ_l zBz>9B^8zJDE^wpW=ZRYW9kA<5GXntVjj2au^6T z1TM7%i?wK4I7T0@79zvTf8nxaEkz9qHJ6|uN~UphQ$UoGWsoK57;;vZf9d{&yOgvX zq~chDQ%SFKsZfOfRt_n40R>$VAje6OUR`LIG;4@$Tx;sMaQZP?khvadwIwT&T2~u9VqGdMVBEi68l>eu5kDqfHO9xo z*aRvnRacWVCu=k-7Elv%I zcFHb_+`jqoCq{4I)H8Me2{5Vii&znuvti6{_1GB1z< z2o<5;8@@OuR)}(O6i7-z1{>I=tyWmjmID4G?m!RwU(W>$L&USyIfOc^X|;w)=21Ze z?%{?`BCErSp#LFLKmNS6(-Qrdn3keUrlMW4IJG!zB@#)NVYO`eu_Iff4p5&)`J^M5 z>ye0~Z9PT37U+zhrkXSuT6Kn?YF z^PkGY7cn!MH&Ux>=a10P6U(l;@ye|LgIp%0u$<)n>%>R+mUwwy6i@_z=j_*)AeBd}^UBc>;2cyJ5Bcj91&*F|H&wxl~?G?5qn z(?Xf=w^*qZM5X5B!5tgg3%9+IKG%HBYe!SwInOM^_%gO=3uJg05n*jJc}5eGHR}EMMKlsTJ=? zi8^)CHU+^3x~$}2x_XJ-E$Zvv`^m|`FwU{PF44jx?QbXR9$vw1`gwN6k5ZaAXVcft ze=Gmqzofs{NG+xyqs4|`h!++jRAu6GY$DkS#lu_(&GW+zk>BaeEKcObw)<32H12Vz z-ML@{IM|T7E%~!4V9T`)iMG9HQEFE+UMBRpdY)}QE+i!3_-!7-+ZZ1AODVY)HSKtO znp^(}$t6hU4k(V4iLGGsS^m?)B;Z$^D2?^wJ&!xMI-O42k_#Y4D~sa=Qd1ulGeQ9R zemiHTrU99PU~KCkJo|AHpSfD1_p zAFdHndFw%;Aj4Q7X!LSIH*Oh=%@nNE+eO@2dtNs}DnX+({CZbHRHc&TCz*8tiw;<_ z=a27`=N^Zrf81pu4ja<_d+9YdD`~kwU$S#KpMCoV)`}9}O+L9MzlN2!Rv=N=1nt?W zQ3C+18&=#77Nz@$5sZdoOXb#=K?gXO-Ig_JrpjRaR5a6{bV9=ejlN##KEz+vKbXrg z1gRr`cgOoZL~n@XX~bywv;KI;OY!2@SMWe7<2=+h0R3Cb9^f@OuOKc zMN+I;l=1tQ9QW|mEY8Fy2#f3T&&2$)iS*b%QE6TY_eiMpu5bCRl8}_;g5> zk$*w%(IqFGNc>n;TUuvI^q@b*4GJ+@vF<_3E?G5ORku(6G>to2T;tO-062v=WF|*% zGpfU+r{GhiBy6C3#?L^=)tww3j@jP0#-y3dka z02lxrPFMSoJ8QcWe)pFpZ$y({@D)cJS(Mop7*xxAvrbX)6;O&P7gIiPeU)}|Vt zF!;^XqAwkL+B`>uSSNy<5L_?TD1{6nnjHr7Q)P%D1m8;%h@-qsH0*Vz)}L(v#5?7U z&>}IeM;(;`{WUI~N8pR?j_H{9aGgJtuN+oIz)5#nb*@cLq`&HoaP*MsP@=I(LM0!3 zP>ux!GUAA)F}Z`<(6XR_gL9Y80)yw5NRg>q@5YT{J9|k(ZkOfC7%iTD&7jxT%9*#< z#rlA8V=F~j=g#1qEzjO5Iw#IywX^NlmDCW(ASJ-c39QEq@unvdTl41X;F8``W%9h? z{=;*6##ckbW|5GQWUMzld`>a%dl+>PGNmzcr*5AbfsnS5Kra`IL`Ls9S*%d7#26E% z&Q)BBvhLosFxjWOz4mdJi$Tco;=V!F^O{EAi0H8uLTc7Tdy;hZ8tO-fn-B#Fo*ggU4*zrN#!Qio(a~Hn!OYFBT zMvaa@WOByXsN>Bs3Ma8f_Do&Q_Ui7LwGE#HXY#kH?y1;v{T>QMB?|)u^oCyX*BS3? z$R0mO#`@p;EY!{Ak;lEkg)^@e1=!sWV2Njvu=`8vPd{<`Gk1mM;c<_z9%Uf74srjA z>4+%Rjj`37zFxig<%B9wue9$H+L4+^=zOVO&9Af?Mo*d`vv0vZ1K$QRCKOvs3Ty6U zUfMO{x++{JN!NS`!d}A>qWw)xMphAZ9gKbW+6nnBug{+s7X4jn8ZtZ+fWyxH{nKZW zKD`J*xjNwbVp!uK@I_Qz7KG;&m0*(y{-L`uzbJXc23#MJW1KL7Y}R zLAJxsw2d1d+JYS`3`d}^_fO+YG0U7Ag{oMNG?f8_TMqNzMUEzn*2iQMx;JJPrMUgk zoGu>AI_bY4Tm`DytEVXR?i{8eMdwa)hU$9PLI(vaG`h7o&dc{+N58>=En#-g>jWC6O`f)#M$e#WeTgJ(3v&e`CO@h~-oYl)>C-7! z&Hj^YJdd$zv}BOQ#a3*om-EC>YfqBS0bVdLtLO0RGAX6d%gC<_?q2Z9T|l@`Su*%! za#A`-g|F8RH+<2Vn$PaGS(0H*vO!%DkpoiumRV|cjPME>Iu4*s$!q|q`RDo4^k8!0 z7yn0*`UT{&1CdrZSbX7;6F)Afcf6AM zF#+ddiXP`PJ5ABs2V->n@~+SCe>b1Q*R2DCawjH|Ryw+*+cUG}W3w_ZCXf;NuXzl? zEij(SFcL3`$c$9QYFS))%=|k&GYR0H$uQWTKZhmCWMj<)CE{nttaY(7`)&SVqVl(_ zC}X1$IVP|3db0_}T;y!ve}jjK|Eweew2;fTsjn_&3LPJ&R&dp(17Q;#)f7%$l#IuE ze@IL~`+0-SDl&QNI)19i;${_DiC@9%;QEJUi=rkK-yDk*2mqAjS-^l8+hrp$z!*_* z<1)TuF2+v%E9mT=vk}`=c~S`_qB61f(@7sHl4vFoOC!^j;5Jk&m8CHxg6|v3HF-jL z(X}GzX3Sl}@|S>1-`YB@vpMuUe9O*dvo&TEKTAq+V(!K|mR_U^iK3#QMrGr@Q7E9E-q8VE}&CEg0sH}l1pBtzcp z-Abb&(E7)1zK4SwMPmxccLhZ*OYb&;xtnw%<1Tlsua;9*Uj$Zb)ft@XMe$Y zHtCLtoF20TS2ywmycgs^v5G{96beU4ptHKgh!T(1hj{|VP|*2vm-~n4%{~0`pPc5* zE$Pjocys*xe(A;j&LDpwiVjiL47QK|!3?3#4XmfgvTwWKnofn)d$6CPERylndZB#{>luFxcI z1G>e{Jbr>sdir(!x?*((g(p06$q!=EQMm>$Pf348_f_qn#hjft9%^t147VBreEj_g zP_N56OVZ57nHS*5XZ^2c{n(R&Dvf*-Qc35bk~K8aJX=UPTJKka-WZ0DjKH6*O!}c} zp-hISb#7N^Z$4ePqoQpska^(oa?yMJ>fIrDRynM_9(PSt3Z$?=Uaw*&J+v((^d9Eh zd^lPBU0^7pLCr!moXSsKOq@alH?~onh2-*P+L%HK0P{b3E?fvapUKuGBIv(L_#bj& z)!+V#6H@`Ljuol_@6VqBbI@fXaJhe=ODd~mQFUcWi|dbeA0^L9{^|4XRoUpKJ=V37 zM@K+Z=@Q40A}?tWuQ_sQV4HSERCUBu+mxwhw2PIbJuS%GsWf#OPL`kVzy@=woby{# zrZN~}Tb2XMuVQQ3Gkp|wv*nC)0Hr)=;J7kt%zo^IN9FiEiqZpXsDn{0++?2W4=WQb zQ(Q_&&AhEwCL`66`4=1-YBuNY)MRy`iK^9BNYhd0Q*|QrSE2r790iZF=Fegw8s+{@ z0yf`OsVtqw^}_wncgYWbaK4878L;Lr;xJkrZok@0AGgLUAs^#gtfpS&+47l`{k?nO zru!;7&U0dc6W_5Y-~C#}%f=nwy4*ZasFZ>m4;??kEy7A343W@UmCIcG_>Fi$9l=~W zqE78k`XKShc=k)g2z^YTpZVaAd*JIY3rV5Uja%)+y2MjO6MuHRM6wJova(!tgf^Bk zZ+Kzt`rVZ$wPjB)2NnZy)tA`A22C3o)vo&5V}?I9x36RmkbuwX0hXBEW6@3bKi%V^ zMHkaoQ=oyCu1{|mF&I%`>On-oJ~KygN*G*N{I8Y@;o$MZDij@7u&BZOR_{P75Woj`j&|OaxX<$B6s>v@Ily0e`ca;jPoPwVPQDBbmw9PMhh&>IFuF zeY!|xtjO=}fcGm8p4nI{D+?dW{X;C>m2L~k-ET$2YD0RwYpgv0dnKkaFTLgY4^{{i zXo&O6A>f%P>v@f~u-RBYz^z@2ARyJH=9te1Ruql7LrIDPLp~pokg`qc=SS z5AsaunWxcwA)$%bql%c*v&p4DUnDJ;DP5BeC_+)+N?@ILD$x0R6K?YaIrRI|Avasc zKbzOwJRoU_YsV*JTqph|G!eqZkC4k}1%{;B5CE5z6lgC8R9DHgd4(ahsDv%ZZ22v} z%^b(nS~pSn;}@`5Np071Kav&2m$a0p6RlOz$Z+xi!~p4i(HYn^NAL=x*N9k+DCG8N z$&cjBKAug3++ZHfNRv5H5~>azm|0&c)=Cz=h@8rhq2Z8yJ4AuVB8ZbQwafx%0FtHw zUAjVx5O6ndTZOaowNAVmbf0mx=208G9(dP*yXRBtak88HKCs#9O~WH3=3?#XJ8@!(nT!%c(l5CJ#uNxlf4>cQ8)&@i%_6E>eV62TnVb4B5#ODz`!u6lMa7dMjo&v?tM-U$ zf@KUN>uZuRO)Ca~&0i^nrGNc0AyzoWPRMT2lUm$zsdlP_gqlU!5)~SWCyIY_ zqsEi2>W0bU7-meN9~LsVr;j?Qr&1esGKa--D9e?kLt)+cO>0V6STc@z2lqZ;(!>sp ztIwP$q`S}cr4`@k51-8cnw~&oD`bw?mge5{kle<5hs_*9iv*y}CdN_m2v!t=0rfPz zsPW~O7X$GBG;FalU=s$@#b1zF2=sG~xCO>PAjlMwn*WVpRDsna!J!&!W;Qe*3t%Xp z4a&S5o%SNK)tBpV1&)W<-J zm)U3s?d`!}topU3T78f=;pj@uNrA`9&Pns`bN?f~Q}FdA`S_l)t0?IkuHZW(*Hz@m z9QpH@tH_ljns;eDFp=nc2|>_=Ug)}vbsB=iA*FL&DFU-{2n+y$2VaN^IQ)Z10vU_g zKBWAyoS*C$x5}!;GZ9iM9O%M&St;e&IUO69Yvs=o3nQ_YFA-b@^R&VOZpt-@iyY;4 zf6cfRq}g?czhTzKMUwUm`k_ zvU`uqeZgwHji~>W0eLA7P|2ew;dLSoivtf}H$=~>uDQ|EZFZCFEFx0E1O}Sgf7q*R zRJfJl@~Nh%P-XH?)sYd~l~Vduv6@~axW-qrrh>;(mG902RDPm!=x0FD7T`t1{FY#uY2}c;C0W`HCu8r zfT_QHEjlzAU2pG?ntCxVJ=;I{Slb)+B z)p)i&-Cmsqn06P~JP7vw*|ECuUCX&6OH|%k`m9bGm|*K&j#0E%)2$#maA0(B*+j?s zpOS*7zVwWz6d7l(@F8kJ(c-sQeP}E{qj|9AYUr@UI_5$KduSv&54%zP{FCBkoNCQp zsC|IZR^(cxcIFlYwDb>nFiy130YPC!(i68z!>)nH!e>GTq9>oTd0o>jfMOS-S3GAr z9u~h7C{20XGfusY+ej3I9S%lg1!2%UDCRqURc5*)p{x{zZN(FWkt_vZ!ERT7LG3Dh zd}NX+XXYxe&-_T2@ih@QlM`L_Bj@vPOFaHiBGh(Re5FiUJuBL3A=1VC%p!NopAs4> z%nG+`n!aU`{gD){IA2zE$x6sJC0|-Cg5vlx>qdyZBF~lAE@zayoxfkva4r{4(nhc7 z=9sb4nbBlomlbh5@~7g?;$-e4kP@QI{@gDby(TR4_xJw>ki`n5-8%6_2U0D%OzK|5^tgSlUEmJ%2Pwvt&h*|6;S$ z>;2846*tVp?&KYj@Zu~#_obnN<#dULST{vASn^j*gkMce#gC*y_Ma!;ob1(Ion$DQ zF7g$3XxCMm*Pl?LRECY z(7`)A$^Ank70RQ^7evBcD0dNag zNW@^#z!8$zVn$9G{wxj``YF*Sq;7ke3a*9I&q^uvI_(+MgkV-|6=0$n2z8XXLETwE zU<5W7R&gpY3y;Em$l2l#C)xeh=r>5KF@Zz}5Bx24RmG21Dc z?g_t14~tx(yU-^6!yqvW!65wDq2i(?x$7rF*>cB33J);)DF?whM;wG9q!eKC`l?~80o79gU zu>_i}(`dCm4Q3{V6Jb&@01}@A0~9Bb(~Y=tm`4#WsWgpNo;>UVX8v8F5uotCi6;`({(XMQ!Dz8N~g^U3P` z@@%af7%SJa!y~Vc@WZ!B8#@a)os(|?Ri_DJIfRNQQzHh_4-p;6S80f>6-tJOo@7=f z;kpY*NkA!M(t_tp(lBO6)jY^}hz2JfgrE2I^AT+FJdT#JU+{&+3k;Wf4dcd|V@2*` z3a!&k$(Jy%(CTT zUw5rHbB%ekVeWY2iTmDPr8n)F8Zqd*?lcOEYc3oi#%eA`eVMYW{`5EFem1nk8eznv z%;cCxPj2+DmLNjJK9(_|VER!EpY0(T_39M5p-&>=e_uPwFnA}E4NWvjx9n+Q3Tyg& zweyt!-LFVMP}u_gr?${Ef3LdR_`z*o*A`WoRF`@dx$;3{0mmgf2UuX7zOgD|pT6*i zlk#Ln77<>+n6z}T!8O636|oHnux8UbiJM5Sil=N2kR?8*0XFy1Y+&QIkSkeBXN9v#(mRdV%CLWPUP}vJw2MMwzf_T7is0j4*B-p43J5j^uA0SBi z8d81NT{TQ?CCSSSSe$-(L0owo%k$q;>EycIMUKGvOMlYzd+lIr3sY=w7lc>Ixh=a@ zb{q7&8vTEs+uF0RzPdrmb`={nyv3xzg*2^Hp4|)Y1NIGaDS*m*S_|d4WDJf#a8zT4 zUd#TN_o4xuje0aJj~S3gAn_WDdmK3qmzbVXw17Fg?p$!VQmvbD&|`5jZ~5jZqnVJI z7bX3Myi8Xwm42?WKngFM0I>4br3F|2{_zFCP#Meg-F(`)h2Hc?&R6v{HA|0Bj`mBP z6&;Gms97f6J^rn`u55WJ^tG$_tu;u=(H@PR`k}(FrV+sts1SSCp42O=RgJW$Kc#hN zzPKgkJHow8b*$li7Ojc6$|SQ|ATcfSPqaZ~jMV73h7d`SX4|pl2+^kr# z$;b3(4^PqdRrz!Gk=^1Ke?M57ly4*?%&4B<3NWz)a0fSdp3v-u1FlLl4rHp$pp~Vt z24l(sLoktuhvkxjB!<9bIr*zLeK?&0M1&Y=ODK%`L2;H^s|yh;?4T*zj5;ny$ZlU^ zyu4?V#rtT%6UZg@D+K~#;zm=K3P6UADB!w!WBgZf(4ovvDjQIswnvhpA?AO8rE*)# z|A?GE4VUc^xll|RfG8-c3|OU%+1#Ik3!2W9j%>Pdmqz@OcqZAQ#7JzZzx1o!^*a4| z{oeEm5%k{#H~{u@DN=D%emPRV(GX2}PZ-0}iN+e>z=|*}Pa@swEKa4Q5cuF^e&k6(FN*zy18)&}xv7 z33D^Tql?561O}%Gevv7=wRHqQ^vHc;uS4x3CmkUmT0DeR5o0KMP%R5fm1N6cE~pCB zTml&?=(33c!%wP^5h4%-2O7keINnWj@YKEP%%x7>#`6rMdr|iCKkZSq7Nz6jw8&|e z$4h5qk~5l+B&px*-TFT>Ph%SA4c@EXKk=R^bYv3WW!*aA}}O{;2uI$$0x0Y ziKcSQhGn9TsvyHF9%tfdD&HfOx+bY(`zw||T`>bB0!&5sq5C|nVhb{=oRKQ8R z!$yFHY;frik(HJ#Ga7-K)W`9!6Qd}$%2wJNE-NW2RS2ZMH;%{%$*;hnvhYCrG=?Ln zsdwn2%CQVs%tt(RNkSXaQDpHd*ViuQd8d-LOjy_&W&iuI1Tz36e_7c3EJE<3%ZlA) z=zLM#du6P!Z_014YjuMUkVE6QQdn_nB1!2E_vO@TtA8=4{6*aT#7)O@>=nAlr$w&k(-2QK64k)J$#g+_@OJqCKeNDs&J8 z5fRCJ>DJXS9Rbj2RTNx0Zbhvc%@K1}+92vVr5fmH-5&L*j`9y%?i-klgi4FZBy?DY zG)o*TaCTZ596NDhJ-_EJ#*#n)0#0?bSd>ICSb#{vAVeTB2ce;t-B=c^AEvheK_Xa; zAjY`A8OlnWG_7EMmIe||xho<*9 zi%a5QR)9_$RXy=9&YZ)8Riu2gp~D&TE*lq+0qNpR3kWbQyj*huItl{RUME$jJd<)ceKew$KWbSgpQg2z6(=Rn z{A4{;$QBS$B?FNyC#kXyt+HmfFw&rc*3&x*0Qz z%H-Z9)@i7u_-tjZ`1`Akc}F&Kyk%<=Nn%5ig{S}k0`Ztn9>ED*JX z2Lvw=aXU6gb#GN=sRP7iu(l4@hJg`>ma`O2_U5^vrg;sZC;$Tgp@T4g+QRcp2N6x$ zwR9awHRjSG#^Symx=5=Ah^1kBpD|?7QZ4oxiHCGC!k+;O;Z*#EV#0g5NEoKxby`t&i}pWlqT+ zX6P{^Rh42!?*bH>a#FY^;+)6p0zE`-wkpt)Xlfx`y4b#}2n5D?&Tpne(Rswa~L`X*qWh1keD1Hbg7&6 zr0=GpWHq(){j;{{Rb`8b2b-X=uxLva@u`Z&=L|yfL`aFLbkV%Dbg2YembB<1xG6|W zPO{OXcDwDc&x9y+S2sG@>gT!$fC@t%z}NtBC$pXSrog8Z&Ft??qGVYqzkJVxSrfB| z1X$rV^=93-bu06_L{+4~DcoV;8^U}dD3!>*Uwf&zUshtJF%?ZGEC&KH5O_`ZltwB~ zipT8f0pjpnzC3BDoJ{fwNYt($twUd9>qJaYvhSQN9OGDq6DGJnZ`|V2XFZvxSLSr$ zEBNBm`sGIdGD{Fw_nvQb_^ti+9gyC+Y4U<Nq6A(3rhNf0~;Atg{u($!HeA-ZPS>&e=g?3u@jM>`RrVUbv3E%RyzZThE= zN9#eaD|d%wcIq-kUpnQ;qAv!d7UB66sy7>IRVg20V#7uYZmt3b|NF26E`lY2URTQu zHz1;H3q4_mo>)13TMRuj!XK$D^@NT&3_xmR!&r^;2B>zAIL_=T8Ro-gIwjDO2ZSyy z6qt!(&0e@@7~leNwH~f_FZ1>zcIj!&&7QI@`szNCqU~YS zNWb(4CUL?502e0)y%JU_k%0^t7(^7PD0Z^6QdP678?wXPSo=ogHtNsXj!?fu<%(c@ zKNe3;$w?tZ37y=$OsSC8JTxab%Lmq4wDOBeM2HTfi)%+Ft7%P*hoWuwS6<2HBGkS3^ndLb}{ zAkL!b#9bkuy^tOd0&Lmo2L=YTo5YVD4gtYPK~leu8r_}A{&gR>x^8w=YEvsYS7&)7 zUWi@{!Q4J5x@l#2WC~$zC2x+CAe*WKQXRtJlo+SvMDj6CpkPF_s#_tspQ~zw5%j=i zpGp>^Rff#&N$H}+YgDQd1Cur6knD>8W8IvnIkn<-V3_$?x(bf{*5T-Yi?F(|(w zpHwz_H*3lf`KiH3M!V?@HEZwIC2-60`L{P!wyV(~3LqsDsR;Kj!)!X>hi^*(X}J&p zDFTHr!np<=3AV|OuP4>9wrp-9sY=#H1=*gJzdiM3k?d;*X$t}v_PWBYrRJrI*wckI418ZYUP$(`uJ^{*%nObC1 zcQbvxAZh-uL`n(f7+Dhl>lc23W5-)7S>N(1S^w>gCQ1QHRS}daBv}9ZumlGH1Xx{L z>kLEil56{2VJ3P}QFU|dFwDXtD=vM54k(ha3JkmqNdb+(zKhXQG#WWu^!Wp3(JV_| z91_*T6W6rZykBY~l~#n7u~RO~D`*_Fn_Kd??%!b8dIhi>qO)u&zn?_?SMZnF31{qBBjMN-4mNqGC#)xR8?; z5Q=E2EEJ&NS!`^N%BtpAESD*TrQSeE zi6VhaKr!PBA&n>G!&+uc;0m<*BU1S}V2*yA{C_@;+)NbWLdhbuQ5XXe{GbTNUrCJv zm}$m;%{LiIsG}036`FfDeJ{M+a6hxwR_nP0o!tLdjDtMg%I4o)r*`}O#@^|7#%He2 z{_V8?v)lZ}r!uGY{tRM4iTnH1Xw?j+s3e3-zldiHtuf)LU?i!aStguc>0>WUc9_?m zXnr*S;Yke|fYdpVYHJ7ySwjwuFcrVzgb5%fGULY!c62vH%ut3#M(RYDL5AQc4`CibL&!tDy6n2Dw}wpd+oQy0LII4&rNQw7U`cUIC0|NF266@UcA zU0Qn&Lh^=d3x8n6j!>a{YwR%%0unB5b%qVO8k}f4< zyY6eAN5Va0Ru=zT;%AONQprKW5Qp1}vF6gpsrqm<&fqI7F`^KV3MyWnq{nv*K}3lv z6|Yp1O6MVJtoH&AX|$H2wPH}D+CTxuD9m+~6IMSFSgz%qZX9nu*~kR4e1>9XtkSjx zo<$b;Opx?^Vmsv5+NLuzSq!M?iibO)tj|C`?4*lKsCOA@*tKO-v5O&`?(!E@Cj!C+C^<9;LKP|)+EHXeZVa)2I7_Ht#A*np>hUGk zQF0vhjQzy#7CGWY8O|Jm;03u%VC5-brdY~BDJZkjr;ni#Rc)?ldv|geYp09f2>KRvBGh$N0ivjyuWB>pqTp}Q0 zmkP5JX;jRlNl?v*SsaT~3!ZZFrVXRN9Q ztpX{VIa(z!hETK~2-tC(FnJz_v>gD&mC6`7A^e+6&itN4UG7x9pvED>SFAL{sO_ob zA1Muqp|NST255#?IoT2Q9i;>a03ZM+9fDY*LoGm=P%z@5Z9uqBs8kq$uoRM}-szUG zD08!_jtHvvN1oEwokDT!|5iXqoKOGzummUq zC6HOyTQ6hqjO+_7VTf)K(UobeB+ZH=E9~`#4mg!*;>MIXMjJho(WPXXGYhwGUFPcV zP109bhAOH!ic8O4%~(>o^SG1geyI%xi}UUjku~h^_OqB~RpyWgf5TB)GvO000E24Z|f)(P0CM^A<_mV&I{!H?g&$ zeZyt5?#T*>XXq)i!|}mnXUD=xDyM75^@f@~7gxBs_1kXTh11o}Nz`+R+fkFZ#E29&h zo75oiT)NYlyjab2!>Ad{n<5k927&9QCra2eoZsA(ytc{t5%V$cT{_&^zFn8yE1Yfc zfpTj>PX7LL|AO+-$nCYS;j$a%x15~Dm43*&0*~j}R9>0+oz~3JtW5Is+$Soi$sr{G z6M^_#tV(zR9HBiX3sqm6veeac$4NjIg!smq#AvmQ3rcX+obb%mv8r{34{~2 zq-Y>Gj$L_|bIHLg2RyGQ)YG=WQ;%U8$f+8&suExT006)Y4}wjn>em2}ump3uz7~RX zFocqIN`S{1>RDW_)VeE$Jh|3tGWe`A>MC0pLr(;5Sola;6i7KvxP3BP0s3RY|NF26 zBZ4JRWY^0KHbR-~+f898d{E_kX{;o1iYY8@b%c(2t3n9LgTv!vUtGwM$3;Qh@X>YG zCP6==uC99YY`sXAy7e*mA%e)Jn-Sd)Yn*iaE!0+e>p+rhS*_5?!`Z82&z$vnAGDqS zr}^=}VmYni5?)89hQu8N^mi@$yF(uV)A9Qe*peUs07+a}5=;{qn&AgfAfXp2W>^D? zNCh`=GHI{_yf!?jxbsb&73g>?0Z1|+HsG-+gqawrSRz!ozQyFl^n1zVCa(UweI(n+XZYTM>vYPX1qy3X#+C{ATH zu`26hs_U)^9z)7JEB$E{ma>)IQ~l#2Obb>O5CJGU0iZWwf&~PN>gK{?1pvpI!=TLS zJa5fMS_Ozk&gX5FksFCjlN3=BOcRP4M2@18ASVQu=82|Jc9~Kg{`VH0nR?wQt?^rR z0gWHH0HGnV-*bTp3v+^V0u6$}ljl*vR-%7kNqDd2%QfUOA}p&@?&rn@57Z21*bV(< z4-I#5M(7M^B<@V2>^(_LT7bi#4S6H#>w;P$r-$k^*a{qcWRm!9#cQ=F(c+h3ge@*; zSyj^``ipx7qVJ3D_Idf<1ByqwhuI&AUjrpO62-c?}oHdLsjEPi%>k~Zn z{M5Hr-+ifd#`jNEMEv&a`$;%B$^Yc~0ySj)BYF2|{ z5P=u&pO{Y4n;-xJQe~zcfruBpyEg}r@TS{wm#f4VcH?jpdu&QZ6b*C;&Js*|lp_i* z1)vg^F>72TPKZ}UN+bjv5uljhnJXzX_U*oQw=cPM1-ka!)^juTe&J%NectJ_VdgxZ zc1@(b=>Oj%<4i~R@e{MTl9#txUlM$eo7wML^Owr9E~&p-d;Oe$fCUIp|)LNWF9F2d4<2JZiID znw}_V^69A5w#XS-BY~ty&DvJF_ClDNCKhPt=(<{lbi+#QNYgxu64zczRjEl#P?Qc3 zN*V@mimdr6FKCc(9_5)Q^P`#U$1+bSM;lFLaheaKhAmy`TG3g|sOT0TQ!)ezG{+ID zk41RpYDIltNB{@|HlqYiPE=AtKqSgIxl1_%r35_5mA;k7Qn+&7AVbcx2FmMe8AKpJ zCX*NE$?Yeoqf~IFokmv+NxY_{H0YP(kl*Vy{1+SU1;Iv%r4w)b=HHNsnL;A9@EmX` z|NEc>F@Pj%Tv_W0Gti4F`yF8;eo;YrX{WHw0xT`;wSpLL25 zwduT?+D470k**_@p*lkuUfWkvt3$rBSt#9ZnxNw#DVv#?Q=dJ^++Ke3Cq8P6T|c0? zP0hjH=a8n5%(ha6PYeu`7=&1e#0_2B&;D8xM~78XFi9l2MgmcE7Z9kJ;d_K#t)UCf ziHQIEumlZ&1b1Cp`w2tPlq=gEWrl20d3kN@q_N5mEA6#}jrk2jqH{-DWq6q+0^_2k zobo25+88uKuz~4&jS6+jTh&D}95LTTp*oXq9T93=*nu}^Z80|6#dkvoh-d9)_C91y zOVtJpg=Jwy3=NYD7y5t#YJBs9yzRMZtXd)mm2?6Bl7s8K8BrMxhf?A!R;U84-jw$j|6@%&PFhgDP{i)^`! zsFQjPF+*zti~ycUkZB3>UDg_ehK}yF7=>Hfc6PGhY$Qzr3+j|G7w@nrqlLT{- z6rRc>CR#ee2u>gTW@!m%bcZ7~nVBZuOJ{J~f$^o~b)0-aEQ5>!!X#J z%Btrt4X4GBa-|VjrLicZ%0rDoBN+f;r6q^$eg5^+jABW%NgzNdx44L5V6QN^qAA>6 zcC@S5)AGICb!alN!7ND!i9HSUb|UXgZ*Gt-`;h?z-w zzx>EaY`C*L!WK)4%3KT)NLpE>N=Hm{I`t{n{!>0vPM~!T=(e74bP*0IwFKJgqh2s^ z+KdYF%N=gpf7(MQhE-AkLL@0n@J!(lkeJp-NU&r9KwAr0C^(#sj6qhlxXb$+${hn( z-NQls|NF267XTzAS=##s9AJp5%ROO(Zc+`CZR{}2f&MFPHG>v;9*~DRkH6M|2l`G+ zD2y>MV#z1}eR)oasRO5Gxoa;q8!a}5B}D>i+lykc)Q7$cV?g2+>T%VltIMZo$g*C@^~J>owPDYsQu9$QwU%0ojF^o5*I|K7ZWcK*s7fJr zKANU%W5vRn{I@qWl1&k&k5VNhGX%#7STI`!G8QJ9NPZeQ(|H>s4V@M!e0pbxOh{?ZRnvlWO$~lpt7DSsVYbrE4~V^< zZpZ$iZpV9j)3Ljoc$++Cul)b(KYlZQg0kvpiVMj~v$_>5?SHkFw+SkQT(Y`}PUdnP z#wcIJv_S|Y&ZA31cCw%l>xQf?y!}QN>dNM$xZH>U#gIf<7Nsn&j-l|Oh$GLzt?2nS zC9P-YW1QwUBOAS|0op(o|6-pd;!g zf3b@4usQ50y|ZhS{l48uTN#7^0063BK{68{1XjL-B~-t|MpH%*wj^p;;{itbP65KL zvcZWHBWDbWix7|%jMQC#%W*=^CK~ceBkv2uPMC@_zQSk4+bXEm)q1!q@6FI=vo|k$ zu*vaBo`e7UummrFBxGb+>j^VZjLRDuVIz)F>3?OcFwKhhGAlKQrMR`Xme4Vko;^)} zT=s}X`}}mw;aVx9yz!>kl)BR8=YEIF%_=Ty%lKg#qLem-PGrxbjM z!EW07FODvOiDs}7r}M2kOyB+b0d6vo002M=1<3|9;uSTJ=#L3@GZrq&lO`^w5%3IZ zZwiD3($SJS=L_Cx-nrZ^oGvL=@U}=*S zVU8HE&4nD>u<$bg1c=aJswODXm1Exey3w=~zc2K$PYDNwEDK*mlCT5?{Xkztz}2I9 z2r+}L6jiUD|NFoMBLW7CVAX?9O;DGM8-HPgj#7b}X{;pC0y3>FHH4w@FGoRac1{oX z1yRNwWDq$Hc?#4eRI9t01VRyrA--S^5-5}*rOezi55;QHKwV3j)GP*>;!V)SLcMfw zC72B=K&YvaQrISFe5-c@cY&@mc4y$x%&-Mi;&Dmac&N z=M=THR~2cyhgatM^&bhsD@DN-t}ZGnm-_u?(5_^NVgM>TxZzR!7z7ZBH8%tVSY#$6 z^J7xxNUD)$bs2shyI10FkuGxr@Z?BLJ$40+Ro6DmKQ5|aYs(_M~t!2}CY9*bwL>ItXg+!is2zc~hieE!2UzniErtnup0y z;w*Kw8b(R7$YvOGz!!~Q4;)>hxBNB~k-G>bJ~PtRhixw zq^?f+%qr$T^By&lz&%Fk7}#kmwij&APQ3p7{>$y!uW{DW`TM(5Y)5eWOhDS`lsKd# z5!Ql0=IcbyqVo>#x_TB7oi=~~0287RtWYQXE;YiiWyeT&O*2?yy7xd%uwNiFRna@Cru#V$ljYhKh+$UQAaCF-AEA3NK9pf&?!xd#7a~!p{|3ojA&^&mpU| zmK3eV-G5VZ>)r1E`=A6lfCP?W+ItT}Vv!4*J!OM@5wU-5r?AZeIj*fWh9R&w>G`Ld z(Z9dyzUJz+kEs{6N9Y+a49t&^ z)IozyjCSxr=>#N0EX6J-?3SVk00l4uzz@Up5s)Xvqz1A`7NuBcGKk55eHRacW5U>m zfYa1Ya@+db_M=9QoI#YQP+9cgFvn5DNl9OG#%5&CF5ftq{vDYn`4gF5V%{mxV`FWC z&?&(}$Y*aCXHuQ&yZqMZ|9!iE+ayP1Alz>3%Xj+M8ID2V!o`6}RM$slX^33d3>!B> z$x-In0Du8k7J!IhVuivqCbUGg(xZ!2mk5UrrR+c{@a0)(%zkF3Nn6EkXN*Mq68=u! zR#+Wbaud0sV9A+9K~bjU;p>D>V3bh%NO>e+((YAV7FkCqi6=={a;~v+RFFg^Iy=_q zB}`xS#eBVulIQg;+)hEF4J`D@Y_602by2jy(&Hg9n5%Dnj2m4NXHW-Lvr__qF_A3N zp>Z*`cI~TVRs&}>oB#W;1PuTr?_Ai!3^mYytLtrHBYF|NdvWYB4GIk{?e&HY=^W$f z3)JjpZhBKiPcfA{?bx#bf1&zyt*kGXb;YNvy=iPt0WShW+7cQIYc(13?4D$0u3l=w z5*jxsxvhm^)V*NCw zGLQF}?>AY>)|pEto$Z_Ml zN~=$^X0T3wEpv*j_}Yj`j!BqCR3b$D%bKL<$q%ZSAQR|Zc5(}Lh8%WlTq71Pk#}~F zpOiM4`VN&SjY^`f`6Of`R5c8$VdHpHdOT%UItVa>IPtRuo;@H2Br@+`If|#I^ip_r zRxl(KgP37q(@9aGAq^-<5%FCrvTs*Xi*R^EW~k9wEIESf+-3wV*B3_-d9>EWg$*K^ z*vKkL%aJlG?{Z^UiX)gGoxMd(lZ~sH7%HwXu<)9j-Xd?fXBsfhK5K-HVT+&Q`X5Y@ zSIkn-=8O9ISz%Lemm9;%-fLfq2|^))Ftv-heQ9)oYI`PGd)0!S>H0J!Zvj{p1rK1a zl5e&JhEml`?6+3J!x-R3U`$gQ9-Qi?>vZP)<4&;ZC6_#jo72t`H?3R4jLkzhAaWx@ za{zWWLQ}9+MXaHj2O5~Xa6#RVG!E9On{AGLEv~9;Rd?Zkxk@pc3BEs8=ac?+;WV}) z80s~Ohkm3h`sxBGV>K}V02>A|VN(Sv$BxPo%oql?TPb3CqLXado0lQxfboYRUx=2O z%Z#U_p-Cgc^Fl!-RB8tQ`>+HYfFv_rTJs4*z=27tU11}9Q1x?btQivmCoHV>mLd2g zcyY<(*s@c>gq<&ElCm{njY5v>aXh0PI?#B0j%$@It`K02V`N^SdN8hRYd4~G?A%{G zdVdr0_fc=uH8u5B&Bat%`=P|4nKAVx0m{5>0002FfRKPz*aRw#CJS83Ycv(0U#495 zE2gy%aQj8TRY-Aky2QDnQ45<*xiI{&`W2+LD!Wi~c{m!@VVbg%4jL+9d6-WyV?ip| zQTq;z1R5A+m}Md}*Y@B*Hd&N99HAAk_l24{l|1P6!ai<%7hE3eFEsYod@+}ER_JGD z+&};j2|*4Z6faCfsAq+>2N<_)ZB-P-kGKp)<&4AkW76o1wq~R@dFH^oR|=F;68w0S zWr=AaxYZP0mvd$Jf-5K{bKHaGDd=H6vZoYz*A!C1aT96F54EJawzw>TA)*sp9QBei znOEkjc!KBu=Z)^S`DyE)`B+M28?fsiaAF6oHZ&maCQB2R_Z+fxeI&rdue9 zkdau8Rv?-ap=uO>OOsK2^$KQ`o~ufNSgtOm=z7WU263=(i{l_kjw1S0k;cg^E=q*4 zz-%9kZOUXV3Pq>ls2oyPIsf~x1UCXEhh5dHFHG=|DeD?xgN{?JbzzJ#5yBU&Z1seW zI1-MJrH84OXwgxuj$%G`r`6Gr=gsirEElM)n=YtoiGhjD9D*rC;c>>zh7~G6ve*~w zoLx0nd6VlYbgic)l8Uo(=TcI4iNLg5Z&hJ=&B?zp?M)N4rCgvy%Y~P`TgA=RDqH{n z01JjRmVi`+mrnNRTnc5#>`0T{rp>j6y#vx}?A@{Q3oJrbo$|ury-8pdhl|cSIih80 zneklw@eFiyg5qejf`^LLl4#F0W#^G5)*Gu5!sZ(%JyE%bkaG?sLU`HzR_OAr`13D2pG^H06@x-HB?M%9Ya4# zS@pP!C`pOnu%<6%nXu1=AjbS%t?2gRyqJ=!iFU zo0w`PO`GM9k%?N=*GjAR{I|ifK|G?|+=wHjB*u(#8d?;$@_{N;OoCLU%_fAp!-HRoKDzU>U>}o0uyAo! zl9@_JhZO(_DAqbSG})SJF|1QW00>(=7ElNRsT^D(Hy-qDdKzQm%@~Y@hPv+Lro=_w zLPcP;mKs#hr3o?6DO5l4Sb>rM`>+HXfFws*T4M=<>+H!bRg zr<;(G#7%;LZq!#9o5tF=m?C~DKHf>l-55@Di%k->mpMhs%OanH!)i}9CxPbZ=p9T7 z%2%g@CncrD>G|NnUnA~#_d+tzzLs^MBLOhezz4*i)P?c9$p8QgnROTH4ncrXMaob$ zQdi8KnJ0_Voi<&X7jY#)a>A0+CnP2tQsjvl5R$n@S~`h_NaUkdXrbtwr9z8yda|gu zG=@YP)Vw6eV}E-2aJ<&|q!a0})yD06`u`s@9GV+4*%PImaVluHkM-UCu?)tBmn;AC ze(DgV2tq|rWB0)8H8L{=icCT(p@=|~rRnbJqxgv;)KVqyW(ea9qGJhZkPGzTIWpSR zF)Ed4?pCR9pI}&WnHZZPX3~pW^NCtDEYc9$bo+gi5uGi{d;Ow{X-#^HydbYj$5L~T z^Iu*$S*%;I2=53^>wd~+xyNRx`4wDqB0-BpKWU(5UY2XTQdj&}ENuE(AwN7k`w4;8 zVjhhi1fVb@BH@Eag}lPW%kGcHY&cXRsF$&$JTJsq-%%#^H4U$qfkW#?l-1-R3^cJd zm%?H_sfM{`+(k~u)Uhib#ab{4A7O_YJgsl*Pg2F|%z_29I1&VHTH|nli+Dh2%>d^^CyK|FPGxxYwCuYUcBZ^a%b6<=w&w=|c zt$l+IDOZaH4n3%t{yQ|)V$c=oOsQO}^$n(mmwjdE&7Atr)M_OX7Zko1buzj`MDS-V zUn|b0GwBVCY(qq*Qq9O=a&cc$FrbyIEX_JrM`m`VXh}Na^V(>lM@x~Z)C|iQhASJZce8(=Mu4k!=R(2ef zkQm9s5eMkVK0Y0?K0bxt#&Yh*KmFy}WNVj#EvzmkHB{}N4!oXZf3J=^7)t3{6 z=Wj1m;t4EHoG#G%=*tJ{j~=Me)p+d)*r@6w)-b^;IBN$N1A?qkGvx%r$;#$b7*=Wr zv8i>5Oo&+UqsEu{>ns`#U$wtBcdi~~srSG6=XNc=*8JPwk5?U=&iEy?%^*q;7j3U) z#La)afszp%!~g&U?<|UUJW6miCy2A^2A0S(5>n?ycSx8lA)Z>BlTRm*vLa8v=&_k2 ziD74-hO5-ft_c)#8sk*Ja|DYKO|{HvvAG~9T_shXod~6DGCL5<-u@Rn{^!W&CC@ea zk;;lDQ>RxR8J%mxQQVrRr7+Nb<+X7C@J-qUQvd-5$RHGIfE9{LP>PS5i>XpYuyr=A zZEVA>avqUB|19~M7WF}VnY`^dVUsl(wE6RF?rX~CO2SSOVL+@kALUA}W+N=pwy?PG z3s7#tsG@Q+TLjWWakA70IF@xP?S2Y7|NF26GJpk7Tvo#`H1LG%3q4@NtPsU>XN)k- z1G=+mLA)k-$frsl&sk5_%C_5HcvCP#at*C2j!L_iB{1!4bv0lDr$SQOp-BRbQK#rZh!P-8jnpU6GcPEc9-GyieQm)h9g*wf#0G5dDUW6vxP9&9k*=awBKxu zxgZqCEV2bAD8R&m&RA-BDTF%IU&wXTUFZvNRpTaJ3JEx{uDkAot4;`1lvGS9OPtow)SFODqY_%WtIwkBWFC%7_EVBImD7qN_j8uA=>Kws z&ZlrdX)|rUEK=G4I4}|r0003DP{JIu2DbnEzyt?^1!r8=^DH#*h|AkeVJLK2y>n8n zJk!!5EG+eendvAR>J<_WL02d^U{2b)UN5_Jw9}-O;7D`0ZWt?w*E4{ih87dR0Og0^ zN@z}SSZeXWA8E1~iHeaB&NL?v4bv2g>kQv@^=%j8ve$7#1xQRy>i@d+(3&0x=)t@u zh;AnojN+okp;%HXoGhxui3O|K5$=07{_hmYCfY#(jsD^Pf1En=TfeD?_Ydp)yLBrV z@&s0N8hn8vJHP+d%XZBXL;w=JQ$Sg?QmPnx8*3>ZneEUpYC-B_)XVM#YwdwnATY8= zP#|p*fsqhg(G6bCk<90fKmpy;Y6nYT4vzRaEy}xrwSAA{oa+d!!sR_#F8dCUT4o(0~CigD$Xo z5HqoZ2!JJnK>|sS3o>C@Ym}ZWnTWO(VtCv5Lt}TKIDO`rGLAz@P=G4Z(=Zpc9m}GD z(d>koY4uW+C}*k2Eyyux0jzPIrL~#~H$ffiC#(pL10{2zZBe40981T00oBpXD|dE> zE*Cp|{Xn2D2TPgak9w$JDVcgmK^29#o)7bcoTzZDW-ibPj~W=qJ4x%486?TzImMbY zFcQOw2>>(@IM&6H1erL@BV~$N;=OR{w?6ti{P#jr!Zc)>eQ?>rzay7O0m2*s7({k0bdyTNq z3~M}@pWJ`tzkJ#rq%0oDh@>z0PQ2PmYka5>2m!hR8Hi>uj;$0>MA5`SE%QD?TOd%_ zvriR{CI>brni4g6+kFF7e19`AK6W0KmY)n?LI3-p1RVebTwdC13^PK9>&q=+CVEd@ zacit3Z-OQ(?6rm=dB_As5)@3R&l0pUSiZ(4-hXFHdgZ(CO9an3y+69ohN^t~+K9)F z=_Nbytk4I;OiXQmAxy13Q?oYs4*2ah+0u`&7 z5KB~FhMrYZE|;oiUXe-chL9XIs?tsKWnw2omlfYO%~H7ou|)n}oXD3K1dVesCpBBW ztDj=R^_&%iE?XbjkBpmh%{}G#ApoJ zx3J_2ya}s$hMj2DEGCN8dDxHYAkA!mgt8n?G~39V=Qj#6!BjO>l zNnqs{!8#G$i8pm@Qs|(50mC57b1I)EqEn-&4wPvHGhgu0a~^kkQl7bgtaZvpv8HIj zL7SP7YFt4r25PQa8pGtF_l*hGZD`%Bml}I!6{-#sC2Kv)?Z?F2!lJ`#l3aWieJbfB zO-TH8NnD~0M)s2Sa1a;87K(}=;*&~Z5nk-*%kE(E~2WlS7pwbLt{OE9spzfRBB6lx#Kh;&+vwB3b6 z3E)$19K;nx`mP*X%EFx7X%e0hk(a`yhEyGw0BNbysAWRY%MTveyDR5aK*bnz{f8@W z-0c6$WO+wu$8EPJcUW?54RhuxK%Dkkq&eeWrXJR_SzH*}M)M>9L2`_hBt`^XP{Xpf z5VIwfrwWl<7;^}Xj^M>{kPHq`gp*`P51bmK@p}PiA+&ZLn8^k(C=~rY!PrSQ%yV+} z%rx_9&xcy>XYEJrqHl6?oqxgMOE1M^K5D*ZY^`sxD>6Q1Y%gnBmzQmK=01GyiJ#xc z&rNO4+!Ljo;Gq=>+P(FnD6R3d03f9?q#)#?io`?OBne7PqkdHiY9YGCa@}h1P^erQ z2Y}ogjd5@!8V24pQiO9M+_oBVqo#x^B4pE~`-!roVB^$YdP=^0m#*I9+IEuGml$x{ zk3}@47+8R3EO}Sb7u?n)>R~Qj#z!l6ZYPR~8yrt@ALK1nZnH2@BSEa-Bl@pJt=0fQ z0x<=l1Q;;R3;|(jgv7$a4LE>FfOT~*9uA)DHMUd`IV3sB(FZ>ZlL#`7Gla-v93#anIS3hlCP?J@@O#Qi4x^zc);N?${IHn| z1N8%hHpA?i4jQ*9-6~WFmx=b(0-;KbT%n4WuvsBNQC)_4+12sY4J>(r$(AZTjdlo6 zrOgpe44Z3*0u`?Pj`y1we*-te+I->dr;AE&d*7c>EAh5?`L28~^Z&Hw8M7GuRK}`h zBxO@9!$F`(Y#*cW8G=&&Ok=@I|?&;${H2c~6OZfgJl^lZy5 z&0qi$nU8b5g@6JTvF^XHfB^(p#hpg-5N}HkM&qV~`inzPF0748=}T_G+$E60o(mDx zEiCos|~?0MI~9twicyv z>38#$CoRK|Q|kWJuSs){Jti2^Mdh@b$12+Fb6uvtzTu7=yKgLWuVW~3l3(>L_O&Fk zTY9ZMN&VAW-d8SzKmY&!blDcP0#I>utPzF<0f5MiR-ka?C`<M07x*eYP^@M4|zM z$JaYFgs$+g6&Gem^jpR_JYeaw3492^#(@iKbA>=N2j#OstKxnk1vf?r*Bi7L>DXv3 zeYi&`pSWTJLsiU(O>SE5ss|c6?^s~(+@4uTyPw3XW=IibkE^N4MQ0Jjp0k9p$A9u_ z&?;_4@4xOPuJRk?dM00 ztS$G|q`NT?@i{pB2t;A>Bn47jLfBy_Ea*vM)JD*ZONZegq5u1!1RnwfA5hzK2}8n$ zsw+%j!?;kfWo@UVZ^|Jp?frueVG$xjB%OnM+-=i_H@0nUoHRBX+qP|^Ng6aZHb!G7 zjosL`)5f;b=-cQ0{)64)nBUAjGuND##tyxU{tOS4c}b?^sG!+kPd~@PB;#pYxW+K6 z+dl(k#hY>Qg>MPXA78xkF160>GMcyU`4MP9H);<(7}9}d#!h0%S&QJG=?bB;MwrBG zK@lxer0PhBXw*~|n-{Okg4&HQMyu|24;5Jhs6hu6%>{wwu zbrQTB`gN$v=ycrF;4h!-Qn9R0PBD5@mEL_bNdq~vTzS63#8IwFr}Cy(+L6&o!V+UL z)dHb7oG7Z)Y;`9_0hXrUTwa^b+%gD*+e8wHzk@>=z^qW`RCrk^YLhb-q>#5jUMVSv zl_8mRoH9^Fp?hSEXsD3IWEDMy9E0MlwTX6N_AKVq_>n?BXhESyBW*}FkbJfS#QD{N zd*8;vOclpMMN~AFE>s*Q_hlG1R^R0b10k~XJkidBvK3;%WtOTX!yLQo^Q%9lR!OK8 zI|dAW7$5{=Uff=W5R=zZZ@c( z;#6+A>K6;&^JN5l5EjrR7Gr3A^nqv9$s~e7LoOm*oIKf4KW_WK_8TS$n$ghk<(vaO z8VSkR^hcU1PM~Ww8*(&Gb#C(g*-?-?jWS1(FJMAC6Q}Oj$G} z8(x?>two}S59hvYhtIaTz486Ec;V&DQ=wyqTxHpSA;aD8TOtKLNd%3(Mkj6Tr?T7j z9>aq1&C<61c=^M}@UH?~Pi@^BcYao;nZNFM8apu3x$mD71EuljEr64Cr6v#n>{B!- zY&xHTenFaWBaEE^8_d1K;5f&5E4xR7^IGj?Br7xx&i%qsqpaaj$(o$~zcG7-7)*lI zyi=mRQXFuQ@T0{zA%wXgHgq-K($jEt6d_SQ$eq)+f({#gH%)fFG$M0S({kWdaUJTPDxX-*v5EYzNp$f%r&0_ z(~^DPR>q)69sxvT+8WpbJxMKN9_@#r%TJyC=BuXmsCfikQ1H#;=>G8u)T$}mz*@%i zBF{H=4IeW$bWvbcI3|ir1vfc@eMz~8fdSL&G}x`#Nr3m0C)tuYT=j=IR-Mw4IBNh= z`=PR8vbBON29^H03{7>XO5*p{FP+mJ)JsDdDdBG4=e|EQ;QSDQRZHkqI^awp*XD1f zp5C0=wa1@>wo#d!P9h#GqjD`n%nHk}dk3lD7CO(QXkzF9Akt%sbs2`4=EQ-Eh6s}+ z2joa>HmHK4j0G!yh;3`KCgJ%1RjNww9DYIA*%x0@z+@S=lF5-c{x9N4f?%PIw8haB zuA`8U6ive&)HTCws|BY*Xjp2vK$#Uu6&4bmXu&`(jf1umY4T+RB?5x9ghwvSEKa}~ ztH#l9oT^Jz19hYsveqvD6@pw*f_{q0KMfCn-CSeM3Y^$+^KB{#zWPc*WOm!&zGR4^ zXS!fD@i>DT*^LytRU@qPnmg;jCbz5Q^%%bnh0kyf=mt%^)9PSFdxurSK~rj0P1IJU zhOKlkgA<@p9#jAfv#gahXrZ9ey0?nyuv=hKpnxu=n)NYz$xGmB__M@**Ti1^MdU~@ z?xGlaqti2@V)~@CgU4Z*)9Bs&LMDVhS_<4jOIeJqC!@cprYcd}`N! z&TMvh|5Cl*_(yR>o3=h?@1WWBNZZaTiFZ$BzTsA@Dl#qK0DuNyrph}Q*W1&Kd!t~8 z&Hbf$$e{k`Qe+MxAn>yy_0*tZXPpQtR8k{dgZ`HcMt&{v^#FmBc2#iyaB0*oJ=8!L zUKs851gsgHfpZF`ObpFOE24X?F_w=QvZUIh6ej;7EZ6N2VJ?&z^BPZLtB==gYe#>M%B}{xm5^J3()Z7J^$;GK9kQoh!c6rF~`;q-LeOrsZA<#}!5nX=y zrAbqiz1|d~WJ9MeUY5tavMHFqgy!P0d?VEq0xfIw$ltP2P^mLl$J9ckW~+X^flK4W zzUZqNL1$pV!RM6K-NQrPhWGc%D`hU4Xo1N<`O~bRBvbUDAh4_L;1)jJNd*!nj1n$= zo&E|KRcy{qkXa_0v#@mt+X(arFN zx6a1xd6e$p-q8xZ3K@E^LIMC!PEF`SBcjzOhGZuLzd+SbYe`sS^2IHbBZe7eUCT=V zPjNQBcFJV$QmT7q0JPsUSik;2I870zx7M7bZ+cugYC^6@W%Bo@W2cwZ-vr6!?z8=h zRE&~BlI^Tw8ayQaHz6gLV167n5Z-v*{Xh=cWyksEgKfrK>?r&&bdy17kU0&ITvp!}k)sY5FDDf^I)78#Zpmwq|+F(&#g;CoMD3!n8t+ zn*22AeM7^8-(bbU{mxL+@+sAh^&^$;1qHs`8y(FSu2=E?y{hX&Z+{<8q4ibB}d&8!wda{Arua>Nf5#L7c!aW&DT&02oYgOj1!nt1aeC_f9nKz zy7tPXrf$PY!U~T_@1bTdi92;G02!|DxJLa@6Sf`Z8c^bXHD91qmg`O^S}B z51W-``YzjfTK*2DXTdb|+YlyuG_|bR1PG%;Jxo*6Umz_}R0M#ijLvDpG)NrEOPxxg zQLn)y&UFICB3;q{y;600yl_2j*~wUeIiU#__|{cV=;e5nw($4YfenK8V)7<23r1$I-r zTiVR1I%WHD!Z0){tWgKLEH=2pVKj)t_RAt+7`NOUw&?rfn8P3BOaIM#$N@l7Fp?gD zXnVQ(U#9J07jAQaVJtY}@Y$-tO0SoTEl--gZHaP2QS7hHI;yr(mJ;E^LZui#7Z(p6 zy}6(M#rAvyU0T8Gq;abRQDM!YXcQ4Ax!{$D&2xxR^{HysSrr$HfnW2GmayCqaVml+ z$SA!8J{sk&8Q1voh3q)^CA)=7zj3tf`hiT2tqMGvcyn=Wbe4LO?hw48{d2vD94^wC z0+5C9r)cSz*xpeTcsNmAoQd@Y%meslkqe^psG)LWquc-=dGtp5*ax0?Pe-!?;H2T7 z`d%rSVK?H@N=9irMTS3vAli7jyZT($7H%mZUxCN!i!qG6bi5qR1I{axzq*<%W1f9v z^mDZAoy@*RS4Rw3M|+;Xg%=O)#}L3ng)55P7bY7X?P~`J;aAgJGS%yNj*8Q$G?f7R~db#3(1JMO>BBkMvbY^Vn zrJAv_@Tm;?!`a#F_lt^j%^K8U&KTJ^5~Zgrvp_2~=YTu7Oue07P{{L@Pozi;MD6YUpx70hD0u63qHz8!mgNtOt)vJN&#SVRtyp{$+Vg%xJ#Fj_OX`p(4lG#+6+ zF~RHRl(Y2%*21SFKTHsAGqiruo`Y1&8x%cRcNb?kp}kuWApVpYzp>Id3!VzmXHug0 zX7~cM+2G2vbUE>->1D5JGF%-ac4w4#mOa{Xh#*X^!dKx*|L zVAwD@9(}I}Zw;|TWXc(0Rg6(>+AEcI;sDt2z>t} zp%PW?$6`qpk7w$s`yaK1@IPc~{0?zZpn9bM$y{~WGwD4nqEAzE;8*NScV(9c|ltsiPjn_+p_FtWza1;eNibNboYL}=!}s2)a?ZLxavd@K43WZ? zOFskZW}Key2XBwy(s2Hp9Lecf)clF&PWs?k^eHw0=*GBJ(7$>?;Gdw0rcAUXUwIzc zk+}o`5oqM`uWE^2i5j-8)bYiYjHcHA87_=3w7uY&eYzEzcszwX~2{i`R_qU*IC`8DmE5 zb3g|`q)1HFFI8Q8B+78o*clDcD@ul2$DOr2h+x_%C>~UyDLAPb84s7C`Y%Wadb*xQ zYJRJoWNPIq+Az2XgO%RPC(w0QS9_&B`Gtf7E8P^3Y3cWnvJSTF0|P97Q1cl4cV8|N zgB0^0(Ez8!+YlL?Oety{Y{5=1-&+Lww-zO%YSeHaTZ(HuR9Jh*LkMlX|#004-d zvG8eft@s`e!NR@Egc6=uHLI%Gz&(f^S&ttvleob9=&tGxNHqdo#IrQ^O;)CV5}bah zni%Xz(#Sg#iI(e$D*SLwz3UWerIyUaYozlJ4Y3%F%e7B>++V-t*_~v3ZzdVRfhx$p zv`fNO06oj@e{?exPDr30S$A2)`$BDrZ6j&Xv_ad5m{bt>3LxQsDa6ZXz*bqp(US43 z=0+e!J+bCv`;sy*Buz*JKg_qDIp#n1Y~PN?B{*?m{pMNjqTn?!f>7%!pk3?C&97#sLrWd1T-ek*MmGmW6%3HQ@ly} zQNw??RKcM1AbtH}`;adDr;#uB>)W^7a!*H@O0X{s1poPuTJ)t@18yck%^Y@(Hyh@@ zSU0F|`8ve}e0(Auf=mIJQU{Hun0gV??~@mg6i+H*bm^9%x7nfpMI3n$G&Oi}_n)Lp zUSG&G(gCN>RUesky`PE2p&4Ah)ooQ%GY5UAq!_9QhWS)BUh}w0Dk{~W{DW+KV-Sra zb<6RCt>rHcc&)M4CvYi41V2%<1#fQ4n0Djqb(pvMOGlA(D3>rypy9uq*!qt1K9*G3 zL{?CS*|qp)Q4buDqWv-onj6PjZbwLwb-7ZeGdaD~1(TNAQu&y4beVQudiMy!hB8u% zRfF2*v^(f0P~}DM8WsB%zBzIMb%I^d)3srBCjRh<*;p6m#ua$#Oe82zrJ= zST>%97BGJ(RFp}p{|*ZVX(dH_k%q0G0JEJT)QZX_k(Y)x&ry`bS5+Dh;J8MGP8Y7+$hM86rBA;ifU zjfzGZBDZrcLd-bNx7To_C*6NjL77%U+eyLf)M)p2$8S*Mv76swBsvvpL6xb(xhH}+ zo03dqahuaD1&MO--Rrgvc!#{Hl=~qhM6*)nu-eVaXvj((rwfXa`lKk}>Z*hq{2DvU z3#51Q$VpWMM$t9TOsoK7#^?K&pE5wuYLyp9t8LIP`nPv|)&Ex!z`<3Au zHG$u_f>Gj64itqYLLB71mnPm{GAKeE1Rb$mO0r=U%_V-~scdTf_h6)gq#-Z{F9;>B zqt7;&!LnI>(_HQ9-zoh-mj7h4F3lsc>|s+#Ul0%6Tsf0Xlqr}(*vXaCZ5JKjV5fcZ zvkF_Qz+%(*%>`y0nw{Y=FK%o5q57tC6J=7>)g7#K@rN+eR(saooWvjyydwt$t4lIH z;I$0}O-ci#vY2dUvm8mmJZ0<#1E(0OF{#ZrHpK-UF$l+z{n=vw z;n~!lRrpCv=@`dg-oLH)aL5R~NhbBw2{pnb9op?0vpd;@{5{#{<11LaNAW86f)&3L zXQvA9;*h19e9IKk3{B-h_d0jO0002C|Ofg^evk#HvZP^MWIIURNYKII!! zG%{NfO`%66_*}RHTHc(bdx@=nuaevhzhTskw%2lk*7bbTY zWB!R&03zc#vr>V_L;I^k(B4fg;*1649D7(QiI)V1AksqYUhqd=1MU zD~{;?yt#uF4qZEGIwz4DC9QjTI!bxK5kdikn;N-6P5_ZQHaXC6CUuCU_SK72n#0dl z4EfvS4Dv7h+vfcu)cz=1&Fvfq-t$Ohc6f66NFlhlZ25XugW6-w$ek2M?w25B3WO}j zN{0YkpQcEAmUq_?V;fsWYU*?eDu4)idwQQcZvJ>5O}^HBpjyZ?#n_gb!h12 z#(+JZX};?}IBUi2Bn>RFS4wu#_%&SQad^K`#6`UQocs%G{z!LuX7TnK~7@a_0L z=%SnN`{(fFXM6MSf~UYkCs$rZ zTCaEu9(|EhT)x-n9x&!-K54X!K4~OJmJZSZpg6ZeVFLiLni7tq^Aw!yzsQKvo6a6-^6Tz-1}I@E~BL@`t#?p&OY-O<`$}p;gB( z{gf$@id@gIfF&mCKanH3CoVYXd9*C(vgu^f;`>qQSatz5IO=nbyCSA7x}IRZ{lC3; zGYtAGg}$Zgg}(|XzwwOPdd|n!rCR7efB8T3*qsIi%>v1Vu*-Nz_iQRMG;o;!S+GeR z{8^^9DM9g&G|55~ob44Z`Gw@tb%RhbdHCYwipzER%#u+oktF5dd+_i}C<-s687T5X z(@09hAg`o$q1hbb7SQ4{v5tM>Z+Jwl3^P;@wGxW$mdXO#e{D$noL1DB-!o(QOf<9P zeF~i#z4bWexe4p>IUt;D2@|SM$vlGd)owpV<}`~$CQF`;=5QdAWT_Gdiqx`_=2HwK zhunvoh2jn!ZjZx=^HwfZd=W<@v#E8WXZM#mtKfg)6x#mUpReL%utkQEZ?~set^S@9 zMM${|lF$y7FU%se2@91r(hL>N*M;rJ#??qRC{oajUxJWRGXX2u_$h9jB5=d@bb>CgYWcnG$N?c#AE7V$>1=R_sY;xYfNSWMY*F7=7)1l9T+E z(uu=_AcK&yTddYBu5`rbF+St|Qt8asf}Ohf_5gQ=D- zVzZH0{!-T;;I`BfEF^Lt=cxMMdqniR`Oh!XT9AB#w4)LqOq)FsLVM-lHX7QL7eG*F zia`(#NrMZWHrfl}wI4H02|2%2(=do^=AhUiOL)2!u8UPWy*(VBz`}%vuEr=j%+gpp zQphC9u-vdF0~7XR$sJdYJBJs}TRr|u9V5xKOp}=j=5j7dkF&l(Y)xG`5EG!|Vayb6 zR?yo4pUS~NBGG&A5Zk3`BpL-c_IJHKAoe^!t`!JzS|}OD_fn~AE4(}m;Q3(ejad7} zm14(UKyBZMQ^~}t>WwoRIT#;5P!j=1Vda`T=}Ewu^?f+?PD_+wo`n|38C@(MB!9#E zryO!ZFUNLVPMRUYoGmL!PX4jdC|gohVGnpB#h^x9(HClxi9s~)QglijxbZD-twNgp zAZffxpQtj2UGG%xRyFJUpC(!ra~LAv)5Ej49NlJ2=9197`zs6XWemknnWk~PUBY|6 zgdnQ+&o-l%2K7W-5tw<#$WROpSxnUY3Oq4Qp_(%(-%Y|+<26vxwksj%?S**o5iUC9 z=8(EVIhtjB&Q5|ZMxszIi6Y*tw0>#u=pvPZi-{nI><+DC>U@hV1Ta@=5{``lmCs|A zk1j^Mmr2ym{6_PF;Zkc*Drpk+lYrjmEi+nQ&Jw)$o!i=1qQ-REdf77Xv6EV376}5! zA6-*{dQb#%6wiclv=KX~N&^{2I^S#eifcfbPNdlP34NEKMF>L755{C*oHZQXEI~o* z=7pieJwu3O>S~AizF@D7F8(RJ0_Tzs^5h+?-nofkV~iUf7IW1m?VHa z;m)@dMzt}IN4HOmc+%X&ZCt`40;CsX92{;Cj*3^h_vU_OpI-!GebuL=P!i=x4AP|A zp27p$VjL)FiyfLG32nQOr_+3uJD%r*2!*LXicE9Jks-ZnRfFSM3C-^~X07~AH5P_{ z=$S+65@XSaUH%@p=Nv4-visVo&1=4pfK%`=qDhS0Nu++muzcs|U)=>%tC}+KPx#=E z2`#&DX)oMk9Fxx3u>4jXFpS*V~JUl=ViB`GnHD4YlNk2%FyY9 zVJPt^nog9qR5Ngu4>4;L1kk@JR&=cj?aW0c;bJ5W2H<_xxSXrvwV_Av^HJ}$?-QAwAqM%NlI2nms+T-s3*{p`gj#OrJ3JOm7(QU& z|FRXMzef{+$5H!cVTghz8Lo38k*y8~S|0wiR73=P`%F`wB_}~f!><<-o;LnBAc-c1*n?V`8s|KWh}$$p0EU(w z4~wRlyz)1L?G;agDk1{2y=^Jyp!DsPT$Cd6)UYVzKEV^K>+t}*9MfbtyS9P3aKW*J z^RLylBw!{R=7xK12x%lVP>*jj3Q<-KoesylXsKoE-1*5DBHm<2WwJPn{kA}}TGFBt zI;y_tqyX{lclzoEg>rM^UdL^%JULUd z-B;@N%G}kdn)&l$G)xZU;U+gl$3KwY-g)B&@(g;schFk%1));--CKTh_jAmt#Q9t9&|cw@3_s5*A0!`}pk^EfV}DcOSU$ZD|O>t$QW9ILf`GiaVf$8N)fS zLFs#Fq39x_Ovu5Zyt%5Ixp-8=$kH9leyP3Z1j~lyp{ZCT?uv!{9haM+vzruK zj^S#T;TSa*>*tKY7#+Ua8t>^aT~=-^-K2FNA?e}Rbx$ckWI-1Auyt-jjs|}yNASJ3 zAOTX(ORBW3=oMFO=?Kf{WP4)(-TjKbpyxZgK@7?YgUuoP0V#6+2fIeJ$BU^R@Z65} zlEM}hf5twYb;aNrE-~?hf1*M}Z z)35{=n|=eGmE)zpiT~(DjbI2;6e=DDJg&Kk8Fc#rdR@VFBp-41Or-nAdb86hTXi56 zTJW6O7PV={*HzW>mYeTQ=$K%0I`mR#8=byl{^VZe5FngOL=L@pq<=kcu0vI1Oe{}t zpcilbe&^zFR&sa)A)}^v%WUFfNl~>wd+aM)3Z*$?mqb(zN4%!p17nQ*BaupizzxGN ziCf57Ca`2bFaU9rh>=UEkW9(?{t;GJ^z0Zo<@W4QcQ?Y!Y_5d|iso)Xz@dxQl(N&( zFeewKmYo;OKbXTnremLmheo8VFMWMWK+g4$-c#5LNuby(RGh~z|1aWj0l*fkjaOuj zx(LKqMIopzOlo(>YH*H&EW7wG$8}m2dv7rpR6LBH0+DzHDcWGg;@!1jq5ZgX2CE>q ze6F`rhmyN0p5nA~t2`#?j+HbYyuZm+sJIP4Vnim+)m}*uUwUv)WR!BdzIU~De`0+u zyxkc7c&8l4t779ow{KFu_^@7faC&2A5%5NOzTs!eDWwcpt zo1i*Y?6u?rU|?9$harZ>AWe{#OSes_D$84d_}^1V&RjE)WuJYFTV{3kcH$A+M4IP; zH`LpWg8&qXWrcIPgeG}g> zTl}X9$5guzw{KQ;kV>I|0)arE#~_Au8m_$vy*t_I=gL5lHFoG?q^+;i&0g^(Hp)+| zf1hdx-C42ar5=)h^#}u5mhb`a(e*7NrlT3+kRxg6yyi|L`uQs8E;5CU;!X~Cv8$%5 z?g*YlO6jFt#P!Bj0cfI%UFiG2;BnpDBx5$)_Z3e5d1XQMU>PR=H}9c_q&_y$s#4(Y z4K0^fG(D68gUGF`>n0|cD(xg&OLyp_sTNHJ^G|FD@^XmCBE@cHMf_RdS4^IVE^Pv^ zBt>uYXs}XJ^QkZ-htwO8;>0wVX-f>MZ1dHeLM`T(C84(O?S2p02MnzFt~|ojaJ~n; zy*f&I4~;v&)XgyOERntbs@7QcWku>)cuMQfSCy6xJVq=bvH-(~_%$$TfGGf#8>?cA z9(!yg$aUfY8~YS}UPJX}-8Ml;EDKECafl$w;S5AbXgCqXW#}e^WE##SklJ;A*NH3> zU~x)_<$SDGv*jQOHf$ufYaM3H_lr=Y+wbN-)a_ia8#I-%*uyY^+0>TKRmq*JN2eS+ zDtneXInHN2-p8mOdH~2%BBbOYc_S?>1{%fm1kAJc$vQuZycjY}2P?74h~L(vWG~B+ zg>q_EwN6uCNO0=4)=6_5nfdI=d}y_S`aIwiD|%Y!rfuQ5<7IHbaTAJ%Ypx`8*(xg? zaG#PLX!%g}{87o=fOz@xE$ws9@PjC!?S6Kyn`>7|_$ROk{brE4@o4W=xZm6gPC?LC zTB;vAG~dSeM@*xMiTm?P|F(#Vi49c^o=r77(_1I2zOc{V4qts4Y>0q`-*!~H@e`pT zxgs_oI-TTbky~_V7wxQm6M8tg;-mtaT?yA{N@QD1+=yqE^{-^(BxT6ZZ}E2sL0%O)#?)FLi*PT{2|O*oMjYwv zo1c=>SC-z;*s;x8ynP_G*rRb#ML$O2>a&`UmdaDgPx?PDpA9!<9WI zPL~*DeP*z}2Zt-bkcoAnzo)cvr>x`!&zaX%i}!g-rj5cv9;=P#C;>K*w&`QzLfjeI}gcpxS4Ry^jz+X zT$bpX(OJcIi#>V>699^U&<;QdM~ubCEIQ&%wge@M-{8}9gh;aq#OAmrrg0m>xpSdY zm4PI}l#dE!doC^qbsv~jILNl^_+sMm@-_+ovf<*_DWr>6G1dstW5)igNwgjsS`jvd zH9E^Yz!jq>u#zx4mUV`~L(-{r~c5A#C- zj^)Sxt3Cgf+HW(@g3ZHgvDD^b5X29k`2aD%56&N|_`yFmzX-RCCtA4c0V{-FhI)gIkA^u)Gj4B5hb_E`3 zpgSe{KN({W&n$CZCXtEuPU=eUtik^54IQsE6goL{5(4fRNeC*CCZ?}yJ*yq1X^~$65GeW$(qH2dUtl+zkXB6s=mZ4+Y(n{*nVJev?(B%G$IQ$@(BSS5D z7RC9Had7ztH>*>g;PJ>5Bw4KkSZ&ch>{6ISlQU>SYL)bjPw95?EW|&va!^g-B1HdC zQ!-a(u|MBU_`pP!L0eEL;2~ok6$##>hca zb=%_)3Vv-gT=l_^{ty3qGtM7P$5Uw54FP0X45NYV@R}8_SMBXR0vU7FGM4TG=RdlJ zXSe?m^k22KAzpw+!R>GcN&W*`VpB>m5O)aDMKZ|Jhh=8vppW}I+GS|C+~!C+mMWFb zZwd0LWt_RkF<>~F5^lgO*#*b?@59g@`bm6bmjlf-x091U@T*Wa!y<+2#^dhw%!ShK>9#m>^Ow3qcg9 z8}dHBd95s#^s#Rf;YS(<%SJ0T1e}%YxM;M8*^dG4<@UXX{bYuei4LPSd}f1rzRAgR z^>9UK7Su<#6}eQCOU8FAU>=_$#S1aVLik-fC>ma@fWE#c-Y9(W!#%KdTy{L!0=zJ6 z3xiQlLD_=Sk$^OzWedpM@V}})Iz>ZhqK3hU5{szPgHxrlgCbYcYoAP2cG^jUufjEelW}T&OampmodP1xd=+y7V$_FqTt< zNKBkN4lhedR6%m9VC_70m$oeaEAKd>baEMV8Ix! z!Ir~~c1D}H)6GkV(zuSn{8Svm&)>nKBkwdbt3l*6WNv|nqq4IZb*>Y{v!uId5$n+H zRE|yf>v`TPEvMnGio)p)y4{|7C}zO?xAn3F?i@q+-*MY;;vu_#v<(ZdjW} zkY5P??q{bg@5?#1E+p8zlnXFG32MwlqMi!G?btC`+ z(8jLnP;pI%ln#aGd9HCh`rL}^N~PRlk0u}QM4N{F7xh?E*$>wrbG~zOs}V8#cf=Op zgpe5)olbt5Q%5EplU0gXuxM_~I+T&H*-P85v>MyI23az)@((oU{|0gZXgU2guysvu z?1Uf5f7UfZme$qOXwkyp1z|WrIcE1QJ2HOGuN9V0j0>(OjWI*a$7Ys5E@JJ$1ql>N z!Nv`|mLI>q1=-SNfg4=zR?OHAniN_w#{9S31%3O}IZMW*5WO_PAN{6Kjs~L+=LUtL zstRF4-LxrYKT< z9(FF-9+*|NW!!`-_NxtU7xO8MyBS9a8Gmg_^2(S4Kw@Vw(}^vM-0R2`%zcT#kX}pj zB~a(E-%c_>%BLqDNO`Qb>zy^BmU@ugPsQjt%b?G$)oBchgJ&>W7Kuq~gwKoL3D1|E zsBG3E^G)Z-1Ej4Ro%y05*Es*==&I5`Q`5yhC~ovL;!d0E4A&I5&zpKW3;1hLee-dY zbq_Q@Jp1!F?FX0b3;B+Ny=2M3;MKNh_NM9Q=E>0w^cbZrmETYlNFaA3h%y-94u&R3 z=ZVPPB^1?8agevV+w3PktG#o~$xi0PUv}`h_@zu99>@A!A!eq?*y9L5s}RIog>aq{ z+LAp{7Mikp<1(n5C3XN~PsU346cccu4ao4g(-)dDz-oP&`Cf+d|-LU`kX5 zO${pf`;PECITCwCJS?;^^{CUwJS6_s6}UANG=y1_(Iz1$wc$$P*?dW^npSw#ND@iH zip0vDN;jU+b*+ZJQ1`A%Qik$hNxLG_y7 zv*u>?dHCf{pXanS4ySCneKF&A-aH%wl!KLdPTlGJ13H385(p9kqnZcSpd@O4Fl#d& z`OAd6X;P^Hs?Z=Nj(94T*LOH+S@w?}W&*5D5BVURDEl@y>}c`Iaa)+bsg07~Mz+(I zyx134bfYa++UnPR{kJrgy8rHP1{zn&#E|P;Vl`DTndzjo;`L1<_oY!#9lNF65}^2W zHyV^nrI#R|A^)A_Ebm zLt|^wD-{9(IfE%HkOl+I*cT{~gFA)}QXAi{;QVzF7ay8Pm%Q&xC(c(S{Xi5LPpDsf$ z%vNaV=^WtOx^^^}p*rIMc?gFNi@=kEof?*cJ?GC^idu=*k7$m6ZGipY0q!2O zaX=FwoFRm1x~txn*$ymoL}D<6WcEhxZP0~(WECS41#}t-w6g^9k6})_>Nc<4T83y; zWa10>y-U%yPIkjZ^W1PlcgAM0x}LGbjv7}uXIV!}wmM3-yu{LL*XrQA)v&-I@TaDv z7dy&$DX5U)Yx(dhsf60Xg~W)rIV{P#2pER}&jvP2H!Mi$8?&hH7%~rO z5@3tIr;h!U{y>WERkzA?<;Sy*>QY4B?#J|CZOa)ZB(!D>Wo;*so=qu-)R2?y2xjut zM2`?O`d(v-k1`EnXeq@S!*wZ{Qj^UIm}#ihUa|tlj%%bQ#Ok4Hj@52`5~a9#$Fx%?2w>LPw8Rxml7wv zbwjms58b@tE2N=@*c|@ve`3k)_yGC{bJia+v$kVidLH_Y*mWK9I4D|}{r|vSnh)gQ$~#K0F!x#w;Eu$l~@`Bm5#S)@aQ^IXd!!je&`-Dyd!*lE)QgUlE|G zVdqt$!7d{?(JKjE%s0wFz!?Ui!Vn6>aKJ+X`Gt0o{?)QJv_%;+=)Z`=4gwAsZ2G|} z?1sqO2Y^vdswAGy)zm0s?~E6op>fxyS%~~59vtwt=wi?+A@woIDAJZ|W0T}ba>-3Y=zM_C#<|c*T1%0+uW;s6t1TUMRxAnk|q^VMrM408&(tN|^Vha9;p;2PP8_6`Akw0;* z<|?CON(WVwRn0Cp3(mG)npB)U)MoFrshIOO=J6;t|MGsr9BoDu-z_;J9{;%+Q>#M- zjfUnvq+zaH0bmFshnb*49;OrVajRyXCht7m_w}Hzy)SoR7|PnTlerpi46y;Gtj*F8 z8$m>nM!GgD^Ll9#HoA6BbB&r z2UMTMYO&YE$EZqgWj^=)peIUvIl56c6Tas3KZ%>Dkk=Ka-o^3BI@T9N(e9`!``HdNGq-yI(^y--QCp9XN7%Qr$w-k*qA7=?Hpa&paLnL3& zsE>B+Nl+sdhtuD7=N;6jX&jDOzWm8)#xZLy;2g0CbqOUEl5NLWqcF(v79|-5zVf=; z*Nt(iluoKATa=e5_Q{~(gMPZ`RyO>hGe=t-U_Y&R;CeL3+4w-d`-Rl;jfD$GnJeLtE#0L1p3)Zx*jJ zidYO9e<pLC%gIQI1eYb&Ihk0uXeJiIVpt4)3iQ?C zb@v!2F)`r`9lS@6MekrGMaHMl&u6_v3Fgo34|i4QE6UTu&CK>?NlKdh#Jv?u{_v*1 zzH^nUVh>QfsdfHqITw4NF9HZjL8HTw7VMTwvWtzz=f(`S6Al+RC|nY&GWz~YxviCx zBhPFAz4DhN-GH797ka=r0}Ao8Mrk1DQxpfX%o@^}*cDQ>#~EMt#B%&XDr`>8q*vsv z#>kXtMP53Yjh37>_tEWAl(|%6iEd3h>PwBl`=_fc*x=jKZ0`@c=;I^ow+8?n7Bqko zHYB8EXAR0GNTi<^Ud}q6aNcL5=I~$Y%X2dmT&UiZpzs|xJl{W;jV>WdpB&z%uUf3< zoD-N6?u|%e3B7ahIX#%KRZ*dPH+?9w`H{&sO@{oXw92pR|I2Y~0BUKSl?`O> zy2vPj|HdP#Q}(v!KyP^|4!hL!((SOL7tag++Y61~ZWy)&uUz*7>eFIr+#Pf`yT?G^ zWZz=9L`kSoU&IDUAp?+>W$Wh#_n?yhFwdK0t4Uj;#8w(PW7L<=RV0lO@W%?}=@AZN zU(}{?E{l4OK5SzTY!%m3s9MKz4>99NZiNj@3>g!?FDT&0ri!8>ku`I}G;s`|{Wo16 zS6`};wC>h484>lD=WkQ3%6V%4{{b^W%)SiHuL{G(nL}H#_{4Y2&jb`(aD7gi)1b*o zofwNSgP5ZR`Iv}aWzuUF^sP>r`B!p+Ca^|CfCvNvr6K~CXutsjaLZEoqS6B% zwEkbwNO8i4Tv_WA(Cv7)B^srbQp)CLoh+gobQNXdlnfVE0s)7jbXrtPZ9`L?O74i< zS5%${Pd4XF$>I zkbDagjpByL$w?84RG8%#4#Yy7VT?kHTt?|64cuBzvgeCij9c@@+e)$reQk8Ax7J)Q z%KuV3JWFo2^1WwporwC?82|x;h%!_e2LcQnS-q*T2ylBfM`HJ&h4Ojc#ti@azyuEh z1=dtnt1nFOi;DYwVJ37}b#GY>uzLaoEbX;}4k7YCx8GK`7JcKXa%(u4pQ;prV-1!S zh5~N1F^9RUg2r8(4HR()c0&>cy;`n5N;5$Xb7fPf;${0i*i6*H$iAvSCO6-fO%4za zc0?g|ucM<05V=*Xs}r#wDUB1+eTl9yK<4$_Mn%*aTH9|7MAJM+6-JHCrdx)x9z!C)-bl9_94q$Hq|!M@0)Hfj%Rrlu2Z$qcs%t!aRFegb!*z>S)hQ?VXxEBwY~z zdyr3^km;EkPK=~(XT3#AA7i&SeS6ctu!chmUS!NFA*PzXW$#Wl>n+K(Q@!b37|naw z?}wyxcw72Ytk(CFt;)cV011J~xMl=W1{(tpA?ymV64*EenTW$0`cG5I+Drh`U&&h4 zk=Bzn=yEvL+-ZC=iYp9=fM6#7C=p3NsyTV(jWQOq7H)6T$dYmBW!W49vS>v4z`Twl zl@5S;gikCmc~JP}$0Av%%U%&y(Hq6{$|`QKiNnfrA3##RGF~qe2LmFb=su>fI^z+X zbWYo?Ejr7)l&4m&Ozw(8EahseZVRyCX`9AInhP+EiiHvrYlgt0N{n}?CE7HyxflQf zTfBAf7zAQQVg!dQqr(NRP^g&$@bEUyOHGB@hvM}J+JXp-KsgLYc@agICDg@kmpG{+ zGXO4xWlpsu5{CyHmW(biHHLu4UCTH?!T}30j243nj=_^V6B=gR+GcEqy#6XDa)lLT zBtcxtTR3O3V94Q;WblXgZ&&yfNE}1}0N4SjK$sxvjRkBfi(hpVn@4RGp^3hsIPzvm z^6Bb0A~7*tTsIsR4lJCA@I1R2X=#+BZL`P^5#93-jb!5vK|#t5k%v8146bWyY5)76 z1StU|Ra{wP3`1ayYdacYgMLxDb!E&k56UMfY$b*cI9Ov3CE#^ls5GbU!g0uliaCh` z*oUbt6q0000k049Zr4q8&w zs3I%HSSp-Io4Tkli%&h7T2i4T{d(w&X1tI-Z;DAp%FaeG>Y z39~V2`NXZ_vCF9*U(|E{jz>9ZAmLu83)c$la0x-p!8BPw;PS6JR6M{x_s?x@?FaWFhM zH%?))-lh*w7G{7fga;9q+(P8yRYK%ADWJ)xmTRE5=_%hxq_Vsl1|fQA(UybZN@9Bn z5uFZ9q;?yU?y%h&(Jk`%=MT#tGM7$|O;fo+!)2wO^{BR!4NooiRMIRw$Mv6bvm627 zp)}wr`;$cGQOl*wuIkO2x*`6gfXbo2hKeo+(V>G6L52}&8P0z!ilCM|8*sOo36@A1Pr5<2D3)8OP^eqbfX{U(j1^noyx_6gp5GE30N#dWg<+Q#R0S|p-k11uGK~? zx^*ct=NsAIyv&dBhyJcg*7#4yGySSyjq}&4@aE*1%FVpJ`zL|cRL}N$n!0~0Af%L= zm)vH}d;@ag14IhC`HiDs5M)y<(-UQo+WCM>rGRwNW2j}s_DXq)boNs;^(=JV$&SAL z#VHh>%tqzb=9Y4rwOZdb2cRj9DSbe!T!fuxYi^)p?HHM31%#NQy=--GHj$25Mcm!@ zw7xz(*Xb65Kf9f80VIvVD4-!_98;YsZR>o}e)f?&l|^BR5$cz|59>W>766F>m4af~ z0u2#S7#b=H3s9D5miua33J^OG39(^TkZrEzMZLAWBkn1RQCuz_NxpWJIOIt^jNy5f}-8 z&nK?3ifDe!R#_Vy6hIOdUnnVH2{_WugN{TYdvGrqZA~Q>axtfPs)GN*+x9!xlkm!y zPS)nv`vX|)byP+&iZapVu|$YedeBFjf{Jkl`>5oql~E{+jC4{p+E9q}O2)9Rr&*Pm zPQwh*Ye`iAMw>tY0QjT{Tvah@mhICDhZYq9RhLSMv<67vEvIH0E2SjBlIsh@K~(aO zp6LJkuml%^1nyqgV=POsgNQpVVIzK29eH1jF%iOXF)X!)A^GJZX~WdKSQRk_UfID9 z6GXBAw8HJS(xWZ!lVX;$40%r`?&Zb&4A*uES&6$l%jow;; zNa}u;%lE#OskL`C?Nwozx?X#6!U!`RhLp?9p4DDW_e!8+x3rXf1oWxjsD~?&pa=j2 z=>ZJpPQmG?qP;E}8={a@i;1HpV_%+!py%XNi4Y)spPVjjSLtQbJtW#Olq~(%Tr(7^8!xp zUeJnIi!0fMyJwL#<0430i3=hSEOz%h^`m=|xKIFu??|By(x3&=3P1w^@dSz)2}kn4 zn381t7e2gNPJAHHsTk)&Q>dmjj*S7?IXxM9*wVz?kQ|TgmY+u~zw9eMi7x9Hr0u@; zednTOWu+!&_dLP2L)*HCY!1{s4mG7i!bBk$feCzg;q_fcqjah3xMaHCV8J>ZvRS>V zx|(IJIQ`D0DD-=ISUrn$M3-fgEyh?%p{fJI0004kn1fm`@BjeS6B(tY5qpcy%G{>W zq`t}r|NF264*&&*UslU3HPDGm>s?_ZicsZiYpgJBiUcohb(D?h3_%VY+_JRvrfOx_ zl+I2|CGsgdS8EhUu8${YYX^fvq$7esMygpIf`?#bG3KR0CN5kh4rO!FK`QQZOT_YO z*kwBxb2)`9K8)m~hwLXv<_RaUFA0yFaR_}6(L+Xx?h?ce4<>DVE}_`bY{bsb&OYe0 z?^BHL%EOR$+}&5r?ADO{rj%*@^fm7mctlL7$NpuhRhK3RB{{ksK_EjRLNy}r0hFYl z&~=NCB2owUrO=>SC}%@Pa zi$aV0K!@{glKkP?jqNp!1OX*XSpxV|B1@DYIRlN#NyHPV>cOtnY-K|fWOK737)Htd zAGVP3q)eCo&$hkhA|8r{iK%Y&O?S~)Y`t0uhztZmK?V*3rDCFzC37OkC<(pp96*+| z%>V?Vo8=Vs9vtLHEwG-p_$cgm&B(NUoB3f7AtDWeYXJnxMwtEkuXfJd5t%)%rNfI?g<1TPXHav-BV-C{8#2R-Mh7FNHr9!f=$7n~v^^gYQcrVU76 zBf5%}eO`qlZ@~+Xdlu6aRkk}FYyb%&PCa1CEk)3S%_#^RGS0fIMY~EGPHk!Wk(eF? z0Ju9BG)DjX&;%5K1VCR~ZD9Zco9lZ$tS|syL78W{oB#vkGc5lzfB=U$ zVzA-phHr>PtfEznbD9M-In5+l63XwisH&TaxhCdrtr?%Vi=7~ve4FRorZ8MOJD(W~ z5?xwCr>FWycSe5L-hE`*;_?3Cs}l25#g#r};bq(})oH}tjDP_uULi=(K!q=$3Qr*6 z6coM!qE3YaVQ@Vwa(e5CCuhSzoM>QnxMTo`XX&CZoTf87R_lmXvL_>fNt-vJ;{RqY zR?GQ%yz25=Hy38@d2doHXUtp7thIUn$*x4(`SWR(W34IsU7F@@MPIv_?CxEw-u~M; zlhn2EpG`|=C$?)@+yDRd9?o0W&yS;vjR#;k#yP(Kc0g!$p%4T}0g(V;Kr&2lV8YS| z5Gg?uD?qyeG3%>+WEICF0zc%8Ntts`T!R z2N93ZuSea_rmAN!qdt zHS67>oz<9re#~z=P20oo_GVpnJDtq?dL4IT_N!i&%kB1lo0sspUbM6A^Dce*OB44Z z@%l>l=V|x#H@#J*|NI8>;70%Cix@p50wU@xKmY&$Ktuo#5RRFa=|Q4{8xk0n34k~f zIEaW);8Vk(n&1X30VKX{WJDvzi|zp77%VCOaOjc2Je<}lt!*K@Mc-IcGk~R(Dk$Ek zTZsR%X=GLodgB$)kgg*w+3$YW96`p7LAX;|bsA$ReC{MO!qS=gWj)gAeinJ1sG9_U z-Fwk#V&!MjnFA_=*-U0dLlVEM^)XcLy(5njici$sGYvg6_hFq=&fCIgn(s2ZQnoU= zed>9A>h%9fO)*0?*}SsW7wgHnDAzKb&+C70{fl`^E&njXmnke?sZBFdGukV^@~!=B zX@CC#yiOiJ|5%q|QAk*0Faik#yH?Sx$@HQKODHgi1^rhnAv07830thT2$+80Ll+SP zgN2k-Iy%LJ6#x6c1Q>uMR94*oVE_V!>ua6tAOKoLp<4_*+XINPD%F>pVTJ=y1tm)n zPgNXnkfW?ne2!%mLPa2WuB#~#H9HPXNftrumWYX_>&)9vTRo1YRknt!JZ-^gnbY;F zPj$6lX*E|ihA9!}Dpf@I*|C#y;^1-zvQh`rs2|9*PFg?!0+q_SJ&+uP10!+LEx5`S zGK)nYRFQufR1Uis(Hl2JXXmN%jFw6`l`X2?Oeay8&& zc%2r3CqG78Xk7pRFfo9@9Ej{~OA`g1soeuLi?OxX#F)COvn3$6lMP{@HfHa?%xQeP zY4pDtj0msVt0H4_&3%-tFCnH-n$2;~i$0AYAdVwCwAR>>A~Y3fYXM4X7xEQG1U-nA zG>?f?tCIL#R7XMt;8aAji+XYTajk*k=;u36qDGfwewIeh4Hp3nTrr^##4Q-?_;77w zRHRv;s}+zTsc!xaV$^;wd~q$dnfAw zWx~OQ}4(d0jL0oV8<-W znKMJgP5O`qpe4yjohONT;B5|a)i{brCD{(r`pQy6octEV#K|LsbSlfz;b{J7LsDw@ z8Q-_78`s>Ij%Z2Nb_N*CD~AV)Gxh76+pZrbTG?A%tqC_~SQQ|UV4`)>yN<+DNW|R` z*WaNQlN5Pygnrj0{6LdG_Gm8>vQH~Bdvl+^-6pIM07L>uXC%@O0tJa!GeDY}@g@?@ znzSV`UFPKfscQy%|NFoM5r78aURFa-Hp0=1I>=>)^brwzbL=G#0tc>cb%c%i*%N1q zzLMv~^@RY8O4ZC&W=c9p8u-sJCmjiEvK4Z7pr5!dBW?bZJqj5{c$_&Isf% z?O-;Q3Dn{#m5|X1X$n7>kb=axihiP1)2D$2-$4!4F|OSP;Z0({H>CQhKQsEVyT_ZsBOOe5zUH9I`X)g_|jqX+q1jn2TNP zO3=cGA!;4oN9rONxF2Aa(GvXvU;nhJ>i~g(0GSpAxiU@)mQ7`oM3-o3QXy8D^C~Qp zIl9cbTUrxt*3j)Fri0fypJcEL%zy@-AQAIGQxjSaBe2C-B3;W0fv(4W%_IPrVIq>9 zL}nGeW-(RC0X4^FVOZKbkrqQ0%D$-^N0v(D%vFR#^=6dWt~i3UhBTRjbmg&8wS@%6 zfa=uPB?zSjiwnc|w5Y6EL4|YWw1~+N93+3-wXU?`wGkh}^KD1&T~>k0Bk!iN2)|6y z>VNS!mVi2GYD?r?2N+mH5Fv>M5pdP1@jp>2v%D&qB1j?4d}u-h7tx@UWV3FI_L-}- zWULe7oGj;&f?qq>{p>q}!(S23M&+QScU%6|qW6B8NEjSa&YtZJv0! zim5&k%$FzmR;^2Gv}7l}w_UkK@8^hB#>`jCrPNwL&+Yx%(@K9wRFx&s!?0*B5{XYe zMg-c|5^FWRqFThrAf+!taw7#4-UveEDoY97PSN2iDDvE<)EFfbE*GTu+Dzva#kVka zP+G8)W2|Fk(P-`NSToE}1Gvh$`bYbp{ zdJ>2i`$n>+UWCUZLN$w-S#EWPcU;wT2PVOU%k7Fg@Cc`4AOJ9EEKzR@fPw|;2r6k~ zuf_s2fZj2Q$#Ogs2kNc=`@jSd0tKaASX(b*@V=|s)n(?M7U_3i480n{46QD8grT7j z=B{VC^EvjMLm;OvJJctwR~Yb?70RC4xKcHrtfK_oKMy!m0i;!Y&3Yw;GT2msbK_?Z z$&3kY9H5ksN0c}2cy?G^u$Dl5EIy_3|huYB{^hq4k@56`T8RcloYyGaNDL}{OehnRrC za!p_$d6N|tVkBlRwkc;{*u#3@yD;=e7|Y)Hoe@Q(;VK6hGgM+u)>J%l2sw~|F6m?N zc8?a(#w}&$BZ>@UvXFv_GEWBqUM?k?({urt;E#%&F6;<M;wj-mnX$a} zUU>OTO_&%}ObO$XX?i_xEz#Hw#5vOggM|PI9AIR+BUpqW`gztDV2+i^u5MyCb#rD< zTfSp`nYmRv)}^dpQ=z|80HrDb0paiZzz+ZfHcoIElixd6lKI!-%uZWgHxO(1N@8+{-tg!nLsH9~>0AJVPY{+>95Vs6 zrCPq${n_UUft~wYjuBUR+k|fd^=~RBblC9~9F(}Qoy^BWBzUV(7$v0@i~l*X#JU0 zt!{Y11QMO?V0ghHUxR|hN8*yzDal(HVeOa+>M|(y4{mxS=*A41LOR7Ks0FtPjEY8YP2K{2on#J`bBg{^UGuU6xsU2%|d+9JV;u8_R#L%36Q5ARarn# zLH3C)M<*f%;>}LShVlxWUMFE-iIrtjlvSL5miceBn*aZ9pKW6E_iw*1H(U5_<^3&N zCX`91T=@BWH?X+DouB{!0^?pa093E40NUy`*ilU74M}V{*IlNv{sz@27|M8{c5|TD zUCc;|h+#xV7$6bQocd^p)JXyYN$gNMuR0>hF6;5M;EsCeU{5c6Vf=dRfNABcYCREm@u+O^V%$NS#2#`op(jmFbY1&&hv@kfz z6X3`7YCbQ!LJEW9f|4gWy=+a8Wd*S45Gv!@auS%S#}p+!ior%iKuOSwFsQ=d;6idE zaxuY*s0>-!*25|)#1ys}D|t(o0mpld3YlA#b63`KLv&9Km}52m9nZAE9J2YQDTA5yint7Lc=kpy<4zE zQtgV4uXUDOfjG0IE>PJDC6_Se`Qr-+ z4TH+<#nQw`khz??*hL5_pCGoIUgO60`z;r=#P8#^_dAHN z|C?X~D^1HeKmb4hsc0AhWifV^EW+70MIWAMQMDJJ%qNyM77UY)K&GFG<~GHlw@ zr-tW=xoXCrz{FP)Mn$|tSono?xw+?O%hIa?PzE3X04{X_1kYm0u@o9KHb_{a1Sck* z>hqVJA=U0r$*w9hMx|J}m(a_KL!-nYi$YV$O9e)V2VCKJIjiYC1 z*GsBwda?^(WQ-7TY$PXCaDZkxyO}8lZW*0-xL^LOcaM{?m+n>y%>y!ZEG0zw56adv zV)bC)S2THh8MKG+00001Cd6^BWejbJm<$G(a2T5CR@l_3iZ$0lSBzFWTkYG3!}6Ur zT3Psdb>V|8P*;iFb?ESr$}@);L)#8>;WUAgRCvZ3mk8zVc?7zk?Ly=mM6BdOEg3+f zI>C-rWfm}L$bPip#qG;6HgvsbrawM%wt#>ntzlr&g|>kL zaaogQrc;`d9AVkEfyx^(K{#i1PmQ&mZX2k0gs`Ru-RJK9PK3U7~EAdkR$*5ummB4B==s~V-HI5wu>s(VdltDX?rH)%?=VEreHeNu5v+8w>?}g&T~o4O$n6)3H#+n zX+9Y;;Pm{uaQ#;$AIT9itaE1DeDd4U5-c0BF2)#8YDX20qD0{d#LfBJTo0#Yd3d7v zkG7j5I9HtHAYdqWC{jxr`|8U-V4~zG3qg%UM@X}Q$6PX&XA4qkr?^|*F;2AzHePh= zoP>v%eBGHKn5#5h<^R~-%hrZ;I0MaksG&7Kv?=Y0knp|C$7t><92MAvI#AkI*fim z(!iwyhc?U$0fLKF~&|NF266M!UoTw8l7Gs1%lt6gD(icpPnZR{lu zf%>W~wUmw_S7F*BR!7RNZ5s?1Gae3~BNVPg{*80g$&Gv}@y#wCjB=o}kfw&+gruwL z%db&2SYG$?pJq)=z)sJ3CO6MWL^b1Y`fn}vulUljo9VTFyEN5pK79Jx^3kCB$vSvC zY7;Cvmm9f2MsXRd0003~R4sCSk6|e1!Op6v993nXY^;85&%xnx8l~~A_jzYJrp{G^+GaBn-EmJ%G$;&#vp9f+Y@eD$CqDu;T25zAg$}_* zZe@O7kgYUptq8}4{O`UaX{Hc7PaLSn0ZOr#-`{sc(HUVBKmZ5{+)yxS%xxJ% zq=uH1HK{ch8OTc2*yh6y*hpL!lpoIbrhQ8ufLJi5IXvL<{1+zpN}R!SK=acTlAUA=Zj~?+gEb=H+RK5 zY8?<9oP1qRu)6T{nWZi%7j!-zV3lwHP(^f#G=m^O@2gXI+P&Bo>>o5=T{s$^9R`#; zLTa9j(Rj`2o|~33qSJ94aT$Yha*P;wwCI+B-kBNnIxr(@%!LF6fk!$y+^Mc?;WB2D zY2`cjc=_uDp02`6#$DD{b~i(Q4ut_gF1nBRs`V>TU;63+D5xL+0bB+H7&_w#6nSv~ zpV zp=#&tuAx6~S0$x{*#%dw_9}vDp3;%1#TEbiummrFCC6P@V-HO5i>tdmVTg!OS#xcy zF$%&cFKqpUjxla4$~7O@dg9#0J8O(-C(dG4wKv;fE}p=%L@1EToCHW-Mj~Lv&lFLm zB{o=Cu&h&1j2B)_x-k#29E8(dLkz!eZ(ca)#`@uCNl3UrqGEyh(nQ9`htR*;RA4y( z000Vh0RgN`>;xQ^oC;J$5ayW!%)(l|MuAci>n*AI`a^P?_CL9%D2Ydjs*~TxUuK5> zvZv5>SDC5QIf+w*BN5$;aP5w&kpjzQu-j7D`hFPuI-1B5y(KuK-BIPQjH({7A3tpy z(^cuGIMh17e1K5xdfq~5QLNjfR`AEh{uLgu;M(QP6G|Ezy1rf#N=+u3vtLGS~iYzrIpmT~l z!s&eRDUX|e5N%fmKLn1Y?rv$u-HwCbZtIJ548iWNh>&wW#2p+4nQ6ZEpU#_K=@{UD|%1|NEc>Er0}LUfTN%GeC+f+f893j8P$H zX{<2K0qmhIwSE=Jeyy2*Z5P`quymAJ z_nD~LZcK2a07W!QumAu6xuU^Tk467o4J=sF&m=PE+*k4^O3J#COhDt^$XZ#Y zz=aO77?T@9rzAMqs}qaJ-kK?pK%6tiuXbH8O_F>erf@R!p;{CJqoG8>p#YmhxJ2Wi}T+Wywo$9R!D*K%vB>S4ebX z$QL(D!y1p{6QYslb8+e+$fvunQ@EmOGIZ8$3)S zob8CR`*&w%`|CBjdvE0Eh=5}rrXLorlvH;%$OIys&NUE%|GFi;rpy^$@_NJJE5Np9Im8oiEK;f5w z$xJnbEaISMfYg}d$X$CKkq_avgS;=$o7D26>W^~Yk4~89&V`MPX9lO`RYitWLLfm% zx0pe(sN4yJFg@UMQ`JMpo-BY{5cIPVnwVokkZS+?umlqT1a(>4dk-=)gv$F(Wg~o9 zy_Z=my_3Q9tL=324&Yt*t6Zx5_M)+0nY3 zI)s4O_uFTzR#A9jvo=Y*F==~ZF?I8uDQDm{T)Ryv^)O%Nu)^}ANl z9oiJ}Z02X4MiqA2%#mw_4Y9C*-YOU7yPb17T$AGlsi_qliU0rr8|Zhe zQ837&h6;dXh|y+Lf&K}vT227OtR>| z4uDx5!Ye9Gtlu;c^EAC4B1();t{Tn;WV+?SDs!omsC)%sy5{E=1M>F}@nuD#Ebb-m?=Z8d>H!rT= zvperx$}r8Z)OXVLZ%ApYVR2=b`W<82ad*=1=glTK529zpWW-lW`bksCS^$6vb1uMI z2k`p=;5i2o?j{Dy7!HJh-6ulUz^g+cL^&YCyzHLnQ%m+jDDu1*+`!lXDouQ~?K z!^!l|tjfc-|2eMtPO%#8dkvL_^=m-NW>Cr+lAcBA+(I17HD8@Bv2)!yqit$-qjEL1 zUvO=8&vCO==Iv4~-qWlA2mmbv7DOY=JVqqM1|+`<|NF263V;McWLoPFLSTrjn|)y; zjuAm;Z|pqD3Hhz9^@9#6UW#LcqbX4+l0e?VekqCiE)&9s+3oDJcJa-T;)!e7VBh6GI{r`U#-i`gj zSN&V@&zW9>P3j3E3F(H3wq)a`_3bscG;QPFd&{FC5L=hkIRx+Ja7>8^b5W@}niJr! zo8&ByGZr4jTgk`@WXOT&%`{M&H3ZmTj1W|e7+BE?*Aj+WRRFP3l|W0tA{zlz!g@4Ik%&K$@YN-0K17|)*H7d` zTAq#tktBjiXw?TWP-UO!KJRQY$mtjfrK=nIdNZlDr!J^{)EP68-Q}`xpP%YZo@vtc z?_|#Q0XMtvdbYo}l6}8>k00yBc79|lwqB~U#7Dkoq3#p5L*D1EcdneiD^LKGl-{th zn;@XUOF`6LgedOTr}uy_5?y(~CGK zTYm%7&Y=S)uZ)VshOvW^i)tUIUnfk(TAlQjVfl5hZr_)g*bSzRm(3g$5=4F^vc*t9 zDG3JcuNJW-i0_Otq=iK}H6~(ygts`KWQjkcQrTe&(@4 z_R1yrARY<^=Zg>$s+gsRH6_JJLj@j;i|bn& zVS|oXA)Q@}F&u&;u z?#l{~kc=1JpVej!$^UIez07U;m&*Na164-2L_p4l6+Ls!p&crjoV>`EwRNx;yv)s1N`E-(#;(*oUTIDL^=iVxEjmPmeuvE=4SEjpWO+ z*DOFTJf8gZmaL`_?UZd{vN=3it~t_(a#a6BTo{ZlD$EtMnE6EGPtL5dX)TBf%U^7A zXVTmLM=1`b0z#7W(a5bxdSHHAQv?eVK8*PhT{*F-E;ko6!uURgGvVqo*oHZ~tRDKK znGY;XJw;TyP7O4siVjbkdy(hLGbr|orkGe{7#35wDB?#PQjUsY^5kDxkxJ3DIenVK zfmZcW31+xR0L^^DQwYiqG*pBv({^S~8oYd18b?z=j)cl)129aL#Znt%d6Z8^X^l+` z1sW(2?~A}aV#Up&QAH2UlzlZ-W;EXBB*n1A)fz_-xla#?nL&{ZVhR?AMLw^3J?&P1 zLmf7&2|mOQxoDSQ!Uz;|nnqHiA>${am}FXYK~9%pthfoQu0YTkBme+02t{nNfeZ*L z0s+$%9NS@DjDS%iSQjTVNzqkNpO&X;w*;&8eDa;^>2*6A|NF268Gt2*T3BNbV(^H| zTU}uzeo)zSaqJkef*vd^^@N%sc3iK$VLFe68@AEfDMR^@c4dowB*5xDXoRr+rVO1z zPE#+O2&$g*lMA06x_+(4$*SI}R$e6-EV290j1F6D0m$V`0|B6Y>T041*}?OaZQ6Y7 zv6$3dOJp!VxlQ{luYR3%?bNTk|1J8f@9yq7r~3#6VL||&Tn3hAzpgbkvO)j=7kX2Z z9j$_jlXOL$rM89a%}km6UAi~YIkO@}L9&7CLy1A{GMwV95V251;|(sPhWXi~gxmZv zj?!>yT72AL=UXUCRzOGQXd?h7u)Kf+3l0clg_FH=1W4fCXf&!we?$8Cv6 z^(24*3DrAEWdIloY&L>bO<6jPrz4K`FXcIh8Qn?S@hN&KER8G}POdtHQIlqHYIQVs z0RWaQZJvHh<*2;jc*LCcRJvicRBGm-=)ZGjMGVJ(PDq$s%o67dGV>Z9Ib_x0aVNm! zTp`OD=+=?!E)!28jB0j^Be@dHvM}dWu5~G&ZnS^_AQc`E14C2Qzm+FUnurxuS)EX{6O0_#qct`l*UhWs}umAv;Us571prM9^Wg4J+35JBl%&jTJ_KgMx4Jc_TfRk38e3z%x zv@frIa$?q2DP4AaobeIYv`?bDJ=MPL+mdS9=;I&=TNLuU98?CY-DTJ$)zD5Yk?RCa zbY+#g-1|RtTUO8OcQ9riaKUgF>t)G0Di|HX^;bfemF`vi-?41nTdV>A0I7H&WkHvm zh;7L?)tQwgfS?=&IFd#{pn2nJt`MYZH%66iRO<`r##g17Lehw4kX;>?M#hmud3UK5 z(7vv$lBMek+WfR~xTw#Li6QIDeu+q5KUcX)9fdoki)|NF26H2?%-Us~%4 zGhmI&I~`#oo)fWoWsD^g!cDI1^@bt&$87z1^AL=!^!U~L&Umk!|E;a&;sg6hmSA}4 z;dBpdUTqZ=%&>p}00kN`P-q7R#JCUwcuSS@9b}A=j5wH(#n|>^2^B@dxuf&3xvs}H0;Z@g4}LW000_* zny6GLplO7*Sw(x(zPo(E< z2r%kEN`RD3$%V=a$<>sLvVlBiaFtw^zWX)Sl|M}M$O9@)n^rQ>w)a>RnwqOyWP*Z% zaic{bVXo9sR>e~I&bz5wt*feQu`w_`&||l8)a!gbGK>y^DH&nb*ety3KT=7hTqJ-1 z23RnDjcl4Efk$L%RjNUJH8{)6&RNT=9+C+}Kq$FH(6$psEf|% z;eOWp#I%H-uI%H2>h#d={ix{b6R}<^VhC|9cnc`983V4KFgQkj-p6t}t5WNgU!LRX zo_CqKXS=bEHHA;5T~$QotjPO^sE^|2s+_C89gQig(WwAE`T)#;0BDG&%78~20)CK& zvU)cs)tE?`EF6_j!aJMS^R`ea6G$p8QWa}@*_<{pt~BC>=rwSY?{ zFjBYKDqJv8ajVoaBr#XD)A%f)tbr6K_m3H5ee=XbZj2y?qGXOpqp=9H&6K9(4ohb> znRbf`2~rQrLpAsPndco-uWXI&w7thKJJeg7v{a>A3(RUKvTPE(YJ99->R-L(8@o-= zci)ncWEY(?PWIf!&~mDq0J#_d7#P8T0$Lga(Q*Nh*+Ml07Swyj3KSmP5rs06-TI2*pN^Fl}mLNX`aD$pOqZ;&&Zg<)$1KYOI+U&$5iOm<9X>Llk1MQ85scJP<~QL5KUYvOsx?@WS1_2o@bqA1YGOgQK| zsp^*NxELh0n0mJz_TO}4lLky>_f6C6RI zYhv*rFcXh)I}K6;&w(n+)i+Bwh5CJKST3X6n|1SD&dOV@*Nf*SXRnUisWRS8H4<{y?i6W&{h-fa) zp~&zzP=cH^!np1%1p;ucel10{fXFzLiE$@DE)66sL(S8G|1woTRW_ehR&}7d5~)Mq zC=1uS6y)yD%)||{zXF*tEpO55ftjym<`EQYyh>9NDj*&1LJ{V zVn8Rt@M2pCW@g9ovO3KLwHb{Y+v6j<7oQ`X?|iJ>`~QDGKh9GT{)z?!KmljMC75Ce zQEybm%~k1+vK&-0U(reDMdIVU>3Gbq-56a!A0xsjTij?$Fmx8o7v>o|#=K~}H z@FoE19tDt#gA9qsfna=C7Y76;Ns$A=Gwc{t*nuKZGcq7bOo~gZW*H)gNYbhQ`>+Hy zf+a{?*TV@mK#dA3Ej@#dR8e_hj6D&;CNFIDh8dwQ_0*h?Fxm-&z^GNY$ucq$CMpXv zr{&&mnSz{6Yv)$`3%9%Bm^jH*-Q3K~GwfN4BIPXlyT|IjeBB6m z))35TL9iw4$jyTW5=K>38Z|M?*#Gjp4HTjP08!(Ji>M_=DBebd0!QU;TR5Nz{@tqdO6N+?fWBu}tjme1rHW&`{ehl(X){nK`JXH@;c1>-UsbTI5 zLrc``81;_|X9us?+Tiyu4db=C_lph^*l~v(F`+@~4~4;FL4-;GxYET;u>Sq#leU@O zXgV$w)>J#36JFnd=p6 zN?dj62aRdt9tX1q9*^8cn6^K)2{EAx{1S8!0w7@m1RT7czErsqAf+9J;Pla2Cc|vi z_~u2O=fSz|{x!+_?Y`z&yWqWPhJrc0qtox)W__*4e8DTA`28B-e`+aw34FhG>3yujf&$r|uQa@B$=a%%)ABXEs!lMecua{v3l z1T2CjDqPrOEHv=q?AnHH>ADn^b6;#Q*#a7??6rm=v3K(hiyqWyXjFA_Bg4dnx}7k| z{4?@gt$nu@+x8)4^U2!TZA_KF+)eV^_BA)@>rS7&+MAUzKUbOSVY_19CJti2>awbbtQg2YUq0-NF|AOsY+%2Yw5DOU7ccG2~FMAvGT zQEyM=mIaKnN-4QxC9hpKVsdOADn}-ATP~4C81=}2F3OTx5}PJmp&MeOV&Rz>%15GE z?Gr8&)VlPxc#^K|&?1<${d5bGkdz-##d{1!IlK8`?4Z<=i1%YFVVdGVMpi0cA<_HS zlNc+1Z?;lbpC@(m{CD?1ZT{zWaAo+UH9`Y#$Ql3ttR&=UfC6=+iU|Ovfv*DBgaQ3T z1 zDMps_p!cTbM6%Yx`7JuhcWObLTOx_tcr0CoTND1*9Y}XKI7Y+h?uOCbIbd`nNU3yp zw{&-RcZYN+DGh?4g!=CLd*1(Gdvb~cqi7Bq2kNvJiYgQHw)i-~k zZehWqYp^PDtAu~t-(ej50;$%X-0*Nx1~l|HHXMhORDKa@d_hPY+Ma8ZyQUTW2pz*g zlU1lVBCw5o4D3Q?Jz}X_6+FbdD#5O<2sKg6h zqzQ8FZG<>FQ5e%W9f+s} znqT!{soR{A&f(|Dr#mUHO(WE@p^Y5huxGPdq;@k`jEievokaQ?5aY}JCt@NG#X6PvH*m{Xv8cZi- zbAiFW&aY7C17iywt#_hs+cjwYE(}G+(dXyoBDnZa(yyWZ_*lWM$yI)SS*hCJUoR_J znx&MENbZjoEUTI5$(2MSj|%c|Rr`j(mNz1h^fA>~kD(;f3(lYc7>MPDvrK*6=QX_( zaLUd9dsZ=nkm5}@U%+zB3C;l;FvfTIN^Txk;;72>oa}J9anlzxg`uEAr^h}$WTsK* zMjhBM;jUvZg@0Xh7P~z1$I|g^7rM1su@0=h01b;I8jRxFI741EgvIx>OKVw?LO(4; zMJC_;vT59!K0qq0RAlHRT~$@@tEu_Md5#j1TKci*5$v9SrPgIu(VHl(usW++sE_-f zLqUM+l5|NiEj%lg!+cl@oeId_dX8BLW&^=W5e8#v;|8x7ng_|T>8L&4d`Oi&&yISu z|5AdOU3mW`N^VX#WpDN6 zPgWixBdnl;lNL6x^G|QU>SK0CKThl)te5x|jZD(;!(KIBgY}y%Pqb@=wWthlJSj-u zc2wcd9s;m;P?i>6<6w}#sL`M|T4_-u`ww8%3W{0cP#a%()DP=|(-GLL11b(avLag4 z@?o*kTg=i7)sb4BJR3EDNm~NsB4>K~%Eoxdu)1W5olUtTah^gjj;mP!OaXkuqU_hm%JfQr*wph>(8= z1HTsiuaP4QLaMUe4nUV%4viHRw;YQjFiW(%&zz>%AEc9 z!mXEKhM42+5vluN`yF@`P=7sk`SlO7@E#-1$puMj3# z%UEj=w66-w-y*u_^Gul}dRXmAq}AbF8&(!LpxZrW7pqD6zr&W|y%=cXz2L~Ud^N9IucFKB&GwAJr|n;! z8Ra3Zssbs~@MuG!q3(E@Bk2 zFSsH}PXA#XH30d=ZtW1BkrTrP=V9m)bn;`}E*qDpnK|oPeD#!f>(fM>IzgQAM=qM$IS37{CTmcutm;GZPze*JwEnpJD78R)66Wtz^4 z3b0vj2{Ozp2>Omx&50QIj*Xw7QN}R5s`h$DISpp3CG?UB^l6|cx)BCO`XNC!q-zQl zwxTvDD@(a7gZD`PsYO-rSWW%S)tG-9$@5wiym$)5c>XC(ZLieB5)+uj&@QH&B;U{$ zqvQ*dr4Nbk4Lc+#O2b}6Zc)S-E~WcsIzAYwD-cqk-^Li^Jb9ReI2}Eb4fjNspb|+~ z^_!T8ucYhTQm8irON?){cW$hFkvZF7j;eRg?AB&dBlHwnii+CmIJz;a%pb5;Dr!Of zYU{%P4H3l{m2zX0P*i(_EvbEc;|nJ%`pK_e=kfBz=ki$jX7tiuHVuy-q8D1&9*V17 z7}#v1;pA7(uZE~rQFSPBN;SvYHI|Fo9B!Mfs(dL68 zxkx?Farhetz!~NdAe@$WQ7+40%CHsLJ;;UtXA^Y39OZH+j_1s5j=tqt=Y0Fg_x8(N za-7+-aC-%LF%5V|E@vr*lW?52{ide!yHMCuLs2odq>+_gP?wk`A*6$H<9| z5JfHPH!Dc{q?Ifq$(`1CL?+$5!B4!qjo|&PmxB!4Q>E^5#eLfOwE9`G?bt3k;?`1Z zjB1vEIYgs~e;Vl=k5@UFrG^jZO_>~n4gTkb@3(hq%tmh)EZ(;d+?`qHLl39wgc@M= zjH-EOxO@5I7^sKCN2_`f_}E2I-9Z3A{Xv_^o^|jrBxxF--3{4rt9;waa*~(PlZMn+ zz%)&hQReV5r!HkLwY2*~S94OX+K}v$NRT3#ijhM3xOk3%6=F@{5wr&-g*p92Le0GPhbChQh zCE5S0I7+yAm$hjCirlxLm=`l~x{r9PUT&A%xH9AoF7WM!uRAg<*G;?7J`(&-d^tLm zNrKdr0R{Gt3TOMvL0uQeO%!sBxLlNtqK+J|UP+6bH#dHHgZR#$K#heDQ$M)pK20`f z+P`OEW~!*a2I-{GH0mxG!k-Gl*g{%rDNj_gJ*?qpV*AiektoQ3e#>XHW-0dl?__FT zi5{KGm?X@bsAf3$o5R|gOF%wZ&(JCL0sL#^{b&;!urb#5&ZrAQ?lZFSw|x$KeUO-h z#OSc9VNG5N zEJ!QVfxs{isqWl-s7PtW|1Afay<-kq>dN8oWq!qwwp!)g3Go2loc9E>jO+bt3=l>U zxls|kDGw862b)iQ$50B~Z|CDGdkIp67_F#W^X)Ax>=WR;e=G}_Z+qzVUVeC~FT*q( zsO~3ptoP|f$so)tvqjNHIL}uwxC-oyna|%JrH$MKjBYDWC67v$MjSIbR+S!&O2QSt zks(p=5_dpTZTkGaKQ^uCOdR=yW6p*u-6fIOP>&>4(R5Xrt`%GC8inXbv5)vPl+8fr zPQ$iz^c>tin!qQiLXi09wvD^DZTSd;5_WI6VqR^)PiwfpplXw0ErRx<85FUlKga)L z?d8vZGo(-u(kEl%7c9Bv_}CX0D6_vd)Y~DlbVWvnt@Z)#%_@0vVLb5OZKCScm}hq? zR6%MK84sLN^ zgJPpl^#jogUHYAuCy7($6(B5xwAAu;FvuH*_(&oKs*m~|HVH@Gn<3l99rKg##0sVb-2UysC4ar z;QNRb4ET@xg;W4%i*f%7>TBHnZDHM5zufLg%t#QFrAZ!HnBqgr!8bnUDP+NNf%iP5 z6jjctMSZ;30x9XrgnhlX;0LGX_m6E<=SMV&GF133K3`+GC1tBy~11tote@-fW!SCuzitAINGCiw@{c9_Ei3 zW!xAp+shZ4*4oj@oR}$Tig+s=%U3J5Tm9pgI^+1olR&ypxEFymkVQ`pOmK)*_7!Hi zT<~Wa*nG*PcA2?y##NS7Yz}BjEUdKiD!2UY-8tawU6#N&C_Si}&Uajmj zjJbTRtUoLhJYM7FiKR%9U8GGPH}Thjn{+x>SF7UpOvt16$5q|-ZQEo7CQeo?G%C$L zaBT(e8;J63f;a#1n%P;FNDS-ta^->6Zn))-eHNiN?84z4cr8=;p)) zJ%{7Ma_`aIB#7Vr*aIPnI!A4)R%z~Y-0kitQDanhsrY!4#dtq+Qlpd4bn*kbD{?uu zF(&?Wnf}>845m+l|6mvixnMpgdexE=5ZTNq z(eGzfHUioK#}iU3XVBXMeP>kJMV22_{muo=+(x0$H1i2w5xH zluB*hRIJnM!?aFG=~;Mfu20#*rd>sWD4$3k_yJMlo{~*=pJJS zSam|lC7b_=aYGtK_A8FNW5nN@z zyxr2?z2^1lT2R*c)Wvz)8u!P1rF&wW^>2fn(^G@+Rg+NQ?B}{a z7x(7&2ZEHl5rPKktqaC+r!Hxk6}DWlu$e5h5m^#DeE(6`O6IV0*%l}<%R4P?4;ee# zQ9A3N|53B>o0mEZ(-$n++g9hTGic}u8AHB_b7SBzBAC4`GRqxWNkPx;Kip-ZCw%2U zL!)ob7_hm{!c9SZwr1JCEVFd?EVD(4{7>jv+6BsbLbF*cVQcIgeDzsbrzD)rQLCba zEt+O8FJ~lbsUAaLf_3t2*9*x=;RHnueVIZ$;2%xr_c*=!%v}Gspbw#V0rrUQ00362 zlD37{U81b&=$gaD*pUt+OpFnNGd2%=<{#u* z+~b7P<5ye{D%ct32JAW6w+m+98&yTBH>^4_=y90=nXt-scVwN z$G>w%GN#HqO#pp{ADSUwJ{*Kgvwb9)B@kXqg1~MLGZ`JOwqnA=jeX4&=={^Ce71CS za-t-Zv5V0ssS+kVG=DP6k7`>H^qG2Uh?w3D{cbNffdSu%)72RTrNl{C*5|d3KonV~ z#|^^D9vwSOry*T8!sT?XUg5wNl89?CK-_&8_`y+|Zj9vtY4C=klm}Fi_G#WObWez7 zt=*f?W?KLuQ&*G$E2&ky2R~KQUJ`|jCo-t5QX6t#r}MQe_h0DxDzGLUsRexSw>)(l+3FqDlG7n4}quhzT7ryS9 zr|R0Y7SkF2m%XWrzMS2;wzMkgM-lg2rS1S3bhJtUF(Q%>Ifhvg22Fb?47Myd3=9N12hAj0s@cir-_K653SS&=>W_9Ba4~F`dYW=dSpu<&KRe^I zi&$sxl}1;n^K$N3tXJH8ZMBnd^`s=n{v>uEQ7qr(U zbDnTp9j%D7j57Mfk-*uUu=yioMPoGe2E@W5&5K>+mEkTD8;qUKz}W|WP(*jjf()S} z&>p)6Ba!2Ml-#Tb!Ds%QmVf{9b#hsd0B5g;!cIoY1T$K=$U&OrR2yp}fqy0njWfE0 zt2P)t|M)BQt*od{IPxmJ>(7S1v#riims;U8=oRG9-yV|mKEKvkv?yt&nZyfRd z)KJ4?7qA9EN-0-{hIUrb^JT0uQeY$-#3%bzqabd#lvXG2hIODxQ-mkTSWodQ(JxVu zr1dE=VAH}6UgRIow4*j*+1Z&Pr%I+P2HQW(A`Wv=JyBp`)$UVZO{q*VNhP;m#@d{N zKInwIVqTP8R6fVNJZY3_x0UOAX81XC-5Sbj$u!b;PZbJ=46b{phAZ|*9%~vrc-7hH z(Uy?PQAv5MKYd)~Sq?57KL|Y|=^f5Rf@RHIbCjj9h&x$I+8<7#f-hLT8DXu%EW*>BqZG=Ke->387x zzjkTgw4%4FK*ybnX@WzcZCvNT`OK$<-Tr@_WH12YG}pvO#Dfw<+}0FRdFhb+yUAFb zC+UXLko<{M@A*##SclI%A!s?8opGW;e<_M9MdlT&3jd&a%8l?~;&V!)O#K}HOny%A zj@I#zMNTD^NfbX!-44Pw_Ss!m>vAjIR;$YJ*~o>ExZA0L7u>|Yo`;sDgB<^-R;qI6lHZKMI%kZL5@@6`@by;4t&_hpsjxJncF;4l7y!JfWRP%Dr-2 zd9+aKbXM7NQXy-R+bW8ZZjl z7-k6oaGs&9C@GU?1MUUzoZPW>E4yrWX{5s< z>At&J>397Hrh*}i*cSRGxN^7AD!Jm8BLyT%US_jmUPG@(TF5XPDoWc{ThJxf`Y$izF^dcAI$yg#ys@XRT{p^mgJiT~Ouc%u|_z{@zCXX5ItQ^Ph zXRY51nj<}!btp;`At|I_`6=we=vJ&xuK&5IY6)X@+@8;>WY5;Fnm^#!f4IBu0`Ksu zy`DWq#?mT6o41;Nn@=%@bZK#{cJkdm-f_DS!^3FyaHKO-mE1vIO;w0F1VLusDl`t5 zIY>9mgT=G;cs`P-s>$t(rd=zjWbsgmHN^%5sGa_f$Lh78RPo7_igVb=*B*V;b$RT< zFY>b@X>bPjPFN4{r8B;=%wm#NHBe_%Gx=@2AGd6>Hb^~oh@*p8O@qk{Qjfy>OZ=STHkW>I-vx<}q@;#hHcL96sOt@ko; zU091!upu)`M=_T`wF8BTG!0$phji#V=z8M=nr4;i$Lmn-%cT(R%-=2#m% zdy8`SR>L2I?&BM#6`P_M7PMYo44MJ+w*4`u=YsNO%r}*5-#uwB9PGpOS;&MQr4dSG zG;aDxc^@}W$h7c+;KPPyMwmU|sS$-9LWeUc#fTL2nP@UH5yyLL*@x=B`^&0#ZM|xA z=V*kxqpt@YXUm|mgJ$uU1fU-=$kF@@MxK#WQN;jAQcZ6&0lfnoEId8$0*PDi55GF;5A7P0eV=K)@JBj~XAuf1w=9>|fwc4l}Kr7CvNnN>6b ziu#r~-RWhAZDKKX`7b|b&F+TTU(oFQSDT=)SfE{?9c|*_=Uk#L=t};w*1)Nz61}H1 zoE;&i!cQg3>I|xZhBfL4$|L!EQ6rZ&hMVNG8RYUMxRu!br`Wsy9b$5dGW>|f$$YmCifsv|zVzHI&L z{8MLJa}FziYUutQCMS7cr%_sSxESk1*5|_4{JFOgfQTTOqFvIRSein%E?p=U6<0my z9o6vYy4EFfHFP^7?_X%#0l_IPR;#AfH4P`S;x*2>ljWyizqSi8j+_BHD4+9*O!Lc^ zhE6v}tpBfJ1R&X%Z(X3vHOH{caKh-E4fj77IQOm&gV`@Xgk_((mGz3PqPSaKt1BStAdTHIm|v7#ppmX!Z|#g-o?&Y`<$QbIc)4 zS#tkkQiirwsR^W20JHUR@mm5&vA&JGL5bR9_C3;N)1!AB0Yu2sPMvYMr_H6ZCy>*! zWGvzSqvO{-v=V0{6!X$`zizS#3Tc<71}RTlR`qBPH|m?ts`(-Hy8ImuPu(0J6O@EozQ*LCEA@0|0c?2-=x0?seij+cH{?7U!31{Iw;4;osUu> zhFRJhosdg8Ys2E>Sn%~f#p_Zk#5ex7%##@cc~&du#h^2I(qSuOJeYl1-2Jhv5FgUo zIVEkTK^X8gxBd8g!wbL2#j(K7jD-4b@4!H|hq^o8a?3}k{5be->vKSWS*+kEk=?1E<@tf?s%-f z9E3&BX#P{PQU;-x!B#QdY-Is1F|r&MD*@HPi!lEolSf$ zXkJtH`0*Je>56DSU(42I`Po9tXDfiErihiQ*`w)mfsjvi*h3seVbNg8Jh^|@^wZJ1 z>Hfo?&HZf_a0W~)N@OW?WfJ9wq$U{`06l3iU%4v@pTc)P5*uxF=uH%uObCOStC5fl zkvpjc1&<>*C_Xr5F>5pjlOk!EqvNa-QJq|lO93TnQon^=zqK%kn2uAHj|5b**Srgv zaU(}2XIzt;HA@|*kFC3kAkRUqN5i19sl94X5Frq_tk-K(OXWuQxFnGsY)UI;HfvYy zAs$|WyzkT7{_gE4;nW~e4+*`yYsoR;o>Xlru%>i$3sns=d2afRCgZN%WiOZHW&q@x zERdHQj;3WAk&(rgKRO4hs=AiA2uS7qpnO+?UXn}+Ly8)+567ysS~^eoFrj0NXJNU^ zeB`BsTzNLHDzkmAhGVh1nWJsd;2svkxI>#VoLz-RY#5eu%TJ^s^NuFx7BO2f7X?Ju zn^$U^@8Fy?GFhHL2bIG|G~!PYLY`zUK3acw2Xzow{Us^Qrsh%G1B#YwZnsm1IakN@ z|NPf69xrQ6BY9J`84;>{&~fx`CO%zq+*!GFry=vR=*gkm0^HxFLXd@CZ&l9C;?)3W zKn@)$6$JpGsSUb#e(D}s?pf_Cs#LF(3q8nQ{xKrW*eI#avH4>s#Q}*(4ve5x~Sa_@tHFP9Do5=_mtcl_7}oJ0$*qD7obz4K-cP zbdoYwa&1Dr>A#hwWliG3?hDI$eao_e&(6s}(+uoP7y*csx(i%*h@q|8k`SquzMl8= zvzby{AO06=L}Cm=(l^?6LZ`Zm$K1AnhB_Nmd6*v)2A4BF>4SofSaHyn~F<8*_2GjkP;GK|hc*j)N%co0Z z0&+Eo6fm6=Nf!%*2QuO^ex}l$m7^_ZWNl=(`E42IX&h8{8yHK32AL8xj+j31%g_C% z&}8+H`yO92NT{B(QpDT5F%KvUJVzr(LQMN65gs!aAw(vRQ#@Oj#3!ArC|3)c$?%Jm z*|t?UDxfrWrcw7J{=Oc;RAIs##@dwRGXETpIksG&=P$r44`)RYc{=$vE)W(@RXw0u|~%V2f+|ca4T2SH zIs;iih>^~;13HcsVfXDZqrvM7qqL>hdtY^b)7!J`+v{8Uk;bKTs_zz=`?(g52<-3d z;c+Pgh=pXsgKQYV?(dKYY~WrKz^KR6cc*cw*~t!be||;uPJGI4eu^L|u=dd3)z6tH z|IAYAcKlz((FD=cnQrZ$a5UzCDaE0T1zJkpPM7oxA;h&Vd_NPo@6d+P0>X?fvy7K( zTZJonX|uh9u8{f%iJqFjeaw^Q`A|h2X!qEzE5cj0JMUbf9wuyDTcV#H(Bfo}&gZZ> zOU(sg2668q8Ni(351jB+936sFiaQ<1Q&arr-W)>8}wI_0}8^l9PWnK16}Y4_RX374?l_fqdb#hBaH z5Y#3Wr!|Sf1Z268008JxP63@A7FRYX~u(^en_E?45Xuv>l45z^0cx(7~ey$|d zHLiPIv}#_ypB?GPjUbUVe=*gM_c&q0NbFl(gn0a-zgMxRS>@OtWXkboguX1nZ*=03 zL$Wuj4ZI`BLjIVf?5VeZlQ>@m9K^{1fJ!lx98Ve91R#)ny4qTQS<+U#puqv~L1lYm zRrE~o*Y$X1d1<@jH1uiGSlhIh7KP2)TyRn#%(P6 zpp<)=yJFU?+Gyb_7|J&-3bx(zq!=iEg)pixQsZ`b^uV<>r8)0RO+$8~eMCH5pW~G` z0(ST1Ya&+2r0jE05C0>nNvvcI?-G%R;y4;LXTFhu#MyY=IqPapA=ws~TR!1`&DCUC z))@QN6ZuBJLzS95ZOf6qh`>@&A{3lHvVD0bHLQs>JKsMbs0*HOZLZ@ilaJ$msck^@ zkQs1C;c=JyGnrRa7>|**Y$s7;3r|>CCLDYNK6UBZHf!Of{g&5EbZAxrL#$*Xh+N89fYkYu)!1 z2A;-(Lcb_HuoTg#g5|VUW4c>$TnxJB%pZe{G)}rquC@QV@)r!uUT!mf_fM5&^?}}0 zRG4AI9inZb0A^A-SaH}MA))H50+rvuwm8OZ%VkT^YWkRT5#`0R&B5*^QZ0}Sp-O(I z8l9DRRn=$$na)}nJ-xSLgT?a<3UOo5slo#5Z!dY)^idbQP@{hS=2!#aK1;3T3IUEn z$;cXN_hjv4rGu5D5BEX6L=;g+Ov|905&HP%54w38T9yP3Y)~z^on*V});@WIPh|D^i&Z zzUHBk>3_OofdB5Ec;FZ?(+%-u@-{W^k@n_h=l;%1K^<~dfguLM_-lp?Ggh)C+>{4FpD55z!E z2ZVqw8ib0|$W{9)dYXlMFSboCi}m)+T-q7%@|^UGrEw;ff)aD9FqxhPZw;kmX@#te z7|2C z9Zt|PCuu9)uEW&nIP;p_Z>ZUsz(se5Q4qS6ibC+4AeY6<2mhYhTJ@Mv5lu|>_!!>sF2Mead=UdR`8$In4!V(js ztnQfW1y!WxFpeXa5C9-M#n(RkOzLP58XDwKHT}wN69B!ux|#Y`MOEat7Xk*Gri1iO z$ROF?JKJh)U?wea%QR0Z29KwTb!OOR0&`Pur7Y)VnfktZr?dde z3SU*Sb4zL^uetJ?H9NQO{4SCzzha8j8^#+Ki>; z;`*=RXaUGpHijx#{L4`nm~Q_?@$e_ZjmYt*-`3W_qxAg5%%vQ8l(-6dpYXlOxfZ4r z5S7zFpa=foJ)Sxe+TNDu+s4C$hPckG9}MajjfxPGJQdW5%nrT~iS5DFvFy0iss{lM zX#NGG==X}Rpa1-6I25|H&1c>jlB8|hOP2b1+P(JOln8VE=uBQ68*ecP4_|#BU7re# zp+Du47Ky<&Li;zwFlWXZ{+}N8^nYE}CWi*oy89H`C z;?%<@X$LTy()n=}j^K%v+R#KaUJmr6vzlZ!9YQE>^#!FjWmUu(<;%{I8c%D#R4%&L zkp0&UKb}gR--j_CIzK*S=9>Q{0?Ui?Qa~b34l6Q)Jw^Dh$)zH45yS1%LSU6)9r7TM zdcZzERx=AQE{-`c4|g4pR}k8z8uz@Rz6u?dl4Ih2Tt^~wY4)4z<;xSNDHrA z&LMJr8}*zPlw;j7BZeaH1g$U^)+Hssj{_A^ut3$hzwJ+8nZ%UwWaGNv z#)!3Ycb2bf{S0f&pyTTaoA9g+MPt>)?>O{;_oNJ5TFe@t++HkV z`L-kgbdUG?(^^Co7EXA?8-@g;v}eYqA09jBwn1h4a7Vji{6h^^;i)rB@_K-Tm6GTi z69tUeM+*}pCuocvfs+08!g97XoBOa3$s?NF{Hf_LD1@3Jan!ltOub!(eg>SF5o)&c z{)AE+`wU$U-Ya!0J8S{@)w&{>zrlgegp^JfYuD-qEaRkKJbKnfw46u1Xbqrt!G z|EoB-d|C%i_pnfUhS&Vhssm5Y&7qdwZ5o^N3XXAHO~RkZ3q9EC<3V~ZAMyDNv!}=A zUM*D_s)?nf+_kI2JB`S7)h6-qSI-6NNj>C~3+UZEn5^~<=Ymtatj8HyvyVvv85Y*g z)vD{qkd>`uRtzvb`-CoJW`cTZ(coa+6Gn@ETSd|+#DW*Jc2cBr)O$H@I!~GVP~*Wz z%T-#cph`+Gm@Nk)4IYjnR-H!lJS$$WRqIb#tucyC=X?;*tl{G>;3ef;gUQraYobdj zLADT}rdd1dWiKF8uZS_nWWUq*Y#q-GI;yMjv^tYV_g?I#*_K{x0#~+Z?~)NdP}&C} z(28US3Db_jy<6~PM)ZI25l=_&jjrY4zR~UrpA1<@Mh8V2%fPk*^*I${L+I^ zRbjAL=M(TB#TvqUN5&M>C@e7WYKWmf0t6ta+Yk#!6TovYv)y%ZQu;Jnt5r!q)N(z} zd5Jivl;lJjI~f>ZT0tMNfr@C23ce-JXJjjw@LZv-wq00G&co41iT7-2p7lEJr<$~V zibX4(-oZIiPhI)G^o7NbocpxRH&2T5)IT?p2ELs5m08WsMtk(`xhF+{GICeg(aDsg z00;;|xv5CVi*R;w!?BM2mh+OrTRbkmpyB*LN+2ht;;6MB;m-83DwR`8Q z{hje$e)&*3PPhIrz?L!yJ_4R#*er&|sd*3TVo9-O6espt_HKJaE1tlw6D|dC=cxDyY4Dy~}!&vpM@2E5t=)JjQe59UI zwk$#J>2$&&2P>Z}pmo^l7$W7^z2j@^;k?|GA%)PKmmuPZ6E5~LgkUH2oQ7?eKd>RIbYYxD zg8=jd1ZY$;)1~{38~!XY#&2W@k?Od_EGa?RhMl_1d|O1c>E7TYu*jUFL~t4ZT(`f< zHi_>-&s3YFw}Xdq@ZYbl?WK=w>t$?i11>iMy%LVEf&Vc6eHT49yDlF5`p^Hqu0d$o zgzu|^9@S?4Z?UO1gt;AO00OO0VWlA?EFl0hPcAJX0-wK!9o8ipm_KODg`n&2e zRk(2XZUdfG0p(i%TT108Wxw`S_l1FWR}`3}mdy_U{zBjw5?j84D%c#)hb^O% zL-xQ5*{HSyWs&5Qsy3lq%UVdbUeU|VZarMc{(epLUCg%E)h(|u!~8Izx_q!IAghPt zM6NCLTi|@f9l1m)3Gl|cnhHHwjVfy2y~L9c|CmdA>Geb5tZ6mb81HwV6ocyf_(HP< zJHP{}Icb(@D!F)Uk*y5TX6~0wf5U+orAr<{bDMR^k9;L}_&w7hsytlnHo1Am>*!+i zZm~#(ar(nbTbQ^A+Tc#$0&BK>DaFSKU}01x2k;&{H-aRIUBdox_Zv5GJJT!v29|kP<#K@rhUEZ zwb?FPDJ+y&HG+O@FINl2ioe0AesOc`;Ilx%g2l+|ead=))t;sb)qUX@AIG`Y_7-JYan zhpV@y>^n)^VD)R!rmr8xv45LNbsn(YYuVAK?Qs2W8|?ie!!fOE_ls21k5$+?f z9j^LYU_YuMa*zt{AdMexA%9?v6oSOYKv*4^?xRmJKOMm@6?Jhz`+2N@S}Yct&y1p| z90uu;oE49F;U?v!KLB%ljvMo&gI0>bmktF6OkbC}S)#kO3dFVc}J70lQ4<|yb^ zmMIgD8FMHo`M#&E)CnK+T)k7p5F$dGvJtQ7LB4lZ^i_h}$vWP-V^vKDG^+ga=1pKflp7H;NUKRjx@qVxMW<<)vNxq<2S4&UVOA^1CT zX?CdI(~BStMdAhdUZ(Tpzl%4mJ50rG-AK=#aeMH0{HK#l>ErYhg3b5iEYFr^-vcz3 zj~>i8!x#rs&~d<4$ys=48A%Nu=MfIKZfRe3A&GIaJ`xLVvtv!`m@bHdsGUHo-ce_J zHnSvM+i2L+Z&@v1_?3v+OqLSQ{R%_`01&vnuth?`6@~ng&}^34r9wPIZulF&VgIL6 z!45((w^^0dkbjpto2zCyGO5k(@}C8)vLIaYmqEV4f<-YXB-^7#Q#Q?YEp+z;I*Oo3 z$E0LDgQ`;77mw-|zs<(gvSV>49P_75(%6($DwA=UHH|&_YcqS6}B*)G`R{!T+zC6==e!>=!9TxJ82G2`xwxkG!Q5T{vOI9vMsW78g3<3r2Y0W%Bilaz$=WDCC)|aD!$%k4@Pn{%GVL~zO z5-erutx5D<>SXSZ_Py8JL8bak}d%}`p*_3DO=~XUY zFD3Vb9{~*wV4x*?8kXAl$IM!|iy)V4!872Zmq;$i#ZN!&-dc3C$m(BliTa$vB!GZ$ z$hRt+e6({HaR@0cz@7>bvzZFw;@Ta2>vKnxjm}!_&tX|9)~3@M&M7Rqrqk`CUR~uK zjI4bW%PoIN53qh-_9|Ky_!2>tYLogtXH%OxdvqUml`sB#ccDl4Z`+Ot@6kzTXoW*QJ{KCGKP3bZ_CsoiGw zuzmcnmQlJ%KLMC-H@iZR9UAawCypvD`27&1|rmv zo8lJGq>>6XPB6y)qG6=ULnV2Guz+VxG^o-UMZc3J^n&mez6T7H&w1Fv$|Y2*eS{B@ z@X+cIBs)0BVeu>`TvGn0q{n42^MJSXh=S~JFEk7xn-C=0{FaQHhL4nA?RP(Y1})Qy19+D;Z#%A4Vo4edDV1D|LCdx;+XBNv97Pp_kE` ziw56*ELmZOBH1>bEv?qaXbwEhYa3gYD4tW*_D!`95ov-*%b!6@GzAg$%gGbCH^a|G zotcUNMsS(R*cm6mF}C0#EeD>OB%(U_R=cn?Q7i0Xe?9R6zg-jUQEdzS1KE5u@TmbW zbek(VYQ2|bVp#VV2W4 zIfg%YK_b^c$W}~hHj+&|WxFoJQ-*0rUmV1gxRQ#LWbP?U$#Q1tn;&O?&nY>fAfDG5 zS?DD!X@&#@TzB#H55+xN&bsOIv}hcnKYjlLBn*5rj9QouTSF8ETt6OvoQR zU^r@5dB*fF^?OGN+w>ErQkqzB>NAd>#!?aOGj`dQWtflA z<>_NM4uEQ1$i87wQTvtNSt0M(xCZdfLSDZ%Lx4}8fLR&K!(pV*H&MvZx`u`P;MD&> z4ig|CV4<(##&;Jr69D(}ch#cxaH*xAm7!&E(SomqXptt7TSLDM+J+_8ANBKGa0(*& zeAu(6$5PrYP#Nc{r6~I5B-r=D1!att$z#$TJi;>T%9*} z096d?n|ax}v{N}&4t_&gzOF<6kq60Zy;;-8YGhp9@~1utPr0z`<7 z)W?}=-S%^{q#h^kS&hvg?@+k4U+fQWedjI1WU{l0fvfOKkN4)!Tpl18)#dGR%Y&SU z?}O}Ej4vqglqgpWSE*rm#je$1vyFE{tQ=vR_S&c161c@~rK3Kg6r+bBZTBrDD%QDcrarIkDd z03hHxRLepHLpX$~1CrPb`(&>elQ|;iSKf1x}c}=CJX)qMB7#K8ZWZ`)0^gqCF29Z@_@$07*oPzsam^H;(J7g$`3vAp(q~ zB(aern0NMrj)UAt^D9N?DCEBTIePB?C*sbHyXG05S+o}QVAw^Qq<-hJfiMAipt>QlQvrV9@Vjz?NGH4cIkU*GG+E1;eJOmAn0F@XUKAxDqnaD;0 zI*lR3^1RKgF5glRJ;!>YRI2JQULqn^!#Gp044+;{Th87@$;Kx!Ow21E-zS9`a5`hVrE^p)5*C<**IgY zvbmVj$I&vpmHJ;d5|X_T=jzsKz~_8Zb#p6{>>H~wS{ZcOxKEE5hH>9^gdGe}ggw&@ zYG{n8ifzKBV-xB9)6!vObesfq-v(0@DIi-zO;|+0#1taEMhF##HXx8}Bv5e4-eS*? z+(}K91LqbQA9O-Hgzyf}r@1__EJ`CGZvK#wVJ)TAR`F!hhfX)mz++r9RY733PpBk; zbS^j+%n!smC`+?oQUte(iT&*^B=`u?QN`Z1S;OWsCNnwP(H#}8E+tKQLwFK;4$f5i z0iZ@QS%VH$aTtb+9xg%(-}#BV(7t{dNreop7Ck{ji^Fa@_NflS`c7lroyD??-H8%- zR#|uB+{dda^xFAnUTnah?cd$+Ug;$M9^#xFJANGE@Df|`h$Tfjtxb6%0H$J=b}d*$ zQH`eLDpZ1(WN)fzOZ(5DkDA|EF@Pkr8Pv#$$JKqRa{)r^gI7T9Yzi4l6r`|DnZmhjhQ(YDc*bv-(8m;>f5HzqA2!vS+-|L=G?e!qtE zk8IGiRBbMOEVGa_9y#R)$(wGW3nN?rYgsU47={W(KMrfcT?30$4V?($O*9(AF}z*= z4{?x$zevNa|IB8irY@7rMsk40;Q#G~C?PRmkWHi^SOkm4X&_BFu)Y@A^+T&Smu@z>!>c=TJz$NU<2-QG@uTQ54(`W zjPJ-8awfz0m`#?U6!x}Wy^9I?NcSgRYj$T&HHxy%0Wiyx#S4Gjzx0ciDy8e+~SZWzi%g|ePN$N`en zz}Im9(X367s_PUECApx{CD1@)$iwR2h8j(oX0baO8WtvqN+KSvs|=IyhiiHOOH_v0 z1;WLUQ;Uvh&nOpN@oDzS(=#Id)SSFrohTI9#!yr2BCo_4@_}X)LUgmBH1Zj{cDfR? zo}-9^uGImxA1$L~BayNA*P~za4r$uzIV_5D3VP#*l|kLUAH9dmgi5aoLD=!_&te76 zg0v4K*4?==07zmx_?2DeR!IT?uA;ZrQYhy!#BgjHw#}#Gh_-p47tC(KziL{ECA8Oo#i?XjX)`K)5FfhB*Ivi5gY=^GdMG+9&@&1g zkrjWzQI&+=%Mq+r91{#9<#b4#l-jUr*-EKKymDL*&K~itlpN2;%uYzMW!-{U{~?Y7 zKqFuTF`Fgco4B~>vJX80N(6kaBWNB*p}+obFC@#T0mM`0F4^14Dy7+q7p-UJ4lI#E z+zU)3%hL9N_LsqxfftRjmEjLs*uQR^gcZYVboD11uy@}`-zVra*ACgBsa73bfr3>2 zEW{#-Au9?hDaz>ZXhcl;%uJb`=Zq!nD({PARX>XjGWxm3kAy zFm8Lwi&WLoQyjEYJr6$_zn^2-BQQ!+B!#j0Yi`b@H`P^-)_RdP*H{%N?miHNRMQ!nMY)m z*k1g>vR2DQ{I2M3!IQ(2T`$xXmr^6X&PW0+2+ZHy2}}2F`1Lc)B zJUbY~fVugNns604b`o58SU^GvJu?9wBCa^=-QVQWevbH{eC&XA;u7}=nzBqzZW7L$KU)U$GA*! zC?Eh7q>3Jfr6=?OR_7HDEv8h}RBFRz!jBn@7iSWaXtu*LQc~HwK5)X(YW#;dNZL1* zf}tY=@k7Mvwlic>rmpW{ThDR zf4!SUtSacx$jD80glzHMSa{)#DXSN?TJM)hsR&=^tHkN0DNskTnjIx5OkMWgu2 z&l-P?jkK#G4^PebfE(pFJA!g>&K|K%(}cwr&h;~;^ZQHFzu@EYB1AxN9;2k>5ub#O z4ku>+ET#FPKCj8InwuSxkrI2*la$_Sj%ZLcsrNLpf>YjjoAlOWxtn#ds2|3qYzs+8 z&3J$G5W&N=fV_LQ9BM(2qIa(eLGckQ`&TzU0S`VbvEVzcn%&>vj6O%ul+bc+L|G&6 z@fVfatbf?GIhk1{Wlj`S-Awr;K%-!BI6<5=(?@tfuRK=aC0-Yz2a7Hn7i=VJ8=|aL zBuMgt&?y-ldWkfsNRy3Owh=8Jh%Y%Pz>h_tmZV;`AEWhI4paQeKyQQx^=icGOq*HW z-V`*e13hbnwW^R)=Jjx+X5Y!__@|BQD5f^BWaNhE-$y$!?o7%Y{@1$X)5~{l*yCUT zRKfr!z5NMi?Zy&}`B;SXF{hk1!xw{viCieer_n{O%fww6rp=PYDi!KXW71-UykXd* z=Ss}<5t>twQiB56Ps)r1XKJxO7E^xlhicq}n77+0>35PqsfVVTv|109UGe{3^jy$1 z@kWr{Hfv|Oy(mjhI>E6g)WPkh zrhyyB_pshS<;oTMCr_`(`ez(-M~_%EN!(6#g3rSkS&~^NnA*#Mw@#<^O$IaoD&@$* z8!9ve<-$~8heG>cEz0Pmmi>A#X{JAERMD%~b1$RkAv0~dZjvN*Rj?cl?$J@181_W4 zZ=O0+28yDzo;FzyP9}-os`}(_8|h=mq?J0;zv107{&6+7J3(WJ@>Tun!y8wtF**e` zE53V)CBp5cPJao;Vo(iC9a|0uHfd)*$m%PP-E&30ZZ-e>>hziIo*?ohlqQ(}s72}0 z@Z)n8sj@hBDOalAkT`&UvPc@MUZ3reNwdOp(=IPV6HBM*opRLrES%a6*TQ^^k{>l) z`#UbHGO3Bd2YFR=SI{ThyIvGI)gz2g+UuJ4ZP&T;1^zb_J|sny*{k3)iYYj1yW?im z3ZWJy-9_f!x%j$@0WW;oEA@!)NWycIy$(77qx3Xk3I>8p2VSl3jPL-cXeG~y|Hc+D zp>RJ;R%=x)@1mIEjLk;kbte;aX8H-CY3m@oo9ul;h*MZ~EM`6Jm8WJ9i&{=%%u@MG z`+$Qxk4<_t=9H=YC)`hzD!N@{7K1JYjj556<-r9bffmT+l2d-XyFGUNtEGB{^!S;I z&Mqk77wto!I%Q8pwe92z2hU7(yCIp+Rhl?rm=Isy1}9p(X$&FAmFjU zcy@xIDT0}2#l3Y1Wsit*<0s3!!Q2W9LMkVED*72Jt|N?vYm_5@s=+1qZ4VmN!;$jF zViI>s`emH(N4%KwJ-vA~I&r^BsGbyxLy@EE%CUO|(LVOX0SRk^PT5o#Eod}m9t1ee zmdeq3y6*wP@m?a$38(SR-GgeH@BXsUwea^FMv0OZ%(m*9V!!q#H!GpM8Xn6{s@W<^ zN8xb7a5{>ondPVtCuQprE4VOe6w0ZQ;jtQ=lBk5^=h~669tynR%-QIVBTXr3mk8_p ziVkYRTf9rVhfFfuRyd&+_Nz25E^=2+)JGL*s5yA8tCLM#R(;04!yBq6`;EW?;+3Kh zp+h-F;)P?*a*UOvU`B??H(|gfRb8xC3 z#%CI|vg~(PT2&6HM-)B>&I;wpFHqN9(kJlCG)h_S_@5{kR<@T+${s(Qs zP*@@3%}Z1+&QOQx|B_L3(9#WAIPj&g*c{+0OMFwsPw}Lmau8!f=x#gx`t}SnW`zj- zJEff8Ob%ayx!nG7m-oo$Hr)4eeG9}_pZjY3K<9jTdRh7B_fF==!&cJTpQx|SNq7bN z`ZgCJq{FSP`S;HfLd5kH;xg0U@jub(H7ENyR{Gz2Y%Y!aXE96GK`}Ts@P;$%!^kUR zG7k$iq}XWn6Dy(JqVZL&-^O#9NU}q2!3?LcR;0}q`V8_&M zBZ+{v^C7}za8cqo(h(*ov(9hsbJNI;YjcyzQ1^o(!uMX@++s?3 zLVv0VD>N-q?=QRD-%@?FF9qtzaPlmy70EaXa6q{sB5&5<{;Xy3)y zPJ|11noXB>Rboi7u)>S48kBh4ID!dnZd+L4YrGZ9m>>Ce%gJFvl7Qx%V?a_>Wu%%C z8pwmbO5aKS88EKS`o!oav7#iyXV2tyQDpq$Oyv*~PPOSs|3l)?bD;~5#o>pZu`p;8 zxMVcyr9N@8be3912!@3u=B2eExGyP0G_frW)M9x7nQ?(?mhP9yx4?O&5XW>$3gPFH0t+>?^8i?UbypotO;8`DZ&sbPw#Q;`U+2EE^=^35 zzp5o8K8~u^ta9)qhok*B#m+}>b{$jFKX#JhrV%1h)mePfzpW#iC*cKr8u&BX++}A> z4*bzUor$_mQ|zE`u;r@m;IRrO_-3;w>pG*Dbme+2R=`$h@cwckKDIMtg@qaoy#zhF z6zxDh(*s7p$S9!i-T13hS%X5A!dXd8Oh?t9ukk7C zLNb<&0cqNIwJ-J_%{kt+61&nZ+GxR8zPOmcxa7>*eN3p3qdy(7NH3pH9zuS6k6%%u zm{ZOn%t=L<;N^rp(n6!(pAZy^wotqA>khFZU~N`k%3|Yo1X`j24LhXNt)*1$amH#t z721+)92{JGEV_o#T`jVz1^m>S(-#s7lpg5x2~_^O+Ibt-@I|P*w&P~KOZM1+Pg=r$&uX&#iZxF7hWb4 z`p4TIEPgP;w2hvNEdcNrwHIyH3_yXKYuQ}~fO&0Y_TUKy7@HlplnrWLUyNvqQO#L2 zr-u{3mK%^C7h_pF-|D&PZ~uax+S6Se%5rcdLr7Fp<3RXF(8v~5%JxoUfluv8XW@oW zjK$c0wYX+KBY!pYmZmI!;O#hXkd?MxIO#RHKWV+er`W@VnIV4&w0nwp$vVy^aVN>( zQu$e&x%e}6oFM>b_@~`{{M(Q`c6Co$YKD`>pnBj#=Jbu`^s&Y%ohfU1zZ{R$*Eb#> zNBZZOFCKay$LZ5T!9S-!s;nBinG1`?SE2JCA0H3luyQ%PniN?2uyo1A_UF!JPzE35r=LSMZOZbPh_FTCkoo}EWv-Fy7NdvN7tx%{3~wR` z5CA&KBvuF{A@Z}x$iwm5jc*~B$7NJxi>VL8l}f<;nZr3}XLqcZm8X*NBJwW3DsR`! zRKB-iy5S~`-k)RTPFd%ar^`4e<%H;6?yM&|cw2L( zb$E2YdOTd!%vC#@v`%|pYyLbEOB)cwP}%B~cTuFMY^>{axE1|}-vn_z)+x|;8RN;0 zO{rz8i;dL};30yS|5&Rk`8dag$ek1*6JyA0!*qylP%jiUwUVP2Z6k~fM;6KS6aB+? zO!209U;+i$I|0uKhQUOhItWlH@kuCofG{@GL>10VXY3q?%NoIPUdYq>&QdC2dh_Aj zCFaZWE`0nF!}bQ!SgauSR3oSXZ>r1a`tYfIrE#h-j7)Egg!{6CW<`I(s6M{lPpmbe zrlncW;tOnsSSru4vI01?+qv|dsoVKIReAbHmix*$)}&G#d0NnB#IL(RLqF5$PB!C{ zDyP-@bYA|$nzmQj%hNBrSiPQFEw3~GaMI5Y(og<1(k=&$-{|YqKJ^_}dkf~|XC2pa zX0;oeAb>JHf0TcHJz151uaO2IQgo9@RdFkUhH*6UK>{^ItJx014UP@Mv$`vA5uxg+ zlO@cM<@X>gE&x`{X#3V20Ej~AExe)t7_369oJ4rSD7YNUBZ-rlzsI2qhmD-=8MzL+ zmf?X*M8F%7R0zDnzGdj>=q=Q7{l=>iK)muAM4HO;;zY07#5a4;_pP&a;9Pr;%zU}- zj+W<()QA6zq`9+zLXKk=`0N^KhkuIXxtogwy<{2#H5dR;^uPnRWco|bMODNETUGHl zk%!0nYKJi>cC1U4zzsu{RU0R(-P_LtWo;8;LrJpZFka%CCuGnLw1N(@4+Pe{@cEF6 z@n_N5vSp%gl3#oyK^+otZm0z@Tr+En_e4}w->0=->b;+-*O+{3Z(D$2-)(BMyw#rw zcc||1wwzu8?QP-!g*xc0O>Z*WCSY}nEjtlT-5q@eVuHNgPZqh*5#Q-O?=5B2c^Zvd z^Le3IJ$T8$KLYTKUrrbQO?WnCrWOeN{TgD|6lK6aLK7EW-D9dEJE9NzN{SM)~h^9oQSH?c} zcE^(rjOWf#Keka)vbOL9`Nh-nbOyL}k6|GVYe+d!D6&*ASlHe$(6a#^0#s7q^)nOb zQnmy93i?O1nM!H~zbyEyK*XCUQUM|A%3OY-m_{YRnNVgDMMT(vqYJY=1M`ZC{&^J? zx8Hz0eAK-6iIqaJ&F34$ADnB}pJB=7%;elAJ$Ki^;>%+bp`Z5rCr6u&C(O%x9tap3 z_-6WTU;wBB2t~747H4Hme+EklSn{)S>-Y`Cg)}}TfucsLh?R7^7PgzQxBT2S+ngRQ z7jetbg%MwQp!m%#oJAk5WV}tj)hw$-vY>?adY97MN;AJu)Aj#mv0sS60_9qRPL0-=BH1n~ftj^C6Wxh5{i);X8R4l34t8Utg zcd=lidJlda%nr0Cd$t@(XVex>h9-9DzI5TVU)}f`-S^O|GcmPJRUEy~MpZ^iI8vSH>mNff^`<$3I8JTLkro-L3dAu5z|lahQsVt5SlCuNc(=G97u z6vu;~6(xWDo61D>ag%vdi;t#BC&xLwq8B)O$0Cuj1hIsb8e;id`C=-90ikA5C>%wY zM^6#Hdt(=<17ZhOr`@hEnA>EIe-SBnzAY@$5e-MiBb3!u`0Bs3%*OaN3c{ zNT$)Cw24!&*NMNnw*H-tF3qs1We>ZZNU)LuGTq3vtiY~+kka5Pp5G=};cEklXiPJ0 z;_pp%ap>3gltkc}^SMb9Lc6#{TbX;QO$jGZ=OYY!IC7AV9Xe^sNh2aQH zdGi^P)7F2i&&@vn3;g%>$7UcugLTB@@SEkYOCXYx9nq|2?BH>m1taYNS_{2`pe$}k zsc6HI+6Kr;6HO011*YrJV2)*UE3YbZQVL12rijI4*+f>)BIpyeDWP-Q-B-%YxXs;c z^znBZ!_r`VFIrQqvy{CYm|HqtdrU6~7&-acv}*j5PxSqF`^Qb!xMwb9@|TE`F<%~x zgvq=ytQv3LY-=q{DDh9kRr;1SP^7TvDH$BxxbD+Gnj;)TcqhV$2&1R9g*}kNd2r`) z>U$U+ck2J^9f$xl9L5lXW68USOB82w>Of6tJ!q@uV!p!H<;H9yP(hz@wGQ>5oVNS0n!F*-WM-jxC?jF^ zE-Fw&^{1#KiZoCmqR43e%klV4h6dz8k&hgrv&@{=?`~-^`{b!xN1WvPfMH7RAdKOGb{0FY99E2 zhvXO7FeI;QVEOcef`X|N_iccVk!k;?%nr}0Q8RRc-^ux z0DxURSPc~@5(>jar65m#{OcluslU%C28W`#8uR!CLC6BSTs~I2`7KnY`bmN7eYk{9z{TLq;e=rjDo@z{gTvz_$NuDp*q>Y zYRovWDvAaA01hAkV6aWC{lq438l(entFUbZn&j%MI(D)w2 z{jYsf2O^jV6I?A0=doUo3kxr#phc~ljuX9Hh&nnEr^;}lI(MCq8_VHVJz6U^;Zz9Y zd&{5?LH!SLjG=IBCL4#S(szC_OhFLDsrTnX^vknTgtX4wj~JABO)cP)4afP6I)mA& z>#2XWAlng5kBJh=e)r51a8cVN0aa~Wlw(r_?Y8w55e!QLPHhdDvFgjrqR;l@ zE~ORaF1wiR^zeYt%YPR;{;iW|6aeUK82l_P(5p0m%{L8Yfv8rRj<4H}z~3*kczRIZ z6Cf5add(fn?qG%Lr;?fu3tiad{4!e+j&()Wy);iJT(x?T5p1M)dbnnpZ|An)O6(rI4_qWC9c-&DA{&k`GeLkLzvx0}cpwk}JLZ@&reY7}~dQ_y5BtT0MbW^^} z1IkPu#K&E>0f!y~7=)$vIHl`YxUpBvFVsR;UUox}Mj~;*gl)BXR=Y}1ELJ+fs^Ud2 z6LPkVl{e!46XSOmch`w6y7JLVz38Tlj00R@I4zsVqCB|H{icZkS2v*?HHAO65K3y3AyF?LVoi zZ#$yxA|-QG8$Ow0@8tZW)Y%YYcW?rZn{fXN)3IYF!`kBO^-nS%R=27uf2;Fv1)I5L zI+xej@&6%?FPJ9KYC8ax^Df~s4x(R9)RzGpLwxauE~@_XXgGIV_2wz-Uk|j&xp{K& zao|=qUldS(&gW_`|CTW|QigYyCSMi|0HB1jS4xs@?Rgrg`@!UF=2!`yfO1gtHv`IZ zAi_)7UOkKYbw-B3Hh%u+c-k{7*#1>< z+sbfL&?*3NWjjEC=;K~Qu2D?-L&W618Q{26#vsvNob_41!W%aE-6cw(m^s?^0;88?lh!#!SF~BtonnckGFi7LGkiM>f+;U zYX~IZlJwjwzIw>BK7DJdxoWN*$teX331%XQ2Ff#w)4+Dq4i$sOP*t_!E9^)xLK}fa zWXM&qQ&fC(WC{uHF&e)U1Zw272BV?xCM{tzDf=kA(*~gAF!IH9re%fP$eTZ5E-Ts- zWQQ&D4R|O6ZR6g&uC^^Hx$Z}fL^cl18Q&(KXE`qhwAOx%<+;{teHBCcrG@-c$4mAX z5Q{<^K~aj=Us@2~X5^2VC@A-&ABWK&wd ze||Vun#8g}xZs<0tBp&xfrJayr6+D>ryetvfst?@oolI&n6^jN_o0GE{1GP?Duh-X zds{P0ZN2pMG(;o?f*U#zqia=gIeKh*Br!ZHiOg;i)ep90IKO?e8k!eNb1Ng_Q$kK- z_6kgy@NbxD20d5_=}Xp^Pa~4ax%!|;bJ!^UGd>=DtW{d@%0O=SuY?7b*}4c1Oag5v zr5*8q+2+4DN2wp96Af|>Z#ZRieuqY9)F$2mx&xo<^nGnRi9%nqyPCU5vOBo4(H;U$ zPi$IIms;OH&sHp7C}nW+u*w;>`2j+;#+e(RsGuSB9zfCtbs$pYVV~S&X#`Ys3`R$GG`V^F8W|Q^(!)Cic*e#OefbTCsC?1- z$N^C3Ks-XC+efIyZ*%)6eH(pn2bcn2=W8bql-5>HJ7iPnugkn#%*qQFenwsM!NaSp zQH8g-dY}~6;9*saq2fy{#iCv$+-{#$2tyf5(4HEf+b{l*}!#%&$F%(Nvc-*7vR zmBfJsw#Vq=+p1C!cQT~%c%kNNYtt~IAfUnEGHO#qG7lUvgZ;lLyHAC5r~;dUt6tM2 z>FJBZ%B*Ovf|wOl;vcZ67To*>a%Se?Y^iLpmD}A)xnc!CF|vUq%!JIx@X8jt2Ci-P z@`SdnRKZRw1RNB9iG^o5G07c+K$my~)>p zyJ-D_X@>ADM`G`Nm7o4|o(!Y=!g_sE+Nl@;!1vFjNNw1)hL%I^VQgQ!q4DD9?=%)% zY3<{K0WSR{e778Rv(ow{euB73KWb1%_*$MT6{5-*bcnnJwx)j0dE5u#i~U+-lmo9{U#IMBpq-+qb-ozUxOfnSB0R;H|4(wC)$A+HpP-4s{PR#Xmu z*3Ov8o#yO^3gvDQQ6ZJb5T4)rU#AzFfbkd~t2al;nQ~KY{N?>o&il3VxBqT&tDyc% zfQtyDAA$mHxx7;}=fo(fS{ZuSycDXB z6rb~K{j3_oAdI1h_8I<-fl3n+)DI0SMkq;m5h0J1v1Gl$KhHjGP_Zg-K63l&LgkF=-O^vszx+o6s+@OO zU%m3{n<;T3(~d7r^8@H+rEMl{TQ9aAaNm;m5YB#7u!OO@k)j``jy6a}GVp zxD=otou&NG@zmr+!?g3)rn#QkLCx6bwx}}QTNTcT6j4QaA1}MOvKl1#_&*%vxyK4e z6@ge3ov$|n$LORd_Czt9W&mrD(v9jeFo9POwx@USNCrke8Fo~1*eA{x5$jr+$C&Xm z#S7zAD*3%1havZtNVDD=0%$(ln0aY9_4ani45re_ruu5 zi3Vq47kaOYmOgWC5s>=6wRXux!^k4J{L(k-D*8!vh&5XwhBp| z-5%+xou(VXe0R&@i<4KDgApj2gJ=E;btMtkgozaw-ELNj>2h-xy;U~!?F3QnSuB~7 zeYc#^rBV6acB+3|B|&`$=!ht!I0*_S&`D+TRl|Bmo5GK#v~`v&l`3u8%ZQ(A#+RKT zNK6;hjHW@w@ue|P1Q%!Vhts3$#ZT5=VvynzjB&D!L!E6;~ zL@P6j2)%*W<{^<5ryeCf6MbRa6{bOSvpKim--^8o)AL?bFW*XQj@p)6MD$TJ@Ig=7`e2EGpfd4dq;S|}ma*^NZg-gP6IBMnS%enbRV&k((uZY;4wdrD zgTM(&G?}ABhlt3S0+NsJ2Mm|%;ZNe9{OU{cMHnRp2vS&;fn0Oot#|Tn8b^3U9RpHh|P)(SOHKheZ z`G42yr%+fOlP&u*(t}p!*dOMRYq}v`hVkq_rr24SpTmoPqi`Z<$<#k|+;HmI_Y4L; z^779%tT&~9FgXr|3|EdDPrwWNG46Y$?DgR(>B zm4~L$pl2k58y?!=t!BW!g4wW0|!Zdvf0TJAWNjK!NI< ze8EoTL&*)%uN`pEt#(^5H{_E`Xv%o{mX?^=kBB29Lzg$EuaYKw+_at!of#bKA{~f= zUf_hTOD+;;rBEkpt38y1wJSu(U0jw!s=QhTejO;t`h8S_Ti|Bd93SZGoO{KWvSwh= zd6iZ!5i&8k&mr!Qj43FeE5&Z zgD%Ba+;Rfmd`tEEvc5-6+=}#g?fpjY?J03ONvx2xw02IaLDI()FH~*+_VKz5u7Z#u z6};}@Lp-20GG*T2fc*yXJGXKfIlX0$7a6c1&u|@OgC~l%d3qGAY)J^g#!4w$)@H6i z2D6&9!mA-snND()7g5{&dMYI*>r%5#%Zd^tbq>9lJ0TzMi`&)FZa(p2o!MRS&(HUJ ztYF ztE6%mM5LMh9r}w@`rjmlk}oQ_GsyTH|AI(CTDq=<^h-{wUsRVBkh$n*gO8|O^}xj_ z*jj1WA=P?VL$5DD_wTaH> zf1eXg-I?ST$o5pjk;M#6%+z$c?2k~QqfoF0 z2esV&Y}BCU_2!NGSrrWPbaPLgsu6HyVmMNCPz3rZlu_izQT-_6_aZk6TEI%jEI$8;{s*K%K;d9Tn&f@sdH2_729wI@{nhROKY zXkr53gch^L#rxtaQ-aa+IYJ|3J+Cm^nI2+gNux_6ucQw&&cZ`=rqjf;1r9mK)lV4J zmUYerJc(j>UMlH#fg0)-3@H8FA7jKba^Oane) z(AqggPx9iC(R-*+EK5|xdaR6su}a;fNf51^xNR%nMz3S7eEg$5xsgGWJ5@$pv=e|TMHTK)3+amEfs|h%v5LT09Ekr&WT5hu+ z+b)rdxTw;I@_cULo8DbHbz05c6Q&1g1q=*NYTDdIT#)OsK^?^D>AR zzk-}5ioPE&=fpjqb)@B3kcBDMM=?JDm%38_+4R8F=v?rm2krE9C6nfG?qNNW6blPbk3d$B0 zM4+Y0v@juCu$}!tGWm-}BeucMa2{S;#7uLh{}hEU4Kn3Eh~EgCMPQ};m6Y?fF)m1x zZ==`r9*n6Z-#gp3TZh5{3@Jyw`8VdWL`Pl7^O5`WkKtmYonHS;CArqWpKTdI6e*e{ z3NcZ_He=~$WO9#CSv&d=YbWS(fV4sm#W$$oioLQU=Lj@hlYtQKE8dc3q^wBzb9+5 zs~VqqkT!4VbCijz&B%L{LMa~yPbneIq0U}gm;S0TipnmG;MPGv)h&+HksX5m&aCFV z@IMbrieOk?Y32V^6}X=r>j+whx!CG?!l)P|F;h^IxF5LVZsxsn2As{T zU76Rp+J8_WfvGXpy0o0$Zk+xcWRx7}TJHmy{A;tbmuh)5FPL@;BI_S+DC5#?7@ZsI zAMpwj*+Bp}CMtNJ8zpTS)u*3U9BtNUi&Q|nGGhxQkp6_Nm#UatTg zlhcg&3Z>h!rxE5VJx*h6Z6;OFR{Wh^o&^v_G{&w!!1~eEu==VarHA;U^+jTL`{$Q` zeBVx5kUl?WCpO~5cBKS|e!zI_kuesh-6B2Te)d8W%x?<@0ANTtQV`cNW1FK}eM0Wc zk`yD$6D`f0kM0pPNb}NdXXqHv6III0G!Q!kR#Ko4V-cWR2ymiFNJ*P^6LGB+Pb^r} zVdEzxnB~sOcULu_`tcclEyWUrHOvrt<$fEThm;g5gDD8>Xx zgv!Do4YeFuc@H-XzjjnZDv=UrG7DBYc`h_&Syu^uY!5`o0s5+^Sam*TEto7F3WC9s zz8lS3wh*U5^`VN8%16e-Qs3a#Khj?Cs|XZ~D4)$bVHQJ$^K<_cI^J3@U4}40hGKV2 zR%@; z{;P4k!LWPA`j$v!O=XvV&aJ}=)WIH*J(rsTdA+k&BwF>wWA;7L1rEPvtH@bF)cGiI z?ln@doFqOxwdTp~ab~BColGH`m?n0Iz1yct_YxordAaR?vEee{8Voyf8fa@$U67kA zj5;J3+~}C5kDfHPu_lL#5E7M=m;sW5Rl(%NIKTpoIBbj($_w_oEbo5xtZNH%tK?0W zH%a^N1PKABa+!=+NtS;4WN7S4Nz;pxi+1O{`XUKkub#0&{W?lcIaMCeB(9`b@BDqb z8cOC8si>XjMO1dDi1CSNHRD{&w(LVOqu?u#8PJY}uee)F@0*>2on1H}7{CZ1BYL#Q zl?IH>WZIv#ti{o>Y@ZU?V>n|wqW8{8Q{)>HvPQ(W@X@QF3lJ*W$Oa3-eFHY)A7b)O zXR93aA+ox~i*FG#G?9#hvI0VtvM|Rj4{Jv;xnYeT@III?QNBaWbK=UTk6o3G_#- z;{Mi?_-eW0+0a^EWe^9AvWigt=bbP?0`ZeMc7a$-M8vZ@26coOy09=%5)E+{ki_9-?BZ8)UpCsj$! zSt8C9rbShATPO{rw5|bW#!dm8B6KORO22b*E&oGyH+g04@UioOPQ1oQ?Z7=y2#Kioe?jZeBE8fgGhZiqxy@#ipAq&N`p^NwVOq4&i$8H&rKm@z-DeM<-N}@}E3{z}g8w^{M9OUbGn@adG zC%u@@4>;rtLyCbMICFdZh5cSu_KJpBHeB+xM7LSdth#D$*O+GKtKuol>yEp3XVj5G zJ$$^c8uOhC{^e^^j59h3KH$ZTsE;hcN-igmKI|GVu0S8(2zxiU3TddXevJ`0(~78 z>DnPm%&ZF}>2X3#c+FF{Xy7 zSyKMOez@Q^AVmp#D{q1qV`u0yTPfNO8s@es%^BBS>;+e&JxC&SQKx1Rd)SRYbA~NU z{f9XAFkpf8FUaJu8(+5p@sabzlnR1Sz;1)*T=r{O=sAwBpCYIG%?J7WuHV!4SHjsxwMxE@;Cw9Djw{ODvmGzLo2Ii5Gx^i1&cpr>{Ik6H0R!7+Y2I@BEy!4{d`0z6lE2HgOg%$mz)O4hM z#>D;3woxJ7lTb2D%P%{dK04d~`n|(lcIuwxaCMKq1(45rKHL<#mSqG`EX=b$;CosR z0?@Q1Yg|(~7{|@!qa!uHJ{Hg9U654SFcOs}vvAQD@zbY@)7S_~gxRKcryf&^qOHdx zNmU~!GSEbFfa>IDH0OkIV%&O`TkyK<57VN%r*_ox5W+}Ee8UDiMM<<+xrC&@rc-;} zJ-Pq0@p`wdauY{~J8K^JGloiXQ9KFnl9QHMJAyb4fMaAHxGa&7gQLJv#l5Uijp?le zF;Zqgry17@ohov!pvv!Yu1jO8_D!nc$+yzWbTHU6dWFc^NCRwG6L`>D2!FvfHlN9S zN4wAn%<92+C4VmL$W-K4KaN`#5l4~ejcXb zMYJ>M_NrO_%Cch~hu8Y!&idr*_IHcBMh&qUp=05C6o0aETpb#eTBAdnPp@E#@n=?P zNzo!8Z~CBcHZWSabsPYo6x2gw;G0M&)7JE{Q(rI}3Y*fT=iBe{T*wU~5sk5+`HVy; z{2$_QLtrV54IJP}%p;MfAWMe?3~@Jy1P)XQ3h-~QD9WZq9%%d|%T+KL&VYC^B@;0w z{XvG2Lb?>ATPrsr5kr*%+b0WC5<2pFI_W5t5hZ+A@8Lyyx^3Wp%-@yn?P)j zg%;{be}~p1-kdgJPfid;O7EL{UIKhyCI*3*R#!dn_pgGiGjAW9=CQkfVUvIM`0~gP zwvxvR0zE0}j4_!Q@&4vQ5)0X7da+uz`U!%f$+$|Xlpqez5{~$gg77r0urczL>^(*c zdlZ&4pwa~!6&+dwuaC9#^&N%a&U>>uWid_fc#Ldgdv(NU1y)?^yyJ$rP@O6=y_}ai zS|w6^O6rKwTEjHHwm6rX$K<@@_Qxc9s-5%QWol=#{&CWZcdn%!O^)I(8s5J)zc^{U zuFPmKx?`j{(j%`VxCMb6<(0i(2yNe~rBzAsptOuf+0 zExz|mDtq5+T;dwYhsCsJ!%)Py z&L%TFtD|pf)~+acwsZaG52D`jPlW01Z8aTmYN0{}Kl_s6#eR>gUx$hX_nzFB ztMtczR1&ne*F`de_?5X+ME!3K*)Ij^>H|_2VW2-8s}4c2-(BP-5kjDxO*NqSa}@wF z%<*5NVrAQ~N=Ve(#!Qg&6co?bscs$l#zvZoHuyA#ZAoN9z9& zM-EZp8m&mOfgm@Tg2F;W^%_TR7WM3lgLrI?kKt(SFt^0MMqddk**n_OWZ>6GRx_$Q zFYQJM2T~%UWX$!o9-1gsgm&cGG# z8VIU}C}xShikJM{4m=!fN2zIFt)Q;l1VGW~m9 zq!q_`2~w{MzeyyBhh!qyYK2&1up3fM{3yVdYWhMM4a?i1c#8t7ym zn?}b@u7O`HUoCa{MenNP#xTOt@j8KXv98X_7m={Z5h8h-LJ+mQtSRfM$gNl1V{Rro z{f=Dj>Tz%TL%-Ny@r#Yc1cpLNm}ic0&v!;4k!_V~a$GwAQi>cjHlN(YV0H{ZcWTRQ z4aWrB=QnNx}CF1*TIe zau~EU8W%djma6B6U=BodDgO9&+qryTX@md^TM8R%Z=N?9qoApQ6L|H{Fy%?k#qVqT zC?j!d@G^#0DQ$xbKEMhxF@iC2P-&965{L$4zhgp&Mk9K+U#ycxn;f&C8^?F(aGcKk zw@$+jgBvu_om*ZiY?V4}R#+~g9UNrU{)XPG>P985b%*wFM_hT<<64mB6eP)7R zhfd~`d7m(M9zymWsV7ac6%JBt8xDwHne{SLHODguR9sO}IwkUWtJO5U#o$O06h0!S zx)2Kg7^IvjgN${Fgo-WC~%2_^;FL^3Jn3k4k^wlZbgp5i8+>%y7^_iAhIH5h{mZd7$!D9IS{*2JEakX zk=WQ1=+e}ywfF8cRUobFC<bs6VaOQM77|NVQl_Yu&e06@9VAj!JB5SWwiVN7+JRBfYc=!}R|x`R;=5fYVj zx){g*Z9PEaILOJq> z68Ooyjp$WHDc_L`wI1QW)668)tePX;#{Ny+Cdz%m#?Ox8`#IgKFj9x1H7o_e@HQ8Q zcr!^J8goPpE+cxKc{?*_rRsCgU@TWvw>V0#^WTSTJ|~Uui<-%jeBoDI6&Etl0!|}; zqRjtSOaZ{}mj6M!IdaN@#f;t_BRAZxs@x5Uj2&{|o_LxF?fz957DrvS_YrnF+r zkeuKn#*MF*2p!DAIvt|JVa+cLvpKs(DJEua56utQ`*9dHEogmQpx;l{Fj?os`> zqj>r80mzh{g~iC7%<3PXn?cXx0nO1G=(P04ZEZa`P+K}Mml4T=>#<9WM+@&L#u=%d z3NO2vA$8}-dUK7!QxiE9W%f`SU5d&1P*9i7ksjDK z;qOr}A#mbTMpW?A1WzwK)gh$hrOoGR!rWWi>&x-@RBV^T-Op6AM3@9$l+aEbo z9db^C_rtcg2LX}L2%aCtF2|MEjka+g0OFvcjz%Mc$BohH*&Jk#!r(DS?nsBZHPEJ> z{&Uas6Ql~RG?|8?{(1$^L4%zN{Fe;!$cL4-lvU=7)5H>qRPE4=wgN%N$O%RgVo;#- z>&C%|vxj(-=~oO#YkHg2+RhA&^P&D6dz4bIKAcd7`B{%flD1FC1gsajG}aJQSWbk* zaQ_!2Lepik@y0A^9;I;cpVNTqnG}SEL5+iBY6yx*yfGoRNxQ5LyYHpNNHtGlcO1&_ z!iZ>A7&~yt)4Ju}*qvXAACXzO;di!m84Cny%r7jEJyjLtoL24SYR(7X`b{wBD)v-o zQe~-`Q<+Km3dxD>Iluoc&n*`NKwrz4)=1`Tk^{d2J^NU&+-mAW-CK3c5lZq=Yy+3l(3j4pp~$!x6YR9F-X_)Oil^p6wbyd6B`bF7XbO-GcofNF^k6 z3W+g%oCQUcnO(H8sgfDnoGTaC$G{sZgNQ^P=qzF|z`XRiXq}++TkcdMIv4p)WV(Db zA+)_iB;-S0*AUuRqNjCvO--VYW|q}krVOJg9Si-6mOTXTr@)T6e;*d*6}2jV+X=Bo ztLLjU8g$Qm@{TsPzm>~8JJ_8sp2TeqQk4>hKvxb(z^EzXv4~qsoUkF0q!)%ac^e)W zX1Ax|>EMmh_+D6(S?R{%x!*XZJfJ}J+Ej*+Vh;>B>EOiGunxR}hi$WyQ1-haFGU5) z3z`0U(~I;G7<~;k^`4KbxtF63+2##4I?5M?h%QNWXW}j|1YKHHG^c&xoJGpIvx2`ONHFd~eYIr4zHs~(UO6p3c7d@q~Rj0fy}stH>PtE&2|)6q6pQ+ahruCijNKMfiUIF zKv!G*8-O z+K4|ce3NFz&L?`_xlEL|AUHIY-^O(!DsZ~(;=omX1z(oe0y8Eiu}+#`^E0r%HRJ8# zf!Oo1Ynq6*zHu%J&F*#>V@*@A~By=EZY2yRIJM0@zZ$z z-JgH0Jv3DlcvMmhwA*Y`e4!&bbMCg;w#g))vaU#&(Q9)Qy`(0lRmCJ)9u4YUIw$(P zmdDzrcidRwgl96ptVE2tt}OQY3v-WmdMmrHhm(ZnPH~pxgaF{Syp#`PhEcFvDd@q= zj6k{;0p*UGmXKk%0dLrrsC+)`Z@HRv41F<;p)fS{)yJ_D@+CH{8;MQFIN4^w%)*=? z3sGX~9t?l>xum0imA_OKf90g@UA-RNPpy$(>exq7InrqHNoyB4>lCX4A*vTdVwdl? zJ2N2M8CpnZjX?47jEP{(VEhBmYz$p(*&P1wH;G0e%+Y?sQ&C-PmkDrXc!bSsHnSZvrdwqJ@*AM%Z8JjH! zVvg0c2r$O!K#f$wTaydTGwOQ3+iW)^ZtT}`q#(GDZTTI^?H(}uvD)W2{i!d$#yhRb zBRjhgy)Z^5uq%*i#?tYnm7kzjqpvr;w`r z`h<5R96G)ir*3nYFyjIYOgazV@JL(=ts;f{GoAuw>qhT}A(m3tdTFX4O+EKEBme(( zyC7r307OaCNP7h%Gg^OLD=+;7VcbE&ddT}K&X+H3B~@2DMPJqKi5Graa=8t}HJ8Br zi)6^~p>bXk&#yB5$0Wv^Cs}xO1>FzXpdLz+b)goow{p>`lo=yG4fD<^Pm0g3d|bY# z7f^toQMP%ekUy*E%WYmlPEc%ae=athYF4($wnnQ&)>5a=i3`Ljw(?w3!=jpz1+8)B zN9yTeN`eLC=jL&W>GTt5Y4*^W9HXc--pbY1mJ2%yECo+qdkgUl+b4wImEXT#6U2WH zD)`R2cz<<$BM&~`HAF7LM2TrZ%N2h}u6Zs;!2QIQ?1%FZRA-%2Y+Cuq7u zc`JclS`WDKiIoeTZ1E&Zkv1Eg=+yVsE!I=z%Y-$DupO->u?7pywZuu_UY!1d=s&Cr zU;etXw+u_nWf*#DWf8=}$9s%`KEW%3g4UOwH%_P3U-?^%ub91#sxVr^TIG`}No^{A z{Pjx#}WETqFp8!U$sd1o4xK6H+TL6`GPGN;+?kNVQK;Z$)1@ zr_pY?I235O!*+Ax=WGdZ$vkXv`fgaC|60Z(RTk+kz{--*4+^|2f(5WgV{$KPUUgH$ z7;=aM0PyGT70pUm%>W%XViL9?bdWcp@*K3x$P^W+&cyjtRt$1d4L5cMx-0U3!zw`- z&2K|J4-^I0s5*#bHOf&d*3HC`12=4u%Rws&J&z4@p8wun$XJ3h{5PUBa6Ad0%5wd& zCap!r1b$w)O*1!3R%(6&K~T6XCmJa~MbDj3SRXW|W;F6B5la=?%BqJZx2zgGxW5z8 z_n2SwO=R>)=I=MhWysOjsl5-wPsaCW+r@F=ge)g0rhkea#&;nADAr4CB?f(f=V}R# zf%mO1R?_RPBcw*ti?gzUQI5RgFNhQFvsgw>l31#GcLrv>dC2^ldZWYsjkocB@jC+-`SkRNC`-2p{W2p-QsjNQeE)cFu3M>aJrWhKIVQe% zdhH%ZKbEiQPJAHuSA|HLSrr42C@gbxPtyR0qs)N=ZiEaf_ zbB-)?SO%b+CvWXYuFG!Va!h5RQ*>VfQ4>jDbO(q-pfF%dqv{$@A{q48+~lB#bNzpO zZuo_~;5%)NEi_Dfpu7m#D~u!`oM%g zQ5T6??@hPX>RiIOeW`aH+~4kEuYbMhfA1x#NjH-ASoQI0-;9i;LWwrz$(ogEd7l1( z{>BJP4cUkSa2IOV&w9r~S6Fzkh!F-tBD{2F887Tm9;a+tGAq~?|B+`(8%n>}fVsb$ zCPrpAShtCywnC)x#ZjbEd=;T7$I7}^F-+q0KVAW&Ur2`$B%bmeOv-O_QTK{O3i1k(%1wQe@Z= zyeAzh;OV2w0p$Nl#ZQVfLk4?jX=_dShZj)>CT%zCZBqO9YODkOmew`UKwf4xV8#Kr zxo+d~@lj_zNW69Ox$*YGG5MD_i}3nPk(m>gFI zgKN575l4!f3k}W?H7jRtp3&Md%%~4$U);$7!D7bpqOR% zp%HULDwts+>R$vg%4b-^nWFOZ44WEgR#qorBIpN#Q`|3g=#|3nD!zbSn+?c3)9 z_(%zM0)HXt?m_747Fh|ni8dr_xf@9a? zCV9~)l5`smi%beCu9j0k^vnH7+u`;CJ9KGGac#CN$A7yM5HDkA+6CvBwQgFEe-5cQ zNcfoM*_+EEBtwC|N;;cn^rX%z_Cvi9cHN*V*|~ zEzZAE&EEN8^-qd)^%#@fKtY5imFE@L;J4K69l?Jm`nMMWUq0tvEL%KH`}vGTZPKK6 zgx+OI_xu5_!#0NiYKJk4DTt_7T*$*Duq;C9RbpWtF`<}qej!CA*t_N3l^(~^$4MT* zX4F&*Fk0P-r+T&4XJb}_CYOCUO>DHY_E{R-?2v{{OiLwFN~pEnMkqi)Y7a`=1QdVT z{IL5gn%B*)p`UG*9(Ra?jMma8K7l8HRj?AM%a!4#f#Kk&)0=7Gt=C7V7%V6%L0(Yn zIRVlD@LU5(}n$|NT?i{x_PObWhle&9tf- z;VS0$hgpUR0|0@VF}rL0@s!q!v_y#*WdqEE&8deD&bd@qfAeR3#(&+Iid(qohz}{? z6u2fk6sjvF>?)e0&Qk+;xpuitSfO5W0A0*ncvAQufta>dwR4rFZ&7}xQVi%k{$l-k z*RxV980r1kBV}ihkR?0hAMu*(?NrP1-8~Y&mT*+i&scE#Imt46&X#6*;szdj6_TY& zz9!OJkzh~_M|mO-lwip9VX1b?=wzQzZ0M^}K@Y>KFe8WB(b6q)(gUDhE1{*UFZfV4 zWGEd_5SvUhLwo9Aw%a%AFO$r_;o@HB*+_?SPOHP@6s3%~a?ZyccH{JDvzKWBmr->S zij4+ze)!gv;^bPhl)a<5t6;Y;6CGicX_2N1G<$8{>`8lvrqL*N4Tlo+w6bC%(Ir=| zQ3MI4m8Mo0aVv&m>Rf%8R)F{PzB1p10zEXGLuhI&AXBILmw8D@^6_?2bmu=Our znArjr$~xnM34L+}nt}fi zM+$(|GF*oonchWQyqQ46zL-#MHVN!gVT7#z84bMn<%z=S4B!3?#Bqu>pH>3T~Ap4o|?sC2z zsC3;h`zE6IgR^ak)(&e565z(ItBFAYtGNYA)fB^{DT38;MiimV=0BX^C8o4lH{N}p)lv?7To{DyW;CY}m#>I;#__4WE zh4H{7VtIW2(Sxg@F|$ToQjv$q<63JDQv}5!@C}(SfCsB>#t}b^&)Qd-iDPTBx;ak_ z0PtUvOf#+fGmn7_MPGx38_bCd8)kZc>qrlZkQ(6)KFvr^CajKN;4}`9el#;~t; z7i#!l7>{e}c|MC-l(9MlasP46jQ>sFB{x}KJ;@(lC((NGYH>>&xOp!SS4d!WT9JZpdSc^pyy?0xKrOgnG!AXGl(%MFGO#R z$sCO;o2|Zas_zv13(&ZBI_l4GYYzOzU6$LsBu#D7hCL(JUbXW5SEiEzV;W|r5iB5yc-JDPH^Phe&6msj; zN`MkHjZkavaB*ijnJWoKyztnMfD}e2xU<5am}A0wZ7W52AbFM%cxo$AOS@|kcPMuh^2-BQLvKl(#`hMEaOPw$aqJ-JdZnt<_aVnmt0}Zc5J+dQdN)=n;wk#McQ_4_fZqnpkFGI(Kp% zvHQA+T4NEPlZcmT6PmUste3+6FnETi$S?KS;}nAd4OHG7n>PGhS*u4?+WuedK@5Qv zG}~}Mku;C2+c2@Bw^mC{b-N_+iW6b}?G=u8Mu9}89y$A!<*_NpTNEZHm6F{kMbtDj%VBN!XDjlQp+E2;UwBe53)m?t!c`6yFVgy=y);3)djIL@;*#T<3%{Q! zb-Zu+F>$3-^yFW^%5R1mtF}n?KrT z7nS@qc4|a^J^y}io1KfS4Mgy-(211Pz>-z!Sp*?j+Q5-Uqp}OQM&hGkS+~KSMLV_R zy@<>S3;vT*^8aqWW~K*Z0cZvsW#v{`V|#A#TX`A?on&!rrsEj*{7rA%qjDk!7|z;5 zwS5Z0&)GI_q*gR2#BQ4=L<#ovrUbq=CtQM6f(v-qH9k$^H_z^V@7+3|GGpi8il`%~_@ni{2ysoG zLUI|?hly?sS~U@bTEFok=@p2jQeh8LeOR|{){qu6L<_`uP$)8=yktYipiHv!jhj{` z+=o#FXNl{ENzp1g8LXGTosaKT7c6nU^?vKVld05Cs7-^z2>GRtt?D>ex#80NAL2*= z@HM7dFl@>LF||x45av$}F&+|);sudZIC(x%cHL`_FzH>Urgb^a)ynBv9mtG+J^Vg9 z17w2YBWtbZi_HfO{l*DMwNXn8XZ_8Fds!)d{@D7+kgw^C81^*x_fk?V^7KAtdJCn$ zK;it4{UOI&_`Yf$XRiJFtTov@^Q7wdgfuVT+O%wZxq$bZn4@y@kC4W0bUCYGN*X05 zKJHq%cUoJDQv=0Px$fHM#z-fxe*RJRnAXA8_}_7ZgbcY5h8m-CW_k$69~MuSfEFm7 ziii=`YUe@Z{=3tI0~LmCnHcvmTR@+(*-PB@eu;9Tfp@brqeiH-wJVSgO-8k#RgN%4 zse2jzBIg)&{LiljlIM+#(lX=6e|8yG8(Hsyp10oxe|>Y`B>UXqKFyXXDL;HmTB%GH zEkU)Lz*FSe)cyQZzx&FE3ILn!#Yv*jiBYK-vf}cIy5+Z?2;qAE&l44JlQVuhmj)QyJASUCVXXfAOiyt*{0e{>H zjm9P4>pe*%a#ir2U6h_r*#1_UQZ{4lS|(ZPB^>QwJJFApwJ5(+(~919*TqgBT0+uv zoww0bEJCZ1chf@#eNow8)lkGTDvVAU1u7#X1pMQ1^!$mI!OTu>p%>n@h30aPZnNM= zk@2dXaN%*$dy>1fecC(i9bEKXf9>J>jM7A3CBkmruEq;1e1Q$rIyU9Kx7rgLv%JA> z6ryVP#L(KWAf(&D2EjvuHkb+GzDF1xww|oH8N2Y$Q4taV0Dx|NwMh(?x!b(T?*D3B zzJ&pVYhFlo$X9{TBUnoDPW3>v$X>{t zylS=7mRbGG&XUhKa&rSWHIkh2@QB6TYOWK>4(J1}ju_KPorjB=#71_O)2(X;l&&IL zQPHC`qB`(6j(ul9QcSMW3X{RfZXmN82clchpF|O2p-_!eSr!yl`S^UyW zTKlw^aZ>;QpLbN<)n2P4{Lu5(iT91Aj(Dt)gpj#A+)<~RABmO`()Qbwjx7>Gc~FBWKa|5_ zuyHK83j#ZTONlS&Npsfna#l4gyj@Cks{nCtFqnr7Uo9-Mh1XeDu$Zfo4)XFoH?z1sEcet3C@7Lu#c1pAC{92LJD;RD@EoZQ8hMmaDU*ui4 z>bb8oA$zA>*43#^Y$@S#`|@5cn+Ric*ueKv9VgNkH;nZPb6({gI9E}pO&w|j8Q04GEh>7++ArS&32DbNvX;X@Clz6R&p|? z-}zJZSoK%Ft}eqbCg`6VR2IJX84%p-j22v$t46FO@y3y=h%U`-4Ux2n0Vtp=^GKVP zWFmN42(ax=Wj<}ecpy!5o9rS*5n7<@3*i?xHoSvQ}F?8F_itx3jpumJ; zoXA5UX!V!4?o+%?jl;2a$Y8O*(P{IyPPRRA=zoFZ{Q#yC!&QohVg;Yj_E{?#VDh==_4k?ge2N^U;IXu<7Ds|L74+An8dg4T^@O+_@yUwA5{W{!THDAL zInvlJ2qYYHFSfe+dOy=mK7Q`EQpan0jz*=hV=mjh6v)G-HnvZ(3vD*({+HHOzE6mP zTzvXa!D(Ga?ctM1@kc>5*XiG}OVC(>{C5evh(Nyxbq+8CF=~{BPxudAoRy04%4Mb=MV+*;VfHJD!w2(ze{YM^{zDv2 zIPBs7myHEaT{uBzNURz+%LI0hL2`N);V4Q!qn|=m#k#@Ev(tA;$39ed@m{QSBuT_= z_GYzGM6BQ|NX2X%T6f0^uptrC(babR5eC-FDxHLH(Xz~Vb!;+5YDyBjBX8g)fC}9! zjMB`QXg$?_!ZNt{JpIHxjAweTJ*F)W59{bCLPfI~W=RmP9QzSx-MBJNkzzQHsm%bU zz+Wv^dlA;pr*^>^c~bi2w(NKP&hzKSwVwS)4dIUn2T2hHal(5C}n-F-^l?GHFxYar#c4kOi+^sC_NbDH#(gA)(Z+mYL;UxA+s@1Ry4 zCA-ec6VdW2GNBcan>jRumG^F?e%S%(LFHkA_wn@NOUbE=P zeR1}Z!|7lLDYY$W^2{vjA()TSIToM{3TWkq9`7tD{p$RZw}_KTt0U8t8Tq} zf!6ypNvIiPz`sxyz=KEQF~or0pW|MBgsb~z+f%TB^T1ecFyKVda{`bQ12FAvA57`n zx>u%CgaF(JOmiz%UByGm1bDtz(-A;N^IC^}$iZ9O<4f@I=to?#t8v$tCd_Ui`e%`!)@oYGsg)Q?JR*WO5 z9oZ9^PbR$2FxGM)c=dJ~BL5KS0T(ia*$Zec=w6rvxLl-bSxRzZAkfok$9xJ0nL=|z zHyTxTV_+>$%qycr^5ADBspvoI%j2`mr*5a@}pu-tutw5k)ZKdd9@BEOO~4MJz;8&igr!fYHz zSLaLRkA0)9my)yFH>jvk&q5%Pt1w9ArzTz`=FQ1LSm#>G$s(*+)VVI7FZd5}3}H0F zdioY9T&fAk5X1qKG|mjn5;!mi@3`!bqR?}$;Yw3sY2Cw)ZlCNM8l3{}`LEx6HhnjL zy+4zV@^_{EoL1>+?RYbJ$?7zGL72x)ra9s}ke4Q;000ozS}{tImT{p!VDrb>M#3Wi{u8;|+2pz-3eUW<&za5Rz$1M!IB1khtQ`eVvdO8z*6v;?TM3vA@9n zwE}NSJk+wD)ztoGPyVHap^>s8UIFUi(jHnNbSInOKd0>S)^Zmt&DLQQ zWCC|9xs4H&-!>VxLW$|&HFdm^5y3up}tbRTQsOco4Bb645 z*&(5a6@v~5(Wx{N2-h$jA)$m}qjYZYicD_Rp$B*$z0M6FtMG>~wOJn%ca@|km?Rc2 zZ(cvAOiB_{OFp#72(=p1mDT-8479CXr=qz?|J+u51Woa4r#^$y85#bBd>w2xqYryD z_*Hm4b!oUww|Lyp&7X^a5CDAhbcHm98-S58wD`B5B4#Qs;lj1ud1G<1gy-kqPDT4B z9V`t^*$rL-jYF0rMe^8Z>7UbL1$#IP&gfu<5&@uR5^ z{HCX6tpALTaCrE+)=-2#&RjoVjs-fgfK1qIse!JlLJ)80oVIlIfN2Y7UhVX;l{JHV zyIm^1;HZ+;{vX@Z{Nvw*Ij;zoZQm1U{C?ff#IR!0v;7wYXyLlm3rm(Jq3C5&xCrYQ zkZ2w3UV^l>sZljP799-WJa4Ow3Od0|b^iUER`612*s6m9exjrbvLA&b>WDg)qgz zUNQX^%lS&e$vIbzkrl5}w~_~_5E9vTB(%|p)mMJLAYYcaNTF+z|&bOc|Gi?(q@Pe zX^QRyR&-37X;<5H&#WLJ^9)xlYjfFsdCoG%rs-LgdP>5Nh8`mo4VNH;?^j}_-!$w; z!wUBvGPG6SWz4u04fgJJr@T7+$sVWbT#|8J5R{CIz*5~F35!bW`56AJ->j2+o7c03 zkgL@ZwNPZmAna*{Nk|ghxI{@PHKHmrYH`(l!3W=&I2&Myk|7VfIEm5Bj+!n-i~m!U z7M@ahD6uyEo53|S<5kiP6o;E^5ivmEWgy6b2qlz7{zJu|wbIfoM0PS`~MxXHIk zQ}UCtsrVUbrG_5Q@F3k#(Q8`zZ}pFo0@sSB;(QG(CM1{5-esIGMhR5&MJOL>Yi`4t z-}WkkWU(h@akvopVva4#tRh^r;IRCcx=GAcxDtcb6IUm;OS7b|CQqoqa%UchiQN1$ zcHcH)Gh6ZHl%5zJjJ z(*SB+PM&Zlv&rgv@t#19XrD#Sgm$AYHL85=*Xf$x_GGR1k%|q@jahI11v?qH&315kcS?&OvI;_A&^h#VO~p}8-V48@|(8?SMmH=<0+7vsay*76EK^Gv)OtX z#V;imsyOcQ8!F6NgJmj!fMII8*g<2d-2?6ssm5TgLRn8>1yn_449>G+)^}@oN03t!%z9j3LM5bUdq;PqXnfg%V)lgXbmeL<)wPGu77-{H$t%&8+?UK%+a&}+TsAP^Ns##|5q9L2iKon)KCsI#`q}?^7 zMrQQ{C)7$k)?yyFxxblQtnPc4I7P`dy2}mYakQkyOr{m|bU*Kbt7Aj}00GS&3kWa;%;)d?32?Ml4UbCt zIoWS^6(|WO`>>PA@%`%KHjogMJa!ab>JA4Z;^MY*B^|INlhUIA#=MAG<)9g59>0Tc>46=%Af<&9uB7Hw z{?pKQiU0rrxm~k?4hHg$BJkoEgb1c+?6Fl264&;YPp_OLIIb!ol8cr|T{Ogr49;ql z$h2U%^`vJ&@tMJA*f~-q!tE)?DxN}V<*Jusvs%Q%QRwAC2~-XsBCwzeErQS?R9;nR zAfXwsPq61uZGRVAllW)okhk=~YJG}iUyZu8P^E~ZC}C!_#FG)jv{5H)`#el?~n{-G)Els)F9km8*L!T&%dUXZ!9x zc)hlS0b5!*J7EJ)lV<#Bw4=x*R%F!1sCg2Tm`IElq-r6EyBomAn30Q2lYYkW(5q3b ziDi%U8IqSvP_Yaj`32&#>q4s2#~pzfMlpk8iGea-hVZHsydpbi00EyQD*;huVNy=p zyBB?;?@FSij9Hkx$j>Fs4Oem`E1@XgOF=~E z|G=Kr!;t_00LyL;vEn8$mi$);u2fRCj{z~0tt_VFFnxI0ZDTHq<3UvEfVd7~mn>}L zW-)DMGLxtB!PbWwrO@wkTqQ(-1gUdYJRyjAHLIlia&^JAojEFimu1^LYBj2E`>UCj z-9d-{`_Ke4fCeUHR!w2x0E~-kO{^>cUYVI;xtst4#j`8FF`xj5GavVLDzRLievf?_ zz1iZdPrZKqSXY)9vk7 zSHG>u!i48rSf1PWDbzwvmdx92D?Cfyom}l+Djw!Sjg{rhZ=oFg%ciH;-{!gcx#})! zH@HgeM|V#ZCcm+q>VPsYC$=(CDG*Ua2;H>3rkKidEYOJ46qAtvQ0Z_=I2x43J|Zu& zXqe&_17Lw|0A|)wktxdwaLcd&qVYzz?SQ$B9s+Tk#e{eq;^#D|38=2yGKJ?OX0O6) zp%g{jhNQ}ZvpsiM(^!8YFiqIxeYng&QP_k{sZ&ecH+}o1cq7mw#{k0`u@6IAnX!a+ zf*qTdUxY>=y0YHFY|c+iKvknux2#>6kw)>qUUM0A^bsqw^q1$d`xTs+?OPblTlS04)O^DK8K`N>5+&CX51xWjQ7MpZkV%T!nQggW+KmG`l(V{(4gn|%=x zAv9$(Z>&2pN9IPLYUMteGFZHb)X~&h1yfh;k|?`|sG-*bYVA3$wWZqnuS)GH^kz`} zH2uVVc*W^l>Pn6rW%hfwNkJfX97)@830$J=8CD*kbz99p^=abN^6Jd0L4|2Xog0*r z8SY`0GKcSx8#QWN&edymsk`;=#^#zUA zl>DieW$z9U-8{si&AK~yVXShNQOfA*RgvY$*13O50$qhd1OR{qdN2cuh=z@uVxu=h zD4YO+fr*lr#KD(Xbe|#wRUV3n!j5IHbB2sWM9y5WTSqTCkETMLGPWNlkw8iAw9tJC z>a4?1PU`>r-~=ZC2vcTQ&T9Yx2yGi3&0qi-36)=+mw*Fmv@2(_@Bl8>?5qr`vY0Pc zK!V9Ckj@)eOi1;q_*(RYKWI4D9Yw^m6A3WXi}KMKqZ8b!U2Z7X7=r|kdbGY@D!m$&R+@$(_?!j3Bo4FmuH01yBO0s{sn3?OQ-0E3$$q8etnNyuc* z$%>}?hYkoqrI?^pym}CQ0Bv1^A!GF2U{{$s+f{^Sl69h(33nTpvNZ=zb{$UTz-mdm zrUV4uB}F3GKrq12$t}}CyFW9tF#51RFM6bDkvO`bO=V+D*0RqWnH?@xImi?Wln&sCYKdGZqaMj+8+@B4r*iTfh(|K9 zor)AacLikVIMS=7(qTaRpe;oE3-~N zwM1mC=6xD@D-F(EX7RD-haUb~K&GJY*4KHh!?h=Qi^r2w&jwxNG3!k=JhB#{N}JJk4(qsm>E3G>sgb4v;Y7Ak(AV=^voeJH>Loj1*L-k3_JoeY}SB5Co}A! zx<=R~2KI|_rd$+YeomKS{y|6LRkcb$i{Ut2qK9El#^5$nfnIcs;&G-CbwiY+bXv}` zR{*~=DpZf9owW;LTY!l?nAarqy%IMxx1_7X53TglQumnT^CM{uCTQ5v-%1kQQW$b>P=L5ZOQtYHl4%Kx zI@In?9-sgWWXaGZWNaL1BSFk5o3vzx~RngQg z?v9X+sJZNuPN)fpPbrp4l2{&v(8B=13T`?YhndP~#GNAyMO`5#nYuU%!{I>Gg_dvJ z(MzOu(g4i?aDQh>EC~X`A?V<|N)=RcJ0%Vyj21I^pD(URwE35FQtR5m@)~AJ>MV4= z4~mKF3rFxwd$Q7tGTbYDxM}!&+!fkg=Xnb$d~w~b^>ZuMwq-5Nm{)K)9tU(UPl<1$eVZ*f50zoON(q6b+LSlZe9UxeIO* z8ahHLLP9A=sMdyUI%gKZYrw8zR182s1{BbvQN0O#D+M}b5Uk(k=a;kdl1Cy8glq7LjwBgAi4O_*w9Z++^ zMtN6A*Ed`zCv9r+DSHLfrM8_31XSe;w9X>49%+A}{`4%CL;8tpH3NIZG_vmgqT5g3BLVj|1GBr9nu# zhUS>-ys-`n8>D%&q^&^C*^4PpL?8AGSg-$)_bD zr{f~E?Cq)3B@HxG$_FDg3pgFIOmO84%f!jC;JPcW$S*svrOWE?mWsDlzC0255)@#92@~%)6Fj zP_PRFVNNb>SRPVOnGBb~T&(Qzi&Yrh^o5rhK@x08vNtbf9DqpNQjuc1`(cDo?-=u# zMl3ZD=JcFHF=L`E^Em5~yk!K;3w32EaD^=++>PnfR}Yya%*_1Gk)WlqGTCC{h*2e% zRyJy7QxJe4Cu$Z{(qgPkh0lTw`?qC9w<+_OiU&L+~r9x%v@wcsOQRt{uw-!Yiw zbt67oksdd!Tw*y;Ot4ygnfo&Q_{mM+|Mn(pOR~F6N~~NNx_O( zG|lY_B@E?_(NIVLgy!|`N*G`q_Y5Kf0Tmmq2~pP}E8hbHVO%3|Ag__9DeYma3Cm2v zx;S06*R-{$S@qHDzkCTpsfbWulLy2Iq?9^}5LYJkWEh?rxn@9u%>!LYIW0c8*0CH2 zl39{c(({4lLkvn|us8b{@NeikNbCl@A9z}*A9aumkU$qpXfYKjI00#o1^iOPL|cre zIJkR5BBzp8qk}h13Od>v;SE=r(w3gD|qdh6W0se zJSi7rD5W!bVHpw3X9tm~qKKC+Sw-zecvFcJqup$H5;~t!j|`nKOICFH;?QQ4@`{yt z0^?ev<&WYM*P;{jvpmBLHoBAOdNkctD~8V~QXP79u!^Y>^gF(>D85RU0KUeR3#3LIPpaT6}siKVM&-oTnnw zIXHu{jtsv1?FW;NG;L`{e$Na#*n7QPk3p%odYi&ST$zzm(v73XTg~^^Gjq7qNu=X} zyT(xXRZHe!0xtGUm665*$ApZnL&RRJLY0JthCEM%k@NQD6f5Q3=|TSD}v zvcE|7-v_C#R)%2bDZG~I|NFoM6M_baT-HM`W}<|v3w>dOZWM8KV~jA-!tbl=afhOK zmF9z7m+}`CYYin7);gNFmafFvb7PaKL|v~uBqA*NT8l*@lJrtgeGp~^IljDDkHbKd zT`bupeXj_J8Dvb)8CE^0ZW3_v;q9Kg^kWSU+QR9P=Xu9S)F4I;-BO&alRMDtt z2f_kjkzvz>^dDO}J~>{aA8lg}s@pLOduvy3joWgJ!|!!ntz37hcz+_utC#r`np!PC z5i(qFA5-$Iey3gE|N8lD>}ZexDcuAXOoS!cKx=@7>quaZLkmx~!tFk*3IWS22zF9; z`oh{U!Xy4zpI2jkvIPZ-KMG1$BZa;1iDW$D6{^s}jb7Lep~4^vW0jk{ntd~%F;I!0CF0#|3c-DKH<09(WqCts^99AFvk!sb$WSW6C@)Gf z;7Fe;S#T}y5oTyd%JZytrrA$Y{)RxUP6RyhW*-S7Sm#<|RhW({M~rRwVq<)kI#!h{ zOQxhNOAihLV5f@h_7>?K%~0D{D34s?I93B2{j;{KFw{V)gIQ53LjsP&T}g*xQej~t zGkDsW2Q0!${aeCTJju|A(Cc0Ziy0mcv~ZEzzwD}QYiIxf0J)$-%T&Y>8GV5gyw*|@ z5&c7(gC%~!M#~0E%c`mELCYQg`>+HQf&?#ITWbt6V1-MIU11}9S4o{+Y%qR;3odQ- zgAQq3M&)8vOQ7ntjPuM|=iwf5y?Z!3X(zSWM&feX)rM0foy{k|vrT^gcXKOSe$L!H zc6_yw1v%cIyK|E5kMZ}%@BK>g`+wQk&kw%#`|7!=$QZC;O1`KmQ&q-*000V_ zJb|bb(!vzaS35;bSA|koQ(05~yJb>j3{4T3^09=G;DN@O9g&zc$;w#76lkj}*VUEq zaG|9BRi_6`Jp@Fd1sW5$kw(T$STPtX4B*U8DJXko-mXp5u;fNO={cWFxfu}Y;DiWt ztD6~=ekO*X)sF>Xj8k}l847LZ^AHo@00VJ%8?H)*a4n&eE`%};BOYXJiX$44N7{_@ zh}2R3FW}Z_8>Ol~s(YbER*lk_U6qkv~Zunw5F0-|LweT66lg}T3mR1i$ zQm*q=ylL~7zcg=IRaL)g(B0;gP$C$mBE*|56geoW4Oa#`6}U6=e|wQ;%V&Z`tEXK# z=dE#o03|!)LQgGP_##_gS&a3Qs6$Orcm-#|-YRHy|F+mBrIF92Xa*2s*!0+Bt}f1au)s-hFr(s%6M?ik#5hBGdm0rlH~cCIhMlCTA!(; zD!!vMaOQeeGbn6X;;F~1HV(5y-LId^GVZECsz3k$05w6V4rzTC1qzV`1Vy=nmU9MR zQTXY~!dM->T_LOr>c4t_RQ6R1yZ`&Z1Q!A&kY88h4@+{`?An-R>EsoybzclUEy5A2 z?KOmr_#o3c2m3QDr!ltZUCj2yQP!Ci)1^vDDFHNh!cW1xET`k<0zjzu;DJ2N+NfT2 z>j6MPRAq_MdSv1gq+($R`lSv@6uS)bEC_;wesDYq1w=@xF`8*{R>`>a8-j*0yk9D| zl-;?n7{g|Uf7eUKvo(*G6z7hV(}Pv2yJB}^R;ry>`v4#S0bwAKjtB&P1Rk{mH+2xL zK1e_Y1_>m(PvSkNqg_`{vPw8erue`OQBphQ$!AN^*>p%lQIhO6xGjw%NpRB@G@6j0 ztigsU_Sz!D779e0%;6Om!huB;lL(k==?H>YoXKQ`EzIN-5HRg6VaWe%9>f_P;db1M?-3rtEE?e5^cT8QL&1hG)dghcSQ03!$!WQS4L zxWU~vv~EhG=H_l$Is1ZHiZN;04ZnFL({7o_Ws}`7)PdSX*fLtJSjCEZF z!DNDo?x>B*vb^afJv5DHF)%o zom`y&k(i1Vri_Xa2jfKVl|!txX1NXI+_v=fui*%-b@z7bBYr)YPj~8dQ)V;Nxkutq z6t#+%82{v%?xxxRDQY1~q97AnL{T6xhw(a|*66_9Nx3uCOa{op#sf;Gl**z$tVxd} zgu3a(pz_4xd7VQv1oU*HFjZKf)@QnrgHMYoZOb=e%ec;mV(ez|u)7j@B9+fQOo#|w zwR`!Q8zbd|DaeW?kG8XkW;kP<)qL=Y zfCg1tOiwuJZrjHtP9~q`p9z*;otD(Q|NF266aXa}UfAOdMDT&i+f893d{DV@aqK+E z!UHpHH1v(|+zJE*%ZiveE5n97)~L=zlIvE&5ORd8#Dd4rQ+04Oe%E zla?-}jf;%u7Eh_V52$CyW+T5uD6$EeRC(ZD-$;9x*9~ z)SItWQ%F9So96Fccf+*YZoS5E3RNWNEWrcHR>rB6o{<0pnRWpXJ`nIY!vq0WfomiH z%@I^uh))$!!<^yNOj*YmDLO$(res!%J4RELMoEk#FSDAIk6EUak(o|N5m`OLV=uCL z5s|HCJY-W40!Oql>+t$^Ixd;cB7Y3Ybxp8ok2=DbsV{5sy=@D%VoVE+FG_`)9b+dw z4iH&&b0Z^z5&!@oB{Mj*;SeZX^=m=ZP=gz2X=tay&_Qt+h)jLt5M88=x#rkeD4%SY zS&ftm2|+%)O)DtAWwOfFI!%44K*30#{Ja1AummLl1YuuVdkHf@g(~|^VIyu=?R8lV zJu|`>FKqRMjxnQ}qn{&RHQwd{-glTQI~bB*oJ~7u;#tWNueVv-Z?fp`YhV9dB;82 zg2y;TarlrOYk-~Lz^ujsOaiYz$r0hl=D=+G3l8nN+3=qaZ z`zp@^#d5NWQl`r?SqUi0pAm6jF6D<1$;uL~PrGktNGerIwK}=E%;j@KnH=R;q?Vab z=6G=1!`RRxDE18LUmwW(})1 zDemni@|3?<3pKltbW??=vAbA>@)%mG)xC`Tz7ZDNAOHvoSm88OP_Puc zXb2=}7MnV*L#rTjrySXtJJ~lm8jIvysHqtf1f&giNNHltoiI{NOvq5uj8JIoS(M?4 zJ(x6@ohjjYY!!1s2LamJ`Y3*b2&LSH zV%Sjh*~t`@v<~`JyRqV-IMW~i00Ak0qRC4{m27FGt11B%3nX8R_BR?Xha_%NS4j(c zk(4N!I;yacOBL0$X$}~_zS{0NMOfWz*L7*RLgBTRK>fRS;r|ECgUucZp76=wfuN zv(dD7?9w{Lpk6d*Y%3|dEw_~It#PsQSATnc*Y10FZufo1zt)Y$^T?@%sXxori_EQd z3^1w~hCEe(D8k$}>nUM~{GTidF}V6OinXJqJ_ zF)O27T5W0Ey5Tl~){_w0Uec$TX7JaOnb>7%J_}kmoU~CsSt84GTf1hbB}`AARAbFs z7k8RfQkjd*aI*wg^$t#>*WaJ`$<6iibN5HrX2X@{|9tJ+w)~7~YB1!xCt@`%&9rte z*p4-9eYiV&A67wrcSh^Dsol#E46<3`C7NT@B3>@_oHqZ(01&< z%13))?TfokzQXYx^#xUZZ|(0>FEr7 z#p`%vDtKS{rq)m5?#3-djTnt9Q(QfbvJWKIK1Kigpae4jBx76Kdj>>eiVNFKVdgke zDUoOFF%QZ)uWY@BA-T33@kS`c9x*G9Tbi|sTAPcgzllElcLOGab8e*o6b8O#Xw#j7 z@|{a;0005I>ZI}pizPHy`k)~o7flM4YYM?>AqDwPg=L8UNu+?gC=fuDbOaM-yFlMy z`e9=YC^SeLCSlH~Y@Iloq4H~_&y6t4`pjyZwriCqXsMihr#Y4j6P+5gai1MHx31r% zZ|~(hm3{JWc24u+`!i?$A8X+;k#)Xn&VHb9&b#R@`u2ZWhv4QY#TM5B)4qcu>Osdb< zJD=BHff883X-|K?q_ zDi4#R|Flz^;#T7)ysoRKAAc~v1XcFUAeoU700N~=0SuZFDFRT60HZXwbtBb9w{}|` zoFFU~PSuv{lEL9UPvur&P9x<@9&nzaaenUu{e+r1O*?P$1e6t&yHnB#`t5sOhsqjRY}!=yAk?YTVT?sJ9mXGZ zlDG;3W)S(bS*IbiUJW&y!XAf988hh}xkDea&FA1jSnApNB=pf=qi|_GGIPP>r+B&z z*+8h^lo&s#XAuX82yClG1=bJ{wnK$kXl%O@6@!LD2+qBes&*O@>DJXvS?pMw2*{A1 z!-V6rblPI>&fY7>Gy(Rd5g?K#LL9Qf|5qK(8#dVT0i4WZP~bXlx!7Fwu~-+8QH^ zDkBO6NRU{u;);S)QA~*QoGUX+navrw*zAXtL}jRG2d{pJv)+z5{1 z7X~lMTbF$jNWCCd-3URp1wDyR38az<(u>j-f@S1zqLivDnu-gDN#j|$1o{+a(Sd8j z^`^}Tf@A;yN^gwFSSh+$;Smw=G3ymTQ{9@TGI6_7;qi8mkAY}PL6b~K{M)lE?1vDHfnneMcBZ z(?V%=k`TQ-`TWvAV&ba;bCI@C?AJpgR&$@A?NnJ<+e)Y>x9J7MVTIxL-%rcd`$v}j z_hH*q{qlh7@8&h{&3BV&kMau1!V;p4Lxj0i`j(0Rdm3Jip*zJ+YGVp{fw6 zLcW1mBNTgOQkWJz>${M{$s%A(sl8{9bvq4ejOT0?5Zzk;`@jSp113gXR>KcAz=;d1 zU127A7pZk$%smsr8?P;OgrVp=Gms zZ?+I;#Zk(vR+tRR1mSn)YP}9`^22~$k0#XuJljSq*BM`C(gHkmAmkyX8SwB}hb%M2 z(|Q`NZZ%j_FeiQBYR&PUO+~1=lT?jwewI`Ce8}ym>wRaA1KDAj_6r5R_OuO@I81_} z`3Jjs{&TspX&?XqCv(IiHE^L9ia(?xJ)%gHA*9V;n7pjEQ5G(kXdF1oJy30?$waIc zX?2MTGund7D!c$-9i>t@hzc!asKf>B)DpulCHG#mgtx@|mA&F~SGaLykY}{f`kquQ zkEX`kcS`qfS)z0OLwB>85LB0CckjDxUcTe)H)4fdBHfzZJh!F*1cU%U76c*4tQg23 zxr{BXvL~gTB5D>&Uxr%g$zNPusSM092T7kR&a?d}tvHO*WN!-zDKlWvB^6<&EUB>$ zG{=E&VJ@bNlxHMV0`QGbp~&@#Opf5BZKQ%0s)CAye@D!%?MxU~DNZNMh)I<)guJ#k zu4iFaFt8bf?ZYT|DAG#iRT6d_??8a4L;zsck+ciBV4 zYnWIgAxKg0QVk43f=d+Q2jQ~;m}JG;n^e)QD!DtavfWhQ2+n{DagRnErJdYurG}$!rU0T7tDNk~|V_RR7 zdSu2q!BS;v@oBP%01d&=h=yUBT$NPJ+ZuyIf>B%Q>3cvicDoEl-&l4Xlj_B|dc+GJ zr<{9UHqi)ykJ z(Qegb$|@uPG>T**BOpvbr0gddH0inlzQX}V z(HZQo5m6Iq)e;&R=Tka*5_yI?=%aCSY*uYyjkSg=n@mc>jZ0C-|NF26EP@4YUD(?X zMDTdV8*M!%cvYcgV2m((0uCnaeT0rUH*VAiD$l$!D%$(jSnIkc@Yt}e!+d7MyE820 z!JY(mR~#o*VS%DBmc>XCiPGIF1k*NJT6AxF$!0<<@ix(M_cg*rNU4WDf`dddkcK_h z)MrV5rrD`_A^-q|DP#p;49Hn{2H2bl`1U%}Vv>6sYsL9KbP2=;zRu64Cp`X*MvJU< zpG3zP_VSR@x;(bDcDi*+bC#YbbwAr8$UBw0J|3~ja*b3aL}beTN|oq@$JJ2(Nzp@n za!Dc($-xy~&vCH8%_8sr|9v#>|FjFB5JS|Jf)WrZS<}&Yt;GgT#FBmFw)L!EjM`>@AwN zN0{%sjx%4`t{7Vo2{c4QK~SHhi^`=UuoJ+}4-Y=dT|42wK|Z)6bpuo|0DwYpsv!vn z0zepX5fEiqA}XrjI_N_B#@h4e0LS3?3Q+uL?J#8hjFN#yTzZw($~cy2*?igkSYst2 zr{|4rlbw_iyZB__kJB`alV^6TUP;4p^{M4K2n2ND9r!5$=@uDpg)>vgv$WW=?NMOD zu(2a-7I`B_T7#K)FX@6eQ#2wF03am_qAfCQkOh_(JPalfxmTn?aWMC`+d6`2xO92W zHq&Yo9cE27lv;n1`dq@=Zi)?#_iPzKz>sGmOy-UrgSM(3x1&q`GkyR2paduY1Xo{M zdkHhrjcbd4V91V9jgxKcF%8Nou5C4hq48F?hQ}%M0GB!BS#wpG((+9e&KNY$sWuyu z?9Wi>|KEB!@Be+;b?5%^z3w9myqovh{rM~3PFg!Y9ZGDbriK83Q&*?(c94NblpPDp zeBn~Cg!M*d3hv6^*&I?eb_2RF86dW~IUsS43Xl|>Spu}`o_woV`9htyIyRKPFRZ4V zK7H(kq=lMLohbFf5GNBES&LsIIpPH@c&-yY1&H-v3^$-HB>7zVW7bAkiFk1E-a2bl%qvx zj#1Q9%U)_d+HMP&r8#(<_3yrT;M%mFf2$e(^A$4F>C~*J;q0KSv$u81N}mVUT}4u5 z0XIHUG}-_F01D}PPoy$}i!pc)5yghqliGnbac#P_cn&iclazUQ5Voy@MiYB*&wnVJDzE)TO^7cmQac(~!AAQ;HdQ z69yyucM01P56{pyOrk2$7?ve>JX4Zt!k3!!haU5-EtPJ1bBg=FWRh9qcOE`BjAQcA zdTjZ9Z&|S(oPp@W5bIGj`dTbgSyarN*K73tzQ6zP-u<5y`zzxwPIsfZz1Fh>v+Vv{ z8sU1;NQ|n^rUaBgF0^vil7%XlDMLt@{Jre0gcAWD;6}!~BCuid;6SP9b+`96iUPCj z2vSjLp;a{Es){a6x}5FBDeA?XIbtpB&1ERxBp!Jha?})^V?AvqQAih6VaLtgbIh%& z50A-id(_l=ohB0$&cJ`<#RzUn7M$s~h*5`woEME@0EzU_gtED!(!&>0BCmXagi z5)xdONlBOG38}!;-+O9;cMCDsQQautIH_CbJ;f4^>C0 z-*swy_kE{`qk3i1LZC3ItpQ)@3T}~ia%jd+&|OBFlEuU6Qk6%t^;krS2TjctCa^3V zi6Jb>uVbB*m{79wgp$3liTsQ99~aqv%NoX~eMwbS)Z-{mE>YCa&!nQ%7z8ehFPGYT zGiF6qK}3R6{UH!0mWBBmQ@%7t2Kp!YdD8hyr8SkUm^4^s2!`ShrL3a>h^?p~9}Nev z#mm);Swn)zJ3A+*Gg5sS-PIlLk;Zzmw9qL|YjK^_RW)WIr=d3v<>o8Pt=A|vQYJsR z`$n8uD&Uf0WhyYZ`Z7n9p~2%$8ihsPtZ@8V9vVpqzdd~&b*-gjT6lS5BEkRruml5u z1O{MS`Q{xkfU6sCV8fUZeRpl_FwIIItgUr}4mc=Dp@J|;01tsccmNbMPC!P3?3a_^ z=^&-a8bRk*D3v#+oGYe@-xpRyxHTHp7%a`+im;c~`T;*08(Q=_d--}seO@0bHk*}S zEB7)obIGAcR&e12!x0Qpmkk=J{dSIgkc!T(EcrJ4XG={;%*2Eq!lpxuu0-@+5ZR6u zOhE*K?oYuO%f=X@_zMVF>+M0%K*Sd-GP0aYz5$3+Sb?3%C+B=614^?68_1%MCRzaM zHPseNHH>p?a;(jkD9*H%R(Qc2Kn_7Iawf||%VeN(aEw-2VE-}9Hu*H;5$6pL&qW~h ziz?*4ZAF~-T=r`QrbI^^@b1a|PGu0PtYQf$1nj`;8jv8t0Z$U>CnDw@3bnGvgu@;H zB=ArbJ4g&r+I@xkvKHFCT3*!UUnJKJyrH7TdQnsgl5NY#EQmc6KB%ZO4@>RUZaYV2 zdVO|$qkryFIf}e?g5y^k2mWsV^R{DuyPe@3`P%+wYwCDo|MsQ7+wSDClq|?OKNjSR zH@)|zdsELN0D=m4Fod^lMuH+6N=7%?H^GKWrwS;}lU=6B=IEf;sysl$1#&icC=$bv zp`&9<00rT+e`HU-Vos|NF26 zAA$sBT-s|4GV*{6J6~ZVd=?3DU(7Jm!X+#0{e~HF*$t4+&)8}a-LG=}rG3*EhzLHG zK<6NgICF2f(3NG{T{2NY=1m zodS?m->!?co+Y$9t1&umIenPDt$wZ?>(IiT@_dJK=o}%Y{W4RL7NXu7&QC0}C|+(y zv(GF01e&p?X+x-Dap}w+hQ90IviO(}Ge}Qdd{I!tt@dQQ z*Lxd`u|^=$>0sD$L8Kp1eMdEpIEck7k2_*n^KMD$#B8ltsL1%%i5{`RW2osKCrgGypw#Uu z_*O8Kiew2nZ6*_p)+dfwRA$j-_ABJ={P@U7JjHm2`M(=1G53_PF)%LatJ{V&de}%O z24+G4003_3M1p}5z>ot1jZw4_T55{`HY}6}kQ~X0;Zu<74N(^kP8a*wTSpz6u@0*2 z`bD*BV_blmB7LND8yM)*JNkGvl(hSk{aM;63)GyaoKT;g^BuA8b1}5KdVPF%nSI$~ zP<=U9_1ioBdF}Ht&+h**ubuhD-o<|yTLF5*|6cA@Qv+B;K>z>%1uF&t9!R2)5cxA2 z1i4F5Wj>v$0;(|v`d0l%UN{8;35++Zky|99W6Q32#rY6{O-hmiBh!_PR34ok#uNYh zummFjBxGG$dkHi!ic4EPV8gmmiFIepB@e&2~} z*}3_SVHZf{s75nH=GpGr&;EA*_RVbHpU=3+M_aUiH23n$n{4+7%Fxc_pnU|T(k@`G zh?Ld1fB*ngt&|e76(jo0USh&+A4PUFHs=7mHJm96?|uZ7PE_A-QB&NM(_O|tdhFn7 zNWm{jsPh*5baIH|XPkW=T^ds){RE(^VOCNZNTDyK|2uE-l!?Sv-FZdSu)BPAW+tZS z4DF^=$~|LF;o|5>4i99y8egeal6Dx9#WXt?y0UV+fA6gfV9dyf01$2PL%`yo(gmX# zf5EFSZ97nXVlMLpdFCMZ2T>&SMhKkZ9*G)c!Jz8qkt-R>LrrUF50NveIh9GNIq7BQ z)Mihev&RU2c6xd$x7LvE!P>sV-#%;?i|h}uH#GH9=tQ-Fj4;{i<{*mMJNQcG?Xi;l zHu9FYMaK5_sj!sW$JoQHyFZVFN~=r&om*z3mVFQqxg^R4>@{`*oQ)AwRaLhHUKtl=uSP; zT;2=RpT_rOwjN#^nw0##z36W5*>8~55!J7s{dRV(X1r{FDtDc0-d4L`{o%<%t67{v zma4Hv+GGF#0I1ytNYO=tJu=rW6!(Ea16{~|o{t=0XtHAJl4GZ~b$beFCuT2}3FBH< z9!kST)JM3msd^b@Ree0NL`WZ{*+C)Fg7~DK9gJo+v;FT_S!hjvZ?RHoyq6H0>iUiQ z|NEc>GXey4Tv_W3Gh&Bo`#oVJeo)O>WsD@V$}2BywS<}2DoE-g+4o`H-P!znvtPe_ zv+=j@%vap~;rUsZRVnq2M~wt^`L%wJ+AaMXKmZ6PYpCp>fnuvse$ow=sx@AkDLmKH z;Y*^BL^>)KL>EyUl(4fcG$=TL5;B!!TPz+yhOSG&bT!tji#KA8atTDE;EGX~Qc#-- zK?2cs6roL>G3^i(Q)g;JwXPJjWb><^IguLq+nC^0onU1KjZKzvW>no7F;dv!(CmAN z-{*6sbu`)l0P;cu&61QB7Gi?yHJd7O;3>m7VQivyO7h3^uX48Ynh_?gA6()QaXHk} zo<)5?q4T6rTz9}|;>n?x-o%+iua>UqG;2=f?yq;@OKww9Fvi6`sJvN%=rUMGkcW<_ z@+v5Kp7ljo#6+n#h$AO+j(d70!VHiqHY84v5A-Yh|2&n7;$?sU04b#?M9RYql&bM3 zS5r_^MEYluc0lkb{I)1ijR<`Jt>=SGlANfHxdC#pXgFYNPoG3=hfdBZQWa>KmbNEw z0$@73&t^rFf^KsA!@fN#P%mZoS-W@KYQ~oBA2w$9E5>7P_-a2NtKP3zx_|l+Q5Uvf ze-s~jv;2ieuNt<3hR9CQ3{`Ld0ssIlC}>R$Fp0zyRaIaiZ~zL6D+*2r$!<8TrNDP( zbk6_#umlnU2AX8mTMu1ugUb6~VTfu`(UE2BB@apwvMl|E4QMn+Bj2t|Vfw;55TfpKL2jLAO%nOhR9iM8~G7hrhE zs($95M@5U>H3_k~8&l%f5ay>XLz}DL{RmqMF#2YssEHI6cdWYjh@Ty$O>0;1G_JU} z;(L`mqyTxOb=Z!&TRgHdQ& z6V^6xXdTSpqFkA5yq!0#@d)NAkWFHviwg!O3V49VVNW4Ky4(2!)R;iXDx&P;jKM>Y z1dekgv^W}MQ-*Vm@cO-lO!eE;%X&!=N*POpKQcw6f#6iV!3F=xEkqZQ7_qk4G*woH zLpE6e|NGDc1ONnPTU+}KGt!T%TWw*6Y+2=dTMazdLw~KR?YEmDxtP(2fGjaU09ZNz znaVpCi8`55PbM29U3&(jypT67hvahCFJ3D{+1{!pfvFx$>REI4vbjUEUbVp57JTB0alDe24D$zwSm%|Egx(Eic!x)0hP+A?l1Vkc)BgnK@Kz!+*j#z zSmWfp-4g#b=G}7#66En8BXBxk5YtgyYqXfgics-Ntu~e=IUz9;1L($SZAhw`4l_|k zu3Q|#WGqGrEk2AQ6{p5i^4fh3;lziMqFoIQqA3oaFPilERHAB7E8>vRm+=& z5?kdO^d@v4TBYy31!T9|PXBSiQBfQ>RS4wUL;wK=K3LE>a{DMflqxOK5>-u=$rj6= z)g?`e#6@PtFyc0jq8hf45~7_zzhz`1?M*m9;13J9_8Kun<80>=mq=N1acKjR3Wtdl zF6*@Bde$U=5!4w{|NEc>Er0}aX4-2hL&AG$TWw{7YEmVMX{<2KiY_kgHI$9{H4x?( zLD3G8FWAA~^s@NgeP`pT;AL=q{ncvo$lJQZ(o*+gminvlXMDB0F=}T>L%~5ulec0Z z027;)BwON78$%;QaY)#pIL2*dJrV74O9f-WG+J_3Sql!aK6O^EfalS4{U8z)*_lCs zz7RvuLWzYSFu-8m#!5(5n9%FMq%InXS4V9uAoSCBIp2TjE9OP~FPi3Rki4EyeVSdD zF)T&ibz(Q+9I*X&?a$B;t7HTK014vTF7}+NVR4iMOfTC&pIV1 zVwCoIHz2}dQ2VF!N^;s?J-#K4dFi%y`M1S4^&8o~$KUAOtnAsG@~=**)F)FcgnzhX zZX2iU&x%cu00gIbjw8?z5z0xtVYr!oS9Fo#yu=_zn(j6z)La-5DtL{fMy4cb9K+}h zDG4!HLMpaP9n?U3k)BjmyVZQxiX!Zzc~W-#5}c)|(psP=raA%`h=O1nAe3Qah@_M! zkT-Nb(9p;Go`uRtoOPW@VhmV=hu89x=MM5H(s^t6r9SIPH|+M6L^*h7WFm@4NyJMI zfUyhcP&Swe8b2-s^IiY@umlYN1bANDdkixYe~If|J%eme!F6%$JqJQbtL=S+nfc4r zO%o1q1q8%nyfOo+kU$rKqehq?PWDzxv-dJ;J8@&N+mEMClY3 zH6TS_I__4Gdw#0{+aiPj014VRLHJKc2{Hue5@0Wa-26s@m@rahV5Fw;kk<3+y0*Pu zT6*ki8ZMq>6*W99XEL~||Z;n55I!v%WhS{UxtiSf9hPu*!g+$px+?QjqqIY05=QYg;lkm{)c|C=^4KL_kr?Ac=+& zDyVW%xO@R(qL4C*hK`Eis`X#I>^+VuyuWPVyenP%?yfGkICI zK``P44_G?uN233{w0AA${`#Y?9Es3S>s#+t-)eQL>QTFShnM(=L*Kr>;pqoF@znbl zC`7-yhXX^_O9^dB03=yeR3QKoOt^55s+thAp+izm=xnw@0ee-_3Mi_AuSe0w83+bM zi;|=Z9XLhEq|z)BWaci+PUIj#lrpTEjSVc(^pcY%j6p0x2BIK+MoY6-f-U!T*rq$n zHe8rym;b|E@cC!kqVty8f2HCNt#bK=Ht&|kE%5Z)Gzrd!ocpgcyIsJCIZ=RpjL&}i z_kFekIFWWR5C9ieuv61G6Jf44i>*1Cab_h9ea}XC9*&v(n2}Ro`&y(YNP`nxMw1d- zCzftW+#=fu8+%&WJE0~b|NF26Ac7=IUfOdBEbxiy>s?_ccvsnZTW!6Kf*~brwU!xq zecAi!O*y3HoixivaKxCB4n+!qShkc~^0pMzwBsk1vD;RagBU{;^g^F&9%P< z+e^E(QPoGt?xWs-!`N!5l!@CtWgDBZ5C8!?l1vRTC8A@Fnd_AhCF<1Pt1~-+uDbEa z3TBa!2+h+-i$w}J46cXS!?G@Qnyhlb#05GfUCL;|YbiF}S`^yJ-QW41;qP}_H)k99&kNUkUx~T%p4q-%y0Y;>3?hD7DRn*n zt^UCbn27-}c~cBB5datP7mUM!& zV{Xc1VGgaBO-_L&LRIALqh z2rMyuo#jNelBiHI9)kF4Zcnugi^nb>r#Y4A%@0aN--fNep?wb{W|&PfHaT_D(@zQ} z#fdzHpNLc&C_bECUYLpUc9W@Qd1SY+wVnA*>rjSx@!3jd{r!DxZ~J!Jf2A)WPq0YG znZ0p-speP&nGSu9n~O}p{^|ni%SZqKv9jd?Gl1GNM+2rMl{Hc*zPr(Q1ci?-JRL-V z)W8R#IABz8TOry$l0rrgor3@Suml-MnV+>00h)c^oVI!UqIdf;sByWNaD6I8_ zjq%7$B40&rt3x!fc6JQW|>Ip7lH&iR0@KVL0x<0|(xZmxCxLesC0R6dlM z!V1uHgsTC6jYt3h1v&&uSE~@I7%^B7ZYB&15lne}?h84v?R=V>sTk`vrgrXblWN3oIDk6*Egz z@Jixt4?Pr+QYyaG$y6RkeYWG&JakOLNx+SF9}p5W3CxktHBBaEV_OkH4uh+vl1h*7 zfTB)K$)I!$BxfM0*rwtfW(N!`G(kfOCb3?OF&*eTAdtd?2~sxn^J3xDsArKlH@pz> z`VdgpNOqmnU~$Tkz32$CJ7k@e1WhDN0H#r3iJmIePp{#uS|jGVd<-PUFDg zfyRlEQiPIKJ3R&E|lottw0Pn9Qz=R0sC`D&P7^?jm>SfZAsqEf`_B8gt3R2IT<9kS5(ZXN3Iu94V%TH7o%c3Tqkx``?oFt$kYy`Cdk_OSVa z!q#Jy6cMoa4cET;^mMu%OPglck1{p&*YXNH+E=?NPqfmGQf0mV*E8?hhR?*^Ty59T zm}nqS1IZ|QfC>6bQW~pZ019^_xF|%XO!D`$A)&p|WRGsns?1(%ta(~=MgUMEN)c{L z8i2U?I1`NGyLVP{%s&FOmL@$gfbPWwYLRn_z7=4ZvQL`XJKDvpXVfwbDKF}w8Bv6( zBCeh5)~!Dt^#v?c5f+zg{I^$J!s|`I)oWRwnym(zbuQ7!J-Q!kx4gr8LSrB$S4v_7 zfQx0DTEWjP^8H$kmD6N#%mR|!B$JVN@*z0DRT?xvt*=~;8EAY%GFnT zcED|vfVp2OkU^D?sJ-OQgI4&b{crhozq@04s@BgFj$Rl8D=!|h`cTbsgXTVOjK_HY zJU{J?-~VN2_r42qjcm@wB9Ila)9zR6j?n!i02LS^2#`o9RfYtK51A|;-IXf0JS!R& z`@HhFhy=7F!>HFJX*6xXIVNfWse}883RIV$SmW#CfW_7>b*B16yU!Ut^9i-*oA~*h zcVZR{LJf-&9ts33R9rR~bZ40X8EY0qTG=%D*6hwarg!`1Qxa#!ET0I3gUOc*xunOB zbu}(RAOHc2K^g!XQW`u91vA3=w6z3mES&@aV3g-p<^<2!L>VhxtR^JVVD2aisiQkW zU2p7#GSy;4KJq$O1;ut#9vF(ejne=7zyu=#202_-D{MEQifbEfVIz(g5p!7$Fxvtl zEo}9M4f&o0V)a^U`u;iXV$+2_rm)kk7mhg2TcH(4cuVO_=+9F?F-U%X!_FNSM-V(a zj7db{@}$AIdaQRGVnQZ>DOw|XxfHC7%#r4-tcVmsDH+8Xs}ZbA^o;}AMMxLs(V1qx z4wkv2cPkL^@ufU#SC93XajyKMfz!y9JeR@Bh5w41XR$y)AeA>1GFGCJQ>&8M7Y*n_ z2bm_bM14`kkc&RpaE-O;Xmx!qGsd0sL!~8!F4W1z$5(zy;B24E|syKQczrqwG!pg0Z z6Y54g20$vnvL^4OR}T_n z*|5jezg;i%MW!(}O5InJjK8GuHoX2m_9V-~0c*}(h|>4A{?eC9;OOwU|I-#5JaEL# zd3dx=af0dzFya%dCO|5+LlnMSQk10&MQ6_{e!Z1=wGCV9iGldy;#`ay5|D`+$~rD+ z>QZ0k8KK-9$#Q+1xzbJ zrm4D$s?-G+tze&&u~hE*(o;tfiF^%IGn8-N5jw-rl?&qM4N_Kt#R_>>imZ&OvdU1}lEdztB zY~yZ2$D*&%+=fLs3-O_{&xQ|vJ;f>kN{j#i05CN!D_}SfI!>U3Djus5(g07in31~h zBr@G!L{jB+WwH>^(LE{2sq)p1Csx$DQZuU{RgMJmIbz2O) z)4~$7Y_)`qxyebm(WF}xdQ8*%-m_l(ZH@aLJ?YcK9Af)BOyFXGdfPKQB|6g3n#|)K17~7A~yZS%~2FR7Puk80l$MGR6e3! zf)w9ypz!vq>g5vFlhZ0>S($6!G_GcB_=oc^ZWmSfRuN|A!bSu{ih6(^)g^I&5bp@I za1M7%oEVblV`M780^mg2>kW|AdmySDBogeD(9aWz`ozvkLI&QfRqFB6r*Oek zt79ii!Eb14V=WbuwshH?x)U6ZCJ6zFIi!!jjV_>p&PWkjED6%*) z!kWIt@rl1mwEHwC)|8O9f#_MdtkpCXzE74>sl9hEDDn8MDYL}pd5>8CzGHXS2iC0x zbnr?^`B7{Ov*dtus!;$ZMFt!Nu!trgH3I0p3jJQ&O*SgX)!>jHa?2Bgy;D$;>>ZG7 z9khVsim6iyD-~C18FT^^Nt~6FKH|z25LBpfVuI@moe8G^0S~kg5SBwI55tytq!(nT z=FPVge$zPoZ#7KKvUaf9*M_R||JdbdE7~C$Jl#sT-@}%7Am`Hqi2wjFa}NO&K{HVl zfRLdGH4{@R6q6MMkt%5NM;++H-peEKn^Jmb@iI6|k`TN~+f|I`6Ej5{(M(79$XHUY zk!AhCa$qnLWl9$fNbO=dz_hf~qenb!khh`#`>+Hq0wwKSRl`q2@QLc%9btoRQBiSa zj3l$d9V~3Mgqg9aHl5i*;RTiAiY#arhlVIijE+U4NhDuh)nT2O)zvUwkT`2!E1s-C zmB52&dFQc7bUF$ZSS2LdQ1nKc%{GISDyl>=$r8z(YRXMBByD|)-bq4m!6WAuyTc9l zl6}#?U@ba{00009%BRGkh$TxjNosJ&f+XAmgM3=!N19Y(JRF}F7oSr|eAhRKv)>Q~4+<&O1@u#>kUEYAIRJukq%EVUbKq#l zzK0Dphw5*0ir1#A^Svr(niMnV!#UQiV6(Ew4-=Frbk5OWFiR8#OV_8Pt0S(4_ z76QY;izb=HQwE0l``-FHvMFR{dMVmV2o{Sd6HMd?5{$6w>Y#%ct`|_2Z4ap9P-CXv zy}2zH#Nqvek||L~M~RTmCZfNG6IpPhyVZ*lt*dSQayu`NHw^+SxI!4+xRpJt$iW*M4`E= z)bwGRo>$Ktvg)nJ)T%#sAe|&5tEXnHwTBVmYTc$#rpYZDDp-pd4?#y>R@D|JbtdsM z7ueUjx;jv9PutvI_}^P8o!=!0&(2CcWA2<=&6I`NrEfa5znt&6=d*Wys)gnxi>JY4 zf5{!!UYaDJrN?dn?qWz0CIGYH;2;TqBy>JRWujW9&<(BQ$Q_0$AuyJqRaouo^>P}@ zz~ok=j_T6v@7FTdJtt<8h6t3Blr6EXM1616%6r#>|X%nlCVnrO9@!-4e3aJB36H5zn`mWz5x7xxIL z=+NS;md6=*W;1w?}&0003v7n77D5fYN=1W3H0tUYqG zB+N}{j{(y~D{e_n;u3o**GFS=qsZJ5UguWgfeIV3TAU-O`;eWAg{P^h%r{d|6$5h{ z6;V{)m-`iqwn(gXcX=k)uvcs(h>z{sjXgGohI)wq`>+Hxf+Sm8*=r0lV3Df}9c6}k z8Od)`4Y1yVF0X8Lh9R(aZ=dW{J^59Ai>cSo_v?Lj&u^8i+#aW_!hkS4ljy)ljm+0NcBs@hmkHs=*=3LcC_MI5~OXsB;dyp3%{XauLoXCXbI& zzYvm;!b#Wonur8XMV4rV!8DGe$>x{3|C^GwxJ{)I+PCL_;?4ok7Q1GUOW99PuDE9Y z+s!@ii*0R3KZ*sz+fgkN>C))--h7ZG*9o%=P@ItcNgqt-76t$S1`1AaWy#oS1!=ZC z0G%YE0RkZ4@ZwPbU|0z+6od3Q0EqQ9T#{ZaLE)hbECz@UviB*We_phfFCv%6B@Ieh zECNAMI9Ny`1Os8P6bD8|{A7SpJ#=-3JMFa@@k3EPmH+#|1R($fnpWHE2{ZEKEZSjf z41OC8omVYAmdY(AEp>(&c{bq`btx=@XcnKenO><7{=24un`YULbqQNUq)jNxJmN2u zQen4IN%tHHpG*ARzIgp1s+PYOy^Z$s(_C%#e$kY@zh#$bRmF8NBXsYA|K5NTBuLfT zGeS&DlSbG^M3gai&}BP;ObiJlUZBx}Pf$_h+$_RTFhxqLjD^}~Yyie&*#RhtDEcE& zgaI8&wn~K}AO`?O5mSMZz!M}eOrtbsFMJH!F=zDw?a>s}ig+%xVlTjei~-GbnLAl% zN*Oxc);s|ofLbgnN}up!yx1HAidg~dkQ*zK1>oQy4F@(uf;l<@lJ4Y5heD7lawov!mznm9H?hE!0000O1+lbO_tm}Go zH)B4PS6zS5pTl)j$BpD?Gsk$%n1yR zz^N3ea_yX2(kCHm9J!PSl5QlS-F?p2ws8pbw7|gOZ7{2YK?^9VESEkc%|QF@-e|Go z?>3M*XXXzvIEy+yZ)W($6t|7-jj=x;!ByU1_U~~&!MSYOMQG!|Al0aC2_g^&b-DRd z)^`xgS^8v$gj7KSNl8t?FD^k)#K2hqtE)JnKvWhxb#L^%|NFoM4*(=5T3q`E9AJ#f z`)y$(ep)4OSq!|}0xPX8{e~g&ohO=ORb|_Bi62v1rMKty)&g z<{O!Xr)ZNdUG58~INF&JFvzCo4Jsq|>JDIH#Sz0%VbcyR6_4&j5jsXw$X!Q3xw4`Y zsh5^Q65Y}r2r~)B7LvAb#pY3Emd6kP09)Jwz+ei{T_VmjXDEO!+CV9Bei4U1Nt!YTcq*7U1^W|)HD*>4Q=uF}3eqr7kwwh$MvN6Y%H<+c zAqpWRayjFWp{kdG9L9#OV_lZRp$#>e)vSd(=WWfwdwjzay@hD!5frB(ADEb$O#41)Zw-iyjGXkQ% zva_}2hj688HK(u#uN*N7t*@>}MW{yyUg-TzG9_Dz8fu>z!$$Q?tW8r$z*iZstMGHQ${}ABE_s&#rYcE{wtiu z(j;67!T6nq=)rGRI6`iX1#-(XbH+DOSPT|cNbJf+?P0Pj-8^Fd`>+HvfF+S#SmO^g z@QI5HU11}R5t(;u%rMP@f3s~hh8gjXGT`NUz{uU0&XtT7a)iQNV#uW!OKFbf0%%z> zizI*fKT|>7t?OU>`eS3Xx>ro`PLsFZLjUaA^M>k4g_8~dM0jv?>X_mJU-UDxjxqoM z09^`%d})M{;9~<+4hn-dXc7)si>1(*Zt}-R8DtY`CeV~~M@^wdM2LVJZG-%wlt|5q z2T-0QFcU&hp=9}ibJ^{ywup{9i*Gnk{CZE!{$bQdS@22@p*%Z?rVsSy zdd<$~f3x4&8z+_eo#A#^;s_`Jhzynl2kId}0nCi5m>>Y!ONJq#7hM6(I25PpfD0nK zQ$dy1k>HWapzLI+uTBrX^I(S#H_gd5rzHzu%vGV&BzmW$%ZI*}T{JyXvE9 zTx4)nK#}l};~UXk<;@+`0370lFbH{O!>lkqfWROPE!62dSc(DFLHJcWF7yFWU3_Y? zs&px9T{Jv69HSj!qf}lekV&^5mzovNR2*3JuQ40ZDQSnJu%wuQ$`Ke4eUS!~E$bFq zNq@FU9o#UvY;4LSzeZH=#E8l)KO(n$70{Qom%b>1&fI4w8Ko@PooDmli8|<^GWSL~ z#EmTTob!FmSG4(dp23l3YC&0(h*A{<8w>$_6rgy7Mrp5Vw4_o2AeIE2sg~ur599e1 zY3~fTwR50ha`L*45iFLY$0qmrB_`&abIp{v$Dz`&j%L;6MB z!;Ie|3RSmdu#nGdz`2aY|R6#Zqxil8ZRZuy{n;3c`u;MJcNl6w()y~#i z$MZ!y{_BKKl~!)UORc(IwD6)SDV?TYNu!xe!bP177|V*V_LwG9egYsx68XR6)#29L zVi^R070kKgFZk)(x6k{~l1w8qAcO$`sI-AgK@tGVZj37ksFTrEr7FUNmc4W>?QVUA6b?H?Gn1n3ufYk-gjJc>fQ^$|wi!#c~9k?D*B!Wh!od ziG8Ue0003`EpSQJv3~}HqbrF&Bnutn(s^#6TtY?&w0xZl2v~C3%+9Iiq?lJQV8g@U zjzls(^KXKd4TCOh6m;L%^}jbTWRN-(f;-NP&rD<;k8Hf(&`Uf!bu;=I_8Y}sJ4<9v zd#3;6-?;agUv)2@_G`z?NauLfHPd-)#it-4AwVMTbd@uWv}lGlQbbAr`>+HAfCO$| zT>B3)@PCQBpJ2m^RC#e@j4;!}EHCaoh9RklMzLc;2m~r7xJ%}$#{kbR0=3*!D4|0P z1u=}~q&Tkk^vMdE@=eprlmWAA|`KmPF~Oi1IB);0NBarw(-!WrS(ik7|Q=51>|?|)OCm)NbQ{<#`Su}Eca zAP-F~4sqF~&_M*HFBDpju>xTj2p3Q-W-&Cxk8;6#1Ka`kXtM^Zdliz z**@Yj7^BesJnt_t#%RVA%h_j2r(#0F)-Qe{sZJ7#_6H);8EK_dTNt4n4U~-6z)dcX z#l;9`6mBM6O+&%`W*Oh!M-y%QRd*Ht;Z()gAd}NKl1BBl5<|jsREGpzE?VE#NPI=E zf5tuHch~pIe_GqQu)6NU|F|jC&D{{QR47DFd`4-aR(onhdTDi3B!DTq#0D^ED&b5A zEWIpcRN6ub+p!=}$@Peb#pfANRk4|U`m)dJ$DD}InY2tSS6)3x*5$>7S7N)AIEuB0 zYlhKQb1{-)mXt#yrwjBf9|$0|+8lihJbZ5T8`Hd}>oUxjOxLpOrzn)N@plrL<04|G zuODa3FN}+|-6^Q*99Gz9tLPFug;rA%fCLp1nOd6wB?HM_N7D*{tP@5HFaP_n1Py=$ zXkS|U3`25}%nM&(Bc4^6k6(;D)5-EDE&YQIC>kO_aZ@4as^am2rx4h)?X0X#;#94s zZMv?h-HXw`L^8uLvD8=R+4f5g;^;7R)rE@E7@wBM7rU+0(jJB^y$$#}84a>)#<=){ zqZ#(L^(Ng_&D`^~^K#|<+fL1MQakgl#2bR;tc~s>#@}njvE-;id4+amBtZnJfG8aR zSYTnJz-dE74M}&5NlVo7F5@wVSxfI_+l)n@_;z9fiU8-4IY=-l4yeI|$s~nn4XgF> zNk$5i1w=%g!bT|5*^A20XJ0EFkxpwTu9Qnp$G+uqFKO+sztpGw!tX00dP1k>T^2Uk z$Mb5Jh!n^?$luN~X~b$5(p)(Mmrqde#HP26pakhqkN^No_`3gg{w)&%p#+SQt^4-&2wv^-SJm%l%siRkDAF(2qL}o!i zfKs*DKv`f&%(r%}NubY}>raE*NILsmpuI1eh(?0xVimG&lS+z2(;ZiB2bfC$ixB}t z`$`5*IWxCe&s^(mq~du}pGhiG*oLLfI?u*xJ+L&Kc66X~%eIxxPeFpdp^UdxvM`>+HM zfCPPDTYCvKQiDqSe_+F$P=o1e9s zR)0nXXbBgTAVLx)lC434#Z-s z_$=M*PTjlB{Lb-ZUUt9Re!17Z@(}RFH@P?x+gO`nQooW$G@*+_t2&{Q2u572#SuVy z`(dhXgh}Y{p^8>C#XQO-ZO&6o59gc-ddI^?IJ-+#CFzSRCLaMt-3YF%AjT$#gtUnY zdfnDb`*=Rx7uD*jeR z3;F#ZpxKWGb!{Gu}{XAim(31XCwIK!NqyP$C(RD58uI!(m*sS@0?Lm83@DqfuC z0T%HMfx?S~JsQCcPIVxd1u5Ek6T}h>|9Z}j3r~TugkTo&sQ{v$G?eIhNRP8wA<5DV zVjr11r@J5RQ&3@zyApl(&tFR1`wvA8H(ltF9_=)YW+?qj;{QYWs%?)gtsAJJC*|(c zFHKCZL|U4`te@0iMuy|OhZP|?g@!~q02^KgahK3)NUt42_Z|CKh0;=` zFnM1`ODSPtp;K}!+H5(ewdAnrY0@dH;^LKfHoC#MMFv_bc5~h7mvE6bn3AS(`~Ul( z1SNn3I9%Fu2{X`#N()b6gKklIac9gi4T2}G?LCBz@#B0boAV|zl~A~ru9#XoMX26$ zxvbB8soAdYUG?rWV|zB^?n!gG^3c2~oA$4_zaM#9+`LV78eD=Zm?21IW>XLV0H;uz zX&S~asIwu`BddB65%Ca}iLNQE4iAe9LCedNJetd5TRz-5Hh!y^>r$6_ECsc zx_w>VL-;*#;zE;?#yBulHWj8U5%e(NmKX(QKz=}oSY-r6dqdXNH!Qm}>Q&d_%%Ajv zYY;Gk8|0Z9*QZ~z3XoI)ZX0r_GpDW^NDwO)>| zgr@3It)|v1GVBOlVW{EzS9>5zVc!lzdXn@r9B+ z3}?g5Fk3{GWgoTex@DfIM-4Vk3PL0WFo-c2!tZca&?!j%LG63ew>VnhU#01iF~att`m4D~zt z`qMv#XXo9&1P&H!J+Qirfy$p_BY+tL&D#~S;6RYpL|?uB$8;lGc86qGf+RO1Awm}a z`>+HCfCOP&TYC>OV18>mZ(zfGQPpv6>?IKbAg^tGgARF+46srZ`4W(t`Jxem5236n zEU4q5&K%2@t4o$Rj2~_=AdEOLA5(sENu9n6h#hlc6{xeCA zSiOJve#OQjxs+8}W?81}(4ada?6`IFamwrUwKJ)BsZ?l^gLHsJr)9(pE$lEDwWyG) z@W1FFXKF&7_H3_B*t3lQ&9|9Abm6#90Kq737eD4;jP>Lb5|NdP1L)7#%I=Pb5K)K4 z!rZPfkD5gbJr5r>b2lS)_<=@>w98=RekLql`*)wIT4|mh?rI+(FZBqfL>=DybG3nQqILrbrsa)KU#*O~zfy z(97L=o>xO|G#LejV9eI2fX?XS?O|}{reT>`L&soVVJT*8bxYg5DTF^YvWMN&NQlCb7#cKT;30ox2n z05B1P>eC#Y(+n^MLb?>8ccJ29uY5iRWw9>9^0@U3w(X=YJB9Oh#S$9G+dW+0s~3>7 zG5`Cp1RQ_`nP*npFGTQzC!0@UCUj8YWoPU#&5AE5EPaL{xr@7al{ZIrW2Ym$TE=Eg zCpUO)^=_l}DT@S}tUG3S@olLzT4hSM-xO18!c{<+m=ir*9lg*>l$XJsQ zZmWEy4+ssH0pM!yA?qY(PI+WUC0$H@WIV)Mz@Gcn67kIOXe`#niZ;$azJ9m5r>CRY z>(|H-wJJQSlK=oyski|uIwU|?EhrV%a^2ODP(Uiy*r`(7gs5ICY~Xx&;}IDnLTWN7 zh%xDqRz%FCI$Q~0c9o-|Wr@?IsZINA!Z{j@?mB zCM_;`r`dCtG)x6b=uM22L2sZU*eRjC)&3rTYHnJoZI3V7sm%u}TBRL%V#!ltl)eRieIP zj{mCj>rXh@3ap2GK}Ne%7a=n7xN&c=bxdvN|5`t9>U*&m?GEy_huo)*b;D-u=O>qQ z3LrQY`aGt8#>563(ip&i00qR#004UFMvHRv>;n<#XiOb(H0J)vC<+q?d$dg|8o<-o z&1r340@aPNL#0+tQm!p@x8;WqZHI1M_ZK{W9`nN(XG%2&kS$ngQe=8jMqVwdjIxZn z;cKLeXc(7z%&YNn4Lzh?rd0HO4n8%R|7tfU3VS1*5==ZnZ7WVu2R{1ukWx6Oc2p)p z2q)p71C$gH5#lu9ut-26YwYDK8Ufin7SUS!jwlu+54LGGk(gkD6pTiM(soyL$${2> zgh43(`>+Hb00gCG+WQGJvWW`IEn$Xi5v7xBtT7FWU9oL7h8ft@ky*hVT(si;dhD+) zZ;oS97oR3RDq@e6hT(B{6 zP$o-KXr*=Eq!H0$n9bvW@qgP^s)e*?s+J@tGNLTQp4)2?coiOSUl>7VwDZuBT!U+F8gTPz5q|OT(xK5!WalRbs{>IgM!6mrmMe zQ}nnK<($-3_M2hj%tz);8=$ntHUY^9Ok})p0zu%Lu98 z4-4&5(Jl9SrTtR>G0X8e1Gs?rafv7|K_nJ;dKB>EEBaU*KOBu+S*?<`fB?CB`Z|!p z3WUK@`vLGuL}vto94%8)Vv$z?aMBnN6d$Z5D-co$EegtKL5Wy)d`buG>L5h~N?{Ho z5G{A9*}lsyozM>K$@}_obZ-KaZGtBH|J|6SpO31ez_0;1f1R$h-J$t0eqCSn6Ik|O6qjHp^Ezd@}Y&n*27_kX|+~Y*lM*)GOKOM27n{>o?2;jG}G}7KeSN^T=f-eS7@xp zs4Yk4YCo4SeQGyOSL^#%R_W_q{4j7s@j>YF8pIOwyS^t z;INcNOa53(Hqdc4Qc;kCAb@~GSp0@b<8cCuHlxgBLStygAQ)(zEg@#C`3Y#u5I(5z zWDjM_$RQ}Sl}Ki>lO2JMj6fCd7gh!W=&ajPMvA-LMjpcCE~533DZ9ZHnN2x{;Iow0 zI^?@Go@kY}y*++$*Q9Ii!~r)ALl5f>XL6XtrqotJc2@E*HFoXDR)iM_dZ}wuNou>2 zni%Y|nvc1q{7L(6PAozKfN8r!H*y}!v{LAO_LN9(=beadRaLZLPAod;L$BP1RP8}@ z@~7%008q@_sr0cK$kq`Uq(>{(=j&2qdQljL=;`w0^tQG%afrpLOz0z0+_0FQw_cW8 zrqTb<3kg9oU-cn}RU2Rc0@&z{bU4YCgT`U|&Mi42j*r97ZGt{6O2oYM1=aJW~%XS9ui2witWTpY=3nsdm$j*yV0wBL-;9M%+ zvRR$U8{#Gq2h~VCh*dDN1cI_a(TN}#bW8c&D7qvHvyyD7rB5C)6idx!ikMv=O;xAj zwJUP$eTsf5-AU{W*wO%G?)#PIyxbclyAhZ>85HnXSB_2)vS&+E!Z5)=(LkLX+%Kk5njttI zEkq>We3Q}zfsKxK<2@dDru4UT&5kz)wZoBrKM_bwvLU3ARN(bWbGW%y?TIz{e~a+hv317nOBfjJ*@W46bdxh7GYoN4U%i z52sj11nw>8u>O9MG)_cOa!VI6{EAg22{S4wI!_0klBV)OSc+tP%LMjC80@MR80_W5 z=SZOxN~Rzo%x&g@!ttL5iZtMO*`!saT&oQv%Od=O0?5h=g&hA%cv+t}BFm4qk4tIHK974>d002oyhelL6fe2X3R5=qAU@$J* z8Af!SeTBc6QU0 z5t=dv4@);1f-N?T1^0!#ZpVS*S(wT7Vi_=%2?+p3DKiL|Boj_kh{8FDN=pt$)8yrH z$?0&VnsCz$92=h_K3;6LCX?NnC&Q^%xQER^s;;m2<@-K)!=ONn5Nx9i5{MRZl2|LN z2W1MOh}nzT6B|L97|@(~~wJgJ#2&b4bYG1f?Sv^N?{j;ouGVdhp)t#N6LByYkYuWkK=jrg?X zM`czY;$RV4t;3ccE;&|FIU@K7Ordk=e?yg>(X%0(nfLSj=8)B z64?E2A9;JdYaMIzP@Q$vX*TpZRxY{HhTT-^Z6;|FbRfcy+Udg- zG?VJW)fc%5oMr+k!|UtGWQmb)jy%3C9WzUNWyW`}xhL{>(C}L7vg=)&z)x~~sLYq` zGSulIv44?toC%H7kvai7{O1wT}?b}N^Oy=Qh6&=Ek;~-1lwEzGHyaobWgh(zW z-n&()k))F>MAi73?b;(i{TrarWmZ!s#3{kK$+pm{^q;E4mAAgZU=g`RR7Dv}{A9yB zu~}Hfg>7|qY{6C#FBFO}s$<~s^$HYN;)zszaqS3;fFlwkoeb7z)`X#d>YoZ4Xg}75 z=0ya(xph7LFeVU<>$*h6-I^JUkOc(hh?t1oiWWoy(Wcq~nG&uVJ1=(DWBAkNZwiIc zg%KQ?bTLh>P^uXdTGQDt8L(AmcdUuaDdke8ZH4LxAV}viIjbJ2al|wl(J^Yt&5n?P zj6fhq9ir-CeMbmDqGpB2uR&+P!A{v1)N4tOZjGOHBPg)r8alaDwQ#Q(tg{BHLTH<0 z006p=8%FE`fKazpl9&BT+=fuk*d@p9zpFnb_#WMg8*+;m^~!qDh^5Q&`}Zd??FALA zDsl8?y_>aml1~&IN2NZf|NF26BmxARupV$nt$|JGYamO-9ZPd4{I z8aKCnnIkgUKkv;--w8z^dIfAOtz^*Qr^!1%_cbMtM1TMQoo;~>DitUMWtoZEmNe0UUP*ohA~qG$7n0ne`Jx_!9eWPyx6szG~KA>D9G!(< z(|;Gm2U4RM-2+Bv!Na1r<&G`!EeMNrlCU{wNV1l>CkZhW{FS zCK)WAQlUO9d9fvbvr%P7uZ~n+E}T4uX_Mi4I2%p49?zy)+7?jPOD zf{PXlEg%1?ZpPYP_s1X`4;k?%z9BbWerZ4iMe}h30OSeyVF9SqSm-b(vBX=D6(;7H z`geM!b;&XgrzEVbR6$#njzp!zn(#PH7pZqL$3NRds%F4`?c#hHDC0<^S9{N@hLXMdPLC3q*S`G?8b%X#X{UADP(%Zo~0+{s@ zTLqB_a*q5446kWa$Gb5Z%628E#dNMt0n`#>&o`5jkexa9st?AMtiU6vaxlQ!iF`}h z*B6QTOu>_;dtnn0i@8j3Wxusm^820VVpB3hk{tjLrdoby1;U+nht%=d#c5+QNc)

    SLX+m*-+nicb&^=sFGC^Kp9S9MNXUJ8 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%0Dw6vTs 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%0ALZcZY4n~HRA8w8FKU(VC*CZoQ zu+W%xP)>BUGsX;vc5Jvl1%si7sOS*Ex?$wo4AW?ykK(cA*B%x1eHwLL^udWO-z!9r zVC_la8><20NSroT36d1oV<=sS%56&gUZJz$vgu^4(TJbU5*wyRpX^!ZK^UuapCp_0 z-%??K0JMXI47kP|+cz&6SOy134jdK;N;P(*)NyPj0+loNqOI`KzHBq9XGr)L`IodN za;V>N`fWC!^N3*j1n?@sSEZs3WS*L_-3ti6o#y%H<4Xy_;0S@kb4a(O*NE4Wf2{O}VqD zSk}sfhXjWOmq@vkBZCwzSKE%AmEL#OM{bQO-TU7vqocd9-c}Vg>sqqT)>F3i(b}!f zTPr!Uo13!X!5iUH`mo-%l)aI*004&Xzt2Brp!RV|;i%2&5-n)aUBHj?1t`KcecM5(!xFfb|nS*Y-+Hlf+i|rSK|*w zV2L*B`@uDgqhi0E@L_FbS$^AyGo}?!mZXJp=#(0Yz(pA!c%SR z&lQaA?Tze*oT_7{E9D_8LljH`%t94zP?#U08Ng}eiN$e3m}```47(u99+7{DmWYr( z=@uBdy@+=89^;D+!BF6wltBcl$CO7_lxQf*&IVnCdQ;k|A^-pacOHNbz!QLc1aNT# zAQ))Sjh><4BLaa~aUI2tK$n1Zu&4bSI=0buBTL40%xJe+b9cMCe&+pRSXzrh8!B{& z7Du^C3Q0|QH&G00Y<+l7MgL^H;mWWwS2AR4maz`9kkWcDAYUg^@`Sw$sD zKeJF@U4kchZC{Nt@@s0A!%gRo+T`d;N^(pMo;PnL^b)Ggqj>%fBY55;iN-GpQELr+ zq@kDA?Gv1c&u>+TVo=DAd6P-r<>!C2r*dte1HKGE(GgXUiS)w4M>blOO+}Eu>rPn) zFvpBiCJ2fb=1;E@VoE0LOk1BcKo$g(+t6^5kLezAHkUxYnwX-^Tff|yxIpYGTUpz# zBH8=5$eZ6j|F+kB?HJ`wyf%K@jW+LQe@r?{Lo4IQqf^W|_M_Yt(sx%ob9)`opO&6Z zu&CI-=^Js1(wMdxpStJ#y-92X`1UP2LJo81QGxQhF;tI z2}AOIs{3zcBYF^Nb8oC9ZNdC7ZMB4rxRIM#u}ul3il9{)84;k2%%GsMt0Go1^CHA5 zEz2@W_w-384VIzQmtWMb-@h8)5*wNz8xn)<5O0CMB%_xeHi7<(KXb^aJ*Xpk$_r!QYbdPR0!I?H zZ&-X^lPo-HWzc^(^xUIo4r)l*rI{P(aI#r?ZBR)wDUQTQ*76r$nnBoLRG=zQ16Qd{ zO{Te`03atDAVgH59y*SQ#Mft$*=!eeTNDZN7ibL)i3Y`lWZG1K#FrG2fz1vM!*(pN zs*?Li4_k5R9dgy@BwCk%QN!TTmlO{Lx(((@{IS42bgIFEQF0Wfs_Zwgk04{idm`Do8MUL3g4oD;vC9>q0 zM-{yX11e8w*nGkQ=x|3&Y1BfHxa!!Z#a5G<$jSqlt=~GnOYAe%$iWZ)+HsfFv+o zT>A+_(2R>qKVc)D83l7&3_Y5HD6cIwgCaQw5A{AK?Kw8D8)iy>8t)W1d^P>5>317m zR|`-a1a=DoTG;(5BM5O7ApigX85HRV#6?F0OPeBEV5Pd9JBePup~*bl2F_`#K~NO^ z23KsIL171aMVSs<5SXWkn+(i=nVJ1s`OV?DQ%ADbmGuH}tEIr^2x z;Ly<|{idZ{zq-qQV3Vgk*9Cf}sCrp45>6+VF;fx-Zu4sOqctM-#jeFTkjKw1kPH9- z0#F_jEt5itnj-;zUbKfm=eWQ!{6i8dh;k;?HN3RfbFEGZ$k*r!|-@XEmhsx6;CM=^55Ox*hKkR|3x##-mDA z6yqjGTEs-hq*b5EsGZTgj(Xz#f+lr^ILSZ&05Mhpnkb2S5VdCwRh>5^6EviKV6W`> zGdN!W{!CdOtu`=WaQ6ENUos+|w1iYzRd8f~@jNsXqZv3=N@2w_n43ds5C8kX1SJ9_ z%UoGw3^QF z)r}lKzg4FLn+~FZ*AVQt8vZyqiuKfHQe$*efmv`shs!E9A;_5OWtwX2W`}fC?SCWZ zhkum6+`XIAlU6inRaU7b&vQX`9V^b~u*|xlX5{?>!5{>tGc?T7$cA7NG+|WF`D&2L z2}uWn50FKouN zGT%AuqDwBD*y6RJYYNtb_2dNIA)Lu}Xhm#yx`7SJa+`S`BiRk-GU0e>HeoxxhYBMrN@4m zs{cp?0s%$fTP9&<^k8bzTxrH~Ub5p03PkXTWmSqJQ-k(4Al(LDHP>#x4bH4-0p`s$-h$2{~E*?_KkS!h!$;yIiJMiQJ%;ESY;CAJc zE|q4-22(F55QN0*G}Lr(o^Zf!Ok_h^e1av=s<~k)F<>q{N`#v37@qV?vDy_A?%t6u zX?qumx0{ulxIGZhXn?3DEGJSW&LFHpRB1;gi0ahqMf6th5^vT8MgRdZ%ROBbYzTP} zfYH$*zD%WjBLRq)5#Y+|hY1nX=L2PVKz&H=o zDN3|w1Nu2SbZ!}H2LUQ_QBF78O-AE1pPXcowaxh_T2|SCp=W8uS`>yI5S4|&|NFoM zID#fTUe`k}OmOUM8jx-2$XP*wSq;52!Y!;VHI^BvAgsC2WF8EPXRPDqgAE2w*(};J z9$vun=p+M(!C-AwS{FyTyC&LA$B*vfRZ*>~guEiNt7f|@+TQW!U5a<=?9zr$L*kZV z9xo6bBP1?72>qW=O`&rqFF4cF1wk`okQ2L40Ui#3iUK6?0A>gl5tJ;N>n-MJs`;5f zC}y8GeAL^AZMM=idIwinH}f@9M#)H54m5#a(6lL&K+pwNyT$VkLY z5A_ONSVPD$^nV`Xg>;%17wLsUxm2BuTaC3+jdYJys|YD>QlF@|id5>QI;CQF4CN%N z3@vT?(FQ|W&*Q0>xfAAQ$L`$NXU=7g<!qU z{+qM4?L3s)Lu#j9SB&Ixc*{8jDy`i;l`TKk3K1SfHaqnv))SeykO|0DOdfK40)ZAS z{R|;h$wF5u&YFy!$a+Vl*s3Psx2(7 z&3W~?=4O7po1V}sp#?u6ulY{-ssI`R0000HnhbVH6A4Jf>mDA{8p0A%1it1NIGG^_13h8ek!v$v7vw;<#E=gviA?b;iE z9d}i%#FZsHQDY4#KE@Y+ z(Y4=y;|y0FSz2k2S$bz#a?dPy!U`U+zwxGD92YcXn^)$nWaV<_FB7b_Y&f~CYq)Fb zT5q-9E(hDm@MxU@0Canf^(p_!gyfGjKqVP>E+8MpsRty8ZNMG~d6*&9xS?vXC{0F! z(4n#$m=2Z{m?Bu4VyRk+o_Rt9eG`sVW0NDHkCx5vb8s-kNxmL+fm$$HL}F1jn5M4W zIe)kF1kOyu<8Zj$#LYyrd>o~l%&&d>m5(yLC5xKPebC#UZhJXg-D`fySLRJVcD767 z272+G$e(jistPzD00PHo1BI^Os8#wzFrb7og$bmUBBhar7Y&yY_X!r+Wcl$_B;+4P zq8@iB5x}(!a~#t&(n{f`TN)6#7#rA}j57F*TVm53k;@m+b?Fo+3^Ib6`vA0d?saP7d-XsdFCn~r6Km#FuxnfK9hNU<0jWaTu@jkE7KTcnH(-Q9001O8lk6H4pI3@lG!S`Hm70Y_-4>b%o5gT1JspcL zj^|~U7PV+Od&!2?D@3(aX*5F=Au3l!OC-t-v2x4?X~rg^%CGk)JwMa0F}E{pw9vcx z>m&dBummlDBy(L_`wTNch3Ts;VIzE1HFI4oFxdhutSohg8L_`IG0LC!x=ym4|K05G zz1jD<1R3p@-6>|)kN;*|W+9t6u3m9Z1N=qcOS3-d=TF)Y4*FY1{wH&M~OKF>( zJXO`~2`{?$QZj3V;p@!RRJ`!XrzQmhk%28G+IY(y8HSnEh9r zbK7r1dGm(dRR?vJLyVcX14qd*y*79U~9y!rJ9OcOWa$QX2F6c=|Uei!6b}0!b1)9i;D^ zyk^ekioC#gy0ovsx+O~pN!b`qZZhI;e)?y3`TW=Z9rn5%@3mD!z9#QX`{z7&cGlAM zBqvBD*EbGK`?LS%82|tT3?vIEWf6f7CIA~Tl?IVzkr0srDKVxKktR}k0QFcCEQ8is z(wShbtG*%#4jiTnksFs=5@?Op`F_!@xvN0H0f1%GZKdukr)fQNDT#@qNtg=e5ivQ7 zdebBU|NFoMFaQT3X4JD!W$~{GqLP{LVYZ!3H zU9+;WskVwyZAC`u*DP>t9R4{FCD5K1w2{ip-Ylq0YpaR#fj>;33(-1N*>s{O%H%c- zl^)rIt^PN2!jZ+U;d0ReqDxn!d51z1|_# z4eDa%eGp=#;zmn}4G&9`Ur#CB#P#>x;0BViddI( z%d=II=!dBsb3IVOhu(KPu>AJ9g|Z|=6)@@}{=W`t6lRqlDsv*GrxG%rp(<}zu5G5F zp#0V5cL%E3?B$Epx^VQ279%ljBl1e01}Q2+oExL5jqFhku14j=0Z}AiwxZ$X$dRKi4aH41BGk_E++#j~-OBCU#>+&{ z_4Vu{QkIfT-sWdeX54buNo$$h-1C?F_Gs+{TX$UvZurp=)8agpF5g$J{#E=p4NbFg z?=`Z3;sdpCTl~(_019A4004S8ksK6dpqb=APKbcC5lUFLq6n<=9SKNG9K1U$q?|oa z$flf2W}tBWY4jyq7@Vh0TRyWYlae*p%r3On%hSfT_i94=1ush;$fpw6KXT=n6tdWh z$#hei9vB1v`>+Htf&`RY*y9W{aEOZwEnz5p8<~Ajtv#B`AgnEYh8d8MY4}YYrGpfP zYybOZ`2OShn17uqG2gL+6FJrWHhS}x{BGkdGV{lNekybXb#SiY`?eC%HB-%wJ|F z&{=u8dD7Hky8LucKQE1wRAev6*ZYDD@7GF# zmM^%O&~wi73}Ik6pDJorO_8kz05EHfUIPdi#|JfokWf_M=(7fGKpbVjhU(mqr9o@< zHlp^$vlqq6OC|ayg#-R=}1{{E8qMEG| z1tAb_mIDMwmj)paLd;a*R2T|DxGrjA$e%YYJxah-A&5kWIgI`7q7$Uk=w$e*cA_$s z$6{&n5~p~UNtM+;RiPnHhKsu^B}kHiB)~E;Cn!x{Fv1Qn4l z#B_lbSwPU>hzxKcIxM_SDi0=Wl5vs4nn00k27)mJQyiS9gp15mbAaSiGIgkHBX8=< z{MYo+ruMmt)!M2}9C_tLr^sh-MtIkyZ^onFHjnY5}Y!c}Sr;IwVk` zEf|z0SD4qHSEJG;BvI%jR#4&c$Gr*2sp9?(#>wT1^v<+7ekgHpSp!Gz$F$r?fVI{k zB@UPF$EE%MihVh@s*zQ%ej?w@P3U>AWsp_M7%BWg^-?rFz)`jdt-??M08_Y@C|ZDp zElu@8UPl!*+r}Qbm-?Y^1E)=2Ha}WbPNm?q_(d&TrwoSy@&__lnERn2WDq>kpR^QJ zq8gElwH{dB(pv6OR+yD%8D>RP)^sEZYHL@S)#;Q5O1 zuiL+Kow<>#E7uiw>^>FwFf!984A6xDnHpqg0f7UVGNMO|rUC@LRWn^S{t6yYG!R6n4Tqr$3IhYZNZca=VM3yKlR;8Jq=HR!R70_D6A&&q zv0w${ErJ@SIuaCuZ#wFB_9bGFLv%||L{L!{WS|NX&JdU&5`iUR65s<70mx0+OwCDS zFjoqwyAtt!QL}kFFaQZFAH_6IhM4ic3J#!YuBL7T6BNAG;}rJT0;FY*0%9#jPfpb5 z>oSGV-bFVbE+YVA;{X8i0U(g5rM4#6*qs?*fMCe2;c&V(>#n?%lL!zxX&~IJgkK0l z%0_Kz|@{FB@8Mv>SmqB|T!5C8=_Bf*^nw5(cG0xarO%4;d= zpfSZAaUW+{of3)&BC!I^uu)yqB?+F>Psg^=J{D7a$0FKIFwcp6oQdOAxP=1ipfv#j zGDar>5)Je)CSlM#|NF26EC2*XVB6~n8{)*u%IIn4o>B#UYpf*CiX1NOb%qVG1wxZU zl9d}(A_!nm$b}f6Jcy}M-2F)6u6!{_*A@LpGBW&MXy7IqihrhgA*irY< z;z|6Gz(2%_BRB3okg8f^8(SJAYyQRq{atYplIdbk~S`wOtR zJFJpmqSQ34bKRHR(8cyQKy;0&Vw_2GSIQz@;#Aq=Bws@ zS@pfjod8>bjg(Iz@mCif_1@a-DPL;KU@cMOHi0%}5u-BpQeKb0lYh3`9PfR0)(1aV zIwXAL>){*?d_4ixLWo+(z`A)`(KpsW;Yy$*hx({Y9k^RCzA*%+Ko8(OQ_ z;HAi=U{Mzc(Yka*sqNSHC1Yx^m?_z6uOkn;Af}OfWEm}-kOp#dYevMw$7tmVx9HU) z=PVt!ofkgmO)mO`Jx$_ujpRz5zOPro5!VMW>Fk-^43#h4L?LryI|4|Vn$pj8smv_tj z&<<%p)TOa@mH%=g@cmi&X-$*VQwG|Ld8MLHM@S55b7|q$-ggS4(M%X1zDXGEbvwbA zCyjn+`A?yz#S6Y4L83NiP0pWZ*Vv8?88XQuur{bFOg9oopHe)Af*;|-=8Z4r7%$6A z!&i!8FY+T<0c^b2WAmMO_Kqz>TmQsb-!{_iq2d_PRiWTHQDFK&WImE7XZOH zUR(37^1;9(LQ*(<)Y!`D%arbdwotM5T@*J-s$7yH%a~J@O1oM*t_ssxN+eiI)%ppP zCCr;S*L1mP=@Zm|IJFaHJ2snt9B|ijefb8M0`{`QXV7;Y8mo+S@%lE?1T<1w2ucUk zq*BUxEd?2)WUAaO=H}syOxI4$2C7n${KRW=vk~BrTAD7T31W1m0oo;_#A#_M4Iq&U zWL(XsPDt%pL?0y22h>sk3b`oHST?Hoo!;Sejm?W3E87817sk22#q-Nd^!(b3L};jg z(DQybs08~>#Klfal>PhmVF5U<%kRI=?3KIE==B5zmDZE*ws~E9T6RDct<_nh37POy zo-K3i?|LT9F$M?)T6`?hrW!EXWjH95u^uPIR*{UQ(_pdM%E`Puvak-?{OnBWln~?l zn%y2=tjVIEBO!llxILf5R$B`A>xA4$Ap%b<(ogJdGi`Tq4hgyC>sRbdFvkTUI7fAg zn{0iHLLJdC+p?+MH~%7z7ZyRo^oumQJoP75G;>Qje?1&1j}m&uBii875tVZpoibJt zLd?(&!EUy4S7k3FO&}DO+AiJNHMx_ko}?G!TL@}l#8Q?yPapid*awb3$pU+L)e%&O z5fBZZ63KSzXUJDybxmob@Fg%mk{^7E98V%wHX@PjRC9^hk|7`XK6)NWwn|s0geV?N z(T^W%nVNK@o|=CA{wctV*K1a4<%LBPk|pISJK8X_%p$}@>;h5!;I69j>2oK%4x_<8GE#{~*3Iy~;hM`S3t6eA5`DNP1t z#&n}mk}G_;1W9Q$GX`QzEmdzXXibQA^1% zye=~;8$oM(nBiy|bc+-)CNYjvX^?>~qfE640#S-k%Be!wln7Aen}S$PKkzAXD7(H@ zyn~Ro;4_NnIp@yyk|ox6 z{{CQh@}P(D{^2dUbSe2}+Q})#zmhj}G^CS?{EvR*F3-#GY0aNe(mG}Sc`q7c8tJqp zjoWijTJaB2VdKlg1)0(S1ruThcga!nv1}_F#{dI|Yw=hVl0+>^tFg?WO9TC@yi7`e zclS0h{wy$uaTUUS`7h!a0d!9$yVh7zw+YUo?3RpyIF^>K(5yPs-Q;W=gJm&ob50k( zFW#-(0I33XR)#A2HxKB>vsd_ny>x1D9^Op9y?Hr?{M~t#9n;CXS4j^GHKcw{qlW6w z#~Z0>1FItR8dm7U!L&qhhr|1SJga1KmahRxKvH{OlRu znLJZJWrTR%s>ENT4KcZPrbM0oPe%uvp^Pu-MJsU+Z1BE1wqMM zKeJqaKjE2d{|wqv#@9Xuz#^i*XaeMOVHKBRG-_>63uXiM9p_X_hU-h7Kr^N@%F8dE znnp%9x>05vCmvSN#|3qStudaL4^X43j1BvA%e4ihB= z(9}Us2~!)9>jYn2z$hlf&5f;{6(1ukGo+L=mrewb8_Hzw4lv|;t7IEV`%F+uS*ybD z2!8ruZ{&E%w4r#9ulFzFSi#4r+j${Lp-Z&OhSbFmP;LNB9DU|hKm zh?x80%#dta983}G%SqZL8FOa9thg1k7&V&fvaLw&>NHk{a(KjNNNfmlD!NRwerkY} zhL*y}xqjDO0O7w=UU%~QFq(iR%EPvu1kH(R6^6EqXKqAXN7U!?Nh zjgeBa)F@q5SH`|Ul+DNxY0R0kYE$)Pf1TL;yQUFzlgIm!uBr0R#4fWcR>xE&0Tya} zEBgiWg0cjlK-2Pc0^ZgDfUJCKUY;#qHNNFTvZ&iqI!n!fmC2wPVMT){Q;Q6L62_}Y zm!7~5Jf-sf^yvysvdc&$aeqQ!qO>9Lqnu127i?{{E(`iSwF<|{76u$b8Las=lnDcDwknh_@qXX|Q!1PpK;mqcxuq7n~i zFfBEdUcrj52w|*ShE<}IlHh{H#;J7)8%fY-gqgaF&~Yurk`oT`OT$@Y%2S!ZG97Q- zG=Y4pT^IRcC~AKAZ;}ZNJGC(TAIg68I==O0r+<1z7$?{xzjq_Vp9)^?lO`0ZEjV9oATT(Bo51FMclG+XF5Pivs7+5^hRw%$2dN#}PrU4xZ)MTqLu~R^zyDS* zw4=WJetVPgf!q+RL;N!J6T*>2ehi}h5ZekPC1qx*$!dWYF z6u8=u3Y?>^I*gzf8&t&5Sd)%s^a6rem4Cf`z-|vmg#lA0YQuquPPuSZtOgk**6F9c z;0sZJa%zz|<@`*STv`d#=e~4R%dfr>8M|;g5=zu7`ruk@@wl@Kxq$5qd0_Gc4R?5L zW46&!zFb@zPOix8<$-ve8}K`B7h#&e%2FL3LB$UvV~=mDcFX4hL^^4N>13rylX>*z z18v$~hT`v99QQvk`Sc8$*9qN9U0`t;b`AWC-8D{ZSWykoum|;9$2He)b8BMGkWMou zNZ8cp*e~i;NQdn6In9(dVbDj8yqrH=YBC%JjsUQc zs(Ye1-n_UboOUF}i9L2NEnoEsV$P~2Hdq}7y)vW(Un`YEI4QJ~3*88TH!E{WW0@v_ z>sDpOLgBwabm%&dM8C-gg>4jv7W%0#O}^<~GnOGE*$5j1na1s8IIn>vty6ejogTDpinR^3Ncb;!aDtQPa6P9!Xx{Z1Wx{rI zqKadW=`U|r%%8ib?WSNa+rBr5=!(9N8s`Si9{p>;XWt7ZxSfh6Elng#x? zXPRv_i`ZB~Sh-YUtpU%i7G)}hfv{X~OwUR7?-c()x4Svt+9=vdzIE=2lqBMuudF%( zjOi}~uqg=w_zAY>VODS%h@}FAY(`PneXD^hI0lvZw<9F-G@13Uq=fj#Z#}H3^3^C7 z)G~iZn2Z>v6V3D0k|Kwc3?c_MR!~$D|7jr^(Nf^U1Q3Y-ixI+@$PvWg;e)#nBgL8Z z$X5)kVNAm)2`&-JkfHu)OfT8ucpO{plH+}K=1SzEG;%`hUH7S5BJq+5CwW zX3VTVS2vlHMe_1=|92eA1q*L)vUPbWqXAahQMaVa)im_7Wn;jK;OBICiy=8I@#%{y zTL4-oW64hR5|x>PiExnvd{0n8A00lwX~Zk<_xws~`&z-*fyKS80}Dovu>k-g(uvkS zqal*R{wxddWSAuoh~JHe)ATX27MHiPC9q9JZEP^+hAbWKG{wy8$(6daZbJ?FV^dEcC(N0d_E|Qtvw%L+Qq%0Aubm|-NAO%-BGyS&F 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

    &t>dmNzeYcoYLUG0xXqnA!2K1zjltBk%{Dwmha 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

    pFDyGHYWZ(pvzb8ihn)5O%p zb@oG!D508FK*putYnmveN+l9ga?}08Y=VIRf|Ldjv6uh|HUOF7K}?bXA|=@oO0Eew z$1v0xp^XTkt(zop3`k%gWdvxiK~b73#-a^Dq_;L#06PxCTsm+^EEDd%abz&6o&3vhy z`Y1YG4#uTY$y81$YwS$O;rU$GHyNa>7PmQCM!W3Yy;f4@P)oTLi1te@lij(5>@jX* zv6)3KagNERC!xHsmVQ;_j~spxdVf20WtKG$zO<36wA7Pw`YBd$RR!z6OLo3or{(EX zzBf%;{N0T3tB=v=8;r&IO@Fp=-dxV6e&7H9^C$#@jW`Mbl0YPsm22#MSQ}FX2n<0{ z!E^+O-O{+tIWfA#IkKg!As(wpiT_>ZnEbH3@Gv{VKQXiR}lFr4Y z5v%do#Uw&{D@iAweWA#m4b4o*yI<+&sNz&m{QV|(WR`URVS5Yq;5EU^GRNk22cCdq za1=8PSdGcGdaax(V)WR{d93eVzYfcz@bsb zk%GT3GV)D_Nn)~w{ZYQ|Te_g?ecfke29P(l;3g*T(lyHxDOFi}xj5)31eruEDx0#> z)K&Vo4#9M_DXC^E%IIQnJv z0>Oc#%{stw5TPJw2ZTTdg4_R)dB>gT^@#i7b za2F)Ca8y=S#`UF3-#*o2Gm}y6-o}n5x!rp65aQN%AEzoS2!y{)W^QVZSA>e)U2-8s z7LsEiec*Xq`zdTpT3r){WAe*+Q(VTEENfcM-3^&Ga_f+%(;10n=%rbHHR0Ujbw4Xw+IAS%P7nw2tT z0)C!{O+hK4F5oEzB7qQ;Ju*c_!~@mLI9ym1Lyr|0Asj&CjS_=SWVmS|CK-!nLe#e` z^Z)z61SWzcN?Y3RVE_V-D+^5QAOKorp<9f-Gs~s0>OrTck+-3fXkf{dt!1N?NlmF% zJ}CCB?Um*pp-J>j{+$+|T|pGlpxClO;{{I?7Q_*Q#q1PA$tDEC5e5qg zrI@7~EnF5)t=(jR;>SZMj<@BnnXfocehxT78wvkr+O~d}} zRdPLIX5De{ZI+GF^sew}RbxmAC|IpzK7K_~iSWFn1py!c2pSPtCRqV$P7{Ek1TM47 zSf6*%1v-`)e=eD9O1vEEz-=k)xlUh~W`SskRjPrYa+dVtQXGaR#8s3|4|Pic2T%?o zQd27&Lnzx=R6b-zmlO2)Je)ISnIizHGB9-Q>691VfY#5T^u^_*K1=n*_T3R3!xcuUpF z^gM11GRDG}Ih&Nt1}YGpf0E7b&EXaYpRTlf56?g)HN_ zJilGo>~dW9OJ0ph+es-%`~;Pj9TV6di$tj+fc6W*Qz;9;eIGEfNghzfbzcbV4lp|* zDonjW!P27$5X-0xJikubxym`1BW)4$(J*w8Tgn$%V38UPpIE?zxGNEDfLATt(8lrp4832MnN-%^=0*7ktcaIV?4I^_rp<1n)T-o;ZM1)}b z<1?0ls7EM189=T=Xjc~$Cf#94OEckTvh}*ABY6iGCirHTg!`o3EZ0ahxPe$ayI0-E z-N*+RQv*mHb-Xa!r>e$%_K8sGKM`C-uW@=MRl~9@RzA6TLS6lZkc$2|0mGpIA#Af_kTD8V7-KU+00=-QA@qbzGXIYn1xvLaTh8OK z^t!FWTKQ1Y2MdYc&NPB(_ZlvQg_~*^qggZ=i@==9fYKF7Z;foT9A`M|0IA)+< zSl@>Dx1rPj`>+Hm03=;s+j|K^@Ry9MPhi8=RdsV=Y%to&H>>RRh9U7Zxf?azI0Oq) z3zXeT3}>@Ebe~gAa8yF9)$oK4>MrA|;pU`wO%;FUqeNP{@Ei^vVCl}=4iHM1Ln0ax z0DuKdHKc4VS!KtK0;bBCB@-}CMGaOJ40T-Do;i^?8jlH7^rE}}UUD@B)y9_n9g7r` z-%oy|4_?#8tySl*QdfFT(tzYf<2>UXn(z6%Qtz1?x=7Z`E>VgCI8CWGGR*Fd&KjOR zjle?l?KCo^P=*iXvsw-CRdR&2NmIfY%1B2wTzc53kB3iIDT>k5;fkG>&ml8%0Aq^^>(j1Qu)Sk9(XHuq_)5O%`a3Fsw@M{cCAjM4 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%0Atm4#zl; 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%0DeC^{0)wQw2SBomzb_ZWBUZI@uXE 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%0D}ka(<*! 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 )MTNvwxO731y!ol5)Lu99 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⪙QeP*0+y+tf(?sq|u)e@g!Q%ikx=VO?1klHE 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 X6SEG-W_?uyO{AopoFvlx|9AW!yb)2^ literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..7c485dd --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + QVR + MainActivity + Settings + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..1b7886d --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8c0fb64a8698b08ecc4158d828ca593c4928e9dd GIT binary patch literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..127c9a7 --- /dev/null +++ b/local.properties @@ -0,0 +1,11 @@ +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Fri Jan 29 22:26:37 GMT 2016 +sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\sdk diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app'

    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�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

    GTYCB9PDOpG+*&ml&#fiCTA2CXPfTr6#bvHBcZ> zC9iU*o0O&HLkG|MNURy2I!(yHjM~dh@(p&<4NS74xH0uKa%vnT0l1f9SK}f?JF6~n zU$c>1HlZWziaNd4bp@}T-+QOp#pE)NDUr?QU(BcVVHPBE+5duNK}z;dKfZKzx>yJncfY}uo}r(xPwRD;Y^L!57ubrqe#tX6eP zRb#-YasK%Om`CR5JU>2cJnQ~sdw*9M@RG*dVKW)KLB2vqk9gCNZ7bn#M9_9bW z_;e#wUNgLFMKVO1LKR&QV$PcxwvAeeT2vN-=RmGqs^ImT+*VdKcQMC`?gUT-Z5!GvS{zD_ z(+A-sMxMeKWAmM|YWjy~v(QFW-NweD#Ga4s z(Kp*)UWYUeFCH!7tNPQ@9yn?08%tslekTW?C)x;I8JBsrFkJaK9{o*}PCRLnKgG-mGkyp7E`mjv_S{}-v(+co zv)nv8aR#$0*)W^9Vs)dKR2250fMn7+<&?!58Gybfz~2Z&5Pk;lRnJF zSYfJ?m1}zL6;al=%YW?+#vd^LkkwHc>FzmbX`!+R5mUu>$27!1w$UzD64OR1tuP}) zQyu0z01xz4Rj~X!@E^@+vN6n)nA-vj$DXeE$xu$7tkLYiQ#G${rMB7e4pK|y7#9^= z16miY&eaE&N}&%@3FsQbAQGGYjdfym$$Xd@|OyBO7kCf1UdHwK>? ztk`}2V)2;Bi*ZUy*I>ZE1D3GhZou*){h7-R^;HB<1kK8zP%2z0%p``S4_Pk$D`f4u|O zMU>nD9_;<~mf`WCL`3lFYmLcp?q+(@OG%<)c81Vy zga!!ps{6tVD7`j%(fn6t-NVu)&KJHU-*cC21$*@6%K zCTXt60;$!EfX4RP1{B7gl$0s@IPOb;^HqWh4(|XLYADqsl^>IjB|s-le_m6P?4Iv* zu3Qw|CN^THgV#s5(e+byPJ-cQ`ICy0#kTJxQtuDYZqph+t1KSCAUqg7M*>#=odT1UNWZVS7{)|%u8-S<*IkEh^&06RZw#RegCSPpB-#O$aS z9BDS+{ZZ52wqKL`k3&7{f|IwSuse8q-VMi}Z5D2?oU=r~@+H2AeCpD%(U5wBtKGHs z!_m#KEP};`+YF{aE#0_J#lpy+U9n2&F|X^@6GOu3ezV~<4_cYh0}&%%e<#u_cq~vY zcM8#?Jz)&k*j&$80eVlD;0fOiChspz%5=O-c$kIq36u6PB7FJ;JCvT*sx~y$3D9!_ zC)Y<;Oc?DjvGf{5qxoh^1)Itli^ip=t(l4Gy5WB`d{&9SF2INTuCKAq$F#ceW^W6X zhHpLBOo?8P>bawjV_B@@RG7RZ0rzka{TajDEts}0XoK8>!5`$P{>Wb0;k{EFExo_gGI#m^j*cXs9V6V z_TxbAJ0pL1Hj9pLHu}o(TcH==HSstAQb9IJ_pBk5ayB5`5 z&E>9(ouyShUo6!8ARmRV`bNJHBjQnoTLPf0z0kSRBF*l@358#oDXeN;B;7B zmc9eTF?J<$4KC}XqvZXcjMagN^|rRYGD4z`?$ZXH3Tu|DRC3`%YM;Q1qy7NokEMpSvPS1e*?kHgD#^l>XQVM8FA~QL zzuzP@FcdH0KFyUtl4UVn^tZPFq;B#Sx5T$qYzD-(X1Rb{K6z#xt@;6%kz+bcoLVA= ztg;29reLyV;$^h#J>He|uzW2LY;nzsE4^R1rLY!zv6O7ZX%}6s8>3jWXC$HTlgU%q z7`@ckq$}&X3oew|lw4ZT^A=wcq3tjrDT#1+!*-NW6iTbbdpob%=GWEJU~+U%gmjll zv&)+zl-Y`QDy@+diT{L8H49%V#Z!kJfgbm>S5S$Pe8(1%L8_UGH<+LM>T8Z8!g-vv zS?CkhEcvBa-vW+)^EE1adolNH`^qV(g22^*ba6v3Qm?Wqu27-fX38%GYp2H0xlzan ze&8M&k#m!U6@?PtyP=RY_8R@Z2NZ4KBd3TAu=rN0TW(SJ8mdiOq3}|T`I&-N(&##o>Sx+JEKC`*T$ zb6(eqK>8n2Q2cfMi1iQV)83>eTpJt({%HCaQy!)4i6PBDL)A~fMrwg``@4KT4jGcv`P+%oCU%kT7id7AC@%_v zPLfFOXcsmNHkJ#%5>aiBi)?Q`=Bqh?9m}<~6MkXI6W3L#TVD2hyoVinY}sL2hV`u) z1uSW2tp*uXEEiS-9>G3=s?g zP#Wgfr#2|XAE>&)5==Seu#E>1Az75mNV<)4ijPz?1B%|aZ?&*LjpI^)?Ftjf2d}h~ z?ah(Z8TwSOkh*JKBC@68PZ8UO*~WpBEQz}LJ+Liz^BITP#+NJVCL&0~hA3aY=-ovB zWx*TmUc)SV;oej}#!^Q-<1O{f1sl)HU&-DXc0F`+H_(UUub@X&9>f%u7<;{yYFrT` z<~a7kDoeyGOg+nL_}OBa-!dS2PuvMXRjA_M3qP^iL4zvCbkJhF26$vq~ zJX;2yH&DIi3IhHp{Y%+3(X#3ocO6OmwBMzW7ynyT`AY^z&Yywkp`lm(nJ92R_~19m zh$sem9q$7E(Nf%%@D~-NjA#(fQva)!HXVyhJOI&c6axG5qN3yU8q?KCxs-cl9rTOj z7bm*c8Pr)OgwHExW5}hd^uJ7hE>{?C7aWk-_TI9`Jx?ZY`KqJ*xIdWHrfP7dd7aPSNsuP5qIlQQ*9_hfDTBs`^0` zaPSzk`rX$7Gx2f=UuR-Sf3v*VfUIJpe3bTV{B<( zL<1ti4Kr$eG#js`bW2mf3F-QXspE z;64`(-tx=J>e{mP(`LVH+L7_?SL{b(!-kFR4)3|WNd5pDEOJc2(#iBYG6RA=IA6R6 zAGYk}YBMkEnEW*I`AuRTqiy7@Z!-B3pna7SVrdYUm~9B|R%Y;#&L%!t`20P)~6Z=RGb z=iWUxJ;|%#>spD6+~`d=VlaOsky=TbT|(niUVjP!X*mW#2fy&ORaf`Ve#kXHs1{uu zj;z0FIN=@?-mXjk&Wc3RtYD6x;W9!$bzSlmZMSWa@Vwu`m4_4H>$Ka1(ehqnTv(Tt zWa+(5JLY*pDC(G2J}Ox%&wSNePv~--JgtybTC$)^KEkY}@g)O`-Hxdg^r-ANNuwLu zkv~94srW0fj_Hu?>J~@}*-!<8fa{tX(WQ6#X!Szm`oi9`g?NySf5c#w|0uV z0OYyYUp^>tU;g%&McRcZaVffsW7|-Twy5j(WSs;pMzp@IKY0EX$&{Tv@1T^#{CHr_ zqjumBzD;SVC=0LJWfBT1cVo(y8tD0c=*3CP>~Pu)6HvBalR1^2xVzckF)B1x`GO7LY*9JH7yK9bT}gFVs&!_n%6<2OuaHf z*8GP6hZeH0QJk}|gFRapp@3pz!V!?1poC|~HI^;{@v_*#*v3&UZgZZ7X;}4~3-7__ zKjp5FJh}NCNUHXCsCM@d2^ zsyni2HaY!4rnwIO$(+K&JCUCX?AX^H`wcky&+_eAsI1*B$~H!I+HAt_5rY}T%plIR zKR1FmJ-W(hqW~o_5?o5nvBj)k&;`qtx0$G6v>Ast20351b&);k!M8;;o-z%B7kJk{ z9FmsWxOORGoIdyl_|vB)>k2b7?n-^Jo-j7jf>6}5y_=v4q3wfGjlWjX1Xt=_~Wz7a^JK9`=396uZxWPYN}izw-;ehdDhP5l-r))3{cUhreG)P=wX zUM~k@yo%!-o92`)F=&m*m!?;0Gp4Ko`Hp_(O`{Zi4SFp#FCUDR(XNvd1i^o)uQo)* zbyK>(uJ4?JZGLOcGg|e8j#Nrv*!!g3-TmbWiSPjZk?4l;O4?V_dA=AXycFzJEo$!q zjWjan$(ChybX4Ga(R2GQvodmn7()3I$cVyNGAHXCUTedXkxU?c73E&2@VH|zA^vuq zCwm27=J4dlQxG&3#~z_ph>0$;?+wn&g|rnETA5O#oB=IfYS>ZIvE?saRSV|T3Yk-? zf5dtBdC_52k~vwh-Z!4Jl)Gq9X8ShXebDRlc2BxgTYm3PS|-Vd!6*i829E1RKjNz5 zs*2}t%F}$5j82yY4D)2#eK1!30QJhEjMyfu!7;k3bRZV&qgrtJ?x|(}?bCFXv8TOK z8~hY;TTd8u*?6gfXip+|_AbM>bHGose$`uAJ?-a|g{VuGMH-RZ;HaMn#fX<4wAd%s z5d?bMTHOEC|GhyXm$fs0R{!$qkq}oX1Fr%{JZnwD;T2-e^8y1C@s=r zo#RR~G`MoA4>prH@_D)|d@TcCPcITA(tZTvnYw$C3nWkf?zju-NPr;?gC&On>Cw+QjXWCC!pcOxGmJN~(U z%WBXK!m7T(Pvhl*k-F-qoaQcIuaLoCd@$HJrsq%Sw<+S1EL2uwDIbH9o%Fh%9H9B8 zb*!zq)^rB@s7swJ^+eM9?fpdB6e48v8x{2X9WjxamW4G1_GCR!XBKGq_iG@?AleF~ zg0G)gir&s7z2qxX>frbNtxlp;G7k&Uwc=inh5j^Xk}VmdxfVQ97+h6V^%+)DQm#Jj z7WkmX|M6Dc1Eq?Oa?UfJ!@OO>mwz$Hy~620=cEv%;4|3BJ#V*uLLxev#39 zOMwzNl9CfV$8?5FDx5p{T6ysmsuAFj3s9a-lGc@Hf$v#hj# zUiL3Qvma1>K0v?)VivL_+w(ydK*pKA_@9PAd9KudjIUPejoA(nPATo$K z#G9?$H-M8FNO}Rl$S?XwQ;xJnUE5xDTdh4&@pS$P%L02)-vjqrV!)OOG@LI5Kc_v@ z*`ZZyNfi%eemd!iXhNwZW%NaG#(&GP{$2|3>G`F^572o1tl)tL=x3#=oC*Whv+yYT zGB)F@t2e9r+|V&`ElCn^{@+&O{cL9;ziE4-eHpe{0b$ zU6gRx6qk|y#@AfbJ!czRYBNt^%>L4?Ag7hAe_TlVQ$fkwnyJ}G2jCnzJOg;+)g0?Y zt3XCfN?0F?N8!!byGRleX8Q@P9G)D-`^}4Ac$(<#%|_COVBO(k74iFmWm_c>jgIa zGmmBBrIm*GV_i37rw}~E%%Ftm3ki8(L&Y5*>g;wcg!8X3^ly?VD3%&QO=CIi{Xz8m z5#75|Us4XMoAfI``5E);K;_IYHR(YfC2S_*E87(Lzeg3oLxy=Ps=X z4Wkkg{TqHDhl?K_Ue?imP<=&zg9>%=0s-BZc~X$h1+^+@=?p;<4|YBiW84=<-#S!! z*TdEOpeWp&r9I$>m1h|2@YcrJcjbWKz}x1Vg_^g>S@^}eC$DAfQkEpr#oc?Wu6TL+ z5gZwg!CzEd=DIh^!mq?ozzBl9M?@8kK#7A_^7c6W3 zaHYX#I+O+b<6ipiVq;3_eFk^e*`?bxhN|+UwS$1*8@=gISzv7Ol6mIadMTsAYBKR9 zGCGYIlf>S1E;B#s8}2t~Wu`g=SP zu&8DT)|UBWrGDjNTabU9`^B%_aD(3@p>O~(;#;dfg!TdBkP#1?>dl=kwNM@R=@h8G z$c`DClCZ1q@HIf{onv9MHPj{7?rB(ftf#W|Mxj08JdLk*ZDEw%Z7-UvqlxAkV;n?l z@5G&@@kXIPqPUMmM;Q(1U$5jB^VGGO*uyu{cCbbSZgu5p65Q9j`1*Wcw2tO;oCZ-n zDDHj1cK?k{RHfR5<(iGJ#sw9TylBInUw)trPO@xG=~=(N?yFpLP6M@;yfLGF5cqV{ zt4Bhw7!Hi8AHa-YHH)m$q%?Ry7pCff?qj|k-e%@O5c2XKxW|?#qmYRl;a`1sO(7o+ z#L6w?WUxtCWjH+*ZI@gcatKK{a>u>IA=fML9B5%2D{1WggiUTqv`6J2_lEHcMNd9k z+I=BzcI37Vqf?f6Fl00uTbEuDU7@T_E){yE;%)+^zZ7tVnYsgkd*CuC)t^u{tQ#=; zllbSKvd9$zg8*7`2m68@oR2)glWh}5eCLfWr>egEoA=stMejQ+-=r_N8JhYO-&u8} zI*;C9Kqlkep(BqA`_6s(@_W1Hv*5u9ZW4`S<_A=$TJ-Hm72zq5N3$}*FYnz7$&nJV z{Tu`+?m&=S&khf$*q>}V%Uo-MdjwUTLVk5RKWlMk$Kl(kc)dGYq0!}6UbfRg>VU(~)irH~CP&|~YwA=~B_FYml#-8OppucLBL)G;mn zLG2)g_EplBe4FjgrL3 z-_h4+_8N%`R4%2vtiT}Er&XQc3z6X_>-^bO6+a%+b9E1MrFS_^7f5C=vBfSLy$iaL zsv0YX6K+0KdQ??`OPqIm^gelYK)I?rN%JYw|(?6kALe6Jj(k@)eP&583&3nAJ>CswF-Rko|*q2|(j zw2S1)Zqg5D!LJh*!HhK^Z}byw8h^fC)KQ>+=V%B3_d3w|HY}T&gvue4CUYEgdn1bD zs(!DhPUC5WEtNc)rwz#LUWZHSQ%tE4zKC>Pu?J<3xgET?tFX+mu*{{-5nA*H?zdr; zUQE3iOwmT>KV8a#;&)d-0r(Z`B0!TlQ-Ha~51VUDxK&Wtpu&Vt+3MYF9y5vx|I_CR z5mW}{>iQdnRJ5h#A9GHJhs(rH1R{W|+G4#eF+zY<``Dh1- zeY8FChxPYA3N_KET)^^(ho(a~Rdt$;G2^$LmluT*A>q&i^u2-OX=qsexmfvtXccOL zc{C&svEC9Y<2tRkY}hxa?Wce2_P{hEadG)Cr5+gD@QwKFU)rLSS)&yLT(ub<@||V!XjY3sY6EKp`vcgST@df3Ml9ZX zSbp;U%NUUTsH;l3a$GZi}*j{wRq zdzps-^CCMp+(rsn7GGaZ)@^Ge=gK^?aukyr{~{$v<`I{)in0RMus08$_?Ge}TZS}U z;ra7<*vlasGL%;`TS~akGlWnNg2c!DLY+8nJE7a8 z`7G}U26a`p6y6o}vdfBal&Bki7{Dhxr@?HKFMeaRb zPbTFilrUG;w3L)WwQ!CL$I9Kw*$zhZay!Hiq89@SMnk&Mf?*;shWPX>H%aZ8LO{m0 zPoG`6t3d^u_K4C#@m5cmCx3Zg(=>OAi-W`{C(^`(!;cL>a@cTkPkvB4>l}C(f}u0T z*`ZcUjOwzPQ7yTzDBK(Wq}*=JaPLN!fp1hKhqyKcUSwh%lI~mJP`d|S6qpYunb0L_ zC2{p*Vh^^=JSNHbM=i*VpnvDpoO%W0Q+I}EV<>nmSbF6L-ScpfakoOIl zl~)>zU)asvKNk5Gpc4t>@bxq>*V`v5=ZNfMzZVFZO7`J~f;wf5cYR)L^rtb7K6*#{ zxcsMM-2y->XBM>YI-2EbMMHl=_!o>oc8xtb?I8$FJ%+ZsbmZqg%y|p>V@1FsPD!3( zukVoA9Lfi3#Qi2oym(^1@r_+0M%TD5G2snQ7EuF)O3xg^Tc2E7=oHTb)mDWNC?PCU z>_TQKIm<6V%W{q1bUqWgc9AeudA%Q$Jiv7@Xw=kFnCrk8V>pl(l+wk43p1N8r-jYi zCfc%z)X?!NQ#d$kw8?px_7!9FRTqjzQ9Fng4V(IU+O=mc*pW{jQsxGwY{9z$*b(pRYo*o9R{03@T=)VfXmS zmdei~bgH;gopU{wdc|lfjS*Mce%=$~_>pvg4QL43T>|1{yxM%?#wW*h%g(-2r|BOq9J*HXRHO&o|w`uQBy}EZvH# zGWl$7P(HQ2`j*c1hrXzrdsl*6#0A=!(w0b-t*ZLHIN}<{B=H=qAzQ3u+5s3!Vbe^j z(yK8BEo}qOrY|F(X8U>3!+FEHX2H zn3O9RRFMe;2lDlQevnJ(XFmB?T+XnZT9saB@u_UYjISzk9qnE-z23)Ipr$y#7qI6WW zdTnV=bcQD+gJHuK!XvTI(s~UGBq4Ql6?iSgjTi{@Eo@>|c;sw9eBoCX{u%m}k&s~@ zR^!1NyJv&*gLL`mTF%kz<;tAKY60C*ua}ma;m5v2=;yg^{uS=nxDs|&ghRlrb>y>m zfx&CW53E$4d14l&B_Ka9Odm$P7I**kn}k4iL42a=`jZL=u1cqAR>r<^lw+lBGN95u zuOWxF=Jexdf8N+yJ%|9yzfw)oTBz6-Ch55pgSP-L!+c*ZNw5BqkViY zV#Y-7G}uCiP7OZOmuP5Q-)3p-`Z_yxoL={enUntM(EL)W&@pZNpri^mf=^u*Nu^^`V?y?c9Dh$Z(Q&=P{(JM!FM`&Cw~ zY!d2_b<*ZfV)pQ9u~OP+%CFeIQ0RB_i6q`zF2lF>gCD^$=8rA=D1A|{rOlhXT6>g8 zjmR~33M%;DD`kqUj8a?_c=sx+raGuvjr=eUkTB3PE(~qS9ibwhf|PAByqzt7Tivu6 z#z_@iHP{g{_|~sWXkY{S;ufh~9P~ZH7Vx~mt!zU^SG+>hlysaau-yGjb@J9(UvU0F zef-Q_R>;-27J|~`BsXj;1;NE;Ity%cI6uLydN(f0wB=VUtdr3eo_Y+s-U^|9sZ9blx<$4%ZCbgC`Z3%s4aXHc{okb&Zw_#O1*u zLj2=Q;g1?}bRrW4VK7zte;zs?>b-K}tbB4qo-{J}_W9mj4KLqUpWZ{AirSQR4+wfC zm-nw2LDp>;Q;76DUwg1x=d#E<&F)<5cS`>C+eQ{~-|P{daP76X?+;A+?Byn8-I8T+R& zmy0~PqaZX_bkk?2+a!5*t=>0_vf-_1ICyIN5q0CA;?!S{?7a{crl=CW70LYI8Ov?< z4;H3ZE2@`x)A)!kPS=YB7P?eUbB>q%#)-p0Y`o%oSc3Y%LDq^vl_S@BA8O_HlW%Ut@n6YBL_qXZ1-IHFntghy0VnZaWDzmRHD&PsG?$ z9q!x?zaN}$(H8rszER&NeHx?Wx8pBT#ZBe;6SL9p`Feco;Pbqwpr~q4!1}m9B1fN0 zZL8oj{Zjk+K3&Y~Kl)94-Hp0B`WkAAQ6fUA_jQKXvxL*ULyEn{1f9;3ceSbS(s>J!{8|7veTTen!IP*~k=-9VVWRB@hH zky$^uLWrDcmkHbM{Rts7x@J`M?22XD`|x|7Hl;huvzIzZZ0D6INVEgnoN};qFtOpy z+nD@{u4QdI`DpKjGgWypcZ{WLCS42il7~21w%;TUWhR)FnM-#OM(oniF@Hm@8Jeac zWwUP-0zG~yhSBz;c!xZFadnq4us9KeRUAMXOclxG9X^U0j~f@AYGVQVG<5H?C|@rK ztTcGZ5Mqn#ir@W&FYKI!v|~LF#1~d&QxjbI66kfyda?ingKwEa6zN_!hO(uQ42bA{ zQAM=S_OB3h#+J0v4?x0~fh^|AbWbG28DEj>fDD2e3w3Ryzp&l&lAGp@=_cv%+zgnmZ?+t@)BCpuz* zNdfoIGl$Y9rS(%Z4VXz0wEoFeT!w@yg`Jcx7Q|>$%RWQ?TvABHtBVR@8>%``OR#7W zN;mKz=VMQQ?ojZPbtfhPgtj<}>TzVxT5)zA)CTa`KEX5Wu+mF^n-H3+y986tIj&u1 z6HvHKb17v@^^Pu8A{C%02wVG(XAuaIbGL5pJU`tdM&~#Gfk~<_;kH~CtPLNo$Tf(# zaqj>kimV3zDD(nkIC@t^ook#nHtlzVbl?1QQ`0 zoZF12pC-ImCFb#)ev@3K!}>z6TmC`|!9!tv#b;~3N&Jj)AAoWjr1r05)@KYXQO28WFV!ti2Z4~5LJt4LB0720B$-^6!+VR5H@#nJ zOH<$iQWJ%+;hE`>s$AN$@HlxPZ6IvNk|}@N=Xoq&TB^8WT9G^~2}Pjp#q!@nmWoyE z$g54hADlMH%k-FKovSZov6u_;@y_EgyhikjF=0WZ@!47h2HD;{=GA(Rd5$u973_eo zGtSA~1HPcFH^nj*0R5P^jg4w7VrQSOV^zH-?-Kq*pq&y4;CM4Eb6od_)Cnix&(HJk zG#*MeA=x2?E9z$IFHDi}2I}5UITRex>HdedrbNr3gBr)Wpg%YbK|bn{LJ3kb?N-8Xy+M4u5{In#++w@tZ=s(Ioj%D6s(0s1#xpYz>)0ZUyx7ZLB zD*NJ;St248@YXC>x|A{BB;U1SI&Vr#cyE@l)c2c&q6EPpc}%CQ&=(#S>l+~CWaJzL z+P}F{+03cFSQ^&bDCewuVv?vMwlPT{U%FxgJGe#gwtjfEI5%Zoz(;m|OTiN^`tp(7 zr_J@sTd}Db__w%ogq#XJmj5hAk>L+nW27XM??*C+)-zQ$4}^wczY>Y_Z6%Dg1y+CF zyId(RyUTXvo>US)8*k61MEy&-fCf%_{Gz~vf#3;lcJ7(Ocqhr2qZ-N1UM9?YCf9CB zfV0fLOyu|QDriXZW(1l{jXd6GHmloApq#HW(o8o>H zJ=~i2X2LUd`^Hj{hx{hFZ--8(kcX|#_B^LC!%NTA<%sa?_dhY#)_;i#!q0umM5~JW zPTF+pDpJW0gq~&;`Ov~as!@Nf9)I`G>(A_6S5%YX8Aef&y*G*q2!_3}5Jn}95l5jL`AD?33zcESu0(x&a{={%?HMelm?=A2w4C;#`o`QG(B z&$p*Sxkjts6|~n>U8;ON<$gAM{@2o}8;&%fyzAUI!oFgDRe31{DYQLy6?>Qmd5P3B zu9(W%h(yaet0VPumdpz>^mA`9=K7d_&=M!je+mO_!OnUDKlWYz=%^rZBp zBN3E>Y!g?cU)?24>LJz#NQ1B^>BLeRahln(YQ8A`A~dh(4ORJ*`&MjY{GfpguFyen zV@w3h33hACXWqphwy@<$k$ZgzIQiT7Cw3H^Nq28=|GX=Ib%0~Q3MQP4UxzTb%*#$E zt4N7N-@hNv>wJT-{Kn0lf{%aoE>#40f_ImlbjHujq8yfr}^@vUn;u%wu!1s#vv#eR$TM=Ei| zPH!9Kp7G3ytXw2PgYk@LkAx0}cI+vN?9!kyM_ITC9{%flv~JHWIR_P7LmmIIFo6x$ zWdU1FJ5%MIhCU5+L@YZ<`*yxdD=BYTmM{+^_fnBpIO337JJh}$yc8s@?HIULv!7d3 zSRHp3e?m_c5S2phyqVcUa`oSisg*m=-+2`7X9$KC*s2;g!+so)Lqo3;Q7$`X6fv^n zzprvi+YkR19PNA2r-`gJ?AjP-VIi!{&3ekaLcu{DlWq+pxvneB8)`xMI8GnB9M zoB(&sYajeVPfsRTGeJaVqG9oqb>Y>3d z{=;jEuQ+(K!$2@@MIOd*g?p#S)7q;Kz|~~lTI3!DVr8Hzlmz*rJkEF7pkxyT>EdDN zT<2#co>qwPunejn)};abb&J0tnxNeD@v=UBImDt$YvNew^(nD4m1_H&(RFATy``#k zHtT~KKT$a$R3uHID0?zWC4@zK`QD(@YbQreF+K$Yopjgn2OE7l{u3sZnL6o8-%>3` zjq=rtz1nv>)R0sG9s_|1_K9eB@orC9i#?2x=L+XkX=ImSxj^8{Zm*jn_Ah|7KB!Oe zt}>1~q8c_BU07is>y=s`iT9F0+CB?EUDt&!Y)|LB7~HPg#bTfj6`dkuK>k~svEklk zY1WtCd~j(XPAn*76dOmRX}BsQXgkuZkUZO2JQ_ypZbtt2W8w!Z{G?Wb;_X>blmFpe zDQWNDrDzzxO8i{{EHbBb7u(XdX$a8C9rUr#6`b@FMn8HPVX-V-$-eHUA5q>B*N6tLk)`u!N1DEFMF6ur(&@lin7Lu^NtHa{)^EcBb z@yw@%*vy2Q@WT48kku^}*)O^!VfWp942^HZ|8D>F*mH4@bl(-c^bwKjH}i+omj@A< zTr@sq&bb3g7R#fzQ}dn(M7&BHq~b?^7Nj*$eb8fcnp_?>R;-{tsHP}qYdLQ&IIQ=P zm);^SwLK->?95GgA?PkIsJBYxmlud!C*37Ea(fn2g(N>Qd5AP(j2WqXh09CUJNW*( za&$Y*s;cl1wz_ovpts{*?PN9ievX}^uR({bDTn==Qd@UE+T^f|@!^3}UQ#5ByGkLb zSGxq=oLqvu(ihFGc=m~mMZ#=wKJxnR>cx$Ph_vC*5n?wG>q-$5O1YU?JsQ!v9Z;xTe2MiWHE`;m}ilNI;`?;+oFNHTUgE00PKjr4Fwhy(?D%4_ANKx z#CL(CX6gQmOy}+hHm}1fSCn$P={XKu;An2+GmzDG=Y=WV$0y0_Gj~j$^A6$ggRM4I zW!)$G$*+bcf6;>P7%eZpfQww(t%vhC%2lYqs6CulI|NyfAnwY%}RZrz$4 zRJaiymzXMup~nl6RJ!_{ah9DHiSJxRQXq|u`QnVP135anP1RVA+B>|qyPvHEj5YV8 z@WK?kg;-%57(Kofgp(azbp18uY~i0Pip=I_`1NTCl2PN;MO*ubQ#g-mO_c}MWreaA zPskZ3Jh;nVhqL+E+~?*PV%YOEwohe4vheZRoLCm2x^SuA`g*5Am55Tx{Kv*>T#i^IydiEPhsh(gi z1-Pts`Aqx zCT2A2i$Km~2v&~B9S13|t|@jxglohXzm9L!Qwm;FJUH&;-N`0>3-cdyK)mo8G8{?p zS+y4HCoUM)2LGsj6|VTO`6#KChOeFhiMnCSO=+V!P7GXWE+sMc`c^2~G%J_C|2mUU zck}VoVi@NDR9V^;k#Q$@R?%_88P-*PPnLy#u|fJEaHiv4oA;tR$Otepv&>c41Ud65 zXhIk?tjS#s%8%MDp`38^(Vu=#c2^-Zh6`(ArWxlA7oVx$=Ph@7gZtJ~*-+$5Y>9Rc z9TT-^5Eu-ua3z?1KyI7L=lK1c&HSc)vscex@;9sNdQ)eEg2{9IFyHj93f9X=yHbuZ zQ5`8AgEWgY3zw~r4bIg$6NSAqzf8O5Dr1m32(Dv*Ub=Bu~L%5H5PrZ`hC zm#uwLF=6oTFT??UO}f&KP=f|JGpvG0M+=1t14-fS^d^4EXO$#@8&@#QKEm`;DX~_j`3Ymvp-Qj`x@h4_Z?O-whCaf@5tf=d(6f6T3~qU38dbidg!j*cn!h zXx-A6pi4hgW!p^YU#}m+(N>vStJ;`@bJL$^7}OKBMZZ9{Lr{~TaA2*%N5y@*LW1C? z=V^kc&1Td3Mx5!?S<)AeHq*1mltdf>m>%jHI$c=1k&RpE`?dpiXo5U6QmK=QAZBbo zLkabF%B3Z`>`^KxXMYd|Bl38kUQC4j0s^j>?XL+|j{{l1wt{I4p$`Cgz{2Pzw znpYR)`xH@B4vZs*R!@80%siUdY?kuO(O#AZxy;4=x-!QPt|IXdO=HmX49*to?TrLkb$1Qc5&%a;cgj*F zKJ1T3RN`!+pC86P;e27EMQd)%Bmess%_NRP?}M*ZorF}o_%UJJL$$si zSs4xjaqLWzBH99Z%o&0y`uvAMb4`RGT;DjH;0BW(n|gZVFs~u%Y-Cq&!zhJrR>~0= z6v&Q;^z7`asD6dj2E3)Fs(a3v@SGd&-_VY5D!nZqQbf()_5%mgN>GU5@Y)xqjL6L} z=#dPRvnf`d%-0bU=C+Y+O7L6T^>`cbEe>Q#%KJN32`qm{WB<4Ek%ZxY*9#z$I6%2A zv81=Lycg=smuv4}>+As#Vy_JFcu{}l*$y6N08U3?jXlmE#t^&M!Iy#H3hh7Ad{Dx$ z)v}dCUHYqVG1TcH%5V*QE^wrOaf&)FD;x@Cf(`bfS1xJ57uv)(D_A4_bNYZ(;==FA z_H|H^c(WOFC6f2>xjwPq40%<11=}KZcLX-HNiC~cQl_LoLwbCaF);m)n#6x= zbSs^z64Ovl4E1BZerG;v0B5>clu)U_X+l-;$J<}OZW|*{u1NVo&Q%A}mlo7BTfehx zsVVw9-J_77noly7f9s&uDbXpyp+GTu1IB4`lDLb)#Tnw?uF)#nA7h_2OAayzUb0Ad zT1dm?`pGtdhokF*s%En1iSHK0RfZ{P&P1)UI}F<^JWWY+IEqmv-AZ`{fl=Mo`B7Jx zLC9SdjiRu=S?tRDl1k4xW=AaEnSyu3Tp;Ira+kBHMKv8(&q zZ-Mv6>ydlVyZXH{sJB_`Cr(dUo8=!nCvAAJ)i$>=HV;>!nzB}L z3ekLw85&;hg?0TJGoBYUHfDo^UC#TmA-S+l_v$wn?ug(wYq#bxTAe@hvqu62^Rk9g z_k(9cf>!$TX?_(bO!HBh2)=!FyK9L%x$yE7M@L4%Nqz&A0y;i5k4pfGb=kf;FOKd0 zRt-~1TYD5T`Q@B2ravCp~&hySOL7vL&{?~iVU3}h~Je$!sy@8eEc!4 zckbk||9r4>^;+_@h6Z1f5Y5ti(Znn_7Bu zZlYoE?*&wyrf91jG4r!q8?pcu_vY8si&Qv}5?RW*9;>$a?XvZ#qhgMu5YBkF2%%x712aq3)`?R*nUQ2pF7w z*Nx-|zrl}V$*reo#}f$#Z24|704`cRe9zA!DpgYeLq#~<%YVN&g*OsXZ& ziQyeWQ^$$)1V?;zNm+(+fZb=@-Fk$%jb*)vlX+=JYgFFP_`duZopjoWh5-Cs;gQ1^ z>ME6R3F)38F^S@W*XT#~Sy>1cgi_vn!_-S1=qHP#C+@@uAT~w-1HWnW2%D&Y$Xl&Y zpX>Gf_@IQZ*W49xpa=IHGE7(Jo~L}IW@;Oq{+=SCtQ^nDh>i}U31TyE8kgRR=pDd)=M?T@g@-X zJ~-FiPd@MiGCIq7x{@oWZ?x)5C;SF3$(M8+*^bD0C2V+lTo<5|78sas20{Q_ICnBaM*=SsB==gSHtwK&fLNH>eY%Ha0JtQSA*wQU{CG)Cq zvT|HRf^SqNxrYYwMcd9Vf!|;z`+Jnhoxyvcqm@f2X^H(%jw?UrColEz&bUPM60!AF zV#hPolwZ9_j{-Gh-8#NC?RVFxC;vGfL}R2xD&`tmy8~?&rz7` zS?2yG^Gm&B^W`#B$@s-0y~NE>DbMfFr$DssZyBCY(xxa_e9QtKIlROLOw#r##v zd=hC0DzCVSL!(MXb0H1Axhv(Ht7ASfgXmr>%eCJTH5{Hp!q3sq3lgdBTndGbx z#V5vAei|wwy(%Dd3dOA|xine^eTt9Ah%;GR$;3-9y1e*cniT!!bu1qPjplt*8Qu)l zz_((3gZ>VR4*ts{1LdN>)mA-MJuXf0qVp}~*_18Kc(t)7a_d=cxgl3@W4(%rtULT_NeUo|nEd6HMT zq!vh;t(r&v>=`27q}s#dWGJP8Z@wnwG-J!%6!SIYo{CmNpyuNYFF-1S;~R0rD_$id zKxQg~%G`uwvOAblV0e6Y$*&|IBvS$_NhC0n6R9(Ze6^D*0&CT8Xl-A##8L<6(rWnH zIW6+Lt!I)&a=OAQuhq5Kick?-i8J83<}UEUTQp)NQI&mR3zQSTQ7AAOWu< zh=tIp-h;4^55q%CkKocEBv0yGbafTw(lv5)^?@6P06%#RsMZw!m#NUu|sW@1dIEfvY+pBb1 zRO)18sR@zUy*@v9DB`Mj#~)tQc`rkxGQNkqKz#GESBb6^J*s9cZPFYZTy|$7{R3mA z+dVcl)r$f;tu?+Pe)^M4C2%-!wFE{}bAUXir`sYbXX-e&RRbuY@us#^l7Q68cblRu zYL$E5FUd64f&H*Q4o4^<81a~()8?|R<-0j6Ukmn{5V>MK+|uqQ-)|fKM!-Kso-DR6 zTn4+ziU}}5*W$Nle8gD#hBL2aD-6yKAJ~jq zy1#W}$KyD41+L1|%exg+PK>}z>t68fnRN(#g25Ro#zslpkGt`_~$WwPL+aQCIln{x%3N!cwel~s8%9uPaU4rprwchIC`nk&V`vnKhwCp=P!$lEz8TpR`jX4Gs9()aq8ByL>gt@tqTkXK)`a@Xyb6wYz{bRj*fF=gTpZ;EjI`RRQSw0sj##fn zTOO!I>|Fi)Bl8&Og8H;mc>Mim-lXKYyrGS@FK9_40Hkt7@H;@pQwx>PD%M>gNCc?q4tO{+S zfy(McVr;2FtIN8;MDb+@NuHE<-3TO3s?aR(r9BrKtyc>r!Vs^m0?H)}x4 zd_;sOS{bLJAiP~OPR7v>0s{LDD)qb(Lgq(+q}+(8hPNA&OXK0N)!zZRMLIa4!qW{W ztqID*JLZUV=y!u~5%D@$@I+HeClf2YEC>P19w)H!oyL1G;3I6BV{!IZSL0vnEhU{1 zQUHLrlCWG)I%f`(gfSNpNlGC;fg968J>I{HF-m{k9J|4ywce?PS*}QSOA4pdtqUKx zvii*xR+z94a{<3+w~@oOAM1J^-D}Okc-v^uY-ms^3g{frp6P47aV1j^Wi)x7pz@?N zroO;Db$nrVsjG)x;q#MYz3S)IU~3EDm(SiZ1U9U^BnB`fgO7M8B%%stw>Mey!oDmO zI(qoC_IRP=#yO6?muybDKoJjF7#VbN}XG`^yEyr_!p-rqRPBKXvG77mS z71PCr`7TEJN@=BBY1?X~S=lN{r$`&Zsa`T=`B?v#C6O}mQfFKB4(?Wr`$c43dCm=c z`5QMgR5|>3gJkV}!p$+ZaAq(H)xaJvN)&)9&&cd#qjNU66&;%e;PGM9oDBBHJnw?< zLhI&KU?i1|dfr}Y6a{{MNMZeZwI6M-ddcmI;Ro)#@=s8&JMY~&Xbpctj6WVv&f_Uwv&?A?3B1;2SrNvK2WK7Qa_AE}5 zKDFlotVJ7KmgrAxyHy_)W8`mnZZb`K1XrfFNf{vdS10&*;3X(^+A#<7tHvUWht>R2Crd?SvlONBm~&YFK!?uexi!5* zB9r5>(3MR=VBXa4I=E!&t^5E69jB#K+l53O%huNRHkjP$A?8pGHfv@5cqIGrnM#WM zTH&UN(1$N?(hT8-u{wk5=KNpy8=ikX1k9A%lvK==8&+#~I8Rq9nv^U0dFQon0pFSWhv4=Nm`H9nSgV>n+?qxF6|8_U)9$IlJiu~;>>A~xtFNAqC?nVRR zU#LDzS2_mtbyovw<8^%EmZc(7;hCwLp`aWGPB9>D_PW`K9yxDhIoD^XDO2N%$3aGk zX2zvLgAW^0P$C}|?eZ-3|0oI*?m>!tHlc!0(K%mhWkXy-k-KO~w3I-B?$-)dZJ>nI zeKMZHWwL7_!y6nVp}hkdr~zJ{R9bT2ZAAQziq&z~LnPVmJb7JDZk)Ud_z?2*n)i58 zN)nUW5bw?R$V2F)EM$r8RQQszBz%L3OJ4K4s!=PAWb{_&$<~oAZ+&4ciomituyP&x zq}akmsVaGXVNs10o@HJ3RVrcN%&v)U?!M1gJE{>F6Gn_~z>`qNk(U$oVmwBYy#UDP zZUT7CjIUVz-GX-{vpWFTUfPVJkGTYf5ng;%(M5!HwJeVeGwG50U^|bK3pgBKL>7Go++a(2V-^{y< z`GP5n0G?)vS+<^O(9ZhkBVa}%51!W=t6Jyt5hCaFn+ctX%C=yZNC9IW+6vG1$BF#m zkSidG$v2J{qTk)Q^a{Au(~07GJ&Ba1ZWY?yZF_PWED3X#{++sIc#rQl(l|w z@9u@_kv4>6tBH3xQs#_sZ^L|BgZHFP6%Ty(p6jWnP-5&Iq<)c% zJ`8}ohhW2F|dAu2GiQ8e9N;b-wMzJvH;Xub(lbL7RSK%_|}M{vD;%_ig!bz3fMVgGUEF# zdDI25ZzLK`&=yhZRR9g^=`_1MBc~6s$NCw6giJha&e0N#cFMJ@(@D`dzb9OL%TR0g z_U3}@6-iG~0_CI}Pu{D|wi18jVg$y+ z2@rd(MH#@^%kgWAWK1Hl=Amy`u6J=HY)_`#z5&`?=Km=*_Bp89g|S0kICHLcRCr8> zQfYb)9F*g+{;~8JJb{eg!p@Pvc&{Cpn+*D;x?u^H~cJ|mZ&3H~zH#)dTNUsPpE=Tyn% ze3#&+2=GVnIvO(jB7-eTs*Oe;{W@_xj3ONjudYfKEM{dFj5~ZfEX(N+!rY3!Yj9Ji zy#4Lok)zyRf;r^eX%_i#+K;yl(#8v%|*w7G~poH9pNFWlnC98a=+1jl)#CgG$x(samvp=E*KWJFxq+7SU2ez+x{;hAxlp`v_D zwci{OM4H_gfZEDly5w2!A}l@xRrCFk7RPsP{I_j-;WBJYjJS$H)q=CB=^<%$ppn@4 z#B3rrr5DSwb~`8pP$Sq;t1bVLBW&DU2=!Z}K?E zd3hD@d9l<^KhmxQG}_B;3iUOdKk7Ejn2UX@x)SD1Wa-;fuvmPZZ!#2eZ!w-9dVuH*gW87i2rG5pL>iWkT z3UCGf#54(}I?=Erz`Jp+?}8Vi#8KYcXuLXhMeEx#N9xO*c}@?xXN<-7CF=6v@J%m+ z{u}lkuSkWqgm^d@>zlckf2r)8r_Jvb)! ze!@E%k^dd}L7#9po#Z-dMqya_Q_fJO#OU9X-I2T?PEh&a-y+|ycF^_yG^tbk=qL*x zt*g)1nJN`h@?AHynli{M$;)l;V9C^Lx&rsZSg~!vCnA}A`8<`;pUR97QAIWijW%sg z{Sqac8W~Imh}!}s#y=NR+FMLWXv2#(iqm+!g{m-Aan@JJP;i>BIR_#MpkN9;5M}ta z@c!j+GzE9J{USM$6eDq5js#YE;yduJ^zX@{SJnzi>{4q**y?d19>AOj>yE#Q25n&% z)`}(XU@7((7Jn-}2JAVIY+zHSwxk5p%j>k=QA7aV)>|TBz9%-$;A#}zP~~&Lh-Y8| zy-ZgRYa~*yol+^_I1SA|`L+ux1%hW9&s!A4k(R~f>b;6>u}kQKFI+r7qAk1q&G*E4 zN2jQM2$^vHMnPE%oSn)$fJ`88R|H5~wN5oso8QygNPhDs*SO5T8~)&GteN>p377O7_ku(tu8XoNTbCFa=nCEFj%nM&bw%C@_V$*L?#L zS>wKbM)7?>hmX`|ah)ev$HLciO?uvl)Z*VwRtjn8cp@Gd<{25}wAtg-SzY$gVjrCi zCuavOOW4A_sE!KLtn|GEIR{4hc>Eq#%xw=gr8@UDzT9J={C9>$w>vkFrA z*;+8B8dTmMlPt@ag1cz2G6f?PG^{5{loaul^c08&z?os$k_gkU8?&N+9@Lm{Sau-jyGH7=B z4$i9Q=@dm)v0PHK==cHK!+So-5%-T(ju&Y|Ut=_Bdz4EvKrh{^snW~k8bZgs;4{k? zI^qXFq-q@0^-!=+QSL#NDOZ)JdHQW#YrtFqH^XejTzJn?AUNa_HE(GKX282ErvipW z=wg4m?|xH)E;^>Y4l9V@Kjx(XO%hdS7YwkY1VaV4vV_VMJ;NAxFK#@w$`G@w7 z>z&VqzuJbUI2-nX);l_OXB3HUq{45T$hY+2%zq-~8Pl6W9OL${&dFKjpmNHIxj8(`gNo-?K~5eB4#`>vvwzPw>Wx()|ul zaYxFpOVvc9{qY}`r$xA!ZhDrjT-nykV6*)Phl@)UHQz{;q;Az>$gWq5wlm8uGVQDJ z&`xmkKuoACR5hZrL%BWCqOq-x;pxqj#kbsIT=!d;1-(`B9!M-?GS)6uRgoYkC)8=_ z9CDNNL*Ktr{7!Jg>RR5WiY+2!=~66ot^k1N#!yoymsvLzy2Za&-9p786rfBeIE}Qwkj=jiG+5e9&h z5;X3<*jE3eIR-L~ejO7945l`0 zS23#D!Z`of;rG5)Df$vi{Z*|JS!1%m=t1A?im9j^lwQS&#Rpyq(FUHQl1~+jb z#_4S-TWp_(&>z*5JkHmiGK5bH3LSMVGp+k?#O<&{O6x614*MvH6;ZO%lnrwW;S?6F zDi?9(Oe2)iwY=0?;g;Iu@$XXPY%m@Jc%|_pIR!Zd>*GwF&t;3P_oJ5#CR!jhrSXcf{OS&qEff z**|EWkud0p!2+X*>i1}?5LaS`iB7yLR3P#cY@NU*k+0QadRhUm6jUg^>v*eu=3&Y( zF0>K&&hP4}X~EO`pYyxf>_yjOycK9h$eAXgovh*w@Pxn|Xk_La<8na(eS^ZT&~~Zd zlt2;Wf|Fqsl}y=WY?P8QS})IZBJx2oOZCV1e0UGp5lO`w`@|7kx&VkZu@55|5L@ro zGK(}d0X(-h^iFLE9cnOrN6N#dSO0iA|F_1%MEB(0MFRb%h1ZT!q(RkluY1p4R**|{ zzPx@^umC!|XRBEC<&i=^n8m1R&N9efNdn(y$~t7`s_v?s(vZ)US~}9)&|>igrD2n4 z)RE7n=x!IV5*|rvo_l>A-zf|#R%hYQ7!>;=9Qtgw7u2gwBD_=w3Jf7EO18B%_I@Zf zO}4rZKd&V@VAh}Rg!{k!-~PwOTUA&qNMI_px@reHiZAeLwD#6H%{TLCBEYKTz_+wC;Yr@?P^YHGTU(4j@r0pRcFDktB3G z(M~fg<~s-k3+ydw!FFMf7Z1og%f#F>@Fimz@NHWd?y9x_Bv|r|^$<1c}$@bgrRq>q0_-_e) zO84gy@>{dd)_k)+CMEad<9`%{$F92+>mByWtM2v7+WzWe4~|Ga$-*Gj#l({36)Yu@Ng^od8$Do68OVvO+lJ4Rp>Sy z9FadGJ7T0PjNjG7|1z<5PF*a{d-j~!V;)r+a;3IN3`9e1q5MU0_6CRTk35f;hQ!Ex} z0Edvbs3pW+TlDHvXk_nChr?1C*Krq^n-`MNNT_>euDCDS7y+{`g4>eml}$QD9)0ZRnI`|o z@}ZU!&+i1>Uw>IM#LJAc^zRv@CJ4z2vPC-onq(KVc|(!%5>-4wwWkIu54dcRx) z@t(Uyu6Ll&9GRc?*?()owd+S>9F}Sod^9Q#6Xt{A>;7l4rU;le%RqSk9 z-B;el8)N}-bcd{NfzMz_yh-TDkB&q9%d%)tITb zETQp96}eYMt9g+H316&|?H~lSaf0!*&tuNcApQ+<#Dg3&XKinTD~KXd zOqNXVq+F!DysA1C>9@Quf&L)e$$j75BMfiw7+k~Hfl`n*=vf=3h~a{z!0GuXPST|! zd0@vyo!?j`+4#%_P$#;NG_?a>sNW&p0GI?7JAU-(4dFL_R{6_e#108cqr^%~MW@5! zVKMf4$z+thsD-ZfyJjytK#u_+|MIuJyKuvKYH)|_W}PnXZ(SBz4Z-$6ghYPz5BmBakY zy>gE>Bqg6l$|m%?iGLh=%fU%iaAjrBK*(G5e6h+xz9FhV53UH$EF`p}w~>^7=BR{d zhiag43nYudwFUxatlxujny@{vus9jLRs|rTQnkj@_k73_igJv*7~F)2vO2tqqx;(8 z_-AXUmK^Vi#~0^nYVg+j%gZhR}!p96*yz76dg zdso}x54?M8D9=&-dbE}iXuo8Zx%}hc;$NSLokG|Bh~Bfr6z=Bc`8W)Cn)aiY4|m-} z`jymNpMXJd#kFbHYc%ewY^`D`z8?HQ+%vHSA3+3JoQ4Gcwmu@FC>y0d{H>s$k?Vev zZ?>#Mn7!Q99KDlZD|i&8!eu7M9DH#icpRbhYP^KKk3}l0zY(KpaVjy?ChdqK8UDOw zIF4^YJ0ZLhs*K(_=#0HnuqZ*WCAw|fwr$(CZQHhOn`hg$ZQHi@nR5s4%|r}te^mEJ zt*EHz$gIpttg_$eJ7lkZj6_hS7?MdxupZ!rD1ms;@qzS#XW?&i(JLQ*Q<|yuMF?_D zCPQMa9eun7YRV#yRXDFFBAal!{&E6eJY!gHj%I??oOLg-@$^!L$K(jqOE?$Fhgn;( zoE4`wK(Ea}U0@|_sEZB%KK z&kA`T-A$QTz!Ba|Tke8Y9%xY=@i#;8bJcX#4cbpXp`n3&k&1igmM$H=~)BK)`J0+sE=wt>aB^NRyYLs@CL8S>ZVZNi<$Y zhitvCUGgOkQau;sFec}zOKC42^z*#0ol0mO-#+Nc+G|f26-rK7^GaT3fIUtf3+E%n)vB~Vw*zztJ$Z~3-&BNMf#MSXMdbz%d2ZSfWIok0isLMQ66ewW=XDdgk;2{;27`vtOud6)749-h*GTt?`Ijio2J+K=vrfG~Xc^H9 z8rvkNIm^}TOS1E{uL}J=iq{`F9cXd$Bl`gF6XCg=oZd+Gapv@oGnM21yOK@`V&*oU zaxe|S=&Q(xj{?yXmM61P3{h(e48Ad3aHLm8CI{mrApw_ym_Kft4O->!>F{4-BEw|+Z;z`NA+Os z<{;UzP-+LLc2f))w)JT}p~I`*O_1P{YoQ*y zwXud%$adr$0p3H**@#sm_7Q@Ei#M@Bq5F7Ws01U|!-l%$Xb&1hMVeu6I(Mi6wXBj) z<8f5{X1Bvw9K~;nTyKXPpNDZ9?>oeZp16sqhbP~*J-RG8Fyd!(sKDTNI6m!W!?O)O z^6%-y=X+@!%}XYH`YjWBvh_w1)scF8EG2^s8^nINFk;MD0`)Yl!#0Oz>{CUAm2*pt zkqBKN+90vz0%_eJ*pbx<)BMy~@W`B)j5)NLH%D9|(%xpgvcrdmVaRlDI8(j&-a&?w2xlZdQ8a;-4NAp9XD5#<1(ds(%1%g+miUcCT7c zT}M39c<2SR%^$|yb`4qc(P_ZY?yvNe>gCTT=N<~C3NA_nv9<`OU=M+cwa*@DBM>Y~ zVmsH?W4D}8^#t@9Xhn?);Pr0jOnQ}p?*KDjDcJPFedJ#Ot#&Hyjnq8Om14{ zNdRX4;_am2oVN*6Iwy0kK8Yqm5tbdplN;Rh*}M^NWbjbBK?eCd+V$A&+?wR^<~?7| zCVo$I33jjHZw7!Vy&%1oBJSxvco+s+LLRhF2%zP$ zQ1KT7b>$IoT!(@E_A^@XtdZEMq`02ZaEZL+ON}3M)4*Z%Okw-pHRCVBU0hR@bP365 z7RpZEJC}xG=I|=x>Ucz@1)k{!hxoqiF;fylJHP(BviS9rerjhoh zF#GQj!_`5cXWw=2`y9SuBM{%fOy~*h3*+_v^>A$4ruZU%Y@LtnM*|uNo103L^pS_vwAX#y@14a~ z_B+PVTpqrF`KjdQWaDNf-TVH=_LNw|6SASVn4qm%{ywY=J&7-`YiHOEWOtA)hcffz znG3Y~{EsgAkwG`=#;DP!1I=pe;`}VMeSfsyUDYr);^!5#4gFE3;BvY|6FQ<_<&?SX zMTXU&e*_c`>e(gP)0tik?y2lvuD7&@kk7)Hdj`7et-<3>)%(R^L63yOZqCztSNXrg z@(L*|pA^4*V~_QdrWrv|ceFuKGCs(G{Ew}i=)G-ts9tCJ32oAxVYDcAFe-9F0&~CP zMMa$?b2TYk^yR#jhJ|Fk{~nFTG+M}}b%UWFi~bh5n`nBX6U7v0|FS9H$Rl@B z(PDeC7x4}Bvbt?7-QX%_v^xf~*PRFjrL=$><`Aw%h~lE(@me_iBB^SWJgcYL4Gg53 z(55DTQj{tP4buA&yk<4#p9h~lVTa~L?DHptt!_}P5vhczdYP0%<6uIXViI<`VvD$s z&iz6M%w7__ZIG)b(5rbChx~rPZ3LrXJg`<_Dg2+2XZP~)YlgIs<{s4dYv0RXHfcvKv56sO2`xN<|YmEY9_jE z!@MTBiix$vl+;BnOmkv{*?srHgrC|OO%ISidFw-Z(&=$lwC>lWK{xLZa&7*pe>_wS zFZ?cGy?xSDDo~>H0~HZmoA;ccDW|fdYeesa>9$}nM><|~4!dh=-uPaIz#m`ENsvvk zo=mVW^KyEebBoCXdzX1MDdZ!}Zp=Qv<+vgtSEWB^fz{j3%@pZI8*@=#ufcNX*1I3{ zPpdJArq<2@Ibsx^&?ni0jsXYMew(!x6v->c?wWA6P^-&a^v5Kl20Yd)n6W8539V&i z7KUF1JIJv>CPL&E5%iOz(yr2PRMUS+J!kN{1W0R=+;7#Bh>qHNei_SfPCN>QNE%=>!f4h}0U~t?E+b$C z1YGW2t7>?w50l403p$qjRm-`qpUriJqmoi^p!3C><3tK1*LX7@{6Pv_8gv7Q>?) z)5jI$iwF7elc6v?AuLAGo{zz$KaMjCT7#qJX6n9>aMS1D1pn>tC-*>JyYzDM0NlIi z2qOIq&^&T!uTL8!GARjCZ=ET?Lezumeh?yoD7_Qz$U5-8no-U0h60=P2Ou;yAxUz< z4#kwnq+$)1=W*e7C~uJkeFumqFcmfB9mVuy?vzR8RPsy*lYep_JTo*08RknP&*~&E zBYzO#Ifhvg*W=OGbM6mwZR<_OQ^Hy}@qQ~8&Gar2w?aIwkVMb!U|ui(&Ou}xn1k-d zp9AE@1mJv9X|HCQw#=EECm*~*Bas9$VMu>2tF1^g!NU!y^%hCg^cc9;#O)rqYZ-vKT&C zCi)ZhD&JP3iM?^`2JevOEKJKMlPzc5DBt`()Al9@LH;qD*I5wd!?E|(7<~^K7s5Bw)ygV}w@JpmX%v_ey{IiUeB&qBd#k@vT$iuhHj62ClOsOMY@A4jd+eM02C z+-6c&EX?KsgFl?m1)b^Lt`+ly2&<{OLiAq8)xVmbHQ^wHCIFZbdj<@cn;U=tOIDkTmFfTExI6ipK? z23%Nn(crmZ`E3sbvVjg8sv^1C3lUOYY4Sg)Pa!ml$xeKS=p~GMQ+ZrpBPro6N%!cB zoP(E;|8f_NyYJp{A8P!MKzI&NiM(0QuKXXbNn=N`OEFTpp&G5En( z-ZIC^X#ESZgd4{A;UsU=6!joZsNU_UaXhXz57v)PNNZ`oms;ad>RGfuuQefB!~}|T z@1h*Ky6AEWKJ1}*ek>2_xUGJ@?p23!pC~)mWZduA!o{k_(^^f&dx_0V=$Nx0)pene z4E@Bh))#V#BdhUpj%S=!7EJUPt|vN`(Cc{F5rqKOt+%)MdUyIR;A?HvpI9a`W$jw4 zVNfsu{1dk9jKcXXz9!GS0okthdA2p@A*+<}|II<5!c$^&0w!_ET^$OSEao=C z4+EI7u^txPfZMX`t)Oqe?dlX!qq_YKkgh3gR@nFQ1%csDZf#!1(r_E4a1>=u30ck8 zwZhDy^LMLc+opGguwo6e30>(tX$(Kpk@!jZAH5cK1$c9CC@f@v9`HNnNWIX?G%oHK%wVZCJ@t zn|Z)9qY?7083DqayWwOWqNg4SxM<=`Qe$7J)yI5kDB-*e4C+X z?{WO+R9B)M>m(XYO~DLzv2HyyRNR?1DfdWfLo}=UW9MBEf|)(q4lp_@6VH3Kp(n15 z-a3(gRo(5v=zm6=g)-C-odzao9JFjh!?54ayb^LXNi0ZZ{(wy|G<=Q}i9jKuZe5%` zpHb@V15qp=<(0ZraL#o5RTPQ$!AJ*$kT?)KH6FFt15p*IY>3Zm;tW&U`=mnXXN2t*zSfdDR>it7#BPRmbl1_lb0U z3_z{uhg-&PqOTW0$fTzy9YSC@A+4=bpIH0z3u{8wXBr3Z3^R)&OvX@rnonrd+ruXm zI~+Tr%Od8Q)5;c9T@l76k$WhAk$cTL*nRJ?5>AxhXgZm>u8-dR8L#uP%MJUX0X?VO zl5}Y65i=YI-T#5SlXvUGHT}XcAsRk+Oeh6HR0&H%1s-cBRqLUOLWZ{XM)?!SPAAG{ z^rvFAoQo2&vrlmyYol_~pa!c%PEQRmIx_1X=d;~V*z(%L_G348ui5QJwt}gkQJXsIZuMhgU}-1 z`gD{C&^Gp4NOe2bi!y5ji)oJ4oFqmf-<70fIQIS!yB$~YAv|olMfK?`{PbIl+!QLb z=3fF$UE%BL%wi8K=2oBI1l&iT585~LC%u9+FbE33e>^c2oD%=_S|5o1mDrv3;1^@tp0svtC&%gy;O)Tw&4Q*_U42`Yn{$u~Ss#|eO3<$n- zNPi9R5|Ao{&;f<2h!$?#3M0zq(ex0iwoMkXaL74k?b4(C&27qEvrMN(E=e2aV&ctb zW1zA8i>(P9^FSkY080kms5koj|8bS2p?0VoQ}+}F8hASR74LUTDfgcgk4Q1%4R=IP zQwmlX;Mo&Ya*#yFf@F2iIrD7_=~RBpr$MI;h!3bZ`%@uhHj#`I7_wlfKu*y+XDWi^ z2FO(O8&4!>gboj7*G5^5Xv!GLO(kWt5T5*Na$-`x#?87vRQ?a8ITSsV!@*0b3W(J? zsNnaj#NA#H#pOM$5b96e3``Xfa<`gT6JlV5OQk8;cXY4rK{d!=F`79RLPYun$VcS% zepA0Zg;jzdBBGM>b*`bR^vsP5yND(~n0`9rhufym&&n9XdMO>t_%&a%?+}S1DUrv^ zef8pi7%qk*Kuw&)8og=3 zpfSfMCq7)adGug>1=)XQeo%g?Mv%_oMTA%<`C`PvGV?%zuJZR? zt7^&<(rrNnAx+c2GxzQ%9p!Ibw|?l*piIU=Rb+{MvXLO&GBPT54}@v$jGVZcanx_J zrAgmf9)CcW?W}J3U)WB$YI zK0@F6J01i806h)>0Mma)_C@U7?QHA~O;ik>|C{KqXj;xKF~IzG|3q0JDM1%+ArKgB zr?cFC0Yenl%(ULS$x1H93V+?LOKvvrOn{SkgtpQ(;C?k6@xXG%&YkBZYS0vm$YExS z?x{I#-#nVqm5}LQM2YE$yhU%sNT$g&cF)_ln7DA-P4S#kZgG0ZT$mQVLCfgzed0Cg zI49c9;4*zzDMV9>xJ#VE&LI8k!!RaOX?w?9R(!^i3)x{Z@x?wz#osz&(8{S{ktY`4 zXf#2>O10I*?}_Jo{8213h5uE)Q2WyqyDvovAqABu!ZKH^t~5<5@|LiqGCgLSs9}<2 z%HXQ)VA-xs$ z1><|?c9cRTiWlXY29>pM6yggGjx1VrV($k~%Ll07!FGrI?VA04>DHO6^N6|<({3Pn z9rVg9+boe66RAj3Mj1b$5|OeHb9`U9j?N{@Zl8!Li%OuR=_rkyI;=uQpa9L6#ry-o zlZGj~XGLgu#e1AIa{o>Y;rNQW5>2pe_$PsK{gSqMb|rSephr&}K!Fc+k5GCl5Nr79 zcr#w6_R%`UR9!9D9+cO(_&~KLm0QxwdKuduQ+8cxx?r%s(fJMN0#;AoZ+?EaFk`7{ z$BPFO*1!p40Q@|4pEbEG#?u$z`)0tpPX;TW?Y+d{KGtsgjRgr;<aC{dQWW22+Tg6Bsz=2G$@Tta{3Oz9r=48FUCW_>t$MOz0k{d zu{tKh;h?U?k|D{lJXje!rbs!gX#+h!^gzNxZ&G{>Zf*i6>Ne!Q1`&DZ;NHh4_hw(A zAIzg~Udu$V38nb!Zm-At<8Z1v-Jbl83?FY`(r)Ls_nmOIiOL5V=D{Bpr{)?D<1@rO z>%PRW(0D1a{jq-Fy;2v0C2dcoj}5Jj={rWna1PgkRI3Tlro@ zChPz|Ke0bIPOI#s)Y!ZmoWl|Zodi}k(SE4 z#2ru`v#EXtB`n@GjD&<@E{efuudtusZ(((8uym@GhY&&*kgB9#z?1+PanYIQ5FOB-&Xh{Jq+480WDCrvPL!Qnh6+(P;kM-vZFtl z_Rfoqe&$7_7CFtKMcbM{G7JI;#EDJQRYR9*IM2Dut5AZWOQCux!gdIV)uEyf7tDmp z!UMU0I3)RW@OAn>*D+i2+vr*rS))Y(W7pnS({2dH-ZJ$c>Gx)$xp4SRt*n3gTbUwYZPlxwEerQ%9}@C)ekX`zse} z)Veo|*Esk7ZNY}1Y{Rihh@soyZYWMqAH6;^003W zbUFiNyJ3dW-y(^9K|h}Lj$`QZcemHCwu7rzf6Mz*{n(uYhT|}(s+lw4aTa%L<|^TC73nq zAfkHni#I_vgAYOzny7?qS=_*4@s=WIZPjwFhzt8_(eBk5=!tXMlLw8p8V&Ji9I|_C zY@d6Lzu)(lY2ah(dGw~sKW*gGiTxfh zV~t!I00xj5yH)M5D{Dd$Wia|LV)Qy_E@C_aUA&6r$3E>I_!k$?#O;viUmYQ-WPq`K zyf_ri!i=6i2S39nHgPl$j){3dCUK3`7=br(jo`?>RpE{`{9PVTM$gf54}f&+8`^D2 z6smTWliAj^VBL|aR=wS^ncBS)(Icx#e_XvV9gboZpdKKFaL&0M^AYu*(Inocy_YIDv?ulCY{L@5*O0D!FSKWS~q z{&TPdja@9=EL}YRtD|v(Yw3K&a?d<{kN-Rg0C(IWx#^S&WEqDfk(E>u@6Ba*$Wj)G zYg29;@V2+HVz`m!Q$jli6PP}_YSp4ut5&@trKP>3eKks^Y;QXIZM~J3-M8~GX5aI% znmucE^Fi3Koq5N}yrfk(bGrCC)M`xIlWh!YaM@9K6J`eemoH=k07eiV@4JJwr3rA2 zx``7umz#Y1b-N=S_IxXF0|tm2M}uy8RGrY?$GXR%EYR~ZgxXpcV!oxU@XTJdJ(bs) z#yMaQUD~>udP;lic4m?1%6;_3>x^(Z)MD8wiC)+o)1(Z(X5Jl-WkMk`mRoysvn0;@ z>^-jwsMm5ypL4Aj)KwjsT>zFvuRhER-iE>(%LL%X_0jQc{f)?5?2`Sp)tMYZIT>8< z+`|q}WKP$9u+{fW<_0F>4#)j;=Zs8>5J{ogd)s4oW|8ggd;Te{P0m7&*5B=BAbkU= zFQgssE+-k$*YIPNYMu9ux}ewP&+IB4>{qJo3|a39nDd-|>MU#CXY0+a24)TL;K;{s zwX1n%9QY$o{#Gw9HX!Fbla$w*=H_SHncn(K0lN!c*(=tFI6T{S2m$BOd|PcQ9#QrA zE(5sh+{{3ha#^(NZWvp&yV&7;zU5M<^c>U+C#B?uTh49ys7&tWY)*uIi!g!7UB_B7U@6X9 zm~4jGN$8be3lAX&_^zFh^GZK^RikFUJ` znm?zS!Nm9Gm5pE)kbQ@s8j%@XYahQR2Vme|Lki+I=q=KNL9*=r*T^<7u@F2ygy?CU zO?-e{e8M0VsM`)UP3|RaZ?T$y-pmbW>n0dfEdoM^0(C&%ngwK)o*H1yAcke&;U`>* z#ldHiKb#UcP6N9Ef%7hf;ovc_JSPB{g=qX3dGMAmDufR=y8vLIn4+jea3uE~{ z&l7@2`$t3YXFSkL3`K2h?95}xQ~@>T#wy|}TN)hzQ1?Bk&$*lw&N#0VSTD*DQ8vy^ z1^YU}`vNUM0li0!fSJ(D@@%iKR2P$^swkPG`6%ldey2o_P}5czKfy;h{j3#BBOI`Q zq82uxE27F$tUp24Pig0#%r!3pL!;K_r1S*SwT)WneD2h}vFIhMku|`?-Wu?Xpm=B7 zn2;9emdGz8D1(-jC$tN10t5;R@)P3E#x@*|DqBPfgh8YrOSrbTLDhRuQ%X ztkoRii)8J_6&) zVg_3U-)b!|j)^}1Mte?|%1@M&5nW0kXtQXwOQYQj%NuMgM3Z_%5glT5VQhaSZyQWl zIcfClskLi$L&Is6M+tYn)eo9(d~l~f1&AEWke?N90gzx_C4jtxX)6{Wq)o#%pTxYS zz2He3xawYG&0x$TbKJQfM}3g*$2pre1^{EFBEV1wqQMs@V*j^7RkBA4OI4|O54^5P z@j;2*U4ft=GKM;eeB+z7i4A=Cy;i!S67ppm z#dL?qfHcD1_H#-m!095sW=yn?^Y_x~?Xp{jNdM-dv5`j#ELf1%F*wsn=+U zw=rZOe#pdVbGre*fp6%OA`tN%EGB>^6}cvpPY%8>aWhkvw(7@tmhx#7jvL;fNhmsI zKr7_hmO-jgd$z*hG8B~#W(7sq8Qpbz7^)vDhTm|@Hf<`VwePh*rOm(u;AGy}u)Q&W zoK1`fZzt}6n@H%s$F$?_;P}q# zh{l|e6&<1e30Hv!`%;@!S#H6{atGiYMGVF}O*@%!22)iOt!6VwA=a?Vnf2POav&d) z;kJdloPVEP&bIMDYewGx;e)KD}mL z-_jO>ZQ>V>)NW}9|2wbD_}bTZcdI(72eOGkC?2k3e(29YiyauA41Uta=oUe`cRU2rbI(`{571~<`Z*Xen;yWcBiU?zb? z%vGqTO3$em>56j21Jldu7BzIw4cJ}ppOz%D;ce|8F$smG5zMumhde%v?jisF!UOQb z2<83h$Oj|4P56Rzp!(F`Z)Q#IRah@)w%o2Z1233hb_uZgv#)Gdi@B;46|Sa{%!8>J zEm21H^nGb@ULihW@fNJo?7#^nE;<)-ieWP7E4Z^b5Hw*Qco6X8Fm=L2@}?qGXIF0L z?|zBse$|-jnA{PXN$V17Uus=WyVT))!^S*|s&^`=!VTbSo&7YSSZQUexemQnP1T5)!m+tWy zX`9%T^;4{ND3PF&z#$*12lCDH7PIRE+q44yiGixYT&W_L%aL|?iD`6P`y^`zw7<{L zaR@P$*CUEO57IHiU!ZOzz|R#`QUyi=J7B%?39YS15s4UxK%DmR zD_|XOx$|N%7LZLzP9VIzCJm7g>rZ0Sf9jNqdOmPK;(vPG%?^Tobk=8Qf}RpqRI8>l z0pW}kG7wiojJEgAMig6^MkKNDJx63_mSrqvZPMWd0u}3sJjrtR9?})8Z+Om8%3yJZ z_vr`lc`tnUJ8)e8VA-NB$+ze?XAop!8N|AQ6=|_LxvF!PbEI2f%?%44&ZVCn?QVFM z`?`J(l_;0Ks-l4|%bNs?o|zyN_Wsx{cei7WDQo?l?jKq)bze5man0#29_Le7&U5!& zzJBgE#g)H$pZ%*2J@Bx&{e9c5^cIx{w{BlXWtmTY=i0l?59 zmAARTAVoe9p(ZP4y@nTOWD@vDRqF{Fa#}w2tH7W%#^_=b9E@+RFK>ei$y+REF`%{8 zGe>$0QYt?zSlqjl;S!0vae7w?pU>ldnJ3308%g(AJOAVVK!l~49M?0fq7L_cE&L(J zjeDQ)%PUvbkOvWYExuez;>W3;Qh^+%u?0pwy;Vj7rFg;5B0JyOkQNCi(af7LTwUWv z$rV34oWER1QYx|nWa2adL_{2FQImq=M5=4B#;!_RooRKE_U;6MM~$C@cUd#)oGHel z;e!lmz{PgeVY2}i%5K>?7!xY`9MA_b-B0%}07Q&cI(Pl*INg2yFYa7d zg;jsTtRDB`qS2(u$<=$|LKkx7=#l5*|F^XPIIhuJ+hy2H-mGn@1nbhrgY`o8Gxs z14j}w>OD(}&P+IgC~*AC8!e)bxG7Ls2ATU4pXgmf> z%J51d47a zmN1&_e1S$u^syDfrQdL34o)}4=7C|l7^#!d$Xw|vE(`@D8YbsLVgVq@6|5$?$#FOz z|L7I~mJ7%H)th(KZ6yd3hvcR`@?o}wBV-|a(%D;~a}iwV#+-Vd%i6d*;zb^M4)`_B zwe87nL_NoQWQ|8`_WLPf&F;HYkq0|k~->1N^8N_6s zlgTJXQXE*Pe!E)jtjT;tladcy%wXhvjTrCC5?rKvkLoZ$xeSC0RQQcJ<~=(tB@E6( zlvF3;wRqx~kU`j918&yY1~a+ECw8W2O~n`!QA5%+*-N9Q{vaVS6+{H2+?_81!@L!2 z+TFAh6o8Gr`0VwD`&Ud^CWNt*@7d7+u=3&MsP(>Y{A}FJPy&sI1A1J=!c*%2<`V_? z8o08C(YaVUr20vr8Mgnr`11qY*k=RwYJ0y`K*%DT`6`fn#RhxX_6aq}4P{jd6>v>19jC&5dic(!HXA2&xUpJm9yGoLayi?KWPCrXL!9jLI@QD zvMY-TdP~8}+>PyPAkVHo(LJjr8gkB~0aEcq{733fmUDU{R9Bm};>11Z5h66dC5}it z1Ho+EPnj9{*vMY>uRd!6&{=4F74#&>GHF)LV`Q{J(d3BA>az#Eds@PkHKGg*$mAOt zSZMIhxUgM}2n32gQ+WUEkVhyf)zZ_#eB^6I2A!3`E4QKgQ-GGF5KbiOuu*)>wa%$m zG7$r~nus{Iq`9{xUwuS%; z@?K~8f{B)AHf^0V<}@%VsXR8L5~I7P*<=J81){T-AkF^Fd@#@$5z#XOm31>T8xI#N zKu<7qT|*)yDkA(O_EW(o1sVH6kN*nhK+w?2d$k$%_nRVtXAVtkF$7uzgOS`onjSRA z5GZUQJyeq1DpAymvaqjb0=@&?P+GnEm4kE`13Uj!@+=1$YQ=kYHlYj`dX9vm3F`nF zMHo?=nTuEd5{Lf6x87Zho&yz?KvDeSBx*pRdbby%-z++>GtdNjV0!%kitS$wXcBgZ zVeJDLAO{Nve|#?(p<%05a^vfxrcH~su|MM?e33G)U}lJ(6F`Tq5yoFYhZ&;R-*M|j z0Umt4maD88@~^0qgDQC;XRe~u)P@=-nNRCowqd}* zfI-!n;@^{ZTwldMf5iJx_lU4!D=>WGYuEyrV_6B{?RgRh;uh`1hw7xn$jUWh^5VxK`HT7A}xB&og{`0W$xJ;lwE|dE<90DJWLi<;TYSRUuI= zn)SW?i`)rZvSvJYUbP&u^5D!kT`!`5{md(CFf;luM(2}KU-f$L&L)_DGVSbG&BmhB z%@inpyMR`bCtvT-rhG3y)Bx@XBTzh%90L^IU%5^ka}^u59#47NMEM4`V-$exmyFlA zEOu04oO_xAKu>_c&&^Kz%@Mx+&;tw=eX|lr0e60sns$FYY6n?`7MvlV-nIev`dsFv zHIK`$aLAq0L@w<18$9IX?akKF@Qq_^FW zSVE#`{>WLmh85oZuB0mNp-Q6Cjlk0ltpy-&xI^fCbS^xZsQa$IJK*(VMzSoPrmc+);@#k&FnV{Tm00QPDeuVM}l9Id8T}4rZ4U-uDt;39CWs7}1GF z6j)LSm^dj8g&!*?yhLCiy{eRLyUNVCmiiTMbf#z_G>(YQvh+t+#zFVEJU6QQi!QQf z91+|#kifkU4K-JnqyiR=8O6Gv|2Tw*W?~R2&&>5ju^m?RyyQK)Z1MAN5~)=>=gNAM zglZ`t6BZn^B&MW#A}sr59{o-bxO<924u=x)nF87{rGQvyc-&2L7@eYPyH)NTW29Fa zP`d%ery`TU#&lV2pBGdNQx-!l@&%@9O+qm`ka;=yENmp2KKfzPx0r~OtI-sjhcmrBI6U&G^x3GKo9}uwQz<_i~vupY#(8zZMF}dvA zqu~KmmWkpI0>9w9LTS>Hr%0m)5I`VLWrgqWzzwex8bDg14EUy&;LE3Ro}8-zf8$;J zX@I^05HkTd2QkQyeL(3JtQKB?Il}K1BTbDdPB!i$!`O(7b0BYgy=Z6c#dj>K-k%>p zhIvi;wt6?gAXK~=mc41a{vT;v=3$HF-O6)|{zq+<%P<#t%ta%SkRB9PP$Z0a3R*K` zJ*RdR@o16_p|b>lHQgKl_WMRtFtjb=*{nz7D9(F_LWG@DC^1{t6!)(QHD(ZHYK0CO zR2`uY{z-%Ny?jpvODt@)Q2d5o`Ju^cO~ZlEBbZB^Ueg3H%_9w+DA$%8KmlBg)6sNWxeWPM22+lh5_V3xLRX@s_ZmZk$FY;Fu$d7%e!t^ z?z!p)=EwJD@|C&zuLTUuNyYak%p4#AzW08`h?JIPbxO$WgU$FvZo8LJjD5a~81mGk zplxFgL5h2y*v$I^X2jN&?fu*{M$@FRGXa!ld3Q66PuE~4jF{)LiV9xxV|mk~G#Qa= zQlbyq|64`i)#|;z^mqDhV-@O$a&7Bt5To zNM+*zmAuS+rTnS=cO>`KO*bg$$H@~fv>EjwbM)gauwQ04_QJtl0XUau^ksyFet`PC z<(z#(&Q|H#n?BD5ax97M{tH6Xfnw2*BPhK>89Sq(&db-4eJ;BTQuU(mJdD?a&1@R$ z%)RbucbkA}q;Bm+fnIZ$U|`lL)NoU${rF%L0Qu(qiD9Vt)>1Fu6(||}H#{&XQ8tB$ zWXox@aX{*Ui6>zj_WRdEmDe_Eyo(51_SZS_l?S-j1SdDi?QP6G@yFA%9T@s<=<`$k za${Pi(xy%?jcS5J3KExR_c^wRNvBvizzacQ6sz_$j-9PASB%LVN&~#qx5gMS=bf59 zDB!BX>~3oJq~d9%PRkiZfe`&g*-Btm9B8oYgX<$QCJKe))u-);F_#qQGWreY?ZWGq z(5FnWz==?Qg?d4n3ggOzWMO5Lbg2Nj#o7I;=+I*unR{dakK5l29~k1BXh`tkyWoU) zmY{9Y1MJa21s!y7GVf6cTa}sn7JxG#<^-UHVSf4}Y-dYrv$K<-u(&vvK8F9&C!Zms z7Zj_iD=w@pgTQZ5p2 zIPxDjXzWgfymV2PRSsSW6p9`Noqqrny9ynn7a_9dY{!`8d5ktY*YiBblJjzVCK%83 zBy;9`GyxHuEX}%WmzY+nzvt={!~Lvo-+uc5h1zH-H&^M8my(3{rTfvF-1 z3CzB#oRo;hrS|~&Y_1W_Ev%*d;l@}&?}Zh&CTYRXJOt`FA_^yHo$$Jv=~M3+lRu^7 zrIuQx8#E@KTzKA#JRJ4|;|Sx6KRgF<7~QO)TrM7=CQ7mYG^q9G=u_6xZEVL|C=XOD zA>e++#qGEQy_S%F&^q;2qUnAYQMX5wJ`UrKC|Yx3&OyBK+A^GpO{ZDiV$jk|1Ae}4 z3{e}TZ}FD#=bRgh12xSFpn9ls#%kE2u=<9jNp@o2jZ^ABX}-mHz?Jb-3jZA~nMe)J z<0Ai{wRrf9_nL9`2^p$tHgAaQ!-^wYSuYc%<-Crf;o;|LIjIW1>yKHSf}Tm_A-=~E z`VucbkVwRKb!VLtu|V{>V<9?5;S)qCsW{>Q&Sq}PGKlayD?O`?lxN4#V6Xqlz0nv% z4ZEWK$-aB^DRlHKDxQd}15e@nd4C}`mdnJ?0tJ6!R0Zq4!}){5T$Wt%QqEAVUU`5C z{z}u?CVEC58jQ`jTNxzhy;VXx=5O}XS zjl`aYwWs4cdx3}lFly6!zTtUu;C`k<$itWif7q;6&%hBU+oekJLe^SCWzJ^TjXBH* z4M7CbDdcB9U)wV>4SG*8t<-SZ40+6X#`4cb z1rTFOH|jeLSky2UoIqsnE35+xP|!WK|G70}T$ z$)Tej3CicJycez~oY6^bOvas>x%9eFyqzU*%HRf|C5%)3cvcS8!ub+8>aXje>O}zY z1As?;=l8xdL$0$e@w4pY4!&(Ba_7?+utCu7A5ii6VR3XO;dPeY5>BL+!sqSDk+}z% zmvm;C*y|+F$lf^LRAf9VlInG=WiXM??~=Ge4TC~cIe$EaOzEjf=h=a<9PfVwS~zAG z|5Yd-(>65Lt8I7t`m(XlkAU-#`gs_tXS|}i)U@Jxhk_3-4)^|b6Ssweo{RP#=x-W5 z2f0Q4(*6yp{L`kRL_7N>ACP@1jOFhg3m((S-0XvfAg|b~+=KN>4~~mKY@4ASnX_K( zHapezcw9X-V5vW&HNhFp?Rt(DO$F8y>@&)ALPEyJLIMkJ$ihIIi>K)KC8j_Zl=cBF z%a^FUYuM%B2U-nT*I2sT?#Jn2|@G~FSY(%qQAJ^AoFbP7xnwC?*E)3I`xd?7KY2SDSP9J!Z|-W8g^ zx4}P1OEFx&x7fMQVB;(dGcVAs3OQ;YUsKYy!{kH19{I1_h1M?}-)CqIk{E!|?Eq7Y zh|!fR_2O}!9q`=v{@yTX2YQ-VGy!#I)Q^)S8u?4M^T-C z`_svG<~%j;dh%2oUFEJEC}~;nDgR&~i~y+|ISX*V_!x{N-Y|G_ve6g3XAo9aFF zKZ3OaB5+Xh(EA25=D0DKlL^Ug_n7eXVzsl&s{{BW$+{QWlR19aQUTjIW{AI?7Om7D zYym>ZRkan5N!h^%)p8FR@w~xw%#=|fl<_2|ciu(^gMsl@-YgVnxiThI zep+;;$)f^de(#+T(F&ZtzF*Oh zp!$5P>E{HEIA;Pf(_QLQuga)k(p2SYP8RX z93m5Hl}IVkW6!}SwM0{-d1nJYg!tm*jVS|SGO4F5js2WhEwh0U_&BFR_oQ(+knvFi z=O`ItED6y1V(8N=r*IJOS13SvZJN4}wjYp7>FLvJ2w(67k7Hr-6r;$z8TntcE=dFU zOTWXqEq_oY=jo;9t>h4zKn*pJ7x016+G4MYQ=A(TSvSi8#YO<(pkDVI^?*QYtUGTA ze_wxYkbGZtHV}}mYg)3}2o!sEA5VN`fFd(W-k`u}Y%^^;#fZjPWV3{lEiyaAUrH7)nXb4eWBY}w#E&7ufjE#4!)v;xSK6nn{j(DP8? zAV1nkzwoaRg)5XX@lK@+u0})w1E|<_+=QTmuqN>po!HgL#Hp%9_#Y11e}gdTyG|`i z-C>0=8S5A&$E$Fe7@|rM6XW>+bQWf2Ka;4w^Hk!EiCrTXk!ZBuDh7;U#Lf&Br6fz$ zAaE7%s6giRtJtwHIn~Z~=(M|q7F-$J3I1aEKF5j(e5YHa69q+kJvv2acpB>s8ZDY} zKAUEUcfP}hQW_^3-D50F7IsXH+^@lnFVGX! z*u_H;8Uq2yGMSM<%6NRqxDT6tIU9H5iBoK4?P@2B)@rM3&-an4vvw{|arj+}rlS^J ze!xi$(OxF$3qJVkxAOC+*Dzu*sNgYoqAtquz8VM4W~2h~`rw{t%Q`GhB~j$Tm4FrX z7V=OXjgCRPzO|({a&$^xfn-(Z3VOfFc6Je7#2aHt%hr}Myq34-^-7)zw)eA4f0e+> ziJMl!(FwSH#hfYS=^PE$_lIS{Lx2SNC0>}(YDT}-oL<_TN3hs~l53v7ZQ^OYWq^&R zo`%5VdvrUD!$(%w8GH7yk=#JLX}-)5Ntc|Mn>E9AMCS3{jMXS2LchUGPF`T!?PdG< z&7fpue(axuQ7M)bd!dfI(OC!xxZ?qkv!OJp*e=g;p;KqWlgcoC7`zKqRB_Z3JCKR) zOdBT*6J6Kl{!VKn1ftHrbS`XOx#T#Todcd{&v;gT^cX|XWnrIsZF~)qR~#GSS7J6hM}DjNUna zf!XE4{gX-Z&zCHz5Tq?zFij`!uV`H;&j7yWWeNMs)j-#& zLb7KQAj*7mnA1U^YF)3}t6e<$|w*3K=Z#;NlZxo-*9%(vGOnh0*HfG0b7PKE=b(c7%C+*E?5Y3_vn3$lY*D{31h~Eq&NC5g;V+pIJzpan; z=uA7!Y?GFz4B1!}<9&BZT~-$z(rKWm*8Y=^caK*Yz6qF+p;NvOkU}<3)2B6G#`I%t zjTn@vDdg_e#^dtjK@#P_m-CNjPF}PWTLR1b;$wmMXZv?s!3K*4fhU~TNOWAZR|gKY^>@C}O!Ezif^NIUak!7oFV2kyWAvla5CMWT|sCkFSLJaD%CW&1@HpekQT=Im}T4rW%y}U463qNXqe_B5>~)812N!ON!A8|$)dC+ z@|N3h741y$pZ04Rzkfwtg15mzFyCrCZT>FT&me3MJeggk>1j;a5JfOJ1fK|H75S z{O_t;+8CPui`0K60RFd9)`lK-F3$hn79=3Dj8}ZOR}16yyA5t&0D$tpYwQ0=8U7!H ztNuTHLOORF>!f%==>Z1B;47Fn0--9Se0Iu8YWI!6Fn8M8w5I;zw0ODp*Q=}xHNzCN zB~YQ;XT4i;nXZ@ffOJAQiQ1W`Lpka&G><6RJnPxhXIq9yTdLDPXKrl01{ku{>QY0FWAKM1IQOmtOcUxkK#7RNq#J5ik2FuKN&rdRQQ>6~Z{=5HxW3&qlyv!$))5m|vI5>qM8f6E@ke-Ua< z+)ZEN8TvKo(3~tQ$^p}9ekQz)o%{9C8KCH!9Y?{yGiM;*cbpDzD14&+CM;5O{nlC@d)C7-B2M9@wZTs)FE7&ma(DrUD^_9u{5LHV_sa z6k#9{MZg3RC^2z+;=joxtl`8R%tI7xONWGIJr#7qAt_QBX>ObB^R5OpE=xXP@uq@RoOpN z03O*Gu%N(~Rdn~U&mUXNO>SToH%6cs^dbIt;Xds#(BQx@Ka(Rk^?FoeaQu(<4qF5k zW(>rHB}Doas$iIrg_ODA#al~Ne*R@s0^KIYW;0lWw?4?R;)G@$7vnG@M28nd07qPM zUa$_fF&0IoR&Aj(un=@MQ4Sl16%is5fdg4_M&8)K3p1ayILVHhd!|UV0Rif%T2QD+ zG+0458bx)iw9%tkMu!D&n48f)(|;aW+44(#+Cr1?L&+Tq&si-YITC6o=*cq_7M^rP zoO|gG*z+u1VGH;L$d5y`s7Xf;a?~+FRxCsz*O^8U5Q8D3I3Pw|Qmmu|Qd|zGNec9C zg{H+6AvGaHhay6rGo*w7DG*Kk$(H$ATY17k91@`{5ivAYf>gn(hNt1MyimeuEw8dkI`SZgP$d#TX2Ql(1@HR zJ2^kDmfNAT-5`gtV8IdLu);D7QO8-MQYvZ^1M)1HY9e5Vgb4va63Z;^+0-C))}bgc zzMA!k0C9gvkvyfqBhN7Lej`;<@MRY;o&eoOkJw!QYKTAvXE|MfU(ozYO&i^Edvye1FJIntS!3SGHM(?}NAdSu4r5pP&@u+EgB)fxAooD2lE z2W2~;m#`rhL4j~Y8$zLwTBCtNyypi;2fV(j^sfXVt3BQw4`5`7)x-$H>NI5rr$_6c zd_~YeY}bwl^3C-Ys3sed1S#U|u<^C1ABYRi`{JR7L46eHFg4|>UMB7n9IrU+*&JSv z=LgwGqp4rqDP1@MQ?*X3U3P1yXK5xXWCciB%qUPOkO*TA1Ctz(0f=yCM*jr#zp(&C z8%K8A6;IwHE`$IJ5^5z+7G`kwU2FnFh0or;9khxl0y2^WO;!^;gF54KEW;#sVJT=O zgJ3p`m#%Rd284(YAw`D7Ne$-VfalLr7~NnBiAlsD`9tqfphcFeP@N6?-W{G5%jbNe zP2V*EwE&UE^De!ltqj3$FnP=Z+=EV;z8`Sg|?N0+?};t%%Fwsi~T1s|F$V z{QHS?`AVdds90O@f7vT2N2DP4L>Va16st6X66!7wuzJ8D^S@9cK}B-kdO9!@=gf0O z7DcT8NMe|s%M32Iv`-AwSQp{IO+FJRR{Yx(JUh!+WUc*mtX|dav-C&Pe97aOR}(QN zW6f9i@60qjPFw!lyyNq(bv#B8ip1C$+V5kq21NJ(5c1YJI4B`1^f-t=i`IW*sH+Bh z*J4Q4MHTRFRX03`q*XcDk>^M$uARgr^>X5v3eWnC&Hny2*w${Ec1v>x&eF|-42Fe; zgN4qyaRNq<{SMPpQ;vqV;Oz4#so(80mC0%D0K8cNwiDFZ{;FK7kb?zPmR{uSDAf-~ zl`Nm>Jz_K{v{;A4iSZI3|A%Y@?r`8TTzkI(Nqywr<*??r=OA^IsT>euq+xR_#Ry%F_G4tr7i z^^!Max-Sp*ElKEwHVuSafE%y+pJ0P)js6+K5LlqJEA%XIrhp<0DRft|R`K*0u=2f{ch$_lkb zZj5X;2Y%>ouzsJ(4#n8cUJ~aB*l||VZ_A}||zkwXUC0a5M3bBxWLjw1fE+oS0 zI1(R(X*=Gcji;GP^+Cxho8O1i?Knm>@e>4-3Pt>L*0oaSYTp95jp~N+y%Mg;LgQ+kxbnfuq zspT1pP=&?V+zD~vqh6%h;cK%ew}p0>A$#7Pc1S=+6>2mi!i5)v`8i@TZ((T_h!i8h zE~KCa*P6{c({;2-0e7Lm&DK@SKB>>*;2)Dcze%tJ>?0$}B0JA%zov#ssq!wvf%(TN zH1fA$ZbdVMcC&S8oz<={=ns4-$>d23@w(!NIAi1+3eWbn-{Y)??)I2=Hf!N=H}Ry| z4bW}4SG}d;Uu3ljGo0UyUmfzGR>U02v@jxk_Ba`G1|Fu6pG8zvs8FGdrmrmftK5jw zYy~`gz|2{~ZBEeT!HPxa>6eX{tPcL@lV_(0?s_?UTv9MUxqPzF`+;V3M}W*|LPqD! z4TjD;uXkecBF%kYn0dP1^^PYzVDZ8=M0$v}820DzUZe){k1sAnc+7SyY1bH7cpe|! z_Gy+3l$Ne}hJD)q5NV_po-F&v=-;_CA0b8u#f_TPI2j-wD2Z}JT#b6&8^xv(2>gxe zce4JQ491)ke8wdeJK$XD)g2DvyxYYKtWfroQW)VhN+eTL3kc{mjRosR){E!_=eB`} zG2?L_MN_pOT(kF61?GB_C^B2uDEEY-#J)39pomra@ueXJyy06DUJVUQdX+HcmW^}~ zlh~bU8mQS(ynJs$R2JQsNdnSubSddwk-~VWptNY_l3Sg$L=mQ63LF7TF?5BFlclII zzH&(t6cuXo^KahXy8t}ylFn{3O`obGM%)upsY8M$B?)t;=T}w!z6l?MAXQ4^vmthc ziKF0D-S!BKoOiIM>JOOwSq7>kDoh|t$^AG9j-bRANd+o9cqw<``TfbdTn!qd;TXXv z^f6582~%uD8*@~OljSOi z<0dMk*-H#$q12AN4;<%WKTe~v>azf*#UJcG*J?u zI7?OiBO{n%!;!nb`=scj`@~BD4T)lM1Hhg?<+)eav=z%#6e=_wX^~xy3Ms?P(+f9t zsl>?_!o*bCI@R5@pRzdwU_6mO{FgBV1UR!RLRoYt-mghwdX}qN(MUkn9JVHxcUHs+ zfOVP#ohgMR|0tVH^ql)V4(Iqb0xv2FLd%c`84pHiC=z2M?-rezB#^JJIU1?nh#;R7 zXOgCKH{0Ck+Bm}o7I*-aDAY1!(o4n+7S?hegg$7n1o5_M%`Ps|Sqhiwgyi8^oShHs zx4sE6_ff!I{nnu=wPYZ6Fcm3ihnV@)4foYv@tOEMG3szoW{ZyO@?$+DaHYBI`jn#i zxPj}V#$`$9GNIW`sKM%;K)4J%jKP1mJs`oPS1H6b{0hS*9xdqqvl6!?A?}2pCWBmQ zQyG>{e!I6vaR@_!Dm{V`fr(4oktM+-G2@cDc-PfHs%5F}BzBuuEQ8#7h+EfcHlR#7 zprlFaXagxKL(vYcYKr``0s!2`c(5I=ji~!aq5Ph5Sh4Ep#5p<^&j*&S>k=K-)(2&a z=d9lSZj!wSH}}DQTjnh-g*2^&EdF^UU-^2Wv)S-2Mv+KohmnK=DWVk#Vo2~n$wBgV zbya(IZZ68|m+k=gR%2urJ(4zs{Q6a8M%??tU6PamdBYm*&()FCt2bcP~1fQSZJEL3O%dbr7j9Sh5pm#p)SoirNvi6JU zD`=el9a!&edKna!Xv|&$U?Den;MRuv<#Qe+Z#18-Ui%r%s#F?p!aSNvnigmbW*J(z zi_~DEBtd38!pfdUxlC%Kq_zBahOj&dIz(KIktsceVmU0oC?XixDf_iELRGpAh_@1} zf!%y|WiiHD870xQptS-g&K-GC3QCL6fA?=Gw5V+7OOL!9Zf?Tk#Rjz2N&<=14mBsb$e1a%paRCijJ0hJ=&HTk#A)NZAvjDNoKVx3R+Vh;A*B+j zigHP!iPNqEPFnO#$)ev=H4e!lPUh@XMZ`ao>KY7rr&S?A?_)N~24B(TuIN*&eAdLF z%a!UM=DY3r=#9kb~ba?X%9d*0=;|MMiRGV9hlXgY-BC>)9X{cW_H|nZXg)5 z>7ifh;D}g}tvH@}$wF)?U5yo4*x8A)lB<}{%r%(X15b6QxGfCN?M(q z;bg=Q8H${HGm{Q7m2pxAZ!K=H$HOtZ=uAM8HdPos%EJPGkv{m&FPa_uD7zl;iavF$ zp1i@HNMEKgu~4m32Rqq0@36v|GenQ?Ibf$J+P|x{5B0gemM*BREOq-^g^CExWi3%t z<8C;m#`Nsb^J-X_*p@g>>P^(P5qh{>;-2W{wqAsXj&5#siLRU7#o5sP2;N%j3H){s ztOZi&#zwO=DKegqq1y<5@SdvQOPoXrhp9iC#fpyW@jaKc!W#{|sdN_4?qubA{51Z6 zgV^e~nw4E%;``i8J`tu*>{gU~!1%spU<6yAm_;XpOUF$Wqs~bxOF{AxG9Osp!4F*J zX#e{4i%9YsGk-pfh0phu^EitUqWbfclILsW>6s*(p!$X71+L=Fb(-Dh)2O< zH~AJR!*PAzf~G$&k$exS^fK!K=yKza5So!5*{|2Vp~qWYH@1{Q^q1UF6>5CScE2ql z!2{x#++1A=vt+_dlZM0)uW`%b9^Xogug`wq3)QNCa|b)qwk`IG<3`TYw*lLA+|zt# zoHe4zNNOQU;@DtYP84jSB=JyOj_OpTJ*?eX+$zwZAk4Pv&xffRl9uQ3FS+UzT_uYu zoLK)MoAc`BjM816D zk!L#D!^q0jzwhVX{>!T4xb)-ZKBB}lFV>Q84SP7}R+EO~-9p3|O0&}aVVU}7K|Y1B z5bXMw55mCAww(1wjaXPBCsMx`Pg-9Q`$qIq_Na#AO6%Y2qm;O?w7F*^7rG1eWnm{P zYVzr{SUA5|xLaf6UB?|06uHl(2lt!W0}Yoi8>Q~rMZs-tZAXpgvU)^mR>Ox*ejzJ2 zdLhu!y5A!v3|t)kHW_T?ad8eGBh{M>4*q5beINE4ddkDxm!>QE0L=BU8*!XG{&=WT(7m?D0|K zRGq~kFwZR3ZA$G>Tb9svpK;lSkYMhE=(cIkTGhGhH8Mbq>>&}L|9n`K%KRm~i@oTG zwX($4(XmU!^Azc&fQi#DIGhvp_O&MlHTtJ0_4sC8GQrc~^2rahA9Cl1x=z?l9+5^9 zEvUS-eJ9|MzybL4{v73RhcDg`jEyW_UZYRhOph2e2MqLaOZ^F# z!?7p*w{6EI)9bZNqusTVWg(45tbp9}hrHMvtl%Qma}UJR;EyRT0`2AQm?L}-z#FbJ zW>xDwF_A@8!pegg<{HLu)-7kI`&6*|?o`J0eqE8T*;KY8OTft;I$@Gc-(4(Um{1wb z2}mW)+DfFftzO8Ft8SEvRPrK- zH7XKekbP29YH|MKb82#U1uM{xsz^Rd@V1#Jegpn>&*cpX_GaV7{-?b@r)kkv4Uxas z7;h${WS7+(_K0`<-jH&fZ_>wUY%uhE4~SiN4=_c>$IUvenf*~X$LAM=Zob|axNAd; zM}GLm{lasF=4tl(l;+zzUdhD#OcZz%>9@-V7J^%?Hk?g%TA|$4pKM~yc5#mvnIQ1J zzar&^msqQ}h|6<6)-9j=b}MR6=>2+{ zr+6W%D>WgQCw7zjz*5HdmCm!jDy46xb9f=#bX*wKcv@uA9~#b0&H zTq4dRRAAg;GPve4YamB@&Xi_T+WwA)sMFQn$X~9bWE4@c5rehq=DGtDPa_2}eFyAY zf$F}U$jiF-rkGlQ;Veh&Y~35wrD`AHI;Uh}9i!dGlF8I?yZf!k;j4B$1lrEpt~$d$ z7LxeIX8E-6etAwDzt2f0_uVcsiBw-?N}E*+(CoePSs_XOyVW;W0zxru-~pOMy4iF| zgQ0~{j*~)BjveJ3u~wzQSJrBx}h3x!wx$Bg++>t>cEv z*L^YRZ<|l(?}n|a>zVZN-B&UXi1!bF3*5uuc$Yb*+_ zmgix9v?)&u$!_oI)#}-bL)Nv&zbN8a-XZseo9>p4&O%rR$D48XsXA5kZO_SH%z)rh zyi#dp?6YGXSI)PI>Fs)-qufTTc>CW+T$r1!aA!+@dYNN+{EyVC2DG)CU@SIxb)V;6 z^y45pZbJEcirLx6(X5PAOP%{88jQh)Sb678|4CqLJ-iZ9|dulY@4_u=aOb+@ULhMHU*~^z%Z9m}ocT76&k2^83@Z$gqvG^XON@b{H2Tb@r&nfPo&Gb%| zV1`*XT8BI`uR0BfOdLn+cQZ>X!Dm&^_?sHdiV`VHEAz7f8Gf&XZ6y;uL(6)-D>-~n z{ei+=jw1O*1dN);Q`yWIU!Mt~_FwTCweQJiCb~IDahg2U%M{rOwG{ANyBhlt&4zD> za7ytrz!m6TBk7-I<0+TfU?&1ONd6HPGqNBvf!`rqRoA|{^ZiqS6k}@B>DQ`IWAX?Q zVIWL~EF8SUy+A=m%;q>=TlN@TURmBvMv*(Z%qkJNVn4>%yMvXdIT4z5K6G{bE)WV` z=E6K1@PP-?xVD7}hD_Nv0uQ9^hUzk^(XLbZW*k$Yud_j^(ITaAl25~awvy5fHFkQp zmj7%j@Y`z&{Q>_QNu(R=yJJC2EXPP%!n$93Bc5%c-f%UPofYi_zX%O(5KWeFc!U8a zJFF7FeX^$WU@&$|MStv$>hlGO`@WRkCmddN^LM>oNZa>n=Jc=1u7MJ25mtub4lMX* z^>-d#1p1)k20c`NVflIQc)Ub)^pn{xc|}E?dyPkg=XHPJK9Ctip^lfU)IU^QdU@^w z$XM>hS??9=gg=xPAYawC*%OvI0GE_zqi)*aqE>+9kji|@%!2C0$kF1Kf_}9XfYLf4FpQSBo@l3 z*=|*X%WqYyc5Uf`1el2k(H^vGbC7J2yD?w?S@tKoG|2 znl6~Y2>rXPLRcKL=$7|BY&IwEOnwoXih+iO97h-|sL~lJ(nv!R{s{Z{nLWK^-DpPL zKl6}*|G78-l#Yt|xCFR`4s=jkbIE0j9|B3jP&v&*7ha2*#`mj(x>Hwv2~nN~qs zMH&AmJmS)cZ;;b`I3=W`?qL|CIn&}q!?Vw!_fZ-9QlzNAwoGpmxT z$YeX5)s03n~hK5<>_DsYGFYJ-dFN6HaMF01>ZA!(4B?x&$_o@R1uv~7S6ABkW zR6|Q6k0=ct*W!l}=0#R9od?9;Qqp{1O=2qTS=JXx%BzExY{=3}&6l@ukb$3k`4GW@ zrNEUMT{O)*W_6evE+&9|B0dUA5-x13Sy-Jc#934;%1GvmY5O+4=9>wnBqkm| z%{25uj99X1B#v7Gpj%VFbe1Ei-_v%V1FRxw9U;>`zDgr!uYHPQWBy+qV~S{Niv%B& z)F==Za?&kZuqQrk#gqpep285ab%mxXwBmg{`pz)O%v(1MgXy1A;=dd!7Vr@w zvKz$aDU**O+X;Y~r}8Ee>e`N2i)N+MCaajGpk(J_%*-q@dl)N-0%oiCcP<3LNS}hcN4njxp z>4b?ETTV;n+orx`kGN9vG~5W_lmvA&f#-S=))2qbG>X347l`2UqVo1LBkNW32?_nd zx8U=5!Ze0^Dc4DRRlDeGs`qSd z+z~A2;SjDQwRq`tI}qXV{nu_8cvk5Jn|UK(p#8xtYtG~+^UJ}3WHAY=BC*_`oaM#1 zA4lDAA=%yx!2zWpI$?;}dJ)~xRiBVf7 z^p>llcpF6FQEf{6yoPDtF%qA)yijkNSEtb)Q<5r)ReqP<%w=Uotss?!Zq==#S&&SM z6Jsl6z)+N$8eQTHJu_$VN^=>_(^2q%5;M z4i>S@2RnFylrVPl50f}EQg&dK^PHR|SjnPjve1*~*I88mqb0>zRhnT@RYy?Kg%VmX zvcW`VzkbH5lxsbe@ET6ZPu9cYc8ipuhYP6QvCFu9ihkkt_1?6AE#0ZB!z!L4v7=Xv z6cRz{@qwzPkJvVOZpCCi;!>yblZV=>+IuP2u4NKewJD<4ez+abwVvJ7{YVojjMe-x z2$KnvFOP)mhtBBUxoK!(NMYt|<@|vej+yrUVN9MrLL}&CnMNlJbI0CqKb^WoX>Bh> za%Xzkm(AW9AxT~tshDeyFoxrO}lm|=6yg}M9vf}$wJ`N}(e zE|%}U+mZcg%``XMi47X&0Yw|io?ruYE;#&mu%KK9h4}C(`U1RQuRt=;!`$wblzli!V)rb9d-0A}DZbg&Z-?ylta z&G3ER(Z~+-ymRrxgNiQ(2bkA^E?)kK;D>rxS>=$blVC^HJ_fs0iS1IP{oTAE*V=Eu z_THdpwn=Z($3zCY$Yw5%qnK!z++A~v+@Td34mY9)0+vaEO;5Bva$T9teS$(;?VlP) z?!X4FcgOy%!)N*?pU52!;Uzpc~dCx0?dq$_bfir<+$&-$?N}M0Zg{Sem2C2 z5l|F@iP8@^LBX?M-f-)`9XE@Z;Gnw+g*Xqi)K;5GRwOO&OgDVS35lXnv3|6@sjqi@ zeZKiQ2m$bTica>MobO|Tu+$F9E0yc5Ir-w4zHY2Yx2o$$Q}vG`)83eAy}D=)e+aG+ zrOFMMTyx?y{~CAiF)Z?T?A43LW38^oLP*A8|Ac@Q|ef( z=Oh=MwH1;kp5MIAnN?D+-x6#FaGt;&2WGc&X9xRz>dw|1W(7m^_FE}XEbAwM3 zWX--ym@7N#jm#`ar*V*i|ED(~TIK(}~>__&2 zjJAY3GaZ`uEnqLf$ZGY^Xv|*0FVF_Bja!X1BLgQ#Wc+n{C0$8iWMYX>JjJ7xzLd;O za2N~x702W9+m~;!ArPI47HN1sG_sMOx7*>~0>I5P?ew)ufcDt6gC&#O&;qfdZ z;ZX11IGyh)-?6fMw$DT|4h80xwijVEJGFkxWLf0L!dxbj4^ff3%94}00V%d%PaKYY48O@h}#MQb%cOG7L;qzyW zL;>+WHLh8E)=x=|fk}5E5sUmZdL10y?l-&Lufr&t4+t>09{X`S!}wlN$PdX@Rjr33 zY0TzRF=7RV%Pzcr8z+9CiC#zR# zJ@8AsbR!&H0Uz^ftn)+bz}247K{F91nVIgu(MgMj}BZ1?{UrDOA7Q97O3k{Tr65!L@G|6eGbe-r(mQ92CYePsAI zl#V*^ODF(a`Dq1peua8ip*Qeghb|`PTYs z@d27#jAyq^&w&-c)V+%QOzK`Sr{&l-O0oX$X*r`_X^E+W?SNGGa4|3OD$~|5)fj$f&tT4Fu2eTg-L{L2GP4#P*E-+-j zLNS6wJnB0d?E6s8GndyV0l?FJ;hF)K82}5|VgDR!z5}e7OUJW_=zn$F;C!@xff(HX zLi1`I5;J)~59(E#K7u|XdS~#T2C;w^W-1m|HX)71+!aG@jU)aO0HUk9-IBenGg~GQ zhlT6_N2Oe2;|`jv3!Xsg%vOvPS;~L{P98%LI2E3dD{4%!AA%SHbZ&$cX8{UT4{xTN zk+arxpq>HF-{pL8dL-osWt0L)p0I9b&#z5#R#rw6aX}L%VWY}MAj$8&19604q6DcU zC4v-o_f0A`T@LLt*}q_NM+`eUAvSQPhZPoKMN1!JC@a9Ke@YK#OmGWSrr9oV+YHF3 znqh%+fs6h|T+EOtGKlsb^4oNM1+?erV}&Fl`xQUR0TOExX+$#mi&=dWnTX*OWnBu8 zWaIp6R9qFy-NR0ySLmt|kpyQQ+?ZrkF*74V2|>lqnRK>7t0*A@6#S0_DF6(bAw!r$ zO=dHV)7FN6Sb4(a`94vhNTBCsdjC`e7N5l*wRIU|G#-j2r+mbW3u#Xfk?EEWOCXz^s|Z#Xvp1DSVAh9Ry02cCgv>n? zCKly@0^7M;pWT{Es_Dv+^FgP!_V#Y9p3W59oJx5znXMxpbqYr4&MT)DK98l~atevz zf`Bh>5|p5t@v1OTEGa^2eDNxc09Bg)I_eo!O-%WP0-;DuXp zqp)qoM5 z#}Ee_IEfNviX`0Ud`HVvE*~!JHEu-5sYQuI)sCLi`Qat-?V%*;dbvSXQ_0=(zSLn5 z8r~Bb=js;37+u88t-2eZch`*qf2)4Fq`^pk1<^bvOkz~ddhFH(6Wu4ww%(E z$29b>4_5*2AB+&DoCq?K!16Q@q#iUBy_QYk>MKNvWOc;2ML63t; z3lVFOOAS&n#sS{i1A0n5dr?EMD~J0&57kSYM8ivfAkud~&O7g`@QonI@uFh$eMd4% zk8oEJ=E6t0o5;R{?<3fH#(NFD%`Z-1Ol$zHD=34{%CfPr{wcIs_Zw#_&yO%vr;D&d zet{-=0}oCfxzliHU+$dGm`g=fw50Z!{O6?^=c)|?>gq8{38<>8r3 zU3a|c;c+*-(JE-i1T(3#O+<#J8LQr`mjTxMv-hpk9e=kLvg;TpfOvc)6{?|`Ex*7C zRw+%4gA9kn1IF*wJ3+#+Tt~EoraVQ}StJc_Ysr6U$!vk$WajT?xK!DIs;ps?a_!i~ z+cNsEP+xb)rV@VhCi(U6#4C>&=kfEg!`gP%0=mR)^=D1X849Xk#@t#AW@E4&AFtH* zyz(qRn4;QP99F`_X4cokYEj6E(PM?9kDqVvrfZ6hU{Il(N+lLZ{s>8muw+T)7PaE1 z7aPA{dI>~}w7`ac>#I?e>|+H|a~O|O=h1FWr{l@P{}7*3!yKC#JI(h3iliHS1z{n9 zl`2p)9YvBPlUwV=wCR0;2D=Z<(!SjzD!tQ+*70=esYuR=z+h|5%{3e?diP9O6GH3# z+XoJA&ovY|n&fS+KESuEf%2K&BL?$um0V`1g|}NCg#2y05u?&*@BDjxT?Yx*^T19x z(Raqv^X_@OJ}TZ-yf3o~rhE@{pA7lz)*YqErQz!4+fKK>9~j6>KEU1LNm8R`Ut`^4 zCG9sbLR&d;l2mS45f+O1Mc|H&_DuZ^$vN8-1B7bLXR!cpsMY#hs5fHb4clAil@dgQ>&=H^mVljOYNcYKOiJ99-EP7Z@n$>U5el<7?$ zIIZ+kMLKl`t6n3_H1a=w$F4G2Y*;rU5$d=Z4|W7~r$@Baa6O6;&ZcRw%% z@OiTP5IdS`E&p=&`KX5sR7ji&-Y7BpL>jlBE=QZ$HoipKNM-Qi=W$s3x!?3;IF<SmS_%=pfL&g4dChP0r_YmSp z(({AVKjy@)(eq2AhCDj#F*I5M5ksMzU3Q{{Ll#sM4-t#Yrfh9_p;1M^2!;z*^9LO!Z=jFAi_k z^GPdqY%PzJ#iBgv9v80|7;+prD#o_O*&hf)vNm<^D zr0)`02-_P-kVh`>+l%EP=Ae^i^8Hu^PZYa#-|c06p8O_y(?&T44ILU!b08!<{Y7ck z^KDAa%GYu!FVe~Idsc#d@{Zc+1-fjbOGq=4z3M7t1H8Gon7W*vf5QsFNRaw&fbfAY z;3#{KY(O|$VrcthHj5*ZUkAnMMccaYV|njuEL4tky%}RT4&8B^j|~zdzzj)wOQ@Kp zTCSC%vY0@cbsb^=B3r^RC@ybM#@xAXf|hIk+$DfAK~$83>#WT7bup3 zNs^Po>)XHDgHS=Go(NQC!J2n+8z^AG$3k^gf7SK3-3lJx=NhO`2IXz~jSt^_o9H+q zC{-^SkhFioY))j0`S-rpYuAZoQq7x=Tm@Jv|5qR86Q}tH=Ni}9Yx}q1JBQHK)QywX zOl~2T?&~vJ5uXL?08l^(2!S!xmh&h%`l!4kA~iyXoxV(H*3Zl?MU~`u0p$%Cr0`n6 zhKZvNSniWo2j%?*gG99y8}P%XKEC5FlvUzt(RI~axvPw{)6~ZC-@~{}i56Fxe*(b| z0Nwm)I?DYk7pW5#&VsSPNQNSr7l}yg*f^bri(*AUXDUUf*NRwk6l4NZc(wGhZ(+r< zwPa5EEn~OX%HlQFQ**0YjJtvcQ+34}jiTuliO3HStGaMohDpq@iAnyUR`tm4igk<;XvaUQ znihp$?|9U=DnL9DDsmLv2S90~8vSHI-E9MvJpD_V6Z;n}krzSsBxpw35**pH^y~t) zLBz7qdVdilN0BNHTd)t4jKPN-vK*=S=;TfX6qOvtrd-9fvf|34gAL%O>wJzAu0g6x z<<)VlB7uac7oKom!lcM);Xpvgg;^8P*Rmv|WS>zg2#i5SjM&r;(_U zm!s5m49u}Hy%vLs$h)D=n5&;F}?LJ^w1ik1u zCtQ&K6EPZ6AV*c8Oa>?A8wA-2AxQYBqf{nt#Tl*%8b24BFG1$4!k=HR3?|T4UMI|O z2n>55!-S4h)M4(m`Ff)pJE_}by#k?6Rvifv^X+PBAFad^u7#d**@e9R`J!Sm_$CU(2_O`TZY;&8BYBD|WI*ajWJz>X6=+;L zdA4%V(`6Doknc)^^PWvdp)p+Mi+mMom8Df87#?Xkndy9Re#I<$omQX`gSryhiVROIvk8Y zE8=`Smm2UI75@6lWqolWytQ3}*)6$Fd}W6-5sHsM+P-_MQ~SQ^rR~H|)%HyB2S5IT z=kuf7SPf5Lz88Xkr>n7X@mlidUx(Qv@vje?4(a%YI|+3~)Yj(aW#5}Y40c8Peuh8q z2P+Ti_|DZjt??UfTRzSM8d)h{t{D2YM#1f7lh|Dqflt*B|t&-2WRo*@=YuN*X5s z@K2%rA7%e%PnE&kEvP4ppdH_|p_2d>!7z~sR6zmYJ|HmB-{@M%O7e1B8!JrQ%-madUSG_! zM_zpNrAK`0Ui`^NJl0Jz9&c}6<0024dniQ$$0)pS{}*F#6%|LfTvsP6-vd`Z8siYgLM0<*e z+|fh`oCs0PhAFx}5e0{+5?>>0?%;~Ni`GLI9z}+#7Ie&tvf`m|e-fK~453{MsqTX$ zek8xn=3fV&`F`kky-EJ>N6bhG4A8N^37i;W2>s`CUq&OjyJ?vzY=4Csz16GNs#0l^ zWLna6h$IHTlwq4w&bPl0xSp9yLg0TrtPw**w)`%2Cp^NZ5f_Z*ZbpO#d}x&?poCay zF38r)9}p3+D=O-Of*=l%DkN(29Cv7hxo`>0{Qd93e@`L8>zp zdd7_%CzTu{jWs`H$0ID&!j@YYZ2=x^)X$hzXY{id3N~C4qa~IE5=1scVuK=5;%Omk zoL|e8<;aj&&%Tj6L_IcbMhW1GvJ-;#v_djz1{sV<4LS6OM+Z87<#;Aw&2UAQ-e;I> zC2@@AX$ZFR8(O15WbXR@cS{mu9>cip+)_U#X(UAK7IWMB?cRpdtM9B!)8Dg)eT%|1 zllP!QxzipeR%z#RXtxn74Q+miQi=)yNQ}!*5fjJ|RX>?xpt|D#nxrM1^2h@->pg=kGLUeI#;gR@%&N~ zs)=NHO;^Dg^fA&pMW-yW=0|d*Jhl>Jf*G?%!GG58EmEbE0!sS^?%j4<0g1(;Qg#ju zB)90opT}kwnGCZfY1L3$)R4@XnE*qNzs)|>zxgqtptL3}dkXIuWbXG;yzn+_BiN-0$c|hF z-eW@6{C}*RAwOt`YI(NU22sUJBYnKG+Gz7Te=7xnQjEQrc@_ zoW$YEf(okzFRpyr)Fvd9ob)G{AX%avaippiaqLO&Jd4kLbz|yIi+L@6i>)VtpOiIc z9!|ZZS1T%-Gpe+yIb5;k5r0<<_~1Uqj<`b8y4D-PI%#vl?l{0EK423O01OCNt{+|F zK2u|_Wz&!^<3zBy;nS$5E@|S!VSqKD4!fPhavGE2!jW#`Q?lWMAVB0qjK8+>wjY{# zH@!5ui+8sd!af(_;J+9(S&Wo5V-&omf*TDju{Wp7_5dI`;8;mlcD4;}qqFRk4A`OA zh5tkOD|2z1S^_Mm)T^T)M$Nw{*QoTx)MISrw5#Msn_rX>`?}0y_z2hEFjSE!un#&% z?qbr4t4p!2cX^EY5h5cZ=)#XN>6sS$XEK>+g&#fVu$mc|Ek<#wd?Yq~$i_W+w+&s)GUfSJsX1kZl^*;B?8B$d>+{0zqJ_C7)>ejh1~r-EFP zU9oOo6kIi1hW|4L@!9>cTW1&_vQZ`)y8_vCo_@KOz(J=0dR!~sWQZ*mLV`HcETx6N{$Wuzpey&?u>a&T6A45rSJyF66^qK zlx6qgGi-CMp_)>i`c9vrC4{(gkH@X;t-Gqy#Fw<6(80XG7e2J>!ob^cXBWY%DnbSP zNuYrPu4@)vjZeT2yNQk0{;nZ&&(j@|Z^UC?}!m zc82ITt5vUiuyCXXQ;QI1#mgRSup7g}4{*zQrNvX)Qb+D&)<;MXrKx~$FOSc$7+4eV z=IywO&$^^E(NJ*4BeE;>ghB&;U9SDhUAi8$vEDd(5IIQK{2lU%$Nlt##`kz!XeY&6 z(sf8{ft{c+xl#~O=Ac<${n0WVFW`sCMFP&H!AOfJCSW6@WPjq{s=`WDk3)3NU!_(y z#2ryEw(!SEb4|7Dv6s=eLYkE?;Zx3K9*OY)ON?kp^q-}OI%x5g4T2k^thBO@7THcQ zVWCm5zDrQ%;fP9%&3MwJAzN|U#}}|62XMvihAJO#FD3U#7_4I}Q&aPkoUcn6 z_VHJl6HUAE>;5+1C>w9kuC>$Qv~p2$7KSYMXb(4FFJMJ(*wSTG&MqY;G4uz{l!GyK zL5-9=op@M`Y<``TOv^l@XGK>Uw)l#CREnBcae5$!y7e+6EG=wAF||^B#NvUc5Mg<{ zQS)%l-E)jQdZYB7J!J5M#I@g|>e_Kg2J)>Y%#EPLeO01_0K+`SwkyM5DcIo%_BDm! zk=;LVU`K9jKv2@vJoSOW+MGyGm}8D~y;gNjZL56gWC$XQV5cnVP|R^|9=isBbV;p= znl{QOYbNV3EMiAm(}9MnJPm;wh~grW7At=bYzk^-K(j0vWy<j3^Sa z)Xcp;D(R<_e8WOeNW64EQFLa z<|o>CgQlE8j2cI*I1*C~%bbIEo3m)c9IrX4ArEn_s+;&lgX_N17H7qgn7O3W;_a=t zq*Q4H_#(wcCVQl_UTpoQrB^QAzSyo}*d37Z+`GWuh4ys9FZ;;#s{$MBz3j{b3I=uk zk-@bv^8#v+*^Cksgv8T^VJgh8-0c6YSo*n5VG|-%(QHHeb=RINOiBnyS(VK+Nf50f zbM!~PrS&hH&jy5Oh&nVReg6*=1=j8*h7g{@2nv)2o%bFO6*w_A*IS9}E-!OTf&@xt z$GIufoM<6pxPQbf(PBcy8<Or$YhOdLY|DmW#)0484k$;PMMai0TK5>rt!6rjHxRtk23&^ym(4WGh3d-MaPjokDCDw9-~kks#O_Epqhl< zE%`H(dfr<)c@5Q`dY^rGJVHz38p7>#;7d^@D+-(YvlZn<8*L?!U}T7R9u;ZO8PQll zWo(xs4!b{|jZ9a{yAvZUJBHMmA7agob)6v#^41lS{~Maqj34RHi$jhg8HlQB}l z+5c=w2^+xT`a*yPnePCSGAq-B>0B6ZZ}Ba*e3Qa%%hiu^2B*v%Y&JGHe*Z3csNj{v z0(%TQ)n(1~Wf?tMLL(b9ghzp78X;wHmfVjmk?)_xu%Fc zXAJcNQK1{Gt*3WRoK3YZrb!8T1yEa317jdaCB-kEZN(iAkYg2whks&QLQPAjVryU8 z?wgihYgBL9VT8X;;V;evR4H7W*ynJvRx6e-D{rJkz_0J*GCz1D(rrL6B^;r{x$ zz_?X=A%LtYDgo55_O z`Bim5+6^Cu{un(6#Rk zW-H*?UrtArxzQP9q{Z-`IJ_D+{NN^;TJ;h<*^KoGE(#3caW0ES?zDA^g01=&;=vbh z66voBHt;m$%H_|si(0KLzXyrAuz1Y*6tctC<_lFVoqPoi3{VoIn@>-V|268zrk zt^$8A+hACp$7k7sUYJ&N(8+r~P+WQgv6t$M7#^}`l5E6Ie}Ra6R=j=Bd9K8S9_KXb zg0Gn2(HpIf#mlnHY2HKe?)TX{m^$*fDRp=Xq!blZ`Z<)7VhD&%TKL{l27=I<)CPao zIa%11MF1wt>LBBajOqGixBK@wQ7oy;u#C{_^*x7vI zs*l$^0QYuZ4$W9kZBhtXq~8KYybQZW9V;$!S-Gh`KPwB~Q(9@76=6<4Mmf3VoM$GA3L>Qi(AaMx}Ch(?WY6Cj0EjKEwC`hRb z1J1?ANL$NxGmD<~3<+E3mywo38ymGF^_;=U$G+x? z+rg`ziwVp=&^(w+!pmV0Y+CeOi9S6K4w+PWGf?exATB(@&L>2GYh6R$AKh6*B`{yw zfK~ef7*3k~WGOWMXc;uhCX7h02JXp?$?wfQ+&!POl17ClINm&vn~HU6Y#T{p`5Abi z*vzA_m*XuwA1%l;q|fQwa4@vAwSx%K6=}4-YJ<#T)EPLnwE1H%N-P*gkv^#O5+$5h zX~dOnLZkIPbSbHj4M*ilT9a{$6X5-+ie&l9C^MCS8LpCDt%^#_)2gL9GNn4!KO|}m zl<&X;zmGX~qB#4&oN9GMnHL>Q&GPR&Wo569sJ)>5**?4m%iUc;*HPzXQz~;HF`iXV zph{gNcC^`rj70u1M)y?$vyD^Im`fkR`w%T-yxEHVkI3{Pjul#=Nz?t@KrSv{bQy0+B5#cnB@tEkD%gV;CBd zLzio+(v?#nfzjNoF-D=4Rwb`|v{+;8n^~0th1#5QH7k~e?ngaM+HglA0rX+ln9q;7 zrG`ZPdO2KOV4f_Kxg2+$Izx%?KLuVmRYw`zL%{djV~&u2P|Z5L5K*T0Mup6>BexOq zI!pJBPJDq7JYm6qSbf1aj}}M7>S|&3QFeFL59u2{Dc6oY@qt1uhn_2E#ga`A;l4MQ zj=>TO|J2NlR9}l?fCX~JM)l@pbxO!N5?blf?^ZzCT?vWr_2zvvp6y)hCszj$ooq{;hrbu-f`%^Y~zIXmJvkHl1$*OJUz zp%6%d1MsVr5E2ZGQ8>7Hof__C_%S=KQiHFES#%T3n=f_hqauEA;oluzK%~CE0AEdl z(JRS4BeJn@7&2l|RtUJX;19zM`Vq^MbLUrchcY4N9UD3eH@B|jI_1*MHDzpol!z*w z<~d%Y^aj2lQJiyA8$6Q)aYv{QrID? z4jP2gm0-)S!2PY|fh(!#beiN8vyYeq_kG!9Fp9g@Jhx_V_&6G8>~~BNVZ}(v z9-*I7F8Z1Wt&g*_6Eg_az~0JJqa3KtWt??H1^d3z@gRv8ElX`_i&U0)SE4Tq<4CR{WBsLPGE5HSqgjcZKKF2Kh%L0##mC>`KL!NOK>XrX1dqKACS ze^9+L=f6s8H5nE5E1aV}#)rSoiY8c856%Iw6RhQA44oLvDf<|vl7B0p4tZ-)nx?hk zlIFyRJ|y~BdGeoZmqq>ejWTE4qAVEqg~z2IvY60XKVyweVDBt7Q^^3Ab{bonFh?db zS)`eg?yF5;OoYv!Wqxy1FQr@{ky^b_yxm5~LRF{F^rDDS>x2>Ex`!9>^>Ie!zeT3W zMnIxrjX`QmLEACT`OU#kd7;3e5!=0`qAd&^EZCSFjVTm-N=q45>L6Rn@VWs74Xy0d zace0FK{{1g4#R%Wq&JOZ6&|0a;vo;3=07taLy8o+nm_v$==2y5H7pL~sm0?!-2Ya& zx&+qex4`u^<{)Z=G1pLo@~}sf*V2e_G;M4U&Ikj52vpNR(+G#l3j*pnw}u zVatEX;!4Y!ULQGVYh7cd-%fqx4%dpuG?C5(Vo7wmbo})UpJxmYPp=~&CCMxyDV-bF zT}ao3g7D5cxluUj(IxA9I$^=Rv(WpZCa~VCp9}L1*DCe5JyWa^W9U+#0+O^)G%tP< zcI*=Sd$Xq+OUBKgg(TFP@mp%aQu{EDP9Y3|TfuB@-$E%$)lF|w6O#`T?crU1qf8M} z_F(2tw9zE;@FgFxLaLlCoB3hGZ!e|cBC-$SrNHaNh-#1%>Vt_J2Zyue^+TNM?y|2D zVzWkurH0tO9@@pGC7aJ5ygKWOOFg-AbfO$Ip>~Ffdhc^M2I<35c6Lwp##{7u-vgA3 zP2O#;GhAOtlVRlhk}?Pt4TkbFpmg3TA-Nh(C;dcE)E-H_Q|W)7yj}G%HhbFM;Y6sVe`qpqdffOeUX{Pgk%aIK7y@WR~aF(C>9~7DPS0pe>(bn)^t$4EeM{myE^^^Jq zoJ!72*xSVj)=0`M4uFQUB0S`&)mjh6k!W8%J(Y=FOR zE$V#l*qXWsfaFKB8}{h?l?F#H;aPBNV;lI11S(#-{*{!#qk zQL|vy3F*kq^hw&@`+~cs1KY!$$G$Gu*^gTtbA_R%-A=MSP`1@zT6+#?b(;@-7?R8QZ{pupckaZTuMQF@Kc_J64FJD zZnaMv-H8<>6FVYUu;$wxJ1U4N_x+S``lZzHR3A#}3?KMan(=E9$GzVk{(dzX5 zvwgdLnN+{L!cTXf@DVg0C40441#d_1SDB+@7_wPlAFn%GWOaVq9lkOS)nkktbI}hY zB=0uW{$rt@;?S1L#=0X0kNYz{We~%&52{vYpquqmWpGMnNMpJsgAqgEMnY-bnw9Bu zWZKVWRh1VrZjLZHXR1Z8OMvZ>-2#kVUpSn0bva9UFuKS0HCQQiP9)$j;F? zPD=I#f~DefHct*f;2h3Af3u_`9`s3P1z|G@S+Zpai3Jm!o!W`K^PSk#-tI8{aAw$^V<53eumdOkxLD=p@* zM28$Vx0OX&3oeYHtDsLtr&rf+`@cj*l3ssy$^r2m&Is2?5CcU2vF!ep!K%fE|(W+$Cw?f%|=T+_vpE!DtEG3(6(Q04hjQ?*a0pJ z*89*yQ;H1+Vec6FA!>SKnvdI&5C#&l`D_MTT14r4A)h~o3Phw{;nd!YLb|%S(MT=e zUwR}j^jO>7d4|*vTxXt_0uF~m|kv8(+UetTwaLaZ(q2j`RS5m^kI;k1vw%s4Z{ZRX+%eSd5Us0<&e?1%d)RKau%Q)t?S2UiWYaX)B3xl4=rL(8eleim) z*@dTzQq0#s<-3XIe?|9D4@b z8$+sM+qsYKuhvHvehV@!?T73^gL(r|LJoKZ|D7efyYS&Hy~KPduiJVNH(n>de*?7H z9s}Uw_m!vC+-Y5UJQ)nS#}t1(&KG^+5$1nOTrt=at@)@q=cUQNpoa|98~K_yy|V+q zJz9v!8saFZ_iw3o#bRAwFJRN!Z--D39te>|!pIbfN2DT?(cGa%lO@7eGULz%KZBz8 z!`n@C(e}Pb7){qW_r03XxA^XjTl*s4_xs>WAUc&;6|-qI?4ExO4kNX_inb-|K*ikt z5AG($f||r5!3cW6cNKR1>YuffK`YGcMlkPIz{PA>W`zc_6T3f*!TMVA#GyI^hUI&g zHwQUZl60%GBu(>yrzxp1!WZsflcWO(VV_B!5g~$#JwJHngl|ufjw)BqqRf@5q2ro~ z$@rmIipu>EmV-d5N*6nY2sMoyClt_hb}sC`GCyWHmAOFU-gR5If8Eb|wZ3stOv|M0 z3+Gx0B5j3aVUsxI1)IJ0z7BZBV2@U-R<7?>QjBRsx~c+*svCWHKl|>(0CU%seENpT z`Vr~jF;Gy%TK`k6gheIXWo|H`6?<)en|^HC%g7puZ*9ki1FX9Dg<~rM{7&Y}{SJIp zEjCZVCG%6J0&9ll%2C1+-p%m|Bs|5zZrL>O&iiKL8<#u#kk2&wySs_%P~?y3U75k; zhQ(Y|CthcmhF>26N=5(l2S&C74&d`23ihv04X>zbniTcDspZsZYX;10{{z_F+jes0 z`;4As_g!=OH6&Q`z7y%1wn{m5NoeYOTmHn>uQEf%xnD_B8PH7>BrOjWd3!p)+9_z? zN=GoXkQTgb;DpVT%er-?4O|{8g@udGrLhUQ+BEy2vU@8rVwsLq6<4 zl-9_u**3Ijdpjn8bWr;rwr3rZJL-0~umC6#6j_AxK~s?ZywEtehFTp7~wvy3qFZpM3)yw0yL zvoh1Auq7*dD9B_D#++)zS*#N;xKH>KT8uV)QxKVNcfp64tXK#=&sMPJ zC@*PuzqoW?gk2eb|N7sB<@L_A?q08U&#T%iPgn|fr!HdLt-<&w~uev*1Bn>#q zvqbJh)#-MH)M04d-kYRk433fqx%_uu>Ec;n52y2%VZ{XY2SX}enf1~`I>-jeigH4q z?~W{AeAdltPu7394gu`3pEo%tZ_T-Nbzu=q_^E@!)`lo+P&n+g)IfqKrBu#G6<*^&pnmbC;ENt9{Sbm-n ziP6<{J%A-+FDd2RqZk9H)MfXIf3k{o&0#bPh5hJNcB=nd~O0g`D zMt876LE9REcM)lG-9fOIeXq8sYj3-5Cx0HIh3!6x_KUucsIqxJ{<`^nvAp|Z{b$;2 zGj9y74AD=N(c3NpMYAQc*BJkAmp{HWeiSUfC+kcn$g7jNH4{r7!mil{@AqXw4G7V0q;qE z_l1Txkwb~Y($oNM*gqsJlUYgF>-&r@E~^S)}OWN71D96!*8Xk*zy;q z?SSBb8~(u0H&3`KswPkmM?lFPEjKax%@^uZ8s3dieb2+)%d=p5v}6^uf_lcfLk8!x z6Y?BKB-E*``OSn`av$m~{}X+*x=*!OfdP~FT(Dc(P4<$TQ1kbPwy0gXXM^tP`s=p11MnAm0-zR;Fk-NO&KqWbHCF}%7xtdS2^=@*O+*(wY%0N#vT z=10{s9KPFZ%ckut%+YYg;3z@YZb@(DS5EUOSf9d9?vMQ_!8vY!z{F5E-?v>Dq1HEj z{T=M15Wa%_!$N9s?4VQrMNHO~9Kv~0cf&hn=B5|eM!3Qrt>P}@PPbGgLa)lZ*(WdI z&u@x=<+@ZCkwao3ms0a?^fB-$`f@&daQcv%gBTIpUVhR8adNzv#B~4C(qiBjz6>pQ zC=U50E;fTd={DD#?#AzeWXQ-ro+x0gZ^5pzTEa_WELkHxun%MT-;Z`jjtWP9k_Qnv zF1x1l;5a}z&O&(A$h~e)>V6-~kNZ<;D#LP}B?$MxntEx#ck4arfu-{$J6Gos>E+GX z`nGL+MOP!BjU0FGJGiL{^p$=|QC>UO4;OL;HoB#43le%aU&ohWhYtM7rJ793OZUIT zrM1wnvw6$7M;ds>)`QeeLK1;8)|r97|3g<1?FzAH*q$@fR*1TQQe;*V=Ru(cI$S53 zYNt$_YKssR?>h#v4Q*P^eEAai#M|U@5#4dn<=AvO$<4YuGQS)vB`tUci98!u*F|z&*bgcI)E`EVk}I9>{P8#lGJ>4 z*=p^1z>`qbosm>*txO^sQ(K`~Q6Ju_%l2Y!sq==~D3&J?k`}u}Btg|24)|#1CjyA; zv`f#+*pnNWF^8E%u#IGlMTnq%Gm!J+_A=UoS-z%-Z!UQ%6295eVFN751i#TyCm1fsFjI>Ujqg=;iM)4Q5$=HUI|m2tPz%#*t= zqE>`r8~s=82@_ag6GiVs$O=Miq|%;4`n9g3v@E|qwpGi^HP47BS*KdjMW8l1XAILR zYpPRZ#ZVN)A}>xg*sgLe{vE|F=jT$l!l5GKPb_j`W8Cdr)lh*!&&<~59f&j%B2@m8 zGZUkf!%k83*N#!Q_~wampoF}5{D-B@t0fRe+tE$$Csv)D@_Sk-9-ejPB0@ty?+rJ0 z37f3YkbU89EWheb|m);>Z(|Ay-nEx<91(Wqpd)x-Yxdws8Ezo9aRzUMycElhJ4P1XXa%x%_U_VNbKWKYabE{ z(}t|iBL|crV{X5}S&!hdO0e^?kokND zq>EeVy(uqrldES;W>)*NJwD>+P!0uFaL+UApcThB-FZou*AYzh-n&=u`A#w=(V4gefpikP!|Z9380tHA)}ySm9Bt}Zk) zb&;CLgzPI=Kl8oDzraN%LeOa5?({PF-;1MTI(4d}RmiTQCDs~zx74#SPV5+pg!mQ( zI3LVK%=*u<72@lVc0I4o!MIX5NMr&x#B1r`AA^%vT%C2KHAc--7NZLE*c5McliH&X z?udAtd^}0BE9@YrvUAK*GMQ%V2Fqx2k`#6x$Ew@(OQT|5%(o_EOUQBTQZN>$<5*h> zO_T7RwG=pfLm|g0n5*XCLE?nfDZ(EcD~oAr50n8TQBRoF%1hN(Vqff;ASNc!YIUaA z#Pycy9Y7UWh(w0uY490V_{h+QEeuyF8=mGKdz~cb=w2KAhAK?@JoIH)1)d0y^ezg+ zq1%Y-OqF23Q>@J3OX+4_ba{_0)bPj@L5m7KUl+>p{m;zaFWR83Z1nr$X=bAVv5doO zQgNKVlg9!ks(0kP9MW$vH+Ez?V@Q00QEoOV&ZsJMM7I6vesLEw3|b+MoXzh-fnZAl zME>9TP##Z?=M8LhIJv2+bINbf%6O#q^wb6OnSG@(26T=b?_gwy*GR^n2x*y9gjTZ! ztPJSpVw%lgW`(}BD9@#865dk-bH)3tmY5P8ej^yzYgzfw&SYy|D*QRgXW(yHpvK7Q zrN{d8t!agU~aHaJAm>ocA=d_E~QFV~59|?J)|!Zdczjo*h}y|E|OXLnZja zPl!b-|H32V^r?i&J6#fP`=6UVo3QQG_{1~PUiVMnby@iMDK8FEfHZptBfh ztfb-DydnFav|Q^}V*k*d&jzx5|3dfGUap*IR=GdS6gx%hapaYta<)l#*_*k$8k}F@ ze>$R@(16=}nodQHviGOgVRMQ8#}_|Tf?N1;kkeR(_vnNl;zNo%M003*I9yvlotlSFsYwCbN5z-q(gukcx6(9P2ZjRi0n)p0h4I}F?ksnHs ziwJz3n<2)4z*e(+P}}MlU&SYR_{t(<9|R|-T#k3${U77l{_ik4&%w&z;BiRik=+(9 z8FSA?C=mV*rAjosN6iQthY!dnL8aF9X?b>}51)E=9WxA1&Zy8!DCYnlA`JPdA*W+g zDr8Gh{0Ev}{}M`1_p?kBfrYx(B}Pi|v!{+TiaL;qn-O7-oZDJ2Inq1BzLwN`Aiz48 z7ko^T%02#{Q0CA|kR(*3N(FNc!z-%wJDJY1bAUnTWnvIfz?r}7qh6b3x+8kK%W7)O ze6J>BxOX~rx)bvw6)sNpydspYu5})Za#)m{o_3YrLY_MTfjN#tYN}26lph&8T%}U+*vjj zDs@!RMGR`3*Po9y0r_^RM$2hJ{Vf~wkI)<0*1SfgTCE#V`);NKHcCc1audZ79&+Lu zrL+LzlPYHr)rQ(20X{=KeR14OKF&zqU-p$gNd)>aB=T>%l0;T~(-LMJRzV?Ey zjH%;_o^d3ze>XPs=`{&1?}enA@CdD8OSjgan$jsCj2(GS7X4ZXV(3!8);JwW_~z#I zz5n8fe8H01LPm(dJR&6Ek&vBi05efDlVa~FFr2rn(>i_6sUrWH+-BL`O+td#b=s}v*xRB%(`2WuJ-m{ z846@BT&`-)R+jg~l=$Kj0j)P4N06@0{_C@>8lOg~iu@kY8uk%e(!*hYOE(9mI zeAyZ-lwz_NF2xpqqqn9me#;KqE-zlntj1>>un++mW&4f8&{~%wma!{h&;M<(A=ji7 z8NPzY!I$E%<6}4$XWpZ|3nPzB2H(f0z9pOtjGDy$TqF-{WTMwZD6RCE*3d$x9Lj}? zMp&)<%WL5N6D}H&#$iDlTh?JX$TW2#ReR-&omT6-n`34ver=}z?MUet_|4Aaj>3)x zoF+f1Wg^V99fzU%37K%yx@2(rf9UFzk?Cgeg!IhB^x9Imi-X#c9219(Hr?ml@wItC zcxy-gKDw`?TJb+a1TrpCkpfw|so@Ad&)yo%9zXoc>(zr?#kf!Z*nhO{sBjKCYW0DN zjegZ=-XVm^2V=zlR;~N3+FZ39j-PF%Q@`6W;$Tcd51yc7>Gdd5UnhNk+E1G8__twM zm?XnR1vi@@O9h~jcM^Dfc~UfFpiC`)d8LH8j(ZKI2fy(mgH5?2p$8tkkafLFGI}Uy z0;(HzGVOo6;?d({E)gRl)tO0#EqsOJoRf(v2&{5c-=!uNAEF8hh5fsy6|N(TPg7lg z?m&sOzELj32$(KcQ_d;I3=)!PWoN8c9}%do=zJfE;C5Gu|W9A)Mi9Vo&fh0C2EUWjp8oeD}*nBvT)gVhta zmdNV=hOj1hWFzFoGnxLulE-W6sjj%TXxT|mj&=5c$C~_@ILub+9K&s#pLX_VSC0l!Sp&7F zj{6#W3q{Rwaye~PdRyNHIF*+-X$#^zv6<`C_hgjHQ^ShnZlvV1BXT~HF4@ZdP9s&Y zI7c$7rl@K{)byW^pINM?4YLJ;yscMD7gS)W#~xDa{TWy$qT*~uFCiQ~_)|MhTOY-|t`PPw{T~0# znef4YG1%O)LknM%?hKP?#)Gb9+u%3ZcO0=Gl-k{5->PHV!T4EiXcIS*Pg!6Xr3Z(a zPKGu5UydldLM|OJIG1Z4L*KhvV9V+&(XM+gJ$Xo}{2st^yoUzpJNuSsgJ%1sxLI?s|pVm4BO{XYez)sH>Y+8X^WUl{BthGX&>ES!QaUQHAf}U(-j*&%3#d1=9HY$|05_D zeZga?o}{L*)uZF%y!Z7|@OBtiRZH~LmP}LwHgIHq!QN`p`mZ6{_qW9TwM3U`THi#w zADIf%u{x)jw%sOj1gr3(U5B4`0B6ChABHj!Ntj|;Ki}Ontv=Veus=lz2=^la}3^T|&+kv!W zbUgU8wMSof@{a2wB?>+#>T8eq{6HuY;A3G*%Vw| zSuNS3m_C2Ai<}00(Dkx5YTMeSRFo_$DXpYp0+r!w?6Cr!{-+jse~?w?N5xL%&#%?L$Al`8sENeKOuf}udR)j zj+?lC*gZe#8fQYbmiG-G54{muW)QZParJD)uFh`izugJI z8rZ^Kogvq87C-)bTKeT*0A1f4`uGoSiFoccAnxZa~ zm^jvTbNBXH;r*g;D3q9)KEdZ(Qt-PhIz3k|eMq9Ue!=GxxZ$-w_!SvW91FVt>LK_~ z_J<_`9$cuizE178XmPAz=zHkKPS}qNLDR?4$2+)=UZXVg$^QVK*3KX62EVpVuYGY&A=JN8l6HXt=vmiJaV$6_7z&FY;L~F8Nq?f$-1WL$ ztD&1SNh1>+(oVa893MsrHU++KvivBvuM=Neg2%5P*+l&kxu0asDGIc6F0JYfOXkuc zncD+?<%v;8Lm<7z66{}eCu??o%q`{vci&sqpm7?|e}b2U7jwxr?6j5-SJcb)*)Nu3 ztbZ&(!+c;qks&JgMJhDI&)%s!1lYA2G*YRzgkc2sB~)1tv{BJlq{)q1{-*W|#)b%_ zyw*th8WOaG5GG@b>58Ojvm*CbV%B&#o?-qx0|RVbLuBmn95Z`S$J|p`?gwLK*qdx< za$5yTRPd$)@LN6L+el83*gzKG^;)|~Ff4#-z=cnUY8bm)xAPUS zVGn}}5`1%IM%j@neev(cEyndqb~Ba&5~Q*t`f!yzmZz~V0?3@P*vG_$$RvT66nQE? zR`1nZ{p{eKxkyB06tuZolet1-ObFXctGK^&t&^@X3S5YN^nmTD013qgk4q*b=scGK zjX;7umqjAk+Jx+n%_ZBcQ{`W_bsFGzX&|;U6kI0Sk~h=6&BAYLOSuuFO+%r>Vk1Wi z?Bkl?yWKjwP#35K-$> z0^sytl!zbzH0V=8kD($t<_gq3k3Qg&I}CuluLjcsxnM>a9p-QKT>qU853zLK&3+uVUJV}B#*YArDaF* z4p@@r;NcCZ`OmkYn}JLYHAV(zWP8>%pHdn{OW*ofK!!>^nR3Ltn@u2ny|pgs6)zqXU#?x{dU zc62FCnG)Y~M}TL|*|O?QI7iE9D`tzKK)&>6d)4E=`vY)BfdU-^ zw5w{ca3t%;ugiHh*p+$u5-;OME2I0^H^GGLPbF5}8h^Wh!XTRgKisiIic7w=Rh|Am z*=2xE>+TN?*VA4*KJ=vdkQ9OB(DHq*TfXz_E~`4Y2yE0Z+%H72~>VQ0K= z2+0!%DRQ>|zSWc?E7j>orf}Cze={arb;1BU5SuJ4v^%fM**5>ikG10=vGZ46gp6uP z0OaeTE!fP64}9Q;P-6-SN(oyBODXtqY_P68O~pkf32;y?EXFZOs`P|SJw^ncwd zJ=M>qGdJ4sK@;KEgmY%cKkVYstT&vwBrb2ONTn5v?9pQ4Ab|HEn~_z3PypH<866z$ zO3sGX+ul_Iy;6IM^6Zz5~VdE6I*F!bLuEj0ABF7Ki*g&kL5j-!?I$vn*_aIt#FRNTBS^v&2O6y?@aw) z0MtM$zu6d=wVv>w6Hm%$?RWxX%ih6?ci+a?=qSb~D%z0QTw30c_rTZZ3wgxcI5Is& zM57KW6BCF;`8cDf*Qzp{SUiPR%NN*>r_$*7KE_8!S}RtK*q+t-(#5|Vy6%xj9*NGM zKYwi&{r}gH{#^r#&;{*0H+Nq$?(PwdL|Spzwz(*bIWapDVvr69lZ%-IqKeNE-869k zLmM9ivmRz%ybxwut{YX>#g*_{T+o(02^WlCG_GPMsc^y&Qg8ako7hnV?G8E$X~x^g z?b}ghMBOk+k4NuFuS3J7=b=$BL!)8PQ+a+%?<0t(N2FN~5KktBktWARP_I^z?dgTzXkc=3 zTpKkWi(z7XqBS{LvCH-5qnF9{M-a&Hrj(g@B4VLZZ7MYJA@ITT-?i{j;ti9<5!YzXg?NJC zl;LHvQj;;pTw4alZyG6$j=Pxe=7RH@crAS3G8CrcF;{;wOtym#nqC_|!8}7{t0OSV z|Kn$iOlfyQ!-~i|b`9Ta8>1km;%gYrh^{QOuvDQ}m~ z7Zg^U;v|H`SShcxid1}M0Z@u-_u`r4GmpHqB z$AIL0o_+S&xfdP1&kKI1ld5}uz>JH4E}x7cnRL-K3`a}~42CkGn}*1r3kT6)!cff+#c0R(F>}*r z(ERv0F@{o;ou!$9xeoe@X$%bX!L=O}`}?$kculc*9Q9faV4}0@plW*GSLA&*UQWl6~?IR)D1A z2yd9Ijaeh<0)u}@8_-+P%gNArKfdASh;;;@BYX@I@kz=i={3>`;VaS$scafnCqN<* z)21+3(1hA__6Y zJ7lc+-{o3UAT$z*3Y3!?sQWEAQ47@uc_k=JlecPSZdbHfTUf11)+K z#$~|wTBvz6HcS7`MNc?HttRxFFOJP)=T6T=;FGq^4$Mu*X?H&LtB0?+d-I0?_+VCVT?|N7UT zUAS;zd*Q-`|57IQFMFV_0WDgzXp_4yKl7 zm7O&_8jv9fx!{KR<*tipr!l1P%is}~Etuh0O2@gAwY$mp(326sMhs}Cadc~G{CPed zN0aO{0ky@Q&j%cl2On6iw1Zbd{c(ol(~wC}?E&u0=yCE~(v>2w0sdR;^+!zc|kN#Ze; zkdbE6Nfdi~v`JaYXw)0GoNbsz8iC$fXJGQL9i=chdc?3qhgayEOu3v2$VWA%b@|$ z0B8sz0xb*WswqPV7>6Z+E=E#F6Cr2FN2*5_ zBjml5SrUiYCR0qs;|gmE-^799w*tdV$5}*E1PUiMYk;=A7w?n*ZGdz{_>6z5 z&L>Po&<$+_J{!K4p_v>Fy%9f~Kj+`+LAhy2Jkq-siUkbLnuAy(iOI21lqbhAIx>c8 zxuV}qPv^!QG#j3Z)vMn1E%Uog2Np&j2($WxklM~eRD1>lGDG+_okSyd zS0bK}k(rR*LCg0rIWehFCGZ?&smFL-WqYl*_@e1^<{**DVPbf75KknndME0=RLM<^ z0sY~7=MFhh%Z*r(AR38SnRG%sh?&OZWLbDd*n)Z)i)^kbtO|rG1!wAN!V`^*rHN2s zVPqd6$HK~XEanK?baVeMxktW<9*W+k-1L=oX<@j)7Rkj9n*4WRE`tsDFh$yhr4f1t zYK9oCSbkvU(`-`g)<%^nFJ%zqmPkW*KB{$J9*71MC+>6TeF)}>myCQwfEtGX;YN`` zMNM|fg{PtM^SgjuVaJIg6L*Z)b)zyMUSxk?50Xh{VXhPdBy0(uiEZMElsq7b(Q>(B z#BJPs#7!)Bh$&}b*G4Q6$H1JqaAOJ7$`gU(xYnxGW8SM?@6;I3!{0xDC>pU`hI2a_ zwdg*xsg!QETB%AiBhV@Q(Kbau)v8z)FyOi?!{F}cZsBf{c##-i!9XntF8Js*17tD={q-3hC496m;;)lSNzoMg3%V@bK zO%uVtL}{#UvqTXDx*jebS6U?*%0Qw~#9XrPkjEt-#p*u2vl}zsAnCej2W?E&Jj14k zauEV)d0cK9>XM=s`g?n|0p(FVAL&#|o~TgFA(70e&gD_Y(e#wACsRp50aogH4-9p= z-T|b029TdI8y&BS%J9mdUK+FBedj&zU1y3g&|^0)9BQ}Q%EE+~g8;cqO2k#YO0iWV zl!ONIF5P+*v!S|2MzpPm#T~-k&4s6D>2f+W2uUmW;E5-qB;*{ixLqStn4+e~w#7aZ z2=hH_i=H8lp+VB%7;0$15~;E5LX44!BcEek98I~L+nM@!aCuZ`c9pdvzWU}a=wH~sAbCB$r2ESTD zWq3s}vgCE^z4w-R@7hynKn>4#Z7UMM3M^$Av6zHjQp>ek%4i6btM#VpUgS;^E*B?I zk(3%2J{537=+UI6w8&`NB0^2k z)ZjT2?iiv;BpO{50Wle9UMGRQZVedxxuDL_D)AEkwT+1hKV)HgYo6>TC2y# zytg{DrzV8`;o5VDyms4dwK_qAcSpw9P)rNL8LkEq9K$<_} z6EtbRk(ko$YT-?SqcopsH5Y+9)9ihQ2iD%0@|ti$48h;c#T}Wb%FFP5l77*B*}R}qnWPv z_Ya`ZKOnM@9?FTwQ63wWq=TtGL)fe>K7v%=3^XT((emmjtzH?FN0wV76P2k0(f3?= z_K@$l+)fav8qWvF2hMoT2SnnJbtC2>rCLMZ+-ZhGGaQkr{Y2E^Ac#Z;l~rcjmO_#5 zmmUaA)v3{mDXnHHgxLxKc2{l4u#-xeMVc(v4d>G(55us-c*oDlq!PkCy*&l=_4TTB zP?{|3J;NhoC|7DS8ks5yPI5_gsu}6M3|G*-2Yw#C96bnsMqFliDx;Gon@n$%OUCsY zJ^|WwA)7=Yn-W;&>zLv@wj-l3-jxbYTL#2(1)ou0e-FH-DX#MVS<2`i=tuv|S=y8& z4s(MuP@9}Ud3*%PR9e4tVB>9&8JLOY_^>iIuU-vmqbsbjy5~LqW@TzT(4tGv914QK z4LY5`wxgs=lGCCohQKi<9N8*w*Y|&Gw9;ZrtXe45q`5L3fq_Oe($q|WV?wDdS@k}w3 zl5z88#7y)sR44L2czrbLJgf83h{7z3rm1WeBf}#Y9vMZW-b8OPFVIcEOi#|NHo;^xkT5_GDl&?`pERpfL9)e-=r=)5;#uOT0K1JJ^a$LsWG5m zU-1=XVKuL1N*Q5QTLr>I91cSoGYODkras89#$Aw0vXEIC!vI5q;)OUQ;oj zQJ5(7WHVZNELd}Zu{`66<%+U?;EsM zk5#-sy|jF44Cr^)d~GOZN8M7r8MNDhMTaAPL>iu$kttAW8U#w^<=R=q>^?lfHV8cy52->IwbpS8{_4w z44CB%wdyF;hI$|ok1cr_CJDS((gI8*xIwx~1%|n<9E4N_H%%@XLr)=%Oe&40N0p_E zVj+*HW200mQ-Uh*Y3?_UO3fHhlC(+OMc-gQ2ByzMBAZ8bVjR6QW{aivy@p9r%4Nh- zY2^9`(P}o(tk*=nOnM#f$@jdeF`z$u@4O)<4t}dG1LBTk*8>fSJB4wa3r*13?ZDth z?v^`@XcX9b+ikG#F<-#IyqhJUi6~Ih{8JU<{ zxoT4kmAGB4Hla?2O@gMYM_L~OP4ZQ_Tne-1&Xv@*G&znXiS|2w9 zF_Uyp36qH#`YeDIwbcX1=U1t-Q<+8BgfcHmTMd_F3eMBl-wig)ELlxSD!OP?AH#0pxtg;6l@uhIa_mFWl=N;hAv7d z_+X5D)yO6o<3GIP$MLBH55ZLZ|H^5^>>sb;J^xP?}(&I=T|~-gFh7e(YgX z>kYYlrS$Qb7+F@HB{TI~%9iR4Lqf9JPVPrFE|*$m2khp_XS1UAdwP2iaa?%y8dk1Y zqXiXHZJV7=48%4W8jFNoYM-Wod6+0yMN4!AX$)Iry^WV;y3Xo2GcjT{{%I=pq%^9M zxwMQIwIb5{BoYo{EUl0~iWw=0jEJ%jZGy;Jr6G&Hsx7*%h(k#_JRhla66s79z0+nO z+uMgmy{?S5G`a?jS{*%ugECI)C5TX$E?Mrq+8US|1G?usUmfZMf!p+2LDTmwk6LGf z=1`E%O)sGpZ@gu|wRFVff?_rfJMJXxvhM=qdWwi8^XPQANTxfY-D)D1%%WbIRPVQK zyBJ>bCZ7BAAMwQR@503Bm>zgKnG}|xI*~OXim*!MsxmjG@Ko@b#ztzAY-AFqA(3o3 zuZLMnH!Gr1#1kx8cq~`qlt;h5+=$ueFj1GWW6btSfPt@T6MEh zROX6*;(ZfH^YxR}rV+t~jfMOj_x6!%Zf#H zVlKvpN9E6Z`lu6%B9=-a-`l7DGK$Jd!>h$n6?=P4n|3A>r1SmOyKlVeJv$nk8UrGT zu6w>)qrSEisJ`6IT1e~D^DsM7O0K~Q1_N=MZ@I;0IQP0+kt$3_r`?2Qu}bX$od{OE z{w$U+U4mvOg2`2j5liQh%l9Ie&tbhyx5VEc`7Itirl^nr03ZNKL_t(obPJm0NpU!Q z@WK=XjI32v8*57(%yjtRjCLrZwqmlil8vg)MLg0%GL=vy%H`5wdoq)Bf_hgthro(r zcXBGVY89iSBPf?@%Iw4$RqCiyiXsDQO8`%-$1(;n7%?D2552)8OFRda_(TtCk+}PO*4QMopnwPyYa1H>R>mI-5Z%SCoex zUH+b!>`XqdYfR^hL4L+uYw>IU@Sa%Oni>PT^U^bh%C)9j_58q&Ml3!cWfpCMW+R`V zKH4+}nn4CV`5boIWmoLJ-+|cpBlG1>{YDiLJBF2SK96Vr@)x}Lx5u%3>3eE}vFMeU zr9~s?@9n`3yYGdM?RyYjf946?_mgYU@S0{Ag9Kn2qoL|McRGPJF%LZpS#Ban{6K6mn_w_Vt=3L(fB;22-ve>N?0}GDswoa1u$BC&w_dW&~s7CE+q+ zyh^pM-%aBn$te&X0A+Tbg!Mgo84(`v=q`Rx6dHPGp-;B6CKQM!$CfH6) zS;2}o{*F6-@E!c)@Bcu(ZrX(Dy$C+ZsYvn>iJ-rj#cul@gq=RU08jt%9z1yG&(QW; z$Yzs9A{v5eE)2aPcRvMXnhrt(59?IAHpiAXV927UAn@mcDSc*WqcYKUMBI_L$z*fL zq%$ZCPD5pK0xOrihtcs#87`X|OVz4MDBUJTdRy{IT}eo{sN1dXoA#zCvI$d<0=EQ0q)f8IS;X z%tbz%QHY>7;Acq+K@Sy63b3+wePYcTj0~^R=MwWY8%>m10%K zJ*VQpbj;jnGq~{-61iSfCf1-fx?09kt5lHAIwQBWh@6lJM z$OGMQ-bq8HTHTFAB0{z&bSe2lMHLO~#1oIjzNegzNHmT{y@X{iK8au5 z@pC-xfsgO~8T|6Pi!icmY1m?8NJ)N? zNuH=saBf6mTttS{E|nsbd~{IeOaRrf{waqgH`J3&DnywM5_(S7`5Z}G zr}g*9NC@N^l7q0_n>}H%SPYq5MxZ)Z?8ACnY!4@qf>*DYE?2*a+W4ppINLj*c|z(H zizSiiogTEBb!*v@x4pl-Rht?Q^n>$G9IDisE^C=&qK&&Sm1W+nihJr$H&p+;O+SdU zzI{1nY_ZmQ6HkaL;8e0$I%_mRg+67pjfr6( zVk5%M-0~5%9U$sRb!VY%tr{No9)G(&H3oFcg{KaUm1=IQ-C;S*lG;xcKEsGn0EQI+ z4EE-6=J^Y;&2IZ3k?9pl_~0*Y#`WL1ShPIbdo`3HEK{DJ3=lOwBFXncX~I993I_8xy{iVWzEOU@XYDA(ME=LdePZ82mK?3$XQ znG;A>mWy-b=MKhk7hIzD=VZJeXD7!=FU~SOC+KUQ6&yutB6h0d(XjD z#2>6#(R&h?aOct^uD||V6ncA5o|urQVMfGNXHk=dSVKlz0_?meiRUN+Bal{up!sil zD~57nFk&wnkLqfoJxr;hTkfH!<#$))-;+ygEKE9^LMENYz_e+?Hf|z`X0@!WjBIt( zanLt?7Gk*`Ww-5S4Q{rG((<=Z8eW51t;*jMxUslZYIeN8k0++a1O4`@vxg=sb+^{^ zgKDE`sYq%%T#TF{{0qa-jd%PC8+~|Z_+Ax$t%`eY`YwKW!%g9w8>5LzQ ztl*O?Qb~sxF&wgBxH2@xY>=;^#lP39DBREAEpe z?luXMJ*L4iYojnL#<_r;iAWhI%Lr{Y4pO?onLiE9u>Itx55!LU9EcxZaHu?y&YGdx7)4#S`rspI)GBB& zlrbz+D`J2d4p~+hpRAx-Yp5hbtfJ;dP3r(k)rP_|u@N&h8c=s?nq~;dfFe>fTE$DZ!sLHT7wsI*ZM@Gr0 z2eEkEs>AjEQO-_{0o{A`IYYI&=eFCepxp2+E{YQ|y(#XYAy^lK`c*9?=RxuQ_sQg ze)@fkjgF};SnWLFB#v%_V zsML(;Kb*BltfmqyRhsIbYlrnROX|zn(|Yu*x<)i@#&mhfZj)g$nL@U2KqMl^<#9mg z#PDimo|)c3c+DF8dX3>z6IJTbg!lA{U}_BL_t%~~RB!lh!}Efg*RsfSa3M5zhk~n? z(cqkR+~HVo?$zQ7~YcBr$>tCShHS|zxRdy;g6*?StU?eydBdHxZHd!*A7W(!@A25aI z7yl$crB@`ONUz0NhU`c0v{;mlBU9|vjt*F)>R4#ht6CU(f?Bz%>VBnKMY&Wpqxje{ z5son?Ys~CzVzMeD;@kjXGln^OZFQS;P^vd%MAUfo!a$GTxNxXcYq<5MACwwR zt6Ha6%+UH>X~m`+ZGeley&kjY?I>%Svc)0 z<;IwaiWee?)?6S;8Tdf+S(A1T4B+6iF2?;gUWV06-ZjJ_!&HR}Xoe*)o8scpxF#mc z#!G}vjvU57-HrrqEN+HlVOa9uH5Ch4%$hUHbkh1BGPz#ldV3WbiAhumBw-qlYuAsj zT8UC=0xOrVP(_@YCv|qPM@<#|mV|5SX;b?)n+%w-dHPwc**1Os9vc%P7${`Ih6N)> zF*7IQD*oy-gx46>ipcj3XciDj#L}24vU09;&}kv+##GO%mM4Rl>naO-qdk3UJkT?@ zUOZH-HQc7(3Pvjpiy26zLA|aoH=Ic(aQ?-YVg6^2kVIqny;rdNhqo1gRd`_gayXRA z418k9Ga!;7j6096mkUTQMa>LD6EOtS-&{J5fnrX*Q|Uwk+kA3A4G?(r?%PE3v$cgf z=58|~tM=+1wQU&}g=5^|{9Wvr;P2|nF&HLUqaqhT9Ma!gz~HojaGZ;Ue6bJxbLODM ziKtX2GVM>2Cu*t^URtw8t;MUBzlTbxtN{otd=mGNM>6e0P2E2?km*%pbAc}aPS2?B z3k@x|#R=)Tut1%RiJ_*!h$+!E24dq`t1I;M$&gv4r%Z(g&1+=Ihi%c>-hPa)Srs^T z#9Fp;jkhAb=@c2z&n_Nn`E3cx#wvA-i!#Bm5t3*}pKv0M`0@pc$0Wj@yyqu4;rLVZ z5E-K=^CW22;*rW{9V?t_Pw&KkV`ju6EeXCN1?Vh*)=b|P1?eRG;+ZUhW*vcT1eTDRj;EwK8neSajaOeQlXAUstk=&!o(4A zB(kZ*lVN8?pY=0_Gd-iQZ;m0H9*H2FgyPKU14yOK^i>)a1#pJ&OewXeBGFBz1qmu+ zt3`SyGkGNdBoiy8$-t|Ytfk9Wc}wFToH_$)cRFsf;RltvXK}}jmFlSbzGMhL{`DU) z@PSP~B_3vUixG4ci+N30B|nr*Wi=%uo=oYy3eI~jjSgew zd+%V)s@1w?4$kDfB!)1{jhQjQ8gXodc4jDo5uedJ5gW1EE_ttpbn(C2M$er|o30NI zY3C%8L=s63FHfd)V9Tscw?Z=Ck7RKGt!51tnf^=x)ip~|9$7)6G^kGuTW`JbmiKD2 zXKFmqqc?nGsOEWYV77*(dQUj0n`79n{na0J*oPVgoj88`qbu-@3og{I?$(1?Nj3u& zjCY{eNkce8H6L*hu@8Hwlu|p6>QnSyY7XSc+psN&0|!2R(z$rz?wj$>n{TMMi-iVdzN++^5Z&gB?Dx5AuC8BypvIa3tG8t1- zB74emJw3?edr+Mmmk6FSp9eSnFq~K#?>zSxy#CamMe5b66*MUO4chqV0iTDP%&AKv z5_Pfc^%wBeL-&~~eJFBMc9q}=mlkq;{c8DPMZGkO=yC z!I>&&Wcz2EmheHI;?qHC`Mao$E@wy!s>4gI*Is>X>O$CWuR3R_)#-3(54B1bQ|#`n zpAXKRg^O>008Tt5kv!wXjo&&0H{NiggyUQw!#bNOrjozf5!8J%-Au;8tVv=k2R-?e zVU`062@-ysdaseV%r4BNQhw;+=Us)HzJ4;s$0wvXWGLdovxa8oR#R32q_a8fvd7*y z;DobPKjM4qlf$_7%ST{jcvzn;aI4usEYg~CgBW%|`Xh?trq7&)L?VeON7<1n=Qx)B z0Ss=m4F)#)FkXN3PQ3HNQ&_cXl{plK<%=M|NA^7o+wFaX)R<8_fnQ#9GXC-GGpZ%B zFw5+Z&xzAp1(1^|4Tsu(&x0|#VliHS{%J(~8j|Uh$jwwXBdAcXl+AqWR2l^u-M|dw zrq4yZFd%h7bz~)m7r%nlOBM%}u@UR7#Y?=_`tzs81KoA$nL|y#<+85Q>M(>co}2S0 zcG`AJoPFcn(x;gEXn?zaa1k!M7C4y}Oa2+o@u3%_9{Sv?Z^E1pZHo?z zj*U8Q`q~$;#=>yOG?x#5E zgi{p;G*KfQ9%arJBS2lN2oWHjJ)<9mVy`O71gerEbUdtBxtfe8;zLXisJD_H{jk|Zwil4 zVAli1?wq`4X}AH6n~Q8nMn?lI8Ad2HV`|SVC!Wk;^SzJ6TaVp?k!A0pQZ1o8Hm*V^ zQ+s|-`@m*6@a(JfTxh)CJ$4UyOm>`TqL|7+MhL|))}8E;D-^KnQDOiWH%1I+j6g| zF`%oza_o@L;R?RQC6*b_YqE*6PdOT&KI9N(!{3J<(^*1D^EEX6B8wQK9vb5 zF-^qHG&3^h6p@7r0)7gCaITOuM=zyP*l>s4v}u<7{YiMuI!a`{Su3+$0r7IFg4r9* z!@*y>CUnjLt~+55B@Y}Y!;Mj^n|am@&jivOBF=Q5T-2;hx5N&Id`X}8+;48g%YS`H zM?SHwIhoBOT^zug#c!fntw=qY%w$yR7+WzjqMg!Vnt>OHVs$ zs1tPDfYKW?)mPPEdX%$I`8@Xf%C!n-%pAy(Jn+*ian3pCYoaN`kp?b>rHrnMkRfL0 z-FC%+Cw>(@Gv|s|VSBF?H3!R4Ay^+ znkqa+T~rC0s<`O{RazYOuz%sSGqCS5XP^_XOwz{hZ@L0c{qbIbZ}o?f@r}CzN_+hGji8VIOVSY=2h2XqmS;R2iL5Y zVDkthdUFC;vdFbbw7nKCJYr9kJh=0j;?o=KzTi0YueULNcnY^*_8De)FBP^zSU|X!umfZM8aPrsJ#)H^Y(NxFIy44$j&JoTT!}2lwNxf?=jCTf<&eu}^sLyB$i_sKEr_4uNrlPU z_?S^rHtHB384qkHYONV7dD!F=Q)57voOaX@g244#9f4?_I2S7a4%=rw&bjF~a{FYV z`Osc?a1jna{798BRG_4Q%Z{qvqv1+?fRQME_Rte>Qh9Zz@{6s_W=yc*WLiF_W;nR; z(4A4ORLl%yrn{{cHrZ-B?0wu<@y(<63uh3LYvELT7AC_nznZuaj*?LqL=0a(=WEz@ z-=m~J^BN7@@$FNw?47rC{rqC(ovbmv5qrn7xh%5ztaupC6(Vs;Fu&XJU&p)8K8{x& ze?ZNL3`v~xN&})tW37v%=7w8ri{mc(k?w~EcG{;lH(oSmWE$O(H=6OtW&n-#gXAOm zd=5un@)M*Bed^$S{Pyec@{@lS9+S6<#Zc_;mE?p3XP#VK+e2k^6qU(wdEZK@613aC z^~U1mUTW)4PmKXFgf%!Hs7(Wc)ocgmz!MADdXu@hZqa=xOq&xxaw>r{FS!~Y z*y>}tUK;H!7aWh*Ui>=>*|cy@_lyl@G`UO~gMCuS@F-F{w<6yc>{mF=Qef6 z(pacY)bzDbt=T=Hao%t5@FyH1S<`sOJ|3^kf9x7lV_MmPXNhm;s2`pO9laNM_l0NaV9S(||EB=FJ` z598P)kHAE!s=?Zt(i%!mg~G$3fdhjBn77#`C{CXxDn4mP@ZMW*DqPLm{-gNt$9Kc* zO}A1?zT&NyC6WEd3(qNQy8Ny`;fdR?#!WxIZSANzVi6;21?VZ64e4xCvf>oEyDm20 za&w$=$@h`U4Zv?T@%G>TgzFccZ4Pb;k3bN>^*rR&>XTL%1`D?vZZ=P$^Zpwz#me^< zYl;Uo+p73CXvAh9C&gscO>O;=op9#Ww;2!A@^SpGn;{jm#WvF`^DtgcP@@;ANxEyY z#_4l6!Y99Q7V-nLP@5RR?{2;tf4cuS!j%l;eLZ>f_4XiJEa=QsCIv>1WG1U!?KYZ)pFa2`;^8U8%)};# zm*KkePsh!7-mh~_1)epbg0clOc-&OvO@*998jFfN$j+FksnTz@`8<67jB_z#qisYY zzVqVKc>Is|$&K%Q^r?8^o*&|(i>_4VpZrfaVc2xKs(8xD82>yMRizXwf{TB63pUv1 zYc#P$vYMMhAj&b&bY2SJ{k(F#`Mu zcG+!b?6%+Mu<3_)L_D2Gvr*L!V_1ChXP4o^%dTB3pf_a@&LK3lH-3>u;PiWQrkQCg zKJL^ru-|b^>CNGG&;99MT)*%fO~yALTSvYBYTDKU5nOdwMWy%bl?0 zjvq(g`deab>Fap#mTU3e8?UJ&gg8kvv3*a5J!kd|jjdr}H<>SpuwAwEU5&3PS1RI` zoM<$N$6f37#VfsOJ0CJN26XnZ3x;YQT)%@L8P0Ix10qMlBR-pL;4^!C6j$B!6C^SP zII*NaGN*+8>V~Uu_5~N2ad%9W9TNjJoi#jWn+L*CGsK;n;pxkqBp)7Lr#8HZg&EVQ zV~qW;I6UT7K>O*k{md7xSuH^4?4ZG>@ydZ#9K+-29b9*Ec5D39X7Tfc|<@A{?G2`ts*sCViuV)LDL!-gN(9lf(R z6q!1*_+>nN`%PH-*2|KK&&~68+ zZsj#9_}g!8!#BVAZH#jSiv~U!WuM_%!V`bOs=oy78XHXG0?s`9tC)Z2afrI+2<|`J zbQyke>&?o7)UE20ZZM}H_Vy3rtm}S`Mc=y^_uO@tIS+$69+zS`bME|TscH^wp$82Q zli6YCUDg^9GtH&1y?|d_e;HnS=4pL42P@?B8P)fu%~>Bk(`I7MyzS99X9I1Z@>1cz&!aXj`-s<>nr4t&*x1?DhF?|u*{~%as{P|W*r5kYTa5rUiG#; z@Pw%`praNn81ezNHgohh7m2urmc*huSr>}>KC$I`_{K$-V)LDLg_B_Gt*1#5L-*f~ zi@$Lp{`UG(0}(k`AT&V!l^!DD7-1Q~uFhf)(|t4P%w%npcwT+wMcD3uV|6AvQ*(N` zE6+X&i+=rkg{N3}G&s+Wmpp?K&+sgI0$g)6rcn)SzUc>X)uM+bQ;pg&fz@+9wp{)f4Pe z;8_($EXbXdOPJIC%yf@%7l()TGSu~EllbJGpTemZT!vKdpr``&hWlOx%U*vOXPBJD zC$&5HOJcb*;eKtl%$2BU3 zJ!9m9=pk8C>kP z*Mo^4A)zRBfa#3o@dTgPaceBR<$e*1e9|LJ-o&>~J`$_ftdWOc>(3th?1NnnIttgE zeE*TEwbU_j;VHr3rE*}oNh~-Zlb`Qm>m7H(7cc**$-=xk&e&%=$vF%lCau6z zdpOULy>c9`ZqAuidB^jS$>r4PyT{=tO3eSv19#&WH+&aCJ7leSPMbPGIJ1#B(}V^N z&|-EsFO{w#R;- zKNam(L&7uO;p@*oiDj!s@aD6B0bA_merP+SG8wfQ>qKU@5tEs1w=jFwOsqd|8v|%t zK32W^8h-hc8}Y`gFXPaoj=@fQ9;|6%&pdKJzIV|#@XU*^89{$|T?E+lbo40Q19oXZ z^mv@v^Zh&S!G>FX*vtU(>bUE=%kj%wZx#rjK4TE)edjv7_572#{;I3huSP3jh*aNu z7$Oa*H=Q6lB2!a9V%U0zkK(i|Z_%}TjT*joz>XpwDXryrWa*nYR6<=U^j^eqMr&mn z5d$&fyMOj@?7ZK>$PdoJEf;Ln1{iDqa=bmTbI1SArHwzXoc>`nXF z6lG!mGlYe9vi6T~wv3%)j3`l;Xxp}J+qP}n?%TF)+qP}{wr$?FZA^bJFPUVLNv4uQ zDs_IGBRN(xX0vO>tHV1-y4eS?+wF`vAJR4 z`8mD09kQ+)&BMoEh`ltbNVlZ`JShG%RT6;Ej_>lAz;SJjPLyCcT@hGP*B8wk%cIcc z`7?{>KQ!}7hUUB9qIJ`GcB52vJlArjNRpEf1vwav_SYS{YoN=FEGP#gy)w`r}N zqOJ0O#pS38!d8$d8Dq1LL6eL!*)T0sM-Fo{8!`_1=Mxj2pGrv zlyL1Kz9=3)UG9Pbyw*N0oP%Y|u#r-3e@;?L|4_9`<9=n*{pAS#wylpZ_9V{>uCDiM zX9F3wN6tSW7YB~>(BRT-Z5|_=7rl<}hsO7FJL>Kf*>AC43dq+?8YCyVcR{#ZXH>F$ z9^!ZgtAG0C6R*dKZ6((H>niade^g)JBNW}w-Br0dnf<%N*r449SNdwUtrbctmqP7_ z2T$G772M_lr3mh2nccA4>qx_D_Y+y3?{Q!%Y#MFe(&pS6THP8}*z$EK6}yk&TKuuzJYEd^&pEX6 zRI=NzNwkCcKE5g>AYtexZY+ep>B|axt#sr8QFLG254@k{mdHT$?@w%=`;Xm&V!Iyz zbbLR6Yu~-uK~|F%)Lu>iDjr~wz`=L~Q`gc|Qy}j?;=R69iA(4D8#Lw>*GdZ@Uw1kT zUi7>GN;GVu6qyz-w+gjr%)QxPLSwHpo#O}*-ursX{Z6*_FkZ6`m*q^5t>^hFx!;O9 z1;{UrLoGJ7`&CVOSmZ|@m}w9^DYeArG@XQ5H5YzmX&j5zSVV+~rTm)mWs#Y#b;kk@ zj^hyFlHn&wEI^!Anx@o>b>tvw*BzI?_gjnS1FZ|n>fJ0OGUs6Xjvi#_(_U>S!-WDm zn)9{)67zL!%(Z`Fw;N1a&j-%!^Ax=O<{MlFA8W+48X^pp9CsA?k3Vkf2FmL0lUG9W z(h`D#e63!nSWTqxOL|;_lI%{Ub|RtIRNL>%ifI;VA{)(m#sXChsD3Qh>$?v|f_B>* zb~9?&@9Tj^)fbO-2WN%+vUC=H3`kns)cD!6=`Mrb7xqQ(<*LQ!6^r3-)8<+g`ai^z z>@~6J7F-fz#@{O7$3$h)lh-=1VW-elGefj^CL{t6EIE5-arq`HI2IVNWI{&ef1aej zY^-$d9)DT(?WITm5sy6^!9B;3zlPmkE8OmPF(c((0ene>45M~<=V)?k|AMY_@mFl& znT~=1n87^l@6&pNbDrN}DwC34-{9*;eO`9zh-ocBj>{dKj;+)QCsGUTd>(i%yZ2BQ zyX+obgW%A<_L#DNp6sf5v13^L!32Vt6QTuXvaxCeRrl*1zTvPI@w~p=eia`NXJpVY ze+jkZpQSws^aoy3 z1rEnP6BuI!&J2psk6K7ERNeOvPo7R&$oSEvewKJeZ#GW7HJAtayDy%~+soHG+s^=y$O&|Wu9=)I0lw${{hd0Qp|j{#cM866>oo>IYG z;>L=K>mvZ4JZ9QhGFT@n9~7QWm@;`?d}3-e!X1A*^Ets(f~#goj+WrfJoz%OScOqxgWbtx>x6F*@VM8eJ<~;-h6@aFxFiwETVafIO2Nt5pd65T zqAE-=e`zx$HpUn<9t=U}*Bf+x3!nu&asm7oxwE1{s7v8zPLYn}d2ms@fwz3RyqsK%uC;~wol!t@6T2efq$J? zr1%=<-_&&?2KR7?qpe%)FHlboO8mObv}%Tmn5MlgiJMQBkYf-3ffb|?S)AOkJb>Cb zXl{dn#%w~50U||P!@ZTKP?qmMp&Dqm?7L># zifFaiVY~MVxYz?;(y3Hij1T8CjwYu^&B(d(rNq__ym)84o5IpBlp?P|^!o=|bfm7CfIZ zIM9#`_uOQ_*6}sASyM9Z;SSZ*;D&2ZZn9FQV9MnsFKTLIA&Yym$`GjPD6tXD_lmAw z3`0!fbay?v-y(g)CgE@7s{Z15UOaF-$0ptPkNWl#Z~8-ClWG|b&c52)jhC5U2k7$s z_pAEDx_<6Js&zFNWN5^czx0G_BrH1E@G);|6Z$%ODPX1+9%kKX_dSsN~PyK@Dqj9OaQR$r5h3DIDqSSsx7%V?Uy-bA(>xeUZg1_8_83#Rf3pC z`)5m#FX7_%Zk93c1~tu+bMJ_<=Vk{AJh}GM(PLks<0=l|Orwy(f;{&*(r+(Si>}yc z50ahj+1;8XJ<8^!D|W&J9JLb5ujI(>Z8j@EYATrX7y0@OB*uI)8Kh5;V=G}{Nr(Bo z8DKbdK>0*`8K+pnRfVF5LXwx7jbSAAI7zUD#e-#jZ+tUXpmDC4F$=G7^jADjXu8ad zQ>*B?n0RHz*Kuc~bOrLxJktRC@5iZco>(`$+EZAI zVnRCTaW!K}gsQvQivMog|*DO@w+7 z63k7+Y6hCAB`^~C3*}!Vg3B@{!i?Wd29|^B9e;R&qe)3{x^}|r$n(uGpeackHapTG zV`My7%^6`tStP#ceBl}*_T(ir5}BnselELKZ3^dvD=?X?3M6@qwKGNC_X0srCA-?s z#M_LH+%-`IrkSG%h~b;Y>Bix*$Pma)3ohr}xpB3`^&)rD{%Db7Vj{^X!JbFzjE!5J zQHI2Y=bYyFAcoH$(=?z7&jIJ)i2di5y-&CcJbj#lJlLJk1cobmN-`y1 z?UxZc0)^bZ#SCOqrg*r0tOvHx2&>qu7{{TAFrdVN6O30hDFBaC5J+N3w#;<@_%C%F zG6cX_>P==M4~-*FFKY%Rg)wZKtyooE1MH{w?aMaDtZ0L*j!=MY_Ibh|y%ccvG#em1 zHG`|_E*tBcy2*6fqAU|n6s|#bn;>#|7CxIQ-F zh#k@$jexWp-vBxFk^EiJwLRX*da7sw{?z$-8sFCv6=?Y{@i}&s*CA7(gX?Xw1V8}L zt7h|Ma*!JN2GhW1r+82@1|r5=b1A$8fxiLgt$G1%Bfl0T{1nWONESpUswO|BS(0GK zn;ed>L=fs}9VUjb{>Oi<#6H6!e|I^2b4Wt50`{|{zYs)rxLFX#GC4ADY`1CMe8-AV z(1Bfx0%M2A1*ITXFJ{s9oRwG=m4ahu5@S9i5NNfT^d|yThBof#Vcw1+v2}|ZmC*7s zbwG^$4#i*MWy@c|b6ZC_>xEqPX)@2ll@;jmH%-Z|#a8>7%VU$ile0{2$kKyBZZuJ9 zIbEQr+7k$H0(!lcS=Jl|ke?+Xsep|iZ1<0W^edJTFq}m(!V;XUxU;(V%k5poXzBto zg(Wjf+8t`qiUrUP^h;Ps7|5(%ks$*cs%^6HoQAWk5u8&dfLJZ_owNNcK-B5OV}BFp zLNweo%z%t?FH#7wGsM2$Fn-~xVm;4(5m(*LM0qdRNG8dqmr|EjmJCGKe+QHw=p!Z8m!V zteh%xIz=-%kO}x=gvJ0+`Y>0mUwZ%~m<1}tsS~0sQVQbABnfJcMWm>o7k~P(i3M1X z#|~5-aiLOM{2s6a#N4q3>>J0*Zf&n=tR{@`N%$j`|xDGH$s4F?Ov8{vS{QL!WH zG&b_qO#;;UKy{2u4#sK{Jn9_afIkt=(Si35yQ6dNa5Tw1o{Q(mDzF6z49*^p_-1!H zaA3w_G10O0Tun3x6&ni)K5U@6OmirKLU*}g4~nT3)w9w(Hna-J>PJ%!;?k9;K~c=vC{9*HTltqX#YdTfXpk2LT%$CW0vf(p z<*ho$S1*!Dg22fzg{cT-2IE9|NeTrU@5!92}m!Hmv zHnRn}CSoscEC6HN3W}vx5ma6%Dh&0J09jB1g)s-K*NhQAZvhC72MD$HWY0oT3VjW~ zf$EIuL;e%G7JoC~rbHKiZT)1Zya1V(<>3qr2=YRrL$@OTS)G2wRPS}EMbsXTi@kngbFb4OE! z7F!$p-B&0L8B8p}k|e|C3s>`bE+*`2sX@60unz~IuA;pL+u}pVRk`OU9Pa+ufohpw z=eMt{eOvP0qsLv9nT?z+WEo5m@|Yd&yy4zOiI$~Eybu{*(U%P1b6$Z8IhW^m z*VeXF+J4%i+N4nSo_rx$sg#8^oidz&I0Y9o!~t$*sa7%%etc0p4l5h%sZYHvECI{9 z>^*Qak!{iD&-fq{;=4_^s!%3=dQFxL?{x$(@8?G=Q|Yi0fD4KPDGC3@i9^bdQ9v47*}gck_IkN2CN%@ z=AzOZ*Rfn2d?sR$@&tpj?W}4#u6S!_o`Yj2%x&PLDePQ`dNOwkv}m|9kgv4lkG}S{ zTK)L4skt--kIpL;wo(vH!j9oIN^;=>jsde_wz9RVfG}2JpR%?DeZjO^Zv4YST4rLR zVnXMr3q@dId;(IFNrQqbn&-{GA%3)Iq35!9IsqvrOgg9?NTjsD`9|v<`myK1;g2*E zNYh#*0tg*xCHs$ozaZRjAf*w@rNsi10&;yXsR}8d-{Uw*J8P(s#KI zx=UxStNP2M;Dp?V2?L~)avaW$08}xdIJ1JneH-wI=oeC1Q>N}Sv;{cCSgJro#vJ4| zRd5(}V-Q(lDLoAZZ+On$%0I*O4QDdVvxo6olkQCM8*Rb(iD-O`PV5f=jKz(6k&=9YL&!`mj7?Cm&qvTlb5DfMJs>Kl9>CppG2Rn(#wc~Mu14`U8 zV-0wvL*DfVi515v*HA75n2~M~+^vco+#8 z0#i_Q@S+0d;n<;wX~HNJDr$- z%d3VB4cysI@X7%D>k2tG+$C{Y1@nQ{PDle8axkAQJ}}^IzB?KG3Vch+Al?;YHo?2yN5>xN)&Kzj)h~x zhNVnI8PHg-yPX<_TJxeS$!ZR%Kgykd5C|=p?es{`T~C2!kq0suX_BhYWR$}hGVEYhsF?JnK*3FcscHtG3magt zqR1ZPlCG#F$BI=*89%26FYo5_cuzU1Jw=>EY;~1z5QBAXbs*v_oit+RH8>32Uw@Sz z#Iy9|9z_Af$5nrgjkm(-6WOj#ip!h6=VtqSkL70YCJ(t_0(B)3z_cwA?3z27`7DMC zM>(!H!j5%X5~p`4PmCP7y8Z^T&9F2aCna9Tg$cn=5NKl&bY}x~Wb(u)8N*R{$2eSa zD@&LoiC9>14vuMvwxr(L)c)B3=omH$Ec&B_c6qj_o7F{9Ftb~i1qCi|Yay55Ujin@ z8RGK@%Q@bIfvr)_(-;liAwbY=!nV4tpNO-FMku2NgJ|YpgksD%2^xF>k?)A28Lm>< zI|>QJRtlPE6Z=)S%sBs6QL1Mud&^~$a z>%4p7O@UZsID}wk(np|JWS(FtI|37#MlOub^{Q4D%QmsCmFgVH45PBPZHLMp*#OnF*Zmq^*;4~H*> z!w}AYGG){$_H)58JRH!~@Kux#ugpSxv9Xjd)2Q>tGQMt}A^( zkEp0w)&^L`P?#1?ivRU=J>dX~%gi zg*4zUdTM^1oA=dY39avXpWW3c2NhmEb=vk_9$Dg1lH2gHS44z0MY>7+r7V>6ry@7@ z<<=6{ycyZQL@goY&}HIRF52z~h8^=ENG4cKZ$JU0v|07KB?q{j zg6X#t)OL_gS3l}7L9$s$b^~gPgd;!%lRi`lAp&2i0KQ8WiHhuGE~kNsN+OmIsea>I znIg+gaNXxao}N02LOsX{oDW`5}6o>#&Pl}cbI}B3lS%sY^FVS`b`~&hp(aS91 zoX6H~-xO2eKHOGBnY1-+Q_QwK;)h1zkWRcjSeki#u9GZy{mg(gTwUNXB`NkQQ(cs6 zZQM`j7>Hq;P|iR!BstDYL-wXtERRGNG9kMZdx#Y-lhzSP{H6>+jr-=|CySxa`gUDh zi>HSg|GJ@`yY~CF)Oa}v&UA(xDN5wrgvb%I?LoyE$A^HL_+$TYx zU+A8%yR%dDugggrfr*9mM$zhhxX zEAzgANd8W#(VlgMg2DXSu>VAOt6?Pw8R_&b!_WFMzGv=SDWxKH4Ao8|?w>dg_Nf4d ziU2ZAw-UcU$pj9#pY*Cu!vjLlO*1%5aKc1$PPo@$`N0wk6*$HkAL-wvmg0+4yO`?B zV|f~=aE~eEzZxRBb$Tw_MVge&A;Y0srw3<5Q@LO)jZP$iD6(SqY^f!_f)<9@IVHMr zC%UMM`uyy{o_UpIr8m9=L%Bm&^VOaPN*T4X7vc$JkPI&eY7_=aa?F9?><+f&097{l zuukT%J)1-c`vDe-H_lpOIA)6a)9U$^8NFtf^h|D$X%NGIUd!qfj=qt}g+f6e44^}1 z`aym!vP~cWhL(T*{l*E`IMdA-5bab-IRGaK55vCdU74_EcWmM;TQysfJW_6C&(8zK z)b@aT?*CHr-)B<2X2QQ_PoBaA1Hh^JeQ z7B8HxB;dL=cF2`>W4A+sdarmNAkWHH^w0i^L$EByf=yEhu$_=*DH2;Ea4CPpirG&d zr%3A2nA;}S(oU(Vpg`Psx$1r+lku2BQF6!rm27j_FA^Sg<4 zY~6UQ$C^BP*=^6k@w~okPxAb}^Xhau7H*xwYqo~zDPMnQ#@=anUq{(HU$))!@9rn* ze_pNiy^gs(vT6|fou1FqMH^L0^Bdz5wRXu4+E0^ZZM_3qNernD8N}6aZsYz=KM`U& z62UKuw7rOL#2=~@9xIDdVjtuNvSB*6qF3s?EeRH$fVvhl?S+T814B%& zQ=yg*0N{t25cUT#IS&3nvtP?NoN$F3?L1k+gayK8PwR9E$0HKr1sw0*&YOC0SeChY zdo_0JxgCW5as1U#uGICuTcN0IXG?Tj19mzdNuB&np+4e$*>bA=(XaC>)1%>U)L@x3 zT)(kVK%p!5Nw|`wA_YZF0QF%-%$uWUN3`*rQMyO&USayBhFYnXahx?9WcdfojnbN{QtyLkC}4AZYco6NIIn>?PX5QO*2 z!g9UA18Im(!mMOY*(;Qlz%v?CZ9=iiRt{e$iadA>Ollvppt}q=6{%O)Oh+a~v-Iuf zVR#i}05BwX%^!H)LL@H4v2FmZ)Rt6U;>!%=L4j0%6EouS{KNfn-klT#&`h}7(8fRG zx_m#P=_Lp*{x<`H2$>i_nPfMbOvUu9S3r?;u*XdLZ)Vr}=zG7fu>yN~>A&)*Pu%Q+ zUNH-*4lNW%z*jv87Xu+K@8B0vcI+5(!2$;+tYEGVM7ngHzrm_cg%#+NJ2TDSW!68; zZzJ3{-A>+5=gaV7{&>Ex`vcPSzxBEoMQOfHJ-c5@eVeu`U_H5Aq3_8_z5w8Z1I+6c zS*!<*-@5~3{yvc`x8Nci)J-u@y_dbz@~{gIRBuT)@%n<(uO_*+aiw7;bdE-%-~~>W zlzHKd;{I+BNI~lwJg9rD&&UWYp4?SCG(uia1jBE|vN;q;HOH+^?|ptg>b<&FRf(Pb zrT2%!U@}Q=b52x-Xh<^BT||y9rmb*mka{jw?&+4|)T|X5gFs;!WH7jp@dk;vldnDs z?&CNBWutmE@T_Jy50JryXnlnTSdikzfq+-?cUkvlYV@9~4RIu`;!5c7sh59&_4DPm;5o$i=c#@Z>JjzGYTHZ`})zLGCpPwu4l?w|lU zoJD~o+8V41gq$GYI9jaa`Ww!$Jajquwzz&g8v1U?OqMMf_-dYMzb)v_`&VFYY^wre z3dw@yg5sFe9U)MOnW$;1bg?5BIy$PLPeG2OpQlbI>MpqyJvh2&+wyC4#qZKPnz0rE z8(=fY(`AwEO!q?|BGLQp{s=bs^!^IF&;H|hPhS2Bm664qE%YxQArE-AO0WP3IZhvj zWksn18kx8GT>wFkv_$7RS&J4+Y%z(c;5syHBl>UBE=F;EPqKKmW?1TL3D!Aim2l+StL$E7Cd^v1mP)z)F9QlGb)TVG3 z!E0uG5I;J2P}0l;p?_r}><{ST^n)HpSH`yMnU3rAL5K~YJ!hUNcu@qK&rG_Ltkd(u z!zIBTPf^m8=*mr2Oa8IC@}j_D*oXq!yhfE)7?o%c$81yOpUxaPJHH*1ACIrSdB5KQ z(UwN9kEh?|dPRUWh-uw1v04L#aKVBB*R;53+4`;AX2)m$k+I)Y7AEStKeaK~K2C%` zU6~yw@PsT|!se`ntDFK~RB-s%fM`K*nqMfk1np8YmP)Nzbs+Ews_tgL;J$82>ZNP_ zV8`u8M;)O;^}s z@3YP>=7)x577x%0Cf$1%R3g?HD}oWjq|Cg@#{KPiI?m_ya^qw+2g@5m90O%luD0o{ z|AY$nk4&i>5pm~$HAqPo;r_?oTJE~WA{o*X!-5il$()XZnW{0r8>Zd8B1$8h+EIFK z)X9v*oZ(q&{vR+9ZQ119zLlQ$j$c7j+3dm zG57`!Zh6C~3)^ajT#lt0wOPWgE(#Q>2X8g{07fl*leGD)nK^wQDG_Wm8?FM^Y+=>3z%hg#M zcr(m6Q!x0$Q!TDV)LBi>aGcSX1q1vw8tm|j-|-mT_urAlp*(I@3ce-F&1p;Bm(iw5 z)jyP{c*ooyld31GXiBS0{6hhWu~{57Eb!%-LpD7eb1++^-YW`;TH`FV?ySfvUl_b~ zfg^qH`_Uovla1Rsz{YaLz%2aM(`%Ck6#C?EmfT(+>&`4G01iIcCVjI7&)0nasFh)R z9yAbE!`+wcc?iP4?pQW;#$=n5CVO&rbdpMkNuI+@U0olVlL{xvuyLbV#R@7aFKgQB z%)$S8uo%nZkdcd;!by&|j<(JH;r;+eLi(hmAUrUD)YLzWGTn(bd+0Gu?dxFA`1$v; zliNG!0i-kAXp^U7`+04#uiN`a)jtvK;1q7)=hsTs=kWFZq(>;vexcLpeD;Xzw&l=3 zGfB7qFmVy2A0StjG;7v${Isg?cM`+Cvql?fq`B(i^!@pE{Qh(SftYEIHRCh|;qLb0 zfdiNb6aksWlB7RG&*gT#WzU!AHu}#&Z;vszTdfz!MVEecb#>FXuWxH-N6g^XjqJ`m zQ|7(4W!6DPLo2yRNTe1ZX%s%QV)f=Fg+luc>KkEKKzB8Y^N?n?Nl=49_jB(7N7{V{ z8c=FgV3B~LqJal!cvlr2>%$Gl_C=TmsO|Gqvgnrl7!q)BR?y-#sZX5!O8Yxj+qKZ| z7CXs4{MPMIJmL%)u=5F)Ym__=N&$(e1)3|6Z8ve9%TxZQMeSA4(4(%-FZ$`T;QLh3 z(1t9^~{(XFIF!*^7+fC-1D|O`Fr>WC99DGXNRZfe3C)D*zdgYvn%2 z`&GnW&SX!6+MY;YOsh8uJ`Z9p0tUw#R1V}+W76$@|M#+l0OOkeAE44vq-PA36-0pF zMN(8wq*llvP(d0P1m!;`09-41CH~*R|KAY&?*Dh;?SC6@|I-=*K>N3KG{@Rbdp`g` z@9#?ge`x(bl(*ShqS`oGXf|6t4lkoQd)L=<0`_ihfs3z0gzelQ3kY~~AP{f^IeT!p zIDx_aCTI`fW)3&o%Lm@O71}Oxq~{it{|uB2fB*n+R8c{D`s{xE;JMCswe5yrVFB`i z%c;h(Kr}yT;6m3y1LIn;AHQ^I=#RO*8cQt?C3+E=P{gRl^C`xmkTr~%jq=Gw4#wb# zg;|(U;@1`_#!>nsAA@TYYjTlEoX3qFAFK&^&rd>I%)yk$`V4)byW7T0L=Q^b!k~S( z``WM`>3AyqN&M#2Bv**=W{^(Ht zyUdRNv2MjxjW}O^+ZWY*7e$vO0eLdwv@e4*EXsJcg`+n@j8{Wic9N$(0D=gP6WfAa z_zrRS>@&n8wgH$Jnuk{oiLmtBfuo>HZ5a|C!vDvo*Oe-R$M>Dk8z!BnKQghXr~ToY z!Jo$0^!4C!6~i)DIXx^bMRLJHly+l^7$*1GFuCK~*TC$1T-j!sT84tnd+9`w_3-UacfPzKMl2VKNJ$H^K-Bk-L9wICjNQ9f#y zc8@e|k43*!;6P%MjnJX$uJYoh{GY@CFWJq(*38GXfuq+wh@DwiBWQTlIgaU&xEHC2 zx~=p8o90MDX1e1h`)Mq;8~g|BUC3Q8xhAihSeMslxJtEtcy*f%EkQ|Hu?U@#q$KLq zhfY%F7+$q9Lp*8E&P`@!OV-}=v8M`}_vDRO!V|Wi(wY!W;Q_ksYh6*L+?Y~*oz6;% zwhIY37Y;b)Hl%kB|8z0%HV>S^5a#L5n9^x9g~j8Zly1LF7_5Ogy)3w*37}O)I4 zjsRNxvPa!4-_|O@GO@ByZk$fl*m;~Lz3l>P`eaSz3PeKgxmA2=qnrDwm)JPw%G?nqJBpX!L>el zaoi!@N`SPc2E2OFiL|8aYc8`wbwj z?#P#&Q-6jl44jud_o!u32cHxtd55M%F6X4XG_#>{eY2pQXf*eEZt=PC0K7wQF4vmj zvh0>Gh2Yz9etz@TyKS(yX@lZDwky zVz7D2mx>81TEnLNf;n#~+Z1^sDsil0) zEMR5pBc}uwlPnqq3Ld7x2JUoIm1c0=bwKGO2?+@=pKx^FQFgHD!t@WYg(F2;k`{bF zFwpA3WeCum6ectgCF6uMnr#Iqa2v@H|$`OM#%ss3u3_ zBsFQe-C(RaMK`)F#y9GI9OG#}OxIhZf8gCyd?7K@$e6A4H>u=>pJ4+$Z|Vk{NH2Kj zPv?3L9WEQr`E~78NJj{dtY?hbvKX$RQr@y>O%FHDpD!IF8nxcN1>aO=iU2Th4A9OU*C`O#(0d+EWti?402RqV@<03TMCj9v&^FbfD;S0*3?MUSYcz_24~0gpB2wHcDfFPG5VQQ3o%Z=KmDE!ksr*}E6 zDLz6!X!Gcbj@j&#Ei%*w>B1q6QKuw4Jc?mfQ(}?)({+=|QlhhpnNByvgyqOmZ0Z!XzfFq-7juQa z9#S-FWW$A&S@deB&mo=P`cKj)i}^j=A4@i0@C*8*bTmPR&mH>MkY_Rv1X-|c;034K zdid6^$!2GK$@Y&I&Mv*s0T7-o&*#YL^QuT}I!QR+&P+AZdg=X+PggnwD1)!1t(!q? zC3|=Kul{9fdvtOdb8H6izgwvFz(c6lliF?30OBvULpv+J26q6u7oP9nPmo z-F3XuQHh-_&N)Wi<NRW9>4GC}a2`YJg?n#ulk;qtyMp8`@8Nc0r zH$p|}iygorQu<9t@CO;_oSa{yjlb#g4~exprzfP+7RjG0M-$OieS0|s4j<|g4k^T2 zhDRyfCH38cI28rRzACa%R%-Fa%gxkHD9F+_z+KGObGEIQBW^V;V?7UKPM%z;lQ}R! zh3#v)O}bQ>uWY4b;4C~E+d|lVid>D<1a&Em2=*yNDIDzXpUX^ZeTfwWnwG)M7|GI^ zee^tuWQBDSTx(vfNkA-aQCUZZAo+`sm_n4}4AT_8b zf9EpZJiK@cq0?EQOEB1X6D=9iT$M1ASy%xuxE@eOz?3R6^0H<@B&`a~3)YOB{x?j4-{R2@_z@Kgm+*2T~&j9^a5{>qBk>E>i$e3mtSbAYNFKe+LH(oLse>Nl8)Fy zz_SNr>7~&4oVLg$j>I4iyCt|bHne<~#w*Jmo$sl8$(#x+Jq>nEu8{f_?Zvb4Z05nj zzWb#ni?%r-3>K@CB__OjG%4^yZS;W^pcm%(&>AoGksU9acsPTm^=I?D1=D`y3HQ(1Hz#MI0_ zxjd6wf{2vqIBFt=FYxl(rdp&65nZD?J}7M2550w4I1F7c`^$PPuV#;no5BRoYLBKY zL@pT2LmMuJS)!Ec+!zP8-ZZ}#P-yR?*y1pE5x%qJj9Bk_7T%Q=2Jv&mM%nX{)e%=u zW+nqOZ=tz<<pL(y7Z-^6wg~2)V>uC+YB7utS|7LiDGALl36#fq zvM#mP4-T}f*13JY0OVFAA-5Ihtx?!%QoxI zrIb1$lB9D(F_guplVbFYcB&2zR0%9lTy};qpgih;Z6P6j-LMk}x4w^SO%$$N+OZo= zTTq5s>5bcW;ZdjobjHjt%x6OjeQu|Q;}rl}*CXQD1g+>ZrP4U{j+E@1QU29!!2;<* zcJ#Ulc=f;uHvGJKaW`iNquAVkD5ahbZUr%by9h?+Fl&!Hjae|*>UNJ{>sN+|&>f=z zWVJOsYm`{ z%u~d_?_=_c)XC=_0-)%LQa^}VzyDgo30OIwr{qw==WspZKWhUvvf&}c?%aEB+r<@W zfph3mbQ1Zm8{QzlO__kkM|yo5PDLA6P&$-W;ZL37XPBmfTWQ}2(Ba3ywhOimi&9>U zSt#yuRudKx;7cDy`Xq)x&&8m85$gZ$(Xe55eYmZ&vsKb-YczjlS|Bj#@loLGMnwqaa_7P0_u zu7cO-J0F(~7XQ&GMJOGx-3ZO|ohxX0*SZWS>ldp@(InRc39^>ncIFV8>$!iY20}(O zx=ALDvZLS7>-0Vqb{?jwsw9K!JS``!uRvGj((046sWGU@Y*xxC6ptp+*QEn8;^is7 zWuh~$R*9f?4&aLB(HiiF<>!@xvPXq&KizAqRtnf_hYcwOJ~Hbdi}I~ch=X^a=hd^7 z>}w~s$`A=4pnh4in}6oR{Zqqi#vk9&UJKqx`A{ZpzJ3%mC7@KOZ4JmTyMcq1!<`H! zi#-BggeDh8WurnEK)U#+$=b6wW)ALSaB%QQI{Vl3P*9AG{%qQA*kY?u3+&7ut1h~l zEih9*kiXuY@DE!_=XiRiQbsQ%=92fIo*_V~SjHp6U>m5%OR$B?kLi#9g6oU?WL@7a zC>1AEH?kgY)CZqV^DS`Tt~;L&d6-r=YD1_GsWOi2v@=@MAqbJqm$Yi&dG(}QkbG2B zD4J?AEq`oNRODV?8>OR5JqWVefCzQ?o5a`C$JMo0f;Sb5%(7#No$9>~6XBU>ZNt{i zm)A{aLUCVSg?J^;+sS2x%`8mxKP0_a{`@p!u_>GzkZ zc4BKJQ!>`82nMOL%Wy$PJps{!J@crfsnvJ-FX@;#p+ZV7sWP=T_`S-J^oqFcNxG%i zLq|U_FKox9zIHWkCwrO50l4Lrl@VaywY|(L!l3@;QjuAOpD`v`v_kv~^D42H)(>y3 zXrp;Fko|LrG>?=guqZXK6rL>ucs}FJW0$n|M=d*2zL?@m%R+uF=9Q?E(wt4{!?U0_ zt!Zd`pQ?>T2CQ?J$e331a@X5JqO*^#fw0~-{ysG8lIxNR1v-cXyjAsHEJ+@l*W4&O ze%Y|T>-ZO4-VoCV9tz|h^kzE2sjO`q3`VONm!wyBESIAaC_qaQgNIYXFp-$QseW6l z)woJTfvhMTQLGgsx~c$aBy!aN^Hle}R5KBD?hmgB>mrpgLF)7d0j63%8vD_{HER*Y zAm~DeUsJVCJCOu`td8{#eNOQ?_onw=0W7Q2OARk%o44s7_-y9H?75EA^^)omtg^nc zhMpL+-L=L~;}9o9P9v++3~CKcJEw2*Tt(M5cXGfbk^1H*V8qj=)wpG9@>Wlq)I{74 zk8O1Vpz2Y0ebRr>oSy2Aj84@mwy(Qq;@EAq<{6JLmghAU@Oz;i+Tk;lm{;)|=>qK7 zX7CAEESULF^m;I0~s8F@{%oup)x`BW!TD?&w0Z;ye1(2FT{Qf+uC zt2*;Q>!MC4dAqW+WU}bIX@;JUn1i1$QuR=b#psM38hs3bw2jHtzF~(F92yk zmcQZ(Osa(CQdF#yES%=UQ43L*Fzyq|2EYHlp-B?iYOk0Zi8<<((N<}D44fCFu&H9E zve?p&N4BRglX-b(d4_*Hw$z)&)qqMsxAXgDEm*6{>s27kqgon4X-aI&&*08tcU?e5 zC`Lh*vFlQV7SFay8)Zo*)kXDf-F^)e z(OH%oWy4@=0wUZIXW3V67cFAyp}kJA4Bo}Ed|aF4=?lB=>HFO?9>5>@axC@G<@XZpz)n28<~>wXhxRRIlxX4SIJRQ3Cay8asvZkQe+Y>+7$v}; zxgPIW@|y^a8bvt%W5B5tyhOC09(`3N8|~!at&$~Zc$?%D%X*0Kjs9F&Pqd!h7#hRD zc!kinry86_2B5Zu`3C&^n!^<*Ku8L~YZ^Qs{9}024&j8xMg8%b&BDpdv<#J^gE6 zQS@N1jJk0N=EL7zYIFwCSZU1`ji-^f0#qjKtQ8YZ60aB&s&isiDK1k!hBx3 z6)Li=@C_f`xyYf_jj~f65{pG%xm<8+mJ%dyE{y$48 zNs^wiQW`2FgAMYO77O*rHE0t!hkt@3B?P1)87Iev{oU92Q6egTZPF5+g<*-bmx)M1 zm2Lw#lHqodUH?aPC6P&ioa2Fz=*d>xNcx7%izLS7E4d{54zobjIHhOWmCn19o%)1; zn)=#^>4d}dHxW&2AzUpPlzQ3#QEV5YC6zmAP=e(BUh!~o!3;4*_A~$&*c+^5Iv90? z|A1y2?$Jkr#u6z7O)zXUYS#Uf@Qn_LgYI9_;IJe1Cvp(w#tHd{Ao)LrFIm5Rxld$} zWJhz7?#0cPFCT{aD6G(L1-X=T1>0=&MBt<)kAM5}PQWXgyXznm8|S&N1?eIQ2zpBk zgfU9Jz1&tt{8@?Uee1FC9bk>$XR?@mn?7W?u~|h5qPw<}LsHkwjSh91#~Z!>6SXUQ zxK_k_T9PY#Ua1HpTExbEehv79%_CVfZ99uvQTnm=AfTP!ON zM>G9rD|E8d;}_daWo*J}l7~305CTV=Em_Y_N~7jwKglp0G{z}Jkp|RfH2Y$yN%Nt9 z?J_}cqhou7ee5AxIU!3UgKanvB=YgrZAVo4RG+7@iBvn+^ACN$KIipfBdPFo9T4i3 zz0EfD{~a-11|51vFnpZeGndLcVytbdpGTX<#xUCn#$ZvG2`H1_ah5me*G1%d6>YE)j}gO@hAL_wEuZ9gknRIWV281y&)FSGLrC#ID|{NfOcKyW3Kg=2g*2z@ zij`>xVV>|shD^ZmA@WeCy?ccC;qaqg)mt@1<(5U0i8F*K+(mth%9AYAb!6SF52(`p zuCr64k3kq$AUzd(e>44K#Zyl3(3XrOcYQcl=*m64%Ee0S)-r2uz5?67VH2 zN$|y|0>(6Vd;4LdfD4k@S$LD#rv+m5b|iP3%rUP=+BpcKsX1-<7Hp}3SZD*3Tdu>y z!!?=py_VNXRJQ$?>r7+bF8uT-Ywyb;&)Z$H<;&iaecpQ|%)2)U#Do8qj~~@*$=!DFCD+L5iD@ZP0#PT{{plgS8r50kc7f8tCFixn;8715ie*E1!| zFO|=j`vx@I*|_qx339kQf~`6ITll(cGu}Z!EJ=C?+Ig5QwyvxoMZv+7LM$q!6eMht?zf&;y!n+-F{rEFl838@;wZx++ zn%A)J@n7rQTgPqrPcnl-3g`nl7w5&(GJI$GA`!XPocsksD#W_|;`88J4PCwa>_aL0#Vv0)dgDN(c}cpasmTO1v1pYTO<`5zY*Ked zfpxr>sf93_vm6vz~G(nXrYLQL_|5Td5~p2ANhb*FJyuv#)7UQt>N5HSAV}!8#zd&b`bc15(Yc^Y2d~^} z%1A!H55F*pLlu7sg}1IPAL`TLmK>~A&jSe)q-r?H@ph%)HmR*Un$E4Z95}WnbFm*S z;A*x8h*Ca;1WTVAsM_UY;DM1Z~d&un9zsp6#Dx}gWBnJSj|fg3T-cW2!L zLggY^1jHZ$$2~EH3;6^@nJ*=%hGa(LB9gmT2&I{$j$?XCZ@P0L%52{XWni?kbf|kw z!g?e$1+?s%>E)aRp|~1vvcvqTAl`_udG+2&7maLbFwRW(PBGQymBLib0ul4~~>`h4!fB=3={$Ccr3gojRWc>4# zfGDs8H@LlwZu%QyDc%LX58sC8!yQd{LabN0Ihf%yEZ#*z?RH)Lyhf-{BlroKx-y;Y zo0FiPDdtM!nv1ibp_O8r)&BKrp@qUH8@q+^#hVHlUNUJY3XW>(w-NT(yyXBF4SvlU zVQM^gewrHZda6yI-%$rL_cT9#0A84(ksszWgvOYugn;xgZh>W*XPv*@I`mM~CWN3>nC0KS}IAJDu}t}_LO%BF0`VS#G?s#L(g;$m)UHgL0_?T~5d;5|e3c$S z-V|=EU~)ya>v3Ssh=@6r$~?ODhDLq{+@)yFKRWVFC0U6P5Y^_6W1frhn8!j^VFI4J z2xFz~I*{?1fhFdan_kcfauT(Sr*1MEgJPG+uupSN@YO`ADh~e)jT1&BQbdLfpgkrc z`y~cT3HFhdJ#1kROa`lHx*((qkTh?_lIZ%g-v`?>!jN z3Xu+I%!k`?qu%xWRo-aa>5#jW#EAi70Ul$n)6%KOQ?mox+D&%arTz^|vc904!@GA(G@T$1M_vllHOb3GveFuhbj-+k+Mq&MEfPxrCA?Xx3m z+1bHXp{c1NRK=3h; z1X4%-c}r$FF`z0*ch;mGuA!CbYUyEA%tCNm#$it61Xhy(0TqU&5knw?a^1q}d_4rJBq3Hk(61J?m6(zE^i0o2}3G@mI zav>WK#e-ICtXj|#fIL1gpnSH`mfu-e%V<-srI88uS{10Iaf~?w;~;z}nTufqCK8h8 zrd_AAu2dJQlCDpwdex`bz-ncV!v#$0Au122R~95M^s=M_MKMU?_Nd2wRmWVJQ1aNgj@XBw2bS0=eD z&VO-JVna1-Q=T1z?UztGW0@2gx(T?_RjeNsGkVOwgc-DtOf;NJ{h{Iz$^(ir<>aR{ z1wKZmhMJw$b&~&`-?IL$ko+&pzjn<0C}bi71Q~NzU?9ouzPHk*zfu!Rul`2B4zR#p zrZ3+vS18cM<#TYxwKl-1pY8Q~ZV4Ua#1#2;@m(D^Ucz6BRgY4-^!h9qscw#VH9TlGmk9zqQUBPaiJ~=@+jlcXXex-I9{2omBRva_8c{U;Quabkg=wnq> z0T>t2m<*sBxnX%qZT{H*W(+k)ch*AeZ@J$e!3-$jGds0(`f8%%iI0mU*`HYlv{hCTCLYTD3WBx7;Ats|6B{K<2;XC0!|N3om*prV> zzwc@8=swfU5r+?2tN*eE-73Xp*^1Gn|MhE zoPz%iD zrteQnrl!b$Wo{-gWxdT~set*%D&)lfq&LX_dm#kfje^=bBuNe7R|#+2(VZacE&Ia!dMr8kH~r>#|52enkLyEX1KUy3ZFQvN1J83G#Oh;-x- z%>XHe983LHgv$Q;s5~sf1x%Wo>f9^|^WFCPuN$%mAF!apxCJbLDOB~$eS5b|2+ahX z4mjd;Iu|AB25+Q}&wy4*+O&Xce6`|qp^zfz{wZ(~-DhcGT4aI7Z>!S%0izZ@?{%KF z<@2WxufEIhdkHk$lhg@ujD_xJ09yVXa|{{Vs||KEqIO5T?TcQq{1NY?UbX&S99NUY zCzDDG!|o^q&QF|XT?PbvZnKr}DXa1RkeG}lm3pB@{FlUmTpgHGBm^nU?ndr#hF+3qTb1 z4|02MUaEN8hm%%ni69*Vpz<;(b5fYu()tHNJLz>ietRHc1CjCPq&X z|1SGZkb=tDk;eYI2ER5SbaPUYf%XZ!ObVe|yiJ16^@ZEQ11JP?9^Zr8 zRN|lzC8Bs`?u)Ukz(7TwT)F$Zv2Q8ZBqOb`cY7$%g@G7;p-a*;>WXxg5T(@Es*t($ z)PfE(9BQ@s0zHKL&W4V>^(34A{{UtznbVr<>l<=b;six`YawYe87m5)@rvLs@6A0~ zT5j8}<4&;lj-BfM_BJ-8LWg6V414nYI2;Th&v+z4y{#o%pzAc~+F~}dxW1GY3sH3I z;jQF*hx6Op0N(q$7wqL;r|BXcPt(ZZL(jW?ddoTCNE!NohgW#~nJQr$mtSg~ z&X%V*&;vq50>gKR))!@Dk{%!#qH9Zs2bj+dFB7=UW^OaGolAlM0Wu_Bw)XO}t?k}r z$#CQc<}e3ls@I|UL|wr_5rr=3`=E@B1PqWP2oZ;vNZ|s(Gv9xpoWzkW&*fd02#6ue z`xQZfB?C(|>v8b<8K~e?bRQye`4;3A5e7=7N+;_Q#9asqZn1lywIt8ZXGZ&fdG~HBR~tI~>;w>eJ)K&AV_jpD%e#+J zx-=OLEgANS^l4lwMTffMLQ?&W!`zNM@ugj$RNt9oY!p zH8f;0mZU~0Lz?4MVE6oI-0NQU*rz|+PP*smwsP!=-c=P&=)^1X#!{szbu%E>^_#D= zzx|`v*bUcxU#U{o8{m6EEHo(v>VsfckRRcoa5zL=n4{631h%MC0|b%cMFY=P zI=|JDt?XQrK|%%Ku-ty@?dpd5&mh~@!MLkOdh<=A0Gj2*aCk|ZE6q4AZ` zq7_Z~B}B>_V~#X=;q3f>zgE9aSIOoxYST=p5d{5)Ej3KPi8?OG7>ys_&rm6q6+JNu zMIm|wc^5b4d&Dwjeq-zubJ9_wDC|)>#{x8%lq)z8vAX9tYc8$owUJ6^_Lo$sb9lc^ z1|wTJc8@ieS6!tpnJ`#`?MHVW?rncE9Bj~ZHjjmR<}BjIkUC`4XLV=Qka8Jv4k-^6 zj{>_hqekGlTo&C6xm~-~?8K8!u?IZjJbU=#f5YNh-5EG39avQ5e1sBV)hH@iGVWPa zEZeAa$iDQEzqikP^dq)~wD)u-emrjks)XkzZK3f+!^%^Og%7&Zyb5!_^M`AQ(b6XAIQrMfc2Eo=R+MA^gz^*iQ3O1i5wsHGS_LaR?+V$W0rrrF5YeOB97u?B%#PcPDce<~ECOsH| z+ys5mz!rtuBcw%M7PT{Uh@5dsGy(n;qf&>3X(|{|GZnxb5Z5^MCYu-BOu~8diRKp# zA_<16Ydg1vfPsl^^@i>o!gQ7nvaom;;H4{0I_HWKKK{s|<`7GAJj?^|8j$SReL&AZ z;#`3-nx#Q}CJw&(B-90(rEq|tivACcIH`L_M;3pSN~Iuc>5Vf99#?5_6|B3}k^T?O zF(?uY%+Nr?2+$s-!ATlRYDfyipBwEZp@afCXvD?UbUGf&0B*@0v%OQGD_(u!-n=d1 zWR|AmWEyE$JfJ2Th*3Av=V-af+0HCSRQzyd+B$f6u=U40@k#b;zx4uJ-gBzW=Y&~L z9eB9B%zQSnWIU8n6ymaUWj1cR$(Hw=taOOO1g?DJcfV!d`uxAz_pkYeCF60gTmZUjLhF#md<0e}^_Earj z;NhNd@+r2oYmXh;cZ2==)gQHM|NX00$Spjymwj1=%ZvB{$Mb4V0SU!fYPCvHhu8;c z@SINX5X~AAShXBxke$kq$+)vDg3rU@0Txto4-swz5s)0+`xCq-o=_4ZC5UP$W}uJn zdi>grrj&@0%tT%Dj4tk4Jr0j@gJGjmC(~!hWMh06f#>Pj9EBLSVb7R)0g^+f&)~uY z>e!cKYd3&2tBP_o$S{(Af8a8Rq>aH?ScFFu^fYW?ak(UwHz?0^fm=(f;twHrNLpK8 zqFY|Ge6eKH$;dYDyiKVon`&r+VGOle-5R@&gRvL=Xy47r_cphAC-`q)_1k;LlW9Cm zW-&yT^UbweH~q z_Qj9>qy6w3Us0op{M`q(J-?QbPNzD^+59V!iVxw+)lQ7_xm-`_I4Bh3d{ijT98_M1 zbcpFJQUkE@R-0k(y!Ft#3A#As`lHcU-W4N(M20#u!zjZ(n*1H9E2xkT9HIWe() zLvJO(qvFoNW13lC6L;P%&p19T?DHWTr;MvpFL`(`avhU%y13J!V{137wz|}krw0;6 z`h0}2@N}wc0vRF=;_vw^Sg%GXtJGr!Q62F36u$6*=!}z^RvL9lrn8M^*xjaippC2DFYjA%$zV?~eV+HT&n=I|97@qVxAAQzF1DP0}!i;XCynr`W?D_iJ{)^B!*pZo1B{eCMCrO+UCcG}{Ua_nPR^ zWEi4O-Y^nVlx7W7g^9B-v)SV8+B4n^o)pgrlqre@qo6fZ*MJzSw!E_Bi}Hdl5eO1q zxZfY@d*R5Vx6^DdTd`8LaldPwtxY?)|B#GE_ib)A-~dAR2+UDuje28FYo#!Z0C#F` zK+|ZhOXNKl=kkcdL@lF*eSmj9XvE*Uv|_=U^|I|)Y8~kZu=97+@9Uo9ASQ`7#fXjx zTQkXj*!Nbi>F_TtuUZRY+|r73eMTcuodGaB$1jWXBb5mDy8-Ja6QN`E){-^Wj!jF| zTD0%BJCkqTo@{Re_{*35*51i9jfcrJP3H@7fi%P&R{ucw;*dMr)2Rmz<9R_wet7TG zPPCW*(dBm1eIM$2lmUl_Ntja9-g>=#_?>@gU;W%??9gUc2lfcbOT!$#Erudcl!-u> zh8BFv>1WtOe({NR)$U`S^ZPG9D@y2W412fQ4CaIP#@^ zLE}f5e4s0nbG!0%USpn}-YDeW3<7zbK$Kv41l|(ZRX?vmdLNhp5+-G%ZdgKLp<1!Q z1`8>+?9f5TW4>(?FFVj?dk#4iYd6*`g7t=Mn0Hi6oPTMJ`gECg`G(D$nx)SBidkwc zm!c1HFJb2ybZ=-4EA6JWkW*i3TeH2S>m78vni0@sTYso)qKM^lN<6n((RA3ZV~^M2 zXYpQrWj7;^>H-ftht+*1HJA*BN|W+&#b(2<)+dqjF&rP)+i9s*k8V4#k$hvjQz72= z`@glfKbpkj=`@YuljMLYJylkL8bc#PfS z?EBdb-}th9;iDh4;b7pTJyNKGcZ%hm19ymepwk~65w#^+;enw`Wb?le=%^(~GdP4? zFXMz5p4OqVprcmPkPL7s9uK1yk*Gas0~W1rQ+9#(Gd7?Gz~5a;s%a zOAR%-7;Iq{fku_qITdoYerQv2h|~w9LeN5poTNR+o_bHKws-i9N3~_+{-!0PfsH!r z8c)U3Q}8z0E0zNq?RP|F(R}c(<4Fh8*>n`$ad<2F*6q{n9Rc3*yU*C$8&6`EdK984 z5(mdu-g zi^!LF`eBZONQ>l*q!+^~DyGaZ62Z?uVc=4O3&g*SVxC1#b$!wQDMN0n*xE|VHC%IE z7h%j8IsFt{>!^|Tl<(3y#^T%tx$F$T#%pf)*y8=w8Ce0?dLykZ@J_ZcFX?tkV3iGme+*7ecri6 z&PF6`^H90Nh7FU^@d&)S*z7lXIE^{N=5sDT@KxAy-KrX5vtX> zoHf?=g!M>yn+>|6L(nq-8S?vwY)UL)Ee_CpHcO*YDZ1^>1Ie`;+uQ)C0eYixJRDD1 zXsn@l*UQNoUEUag{-u!q22%IA7ho~vK0ztOVf#6`_(VlN8b4t z_PH;7QQno@T$>#OUr4VYYP9oSNUtE<`7VG^fP+wIuqCq9rG^dwGy+I)7yjYp^5B2> z#*4HRT1z{UsT319d_*YM0`+1Y@0ZcEDI8q{*9UYI>$ED>NqtHKw3XeZ*69~$WmM2F zr4i(*QAHilR=Z)HjZF>Fi;kgfGpUdzJ|jFLieDK;*gwXS4jN-RJV9@W>s6;1SXX*W z@T9y@CTe9QIIk0Y?jRExQ=2jq0Dw*nJX?vCCh1uQBU)o66Bok^pm&9QXcme^ACf<1H%T(s`v{0%i0vTeZD%q|pUF z{H{NHgMIuXAMv$D*%tVa*6{q{Y1O-Iql;=m-*EigdjXL~1tr=GJCorR32Oa# znyp!_s2AXpgXJThmnK}MTU2k8V0$2-Oa8ig*0 zQ>@mlxBq7AZ>~#Rm-%V+Ch}2QD8|wHAW3fA?w#OwzUIQclVlce4MrM>0XF1I5M6-f zbTop3S~gmE;_el@>>cm1J!e0}(%D#WCk4}u-}s{a*&F`QuD|}KBV&SD(~5^F9!Wa) zTs+hp91J?6ttvZeJ<1T-rA$yFpDiDO4>=tVdf>VCWypz z4h|}2Va(76`<=feUXCOK-6Ohg=}a@tnf{3A1w3#`3Hoke2xl%SlGA_tkdA3t-JU(i zT2&f5AS@#r4f|Ra2ht-*cQ&_fujj&2*@z~SW&MFitDr6?5!yhN_Klmq^VruMp$g{$ zx4wgoPB)w<2Pov61X_61&Ia-^`dE=yddF5Nx&bV=>Q0j=muzXNWvgpzRwFXh+CqIM z!+{NZU61my?;d7DOmoLEl24Bri7a`vpf>0qxYaff+-ZZ(hV{FBD{9+Klom^I)Jx-J z-(u(XjsWlb@6X>moDc!V>1;laq>T@>7`DB5cy(+V7NvVtvxnXHG<(wrKW|YCv1)4R zG_l*S|E_)Xy;s=B|K(%aQsR_fe@Hrv!LWEpE`o*F6uB#2j=_6}AGIMebV@S@DA$CS z=haR)c9*^6FF$18{nDrGWAC_3hhk&P50wwZdz!|nhvFJa3g5@2YS=g1YindcUpPFX zJ%lbXhYG`KlPUxv+)}HdVqJ3%)tasCTvh9zf>LC_WGs#n+tgi%YOY0c8eo?=mk-U* zc^+UeMeuZ)Y%$M806Yq4 z{xvLs(5_&48z*W#^;aHg&%f*g1Z#P?ec$~zyXr&lx6giZukAl@NCzpC7W5Xr7o5_k z2Yc4KQKwZC0iak2$Cf_6!>iojjCaIqk>``CFb4R{ms~9B???aka_e?BZ3wbLu1#vH zm8D@;H!R79_5eDf?K4n~DOkr-6`wkonrjXU3@iu?OFC2!1Oy1IJX5tGhej5hnu4N| zW?5cy%tcFp3yB2G4Wx7H_t>WHO28VnM}TTT#2{^$C}ktHqJYm?<_Ud5>5=Hje=B z`R~u)+aFHiS(>Jc`8?`F-IXv@kP%US=|!Rhuqlyx`Tgm``o6anRoT zwl~^`KJ*b=-`vvS&(a?_Zb#fJC--PI0Uv4Dl6_Op3VwvbI=Ox=soDJG!nxaVm z-TRz#?ZJe#AEh%TV}QlUZOp_1HG07c9f27L zNwSnnO1zPp#Tq)wakn z3$puN^+KS%Ag>P9f(9s&x>PQuxqLp_niZ1k`?c*I0si5?KY#Cd1}KQTx#S8o2n-JiaRxkMirSnusEeT)Ca(D0cwb*m?OWH?Hz=1hD#$g8S1-9knoF@Y zBt2g7ZHdLQH-}nFl366pN~ROe24b{xm^#dS6y?Jj`qrO%Zg=|XuE?L z4F}o{+-|R0rPUDROYM^{lx)!LhzCTJYpv|CGE7h?FY0oWK1+)=rS;I6`i9#crux$li4i76CydDP4`IlBW!*bE?+FzFaG>P?1g{$r?zt3DSB9Y-~D!b z^Xp${UC3XdM!*2@qRt_LuO1ZB!YWW2Yn~^&gb3f)K%WNLaOu*!%0vbeO6-YYdIWn* zMQb)1cE$r9YG*v~;r7LUdYA3H@kWJw-(S0sTp~p-ug@}zZ1(_)2>d+k%&o3dgz@~Y z?hM=2(;q>kBFBNK#LCe{J62&1W3*_MYRT4i?R4owEz-^_M=qDE;>k?V)GSq1JW?d9 zt|*ms@cLUDHXQUMQ@**;5eMI$fm0r`&#g(ZVnGpWIP{qU{){9#^@LCFg@#$!L{Ae9 zdI!;i{tXL901_AmYSes@M%LIYMnzj%YRYlJYGnq3lo0WP<<&K-x7q?XNSoj`^*fth zA4El~sQw|vqLE1h%vCtp6d%WNv^Ab5x8#o9-Ue{hpS(oUh=Wm*Cet+P)3MY*xZ~ok z>gH$!2lXB&A8*fo-t+9dCq3KZN>%vpU;oj?_Sb)Yc}Q72-xqpO1~YfPo=oB}gCjFu zkq?c#+=_VdVXGpCN;;#+_(6`7TnJoumu#oKzjM!V_Q>COo~`fufl?vO>V`ZR{<{W1 z!nO(*qV*YpTD_uX6oV^7j;v|M`!#EL!9v)_<-_QtY@!^)TMA1w@SM~H$Lu*q2oH@f zqGi3Yq^449b%!`Xs4A;q3=ky|Ajjaz`e7U5O-DmJbnu`GNE{6fEA2Q4!ed@LH~^3_ zWkGP*T@0GWQf|^c7xQIDfiLTTy_!sYnK<2g>LyLUaZnL03v(SjA0ne9S*T@1cSm%f zVvT0o8cQoe_=o^Py86sIOl0KHxEBjgH8BQwQiIMGKtUQ63en;IaQkb6e)95{YanJg zPP8e$GxX^tyrMWPOk9PIWvx`Q^Dlg^J^nY(x7A}$mB$-w9k4%s(kyAJZ` z+>=%V6v!dbtncHJHpnFs;R=$9^pZvO69>~mv%LsSwG`w$<%5hYHPqd*paD%&j< z2I=wk2o-1IT_9UfOeoMXUZ*-%TkT_4TrL_iKQ|mEN-45I5k(g*^Kk)Vstg7_ z8}$2j=+L?-9~!qTMiSjZ?}rIII@sbnNd(NBTtrIlC*Q{b7p!ckd9#Smspi?jL0*S1 zrrqcWukBd2a-|}OmHZw@=L7M;on@zdSE{!Aq*K)VDmRwo`A5AiF+>r^YOn24_ZVd~ z?Tw(5-0P;3Q9t_8t^1SCj%~gn=ITGcNU|uibe<;DS>$pjE_uS<--*^5E$mSbxu0G1 zKR&D?&WAai*!KOeeB9pnikI3quKSTZHYkyDO}tdW$!ETOH5;H0G;571x)3j3x1k{q zl-i2wxRPSvf%(!d0i-)vU{SBBQMTjwQ|-;zE&j7G*q>Z1Y}{r!@& zL|O93IAIf+l|-8up&5|cK!@f~)!WNfUs@LBptrSd!*17xqk(m{y6O^V!eSg;!J=VH zxeMC*(mM5I!qN~)r~v8m3lv7_A>=);#nkx*;tdoRK6j&Dw|2Xs$PVO5q!K@h`hfdi zLs0@@fx4Y==GmydsYg(()NR5v*qmj7Gix7niVe38+PJ%+rXP-BxOq6842RJzcOFO% zRJQq!u+P2yReMLkpz}0MCew&qIDSEu#t{`shs>elQm{E2Q!9v;Yx-a|S!?EIZ+ zI3;6c!b?HMkR#39?xQbwrCt5b%k1WxZd7-*JMc*0N^YzMoh!s^lMSPcAUSc-n`fyn zkdTT)(8Uo8Q?l#cNYWrX0#uNv$XW}t$2{^O_Pk5qr$Lt#g$FhS7D{&Amp@^zfBB2-+8b{5j;53gya%8~&|w5I z)4<7c@W4G&0ZhIRWV%$ZiWLe%LE1!K4Jsj-L5fg@R4NtUN(lrwaeh5~mS4EwHMaL} z-efOQ63JCZ=#$GJ9guDzUDK{ zp)rLlxi9tbVo{>Gc+W6%tf+x-SCv|zYOQ8N=@3IEI?SV?6@YNttJdCitW{U{XqL8f z_>leRJ72ZU1N()x&_$+0%y!0fk=mYn-q)7ab_uz{L5apapWERBx7n@V|F$n52|BL6 zEW`l=(kLGr;XB~Q=Og;G+Gc1G9uyyE8I@cdj zU8m7zjW!Bk3_xiRt9t4c<>iVZ5d~>1@63be^?*M~sklZC9HISZ9{EeQ>-3+oEC2G1 zwto1K5Fk>NY)d5GpB!0ypFqI|ZandxXW0WD_6R%meh(HG#?vL_3+Hyzx4vkf`ry0N z6vBvTq+yVme2NzI1vR=%G6s4#gZiyTL-oq;UAxpMipy0|t~uC56lwrEsC(}FaI3X< z+TmNTw;z7-V|HNQO)l>;_W1$r0<(pk@u2hUK0p7fT1`ab(UtX5`|^k1Y2W_x=X4#U zVe0-G2vtdjh=vl;g!f!M?gRtHTi$)54SVZ$=$0R8cYt<^)vJ!ku`UVEUxxPV^9VwT zim~S)BTa z?HvLB?hl^3cfMHoegIo&wvNLChOCpUMbDAF;G$R9&pqY2PBROG7>w6_?A>p(Kl;Ph zdecR6CBD$t=@3B&RD(30vjS-92URt>1a8eei8>R2nfJP1O9tlas>H;F8p1fCY&NASBgB)6PEUe)jlZf3_WW z_5)lHld2$1?WUn$DarXG>#oszi|4~gBeIdAM3gn(Fzh)eNKMUJ!>V<-K`mQ8_GBSKh@H{FW;YnB&>MH| zvqQJvW?P$^>2xxUZacV@tUdf`+uH!%`ch<3rZJQss3#o$ta~aMl*Pi1*|B7=y6k`0 zDd#*$Q(xH^9`(8}UuA#tnpfDhKfEOji+GOebEpo%DUiquI^{QO3v-af04>p;_XDqP zWVSC@xrV!w9bi!E1MviH6Dm7-$+fpS<2aU}i>+<7UYh0#us zo=k(Ee!z(*ooLT`*&o_T_j#a%yx_JRyy-go=f8ZT-T3|MeC24EX2baSg|YLcUBApB zi;3z{4RI+_AVjI;^=a<4n$~KsD7_OEq1v!}|I#z<)^B~r4&8jc^#a9!=`z0P9e52x z@toLGUT~2ecg~~qZ%o}K!--w~JHO)FI-!Y6e#J*DNq@2?BZ?11RMIy&vv%9=|JbM5 z=|B58>u(;mTdw(>-S+LTYOdKqhk^!Rh(ZiEG3p4-gVa~kY4xV99D9Pqj;W7&hYw0H z8HQ+Y{g53#u%ES3X*x@zgIj}S=XN)MH$DG1M1^3?XO_+*4aCc1yFwf{^vsj@*dM&@ zUAFtQvqJ=M<{>xcrmug}F1_TH_V3q#0?9Y};SY-*NT0GV41!ZEL=y3Oj^b2eq^$mdpl13XG(!ieF`W2E#58V!pjG|Mo0%})NA^Q>HN+09@3lnu5v zt=H|S!^$uUQ2}*4)*4X@5P_cdqF32*_xpK|y^B;3>Rc3ao38R*usV9(y> zhUyRY1h6oJkpNUItJ6v94iuuN03&R%?`+}yZDXsG<`)(n*cv2j4}0qNjsTZD=gE7g zX&STCWjdQH=iz{Ih%d&wzZSbJn{gvscSK}?|K~pR?1?zL%YNk2CD_v+rlepLT}LCTNE)tWd5=U4UG7-0Rql z*Ir{cTzidu``^B#@F8(tIOkz{3ute3b;W-DHE*@6{^l)q%~wBf=``#Dh;rH$(CLm` zo;*xhImGJo2J*J~yxr^E2igU%ev_^2K2iJ@I-{elb$jbeo@sa9c_7RvAS{b2Ti8=T zssWLYb*sn>`tU^9qs7W1SA?diRIS$pv(hZvdBUl7_AmXWeeYB6xAj|pgJRbC90E!UQH;jNvGT!%@0Yih3xiLEAOB7%iT61a1 zPI=&??DU8IvXr_v_I=O3cIDsOoj3nbjl6QLp@>zdq1Rls&i-4iv$-y(6xV9fK!T7* zI^2cRG@vOq)-sLGR)>AcDZToGonf-}(5Gx~19;{6Pux47&sqPHrt@4x5i8XJwL3je zzyG~XvDduq-L~tLdxb7A4Jwq<=Jw62|H$}+*s;+Tu&Y2)r7o74&8wK@JyJ;_f%U{|V z=RQK8QP;GX+b7<6nSJ4-AM$1q7(C5A(C;Ztg3LA;4m2i7p^U+hUw8XM8xBWG(TD&ZWlj0{ zWfwdyD8q%_Y*NVc1szP+(L^IkNg|!!aTd#MYb`HZd*|`?uxGy5%Bp)3``U;9#=iOK zk7+IdCTn|n)#}STG!(OW=j}33=oB$ps1--GK+YJ49E|`ThBli_WdNgOlIC-{=-|dM zS$*h}x3>Yj>{(CPo3n*#08m1&Ha(3IrJ)enS*IRnuYLPJ2#*#9ti%X`+_`=IlOM9z zU-V+T`ObAQ6n(=xa)<2Vbt-`d({&(y3HL)De6Ic1Oa9Di%X{=%D35VNf!9Dd1ocH2 z03FJ)<)f1Q+sEE(|NPf)6}>__MPVa4`8N%n3;*;3_VrJF#6I>v-zM^y&)L$`m|C|# z*5ntSk^Em|lr-;pRxR%>39ad9h3@%ksXx6TiPq&9W`8js$cfV?1``G(^UvKCs zh>s%?Tqn@6qKWH8Z|MA2yzYN902*koefoJGZ8T+9RCI#Y0cC<{tGN!{DaVxs_7JY^W@X69lD$dp2Mi zPr9Q+ecn!|<13QlVsz)>Zqj@{1&`CMK#Kqk)Q`aD7Y zgj^FIxeQALFdzH|lB3@+oeV6lwC&CtueCq>y=NU!gQnXmc4yc~^X%7NuHl&Xz4eXO z-P-ceKtZ7YtG)LCld~?@#-EvYW_Gq@Qwbp9D6oVg2*`m@L@+>rB!*DZcXxLB%>TOY`*~(p|L42D@ABlBYM{Qnui7mnORjs^%1hFRLBM2D0K zU(y>=2N)?4-y=!c$nI{Nyy=#<-zn#{4B)*t{$dZ__8nXC-lCRBF037&6Y}R^go5pf z=+rfKJZTR=e+E{rWOTqBbg5jT{AI0Ht!FctWbT4@hkp%l!HI|U)azQ2gc^WL+qm4p z=Xld*8?HUZzWVL&+qQcj#Dl7FM^OYY3w-%`=hzd^ywI8##@;H-_`*|%<|RD8R2kCt z`OB}eU1lCm;#97!lZ3HG17nzi+&Dm=W?jxg8`?CB-| z2$v_R+MCZkY4_Z8CHecHV34BkPRIeE001BWNkl~S=y~`I{KcWOhY9;QAw2V4O==yTVU2_qi{o1uH1K{4W zzFxcFqq~c>NkwRBnBud6*oH3{XDDOC2oUMeXrui6lx^(5vo5iGS2y3Yu;g#{@a^BX zH(!39eFS_DzTol4u8r;S+R%(n^_X=gD?*hDR_w)k)PB|;cveW)DwT4*TCOB7zP_-s z!HnaFcLaa|RO^jgt=5n*7SaaS|CEY@*;?J5cKR8o*fHl`!aZK6I6e$MrBi@N3jh%O~*JLZIw?2wbru=eh;mW9|7*C%Py3k(ZzoW3+J ziLd4FF0co0|AD>o{8L05SX2Y0!sJ-3ZaeHT-3~tEJiGq<)9r6_UuDVz4@e#lX}*;f zF^nnfdSCAPtKd-0*;=lhntZ9PA}+U7j_6q%tgVlKXLfh!`o(IYbjssIhc%rZa$tVpU5 zX~N&_u;)Iu`!Q#+?t+fSJFh-x_uYJhy)*xHqHHi`{0uz)+LPAdy~h2-jl&AnTzj5c zK-4-SGZcFVpmM?4=X#;9FPZbkTa^iWer$Lf0E*yJ8QP$fhDxw6N?5&F#+eN8-n(zN zg}%_}MTN-Z5%dBceh?!UPAdYGGRyuKZN>D!-$8}8L($k@S0e9ZPg z>0CC(I9O7vvN87i+rH0*Pai6p# z-(gSOd6T_8|8)(#kRya*R|e3cjKr)jspn>2xaPYp13>D5Nw&{?WGBu*Ya}WH&e)p5_Sbw44@>$5jLlGO4 zikz)IaUBlGQ<9}zB2f-7HTCB5KF}(ueGzQv)8s;^?`6nLQ zGf=AKs2pp6hSE zm8~;*L+czf-l~-%cqY^zn*GTA_R0&-@}c4?CvQ5%&c5Qi_Q>tm+0SqL88<3|)JKsl zmq-kv9&vscN6Hs!_%32DtIK9=lPxy46A%)4M?)BmW0R(zF#TdPUjZWlx)a+^6iNM}A{3{NX<9>+7Q|3WcyB&;|0I zHz8w^3V>&UW783pdiCR zeWOe%7;cS3tyL&UG@!GqUMUxomtUP%=^pMy@Mn+vNKdg`%i)Yvk=Z!spmksyMnR@A zT{-*wnIE^K&%1^jLg0naHO=KmSpV{O?T25#$bNY1oz_>ZSZAA7dE($CShvi4TLm2s zpHP>C(Bt}(*QFjk3;;ipPZE1~;Q|{N7~sPMV{?-&wz8?aPq%Jp&nH={lneIyvrpQr zJ8!jD{_>(#Y8Bgdr`_xmmtAKs-hZ22dHI!uE#Xn&`Ctez63!mGUJ(u(XK;P13jYnA zUGVw4I_>CF&$18AIM7CnU6 z^ajcgV1yoe+UGb4)^qc9_TJwXklKti2A-39nJZfHga{BDBui*=m88(|jqm?xFap%d zL|o4K$c~Hv-JMvMDzyt30TyEbP6f>a2ogs_z3!Q`;pVpI5hvT|^)@1Pd0_csd-0F6 z?7?5%W(ybm&G#~3Nk}`N57IdZXR!!&!2zVKK-xg>)^cufq>63;`Hqfyty)Ruyz#fn z=$(c+7wGJd9Yj?KqJp4|NCl9^VXOiW6Vq(J9X7XXe)X`mb&ceqAm*LP@o>EI)FYHc zeCX*HsSvE4RhkTA;^Q;I_yc!&g_foBeQ>BSy4U4Rs=&M9T_;YQU^`FS-}XED-)zMA z$wEsiReSNV`|Y`>9=Fm!9}QsV1CF#g5B<`<^o5JHtlG6VL57n&I+}9gD51`Q*Mb3b z`r+m%U;v%_;b#)aqDft!4{$_1O4{nuYBH~d-8Enza0|;qcyaPMsZ|Qa_?wl zp{AO;eEzWASa@Q-SNtEbY(;E?;4l;^FehBGOncro++>PP-S<%2X#2gaZ~41cFBR?8 zXCAdj@4nOCeB%wmwV;WkPQz;;tr|COH2W+-kvI?oS(?r+rh+S%Ew&XapaZ3WCv<~B z;ppgSuNOgvo42Skaj#>BcMWjn(FgX_>R6M?^Fjk~G?EY11_^`_^~AXWQ+y zzooGqF-sXdLs13~e(x>U+x6f1fz5w=F%KG!NGyXR`HhoZ&T{k}x%e((=NMAS=SYOZ z_lE8zUn7&Y32TqHBmeyqw#AOqtb6nr>m0Qf^=TH)dyVzMdK*o#&M|A*Umy6XU2@^Y zE%|Y(zI$F5lWHXLxuiJy7LXVLR<1fh@acpJYuou(ea|-7Y6r*Z(NxOVvk(5(ZoJ}R zXKc!_xq#bwOfcdg0rnM(+@gZ5nG-kM#BTojg*I>QoBV!6L2cL+cZ#gdCgg!6NQNkY z2nNAl7|}I1{bUFgqCs7r8!tJ--uUZFmKb!2qz*?ZMK-;V#(;j2u|_Iuo9?)~ZMfMM zw&4!b2{FI*>T@>tnaAz*7iZg>uf9TuL12Jef0W{k8qsAF)*i=#9yD}}O6IT=p)Job zP7L$E_udkwMCd(W4xH4F_I$lut|YI`f48#H%oB&d0hFtQ29VFn`{VG_04R)QHc&xm zHaqpWkJ{N^_>zsBFbPMO*f8Kqe7*J8XY2=8U2b>X^B|YbNfk~z0H_X^q*NCW-ou=& z3Or7RVK4@hN?5{&{L%%pVx|@1uUma^OPexvC!4a(Ha2DZU2MeI30iepEix6ugM0k; ztL?I{e4UUdJ^^7s?hI3h8;WS?c8jh(l(U5EX>tKK(kC>#PCn;<@(fE3dTZ${akWtRsd{G*yNVhQ7mQ+f228zu@ck!XJKTKl=7H=M`zi~v;QRJIgCI;QXb=;`J9a& zHPR++xT&r6flY0TJ@)4|_x6$FID~^**XUDm~dlVCC02VOwywwceP|yr5rG19wP+L2ivN!X{wcFI39Gsrzj5Z`S!(j#kJp)7o$f-9Uzm&d!Vrc56QzqWLp}jVjnjtkr*7Pt+t$E z=Y8Wk8@=wvybpkY`75GVjePfMM>={5^aO7#9ww?Ds)V_b& zx%TM8kCOcw1Mj#W61PHY40B~>6Gr{ul!t!@)cF$e*o7;YD zy({~uuuUfdHRtXQ?g!g=n;mWat+uyGTkgP#E=KH9!R9{opuPOellIo!m)JPO%32s4 z8ko4xoP2{8Q)eeT*keYIuzc4D&QMU)82Y9wmRhk;vc5uryOFsI0*s|5iXymSNr%p#QW!S?M1WFVk)W$HYo{Ii5j*R`FI(4`ajhY9 z7y>M&cj?>qov(e-ZomCbd#|_51J<5Z4Z#pgWC^kX zXaI@*ZO(J{@UL#SCm(sh`d0Sw8b)EP6zg3_iJP?cdK*)tXxyX?ZNi3ISl769EI*># z`WL@ri{F}W^XI%^Z@u~#`|I%?aO_78=qc4LhsEoVc53rOFWRso06afx0Q?TG z`Jv6$wNIXYvh8=o@zybFG|6k(d>3yXnqJR8dY}FH`fKgM$DX#uz2M3?qzb)IFS4B` zB+r_l=YRouDMWBQ28X~U+L4-slnM?l9?Zt;tz%#O%9m`)-iNYJP_Gn;*ROo3u{_s7@TZ|=N<2Lazq85pl~sDqSB*#XC#Z2NrdRJ-TL-?Cra{6iZ6ZceF1 z4bLNG!oDvU01DOR{R4t-Nh(!;Lqc3;SN&kH2u8{YVS+oZ`Jz4b@cq`;*H07*(lTSZ zyT}PbKLU_5#!0aVBilLBMz6h|P26}>+W@1O-6PloSh3_?dvD$xd+w1Qd-0hkZOM{l zG-wDFvt~0yg*KZoek|_|_(@3Zs7S$G4|OVDP_iA3J*jTj`-_#NP^ngSJ@%a8Z2$)y za6nJPjBHRq|2UA^v2K=iNEB%bvizXIjmjss$F`f;@h6>ZyXkY^;LIgkx0+oWSSqC&h9bOEM4vIf@LN$REjWp!j zd+hQd`{ad}*yOEtW+xd^-T2;Gtz`3_f6{*V-5czIhaTes46Z+QZW5WQj!Y4a3gra9 z7S0`W%e+#s?yhz_=hNrdKF6G9*^X|l5o$DS&g1vmjo}Y-Ve%zp0H` zXFU?z{x;`Dd-U#~+Y^sG%-5#QQ64i5h*E7tgm4@RC2X8`6%5cJDi!S=OQorEiix~Z zxmK^%o5?_>R+)Ol8N=HE4mjX|94O{F@h6>X z(`FuQonyyQ8$a9DX_bNHRxbA0^N-B3pZ)ZwHfPQpa$DY6QQ%HofGuA4@%7ttX5D$Q z6`At5{2(`_cnX8eAeT+qn67r)e6x-0s1r`L-3~g^ve30pDQ~TnA&85)g2W!X`{#E3 zHP_gSug>FC8|n+Kb#+w*-*!)<@kuItE>M}dyR0P>nApted)lcNUTzaM+M4?i;39h8 zn{W5r{2jaJmv`{M;kqU3h$Y(@+i}{ycKD~iWKZ9Jr`>S*rM9vU^R-IF5CJF!Pxuvv zFX1h)RylJFhf{+As36AQePu`^tXeHvX<)!U^O0S&Y0|sB&@lp}iyDKBT+lP}?M!J< zsG_DIrJ-iF(bn6rdAQAmOccFTeOwOQ{2>7V0MSN08nXDT1Y) z%vfIwvR#)G6Hx3X0WG!{}&B*|hDpv_lR# z*gm-Z4mN4yEx9(7g=VhJYNfKxezeEtzy2DFxrK{Y*kAwhoW1zcYg$ObWot$iI5cyR z4&VV|gt35GQx36+wTWo7>Bj5ZwmW>tw%&Sc+hxCltz*o1V(NGpOBTLKICkXP6FF73 z{M|)%|F3^xciwS_&H3vqx^9FUr(-C!kVK<4$?M-)82dsGAy8@CXz~R6^hKB1&If!< zi!4y+)hf2&r9atK=bdYdmn~xrgBM3mzwX2dcFZ{!*n|&kWVc>>xjp>AEWw=Un{ZG_ znyDxeQ?XoZPO`R5v7^5?j)Nsbvqls!PeHdbP*@J(%BB{?OkbeUz%+%z49iDJM0rf zBWKe38!bM98w&NYD%qCj8nQi5$!`%5H0IN&W^3@ zhaY*kopQm~D00OmOc+ZXSZTk$;Y$1UFMcKzso5kMZN~ol+TmwjU~`}9u^YejEnBi| zWn^-EAI=d&UCzCCI2;@%75&QnsgyyFp0-QB^}SXKgeD~Bc`rMDf8RJG^*$(Qz!|`B zko$8{AZIZWcBS!e_)MxrL?uTA-EOZBa|!uclQ*Ky{{y#NXOH&$o^!%ft40*YU{fOH zYDlm1?>tJ58qw~fq1ua9sa7DPm%P2Szp}-_r@Vg+fFav|MPGn!>R zkv4in-qxKo!45rmrtNq1DO{k;f;!)AwQA7@`c_DDs8O?5o_Z8aGh26)Db~H#y67eP zGC2%(RLPM+5r)(Xw2P6LPy)}TJU~o-`Jy-Nug^bYk3QIAk3RG;56!e0d)v&99%~zI zwiOW%bUbI>akKsIfB(j2zwj69Lqo&ASkvI3IqwM(APyhCMTZAPabi<8Ue7MN>N~d4 z)>AFp4hnIN*RzZspI&{5J@m+viZq@}a%_~5 zNb=^Sg&;LUkHl9(srJzUV}6}Z+txyXdIB94f_PK%iS1KSh@sGLwuf zWaDbb1K?J??f{l}V?LnSByxkL9y?Ck&!+A%gEJos=R9Ng-27czICl;s5c@SQbwd&$ zn`RQ+A^?DGpWOd|9S)cl!@|)o%y!(owx0Ur~hPsn022$`5(_x_Xl+X7QyW~eIJ{)*Pgc1z6V^j&-W zfxGRF+ita|pLu~41Dpu%56si&W6AN|Cqtb5$LOj&A` z0d9M_{^E1&v4PZkAB?7t+$yy|KP9fk9Ysv%7s4mBoIwN8|Pv?OzasnklHzchUfxA2K{3^ zBq7tOdZW=u=D)qPvhF^^d>-IGD}sj}`uKA+$Kt@F6m&#WP^lXL*`sE*UU$x>?K0J7 ze0Zkqy3b5ocayCM>%rp_UxvOA^>5&%AR&$=+n9_3C#FUjwQY` z|26x|>}PD=ym|K0pI@-o-dsSWhb1)f=SGtQ9oucaxgB)KVYbus{fUJm@;vp(Ec@LZ zx7riWJZCHWMcpMrlp9pQKxzhJ_~68tY6Be1tvBDmuKw}QY^@DZ46BQc=G!B8-fXwt zaE&cr*=HAAex+@({Z4lKx4vpWz2n#1c%!`sY6QZ&$3bWD8VkF9bQIA>(5&hb6zIs~ zzxAV=|4tR6(A#IH?Z2I-*(4$4#){bl89-1^U?AM`$=LwGy+DSj0fm*WP~yX)!V%rJ z-5z_}{>Pm~iukNsuCqmRUsU0Yt~8d8V2xB3R157r&J*|BOLJbacNV;9b6$7 zMZ?CTITXZ{a0h3}4TPx>!h1)Xee=pIY?qH5M@B3faF~!=@bdHa>zl5z1@q?Fmu|Yt z-k$fGU2*=W?1h(KWAsq}L3`bi&QKYH@{bA$OjWeohP@E(`tm*it_8@_bw8E?1WB-O z#WFj7+SaWJx1kCbKyFY7OOpwoLqfVLwx!OY!J7sRP;0DY9FR@f=kVigr~MDJXYc=| zz5K)jd@hJ07}|lvB${}DSrHj9(FP+z6u=zJCpXupq*9 zS`94DmqaK>UJnmN#-&-+3rXB${MlOw)}Bq-CKJcno_kNTsatPtQ+M3a*57g}vdy>I!M53cJKJRHuJ-buX4zf0-(rtH`LwOc6)KS z#6(q!f-h>6BKP+N-XXvn(SisVc}WfH?(DE{|APVau2^Qr?y)7&CoLb>4r168XMh2P zGB;O2jW05Ay{8iJYHXH|EuOf}btX-=gZ}MI3KKte=Z~$}FBNVuOR=gcy4^s8@MlD! ze#p6`QZ}-y6ZJ(sNz%zX%lj(h_Za5NaQ~-1K=62|WrI#F41oL`83Q7E7N`k2s&)N} z92a&{@f;iXz7x#CeA>3$cwO6L`ZU{h_q}ZVr1iWjo3l1x`5>-g$hyB^i{E+2{yh6X z?5;b1WpfuT)o7m&>3~-hxl{7K zUU=+&yYDx5+N=j3mJ+i|s3R57Xp471#*eWtTy(ze@zIklo5#-FBF8!r z&9pwKXg7TMeEa#GztI*(Ulc-F5-z+`63GLI5mKnJfj|cm8$<*6c?JjiVbmkLU;wxL zT?Bvue0+~BTag5j6R#1RCk(aVOH5VO2a0Usy>sr`BN4?6T-ln1*oB`u!(MrFAv?J_-qhG{KLh7@!vpbus;kR3{jg6L8qGI{A7`_S$@MK(Lh=-v*;M{Su!D3gP;82EEKLP}|>wj|V z-$#Ju%k0QqHy72M=@rl;d3fsoV>6{gl+bI!>l8{zGj&5Cea?oT-#ZM#aII1{&7qhv zBfD+u-KN{TDM_SC001BWNkl9JpW6~)gPt*YUM5zbv1AZr!-O~~%ITx!`1^l~V8l+741tY-gk`^5k zSq%U3>M^B-G^&hr3Tal5@tivZz7TV0hb8eaKpewik&KE{w^@@kt<9I?X{t>rO|U}8 zju~zH?Z2a%S1RW$S>pSYGBkhz6 zzs6BRL@|hW&42b0JO5K>+3c6!pqIyc;xHm&;TNuu*Xs>77%{#nI@G}Faj4{-or2Od zn=q!^uKLlfHfgKfX>7Qb-sQ{eqq}TIbP7KohJ@GC%mAbkRd-M+8)|YcmjYuEy z9A*^F;6P!KAev~HY#X!AL>pMK!WJ)C!taA324PU}=8^uAq=*BrB_Y~i-@q(KJ(DC! zxz?zB=;%+rzlz|F2+v4u+!#QS&SUo33t}7sG8J9Riffhpn{l9n&Wr<%)Cd#`Xi8%n zDqaJ|1H(XM33e#I9oKKvVRZ@%`fc zNJbD%yS?|BZU-Luaa(WW&Frl=Ua|Xsf4BXi=YCuG_7YMtkc!~wP&oqL+$pRurzsmu zvTyw84jcc04XmSU6d9uTeE%DEq=t84NLd ze1D^9d+xEbo&DvjZPYp&iuYtj(SVa?Y)c$I^jMked*__H1ssaNpR0{J^K?bB*jtQ6 zfl}{AR7NBLl>;O_Z0aFQOaTG${Gql@Q86E9MN-H?d*7|b0UmI@8Vyn*`ij-c^pl1; z9Xg6&ICa#QNOhdfE<76fVFr2kAPg$`b9FMo5y62gJM`1)6F7YujaU2=2Tw5dFdA9Nf_(+U=}Q zooz>b@&e1|@;2x3`>2xrr$4{iIuJn>z=22PV%vk=T_H3$qLOHI>H{K00%H-KflV+- zHlBE*?Rm(@)F5=|wOB0K4PQ9R-gtAqcYoDyz%N8xm@HnKx;>Ckhb9o#uX@@Oy$Asb zMhXX|U7YfOR48UPV1!JwLg;wNJU54bQqVC%L##$o1Q-Cym;Q34GV|2)hkpb>L~b*y zqaPG0j$kuQg|!Xw#zZi96Q%hRxHK9zJRkJpDzxC$nHojc6$jlzJCLE^rj?K?d78um z(bFFkzU;QcYZ5(CqA!mg8)$Sb;GhV;)I|hz>4Rad14W8~M-AfcZCRVL`KGq(w0&%s z>HFDQ>uzW-{plgQ_t(F)hyU<|EnV5qpN+1p@^ej>ZM)^h_U$|FL6Wf|WkMP-dE$86ZSNU& z$kE5!+LI>RoM)e~U*7f;>v`yp41GvpkV|vpB=B~?yX`r<>bh^+qzyN;8@_U}&3g1d zv||~cvw?zN6zPzfLC%arjg$!8S`GipptyU$z5h@pJ)|qx+DMgWL=wnBHZ>WC8!HKP z4G|%Ap(wEHAmO8G?X3z_yqAfMPp#4txi!Rxs^C3Prkj$Bs7RCwRu zqO;KQ@j1%+`C-I?M;#yq2EnC~O2Fgwdx6Yi5pw}v5EEi`V}QpI{Heo)_u*kAk|6_h z=*%5_w|rfpl^3Xro7T*}exJWQQDngiYFXOMCg5C+vsUU1iU` zILFfw32Kop;alkUpT39fw9C$R%=P z4*87J&PP&|XAi>Dw4h?M)?+7GMoPy+JytjbMVl-N@={eB?Wtx52suSIXn(m{IqFlF z3~vKC{J;Zx^4JMI!~l3m{V+yhiVTEoLuUo@!MImY)*&y38?H4=I{a`{*m7&8uMOrC`liYBWhO({+iyy;+3kMEC~hqCaPpZ3{J4&^Ws zD;h(UgFt{E>VQ@e5rl{#osj_&Iz=rght z+*htvjvnp?aO}Yc^t5TEFH;~kyM{<3$_scz;NpycNyV3Uju#;@K!V&@=*1U2J`X<& zN2LW+fpDG#X%s^y&VoLHLL3JkDG;!K_96g5x&eg2DZf|eH)tA>z9IFB(Mv>(K#-^u zN1-fTKh?0I8tvU#q;8YOkG6gG-Pexzw@=vkbvLjdee)7~Xx2lv@a^|JkCsOzl7(El zy^Z|~em-BWsgzKC59Z?y^)R%fS4BBeAwrgfLXnCI;lURci36)=ltmrJy$e1}kMskn z5j1}ssnP4G_Q7Etz;F#y#X!=q-5&ZqINW-QxCcR`1EWf5uOh1UvLyz=E?tv`eK=_2 z&rCg_CROcVSa1$>I!UUY%OpvErB*rOlNS%~2yo)z2lTW7e26WP(IxZ)Lh_cQ+A%-N zgT;_JI8cHc0pEihuvnG%jRPMIGW;D7Av~o(e_#ZI41GO(K&CK&&Nf8?6_JBWHt5aB za}Sj_6nlfU29koJr(1|7C`M7xQK!_eIeG$!282d^VvNR-PT4wRN7})M9%3^OKiZbe zd)az^cema5@Sm&?TK=qW5a~kY!f7Jz`CE;|5E%ADjnondTO53@jPeOH4A|gs;lAPv zYicobzynU&iHcOLcfzc$xI2PMDf2=tCFlOToC=It&q}Z=qjObbkvQZnnsyU1_Gml` zMBqwTr)6-#xbv<+DIt305Ua>^nkm3@R~H`XQM%ri%_jY&YUQYNhItBf`jH26LrjuN z)w3{pS8Ai@$Ds}lpCP%R$X(84^w2Iox;QNZfW*A`jr2!dQAHORL~x4&0m6-UXGzbA z=37?|hXv^Z-Vfnio`|pMO&57A(V#0ed0N7)QM+KHOAe50};}*AW6HWSyZkx zwBjh8vWeqH+O!!nY^|}QZP6RA+Px1y#hqgjb+CuRUsgORuQ~YAE-e|x5ATnN*5HO2 zu<2EZB07o81`iyaSu~ft&}IKYsRs=q0}Ub_#1OremMAohw7FiILYM(iQ%%T{?mY}Z z>5rb5oI7@lRXJRPn<0_lLFpLHCxe!qmC~P6P!Ju&o|X4kCmP?EsV7M$DU_>~W6!;G zct?OUk2X>msv8-bS2%E4 zyiV*Yi_}fwUvzv$EPQ72Wt=~ePBl4TGiFpbzh}YQOIhfN*FRWiM4A_o4cE;Gh-G$w zf!#3Z0K6mK&c%At0EI_pL60u0595fwJSdaM2`7v7kGKGkuxH(KcYzW3 zQW`5}De2E?z^wu_YUn)stS^-)yx2uL%V|J7)2e6>_&x}OLp~k%13Q>QtBDza4_IWA zOg)`WC4B>x%DTCPr7M2oS{s@(FkkHQTA5S9PS;-vh(#vn^vIkPo?-mGaFx z4FDmS%_(kH*MVm9$En+R9}(za1VTETK&qaFLzC_cIccS+rNc%xr#Fl6nef@f7*)R` z`V2u|;LpH$5DwOL5dC6%T!lUAf(}YS3il5fS@^y_6A++CMaaMRe4n!q;1;2lz`%SW z5ijm3b_2pe6;}uEEkHs}Ll;8D2$zNtkRaoL6H&9!ua`Xxut;S9czr}7aE0)BprRLa z6wL@T|A#?SXSTOkt(<)RSBJL&oO$GdJ(kjvyi7Wss6hhw3=dd0grchsZAL>Vys`Wz z4w&>mhfY!z$~7z1l=ATTJN6z>D~-d8#fUO&f@K1VO<8*`p?EE}o>P&`n>+X&;T)kJ zuNRFkeh>C!c@4m8bK}c#b0u2;x**Ymm6Ll5%@4PXn8Lh1Cmf$ksEq3r4VirqS4_oa z;)69P#A#$hA|Z?s$Pfeo=>5IE5yY!q25gQsl%^rShf*^Qz=?%SQTzal10=NurCqAS zM7NgIqwbLoI2;>vSn<1)zNOINhN6^6-~x$;J`EPp9u3K$T7v^@AA*AmgJdxle2tdg4?;7(N9j_` zFM!T~td{8;4|fcThx;s6{b6xLaB9 zq?&m6%oL>}^r+rJ7=o~QHRNc{?8C@8Avec+l`E(TuqY4_L5DgFjC+(_kBAY6hgUm} zqd`Xp!-k?fow~v5U%&u#Pvz8@`uaeQrPACt*H@}l&b;_*!`lEpb<9CjhO5_`bvPk> zKr$DH)U%)^M5g~^xfn@N0Iw=m{$3~dHrSg6^ z08$2^Zl;}FVo&0x>)1sahMXK;JzDjuO;UsfgKZhPZd?b9l?RH@qf$3q1oKyW7XLLIaLxHD9n$Urq=FgTZ%~JTqV_3 zG7?5i)&TWx5NzU>A55q@^(_XHr~XCj!f zOw~LRMr~B8HtNlkB^VO>?3ahR0et?rLs~^J+`k$fFaYF)F5=_|Pc#P|CSu6&Sg``h zSE7o-8(2Nk0Ca{u?{tzI4k#$|BG&mf$|$Cp7MOMTv=|;LSc{zc^4ddioRi5M{)@s7 z9uo%@FAU?rLqSRq9aW|+)EPx&$ugXyIM$Cym(*Jv98-i5!2r}al5x?K`xF;`Mol1R zNJ4*~QtmYk137ulgI){e(&ijt>OygC1Vwc5e8N;yu$me!IL~T-aDBt zq8R?3#^<~ocz)c&=<7t^0G2>$zk~D1Ny6_%F^lMd=LX$U5*l5K9<>1|9(X-+z+AbT zvk{CSa6+nAa6aHL(8I&+D%PxW!R5o;0RES6iiemH2AN~Bh^UG;!Ikrh=u|-}1eC#* zi!~3R9FWD5{~RZUxN$|eKMs}K%-{6_V#=%){@ExJG81#Z!D#`EgjOB$S=Jj=QI_V7 z3;>4(Qi95-0$B>YIvPLRR0()B5A_7me#wi8odMdZq-iII2dTK=MoI%@NRapAAtVh! z(IFO8SE^EELw=2a5?9A(ntca=jCD|oF=)p~Bf}{1`H`BD&VkSD+anpdTAh0pt3<|t z&(nje>l+5ZnuyF(p-6a-S{>Wu5#eAE=$SwX4xhm{);FN|fF_ylN%YRd3lr}uXz>y8 zqb}>ogn^QK%Yc* zg_x*Gs~G|uD%B0@wBox3LyDmkMIO@(pd^mE&;WevB>+VpNECrCV}kSp1t_8=(@A#J zRdka<$LP(F7Az63uu>eQb>IcAF?EINT$^mrg&bCrPDpX-|Pf2l3{T zf8anC0_KW=5KJo}JO>{Hm^0K6ctd=mEZB(NQxg>$Yjmn!40^{mkR%R~d*_v7dp@WQ zw*yIW(FQaWLnH}WHNI+;b{11?K3N4w7l)h$rZ0hmF$aAco;7L#SSq)xV`UQaV0b}w zQTqofJQ%|2mC_(5k6Hr}0tX4#hVAhfLZMgnyem>4F2QE5uVhiEmb!#^x!~GEp&=9- zG*qLan9VsKO(c}->dhdn;n1@F2vuktXm6%P|Ha={MvM_t^bjaQ?8cRbQ$d#|=Y-i%O+Z^|nlsAdE(?7@lho z*>IYG&%{ZH6)QjC`RnA-AndE-s1!<%*=sxR*ak)pXBq{knoyDvQLgJf1*Al6+C1Nt z&oPZbih`RT{Q#yn+(ao9L|>vjqo@nXknpCOl@-q&bpT!;g*FaY1uo2s2ckgE%g4fM z)Di*tMb{JGOIn80GjJau9|!|zr6u?GFa4uP+5|2L?p1^k zc`m#^nvOL$S{3YyB!g)lK2HqugaZM7g=*y6T+cdI0SrOUUQ43Hai;AvA*6Q{@l`TjtIe!EGS+3>_VY zaTR;G0g4oA@>FVSk+aF-X^PMS%@7kQLEGQwj+u}9-ry(#kq-m6?&K0}S5(Vrs|vi2 z2EA32po=N2T+6u0q=c7b(+k|4#eK%!5oIB4w zxt@O$RVmjQmEuq{2dA-1zJ-mY)-aJMBw6q^d}tnCn?h3yFgbcC(JWPm z-djePEvbCwOT#<@Tzl>bi~vA^vY8~&hgZ%YMV$&NY0V1_80-MzrpYJ-1&Vlu5k7e= z92_=Td`mk!hTfqSa^!RcSA4_62w9Mz?Q*qICPno!wf==yt1;$?ly7t4mUODGK?fhy zWesn~7mYFIiLv6;;XqNm(~S64>@T3PU~{-&Rbu=8+3}w6@|=7_Q_i7Qz==phpqo>T z0yL!@USp(!3t{}6rgMabh>Rapem1N-#q^h7C!zv8xhM~6L56GzK?Uv?7JHP)m6H}V z@DeSvrWMK+&MXVBmjjbw%8QG~gp@}OM@DiWZ!!15XNMidg8+fhGo?VHpde~0`vZP5 z>MPY_ejJZ~P4-OAftG-g1UMmP^ zf#U^fO+zpWOKP5B$V6%i!3JeS^4Rr?8jr0)PR)*aLCl{c&#|$P5f!XpoeoQJSh7D>4$L(EYjKz0j8c zdlpWCon#CpAtiJEk!k|`s17_{L+Or?rZ6UTlcOs?*#F>}0T5ClV-}ah2ypIY!#o09 ze&#Vf?YSh^p373q2!{x02s{NmM)18u@*<{~*oJq$OysFSkB28A{2%|V+i*Rnd6QA0=u7}X3&Ur z0P(Xd3LRhP;s+Pu#SuY+ko@^-%?2DLk>Y|HW~hVsvtHZ?Y78SARG-GD0}c;QPVSYj zSb|aDU?MUJL6WD&Jwm#s8c0Jeysxg$ghPqwKtpzlI_oNTL^OaZidju>v4Hl-gj6Te zEgbsL3etF|%gDGP&?KB@9V!rfZn4-~PJsr{v{dD+ONKcY=<>5Z*3;RR&1I9Mo=&9_ zcu*Wd6n%&QKt9wM!40gb0p|RcU`*oB(2F`pCmK#N06nO{uJKp#@8pw&+JMir;`?!s zDZS?d;dno!2rvLXP@+Aq3F<6UJQZv$R5XbZK%@pL!o}ZlT^>xBnY=!^Ztn zWRQU~1@S0I850!jxrAwD%w34IC$2x734fk^EB!1T8u&SmQsJ7pRKrsrLa2?ptJmp! zL#0{-#yam64GYoHY0o$p>Nz+m(N(8KjYbT#1h?bN;cfsxf%4fTmoi9Mq!P>mAV)<$ z%LYkP#pGZwpp{NL(aQPsu1ARn5`;Glb#SX<3zyL!_<)&PE;1GNJ3Yp5V&^NjdDp}-KI3XrJeNOYJ;CwBM~ zZ$*m`m!0wMy2WiO4_)PRluKt)Sx(5#1s8l(_&)z;@;r8;Yfl*grb(+ZWkdY z4H54RnAAJYv77@}PJlyeYm#!kSvmWXuMclB+;yKlv8Ph2=8z$nH4`8$?1r|QT0(?0 zFRGkA*pHEai$JA0-FSe^N)ZR$%j&TX%9X1-=`*=RA<{fV3hjdN@KEq@a8vPcB9-BH z)62y+MWqNdKIGNl`LtmJyLe54?^H-K-_9tF;Dl5tQ~1G#Hzu0pXbSTB*rEdCghz}f z7+xEPkX#`g3N*ktr=YN-*;&u6ow6K+G2AmA{+uYzKwo4iDlj26h&lpmW4qehXfW98 z<$YIP1BGY_efl#Za-;VXRYZIpM%pOWeTWF%>M%sl(7YjtdCtLmtNY+m?H~$@`9`HV zHb;H-fv_+KdPs?Z*(Cjy=J1C>Z}|L)J^jTpVbG?f5{w|SLF15GPz?gw9HatAevSzs z9kjsLBjks`(ohtJ`6aj)geIM(*%Dh-xc9(;)x=AOJ~3K~$6YUNZ0K3k`zNs9A|kk$4@XRxur>j<{g$NY&5;gyxSb zWEmBnHSS9wMXVD%;^6(u)j9>F3stL}|CM201YiHT6MM?lDrbU$D0-9A=Up|L7vw61 zMICe<0&F7}gvS&KGqWInQMcduFGKcW;ir&aqR4|s*L;D{Ag8H6>>UMKxB}2bNIbfC6Ys3Om7%y}-f^%9>!HEr z2FY5&;l^0Jfy1wX5s?I8IG`uv0C9Qt5FOLj+yHkaXq&sBP+fb#lbXNP)Ec(6jA+kM z4#iKQpkVTZ($-rj^F86EBi966Eh&{qWi+FKt3)x3&xOw({e?)Al!|FnW)#YZ0JsO? z>ESSf8iD)Iu5;8oUh9=$01ZnDwfBJmeDAz}XCtiHY}SkAY9gyv+MwJ{VL$jkViYK~ zLBXs&RLV!;0TnJaY#z-i-e8B)(7~i4nol&rD=9yf=hA_Z0mS}U7zk(rG)6Yu)cnFh z#&wEEFGx}PIVl^F&kz1QJErn>>L#an$ooqgB&XV%4~K|hq3$j`A-0|r0j2(f@Dz*& z9}6B|Wr)%^00%)xqtSYr7f4CWMG)R4MCt=CL78xlPyh;`TSPi1Q7zqf{EoxAyst!W zPLJ*0Ufd#Z{(%}PY2x(`snft$Qk{b|5+_*b558i~n&YP=8p5l~<0~zVD2@9+Xm~NQ zTCPhQ^nGCfw_bX>PlPq<#Zomvhy-4Y6oJT%9}L|qjUW=ACse04yRdEVMmlu>KZ$=s zY9gpoxOJch!BQa`*mBtFp0!s|l|h{ZBsMxG~$Y{5_^s-**jzsF|{ zdUlK!l3nUBr;srpKMZ1gS4ehrS@8HQ_&!o2oCYB_EYjG-SpeFo!w3iUxmvT{ zXf~5_-723Q?w#PDUUp^=oNc4ts8?$B1mV<|90(X0a_BW)H>e7Sj%#cm5q(0)3Zn-R z429rO7K6BJdrlsh2i65v;jva0%A8--_#QYZ)aYudp5cArneZS)SC$u&1h@;n;;=9( zfdeDRP#sul0^xOGfH@1vthL!%1|*noPme~b+<(Y3qU@R>5Ly}n#pM`;)};#zcW7q}90 z)D zdfR1Z_B0!fT(i;S7#p z5{FihuZDZ#?@3d3AOiP=Gs_(GK^-7<2sPR89+EtXRYhzXdXY*r$@>@V-B5u-_mrF_ zPw6;|Km~5W(8Tvq_zxL&$9V|SA`ibKQc6*g_DSHL+%7#MX2A7EvvSG>mk)0k^wvv| z0!bMT83|F3kPW9ut4MB=)o_XI*h&ab=3W}#!={OMC^=>~WO-fi*pbhY=1j4tEQ?Nf zaUw6iWC4Fx_cul>RU?$^m~)lu1>`FEKS7yz_-JCGScI1be2CY_7xMDfLG-jEhS0h1 zjHpJ1-WItr42|!>0T&o&)tQkRxItP$7}e_*lJA&*FR7UG48s!ef z>&N?}mJ9e<9H^MLNO4qCJsF{F`ga)=T#74F)N74KGEiw$K5^kNH-Mj9bXpI3Ah~Qp z1Hg?T`O7&#Vn)hyAvDHKWcYO+evrkue8E!=98PIk!n4S0<6s~UWnN2FG>zrqrsK8A zsb_;lY6f^MLUKGX;wN$12?xvP4sb|$&D0Rek}(Po%5jj()Kzy87MuGH9-A%rC zr9vhtJKvt_MI-~IB6vBRgd=M-rsHI+l93d=8Q&X|WTIH;UO3lGa|B*v@%8AfeOZPV z*by<{!Qn87xcNp%AvY;1Gjm3OggPNwJiHVn06H`{-ie=(=23_ji`#{x3*+Gc3^+y1 zkdz`tuO)gL9O9>v1q6Bp7BJ4amMrVIREjk~p;90I2Jrn0PU*>K(m4p4W;2!AK+!%Q?Eql-nL^x$Xfa-H9wxYF< z*Ji=yGq8vd!q{ObK5iJaTsHu~oOs>N_BI-s5GEDLj7|<|!h=OE0w@y^AoO)2b>WPI z{~JP`2E)|@z!#2|@OrHcijHcK#~8I-j!+xpo$%%1xmAve|@^)=}KxQ6Ln87#H1CYH?Bl zLA?6dTmlb*gMf#jIaGyOj4+ba#RH-c%vch8vOEGvQbe2_Y1%Zny?toTT&z||Gz(5T z8(g7rg3y&oSw15XEqFtu3^*{+NW(=$_ZioKMbgCb4TZIsocLVG;e#fDL#Y)*u^igF zz|OB{_uB`}h1&;#z!fIg-;jg}snwBwVU!Rwa`rxixd-im5!4SI41&C33Ra2JkD`|K zjbDGcgK4^plHE>&c~4xlAUZG8{YvQU`d1cz7D~(~PK61o2@)EEV?= z-mwTT>aBR(9gx?we>S0z7G|Db%?T^@Ke6x4_Wl2%9PhSx0&l)2hdMq{KI<3Xwe zDZ~k+uwb6z!EpU3MjTmN_|mr)t=FMPFGLZYl_hNAFjEP zc20LkTgxy84^YhBI(^Pt_ju@1kW&=GwQ5emqY>%@^h9W;>gbdt{HGNMC^9L6OF%rz;j3hoTG;H8vC&W}q5Y9>H%94G@E z#sH_CBZ>&sU_54>(x53T+)#+#@<@5{MB-pqg9gQJndc*7aMi3lHP(_+tqtEFvh2QfQ;jRkJ$v7w1uLuZheHX^jq7F_ z;?jvR7AhvE`T>kuP{eLiGfi_0;yx*L(nOhR4;AW!JK0CkB5fdSQvU#Mg661DFBaWM z8_TtNp;Vu1SxF&EgFVy<>3ZuKAu%GCxa9-Ga!Sc>QnbLQ1K{EQ9+E`%Ti_8oJ(_$PRJ z=Gzzu@qAb?nuuVysZ3+|o(a8Wg zhJ+xzl)Sy_3NDofyAtD!b?v#5-n~wk^oA5ISjPZ{1O>T;kmvxwKx1|~;9DI2AiBkf zDeevXA6a_Kj)|)N0 zg+NH~;J|Ik0j2SV6+(Uko++21A@vQE#a1K=qdI`&h801Mt+dIZ&tN3NBWinzOSrp{ zAg{+Eh+%&ODR@&9`{4ZGpwpXE(^I%Myr2r>Ci(cBQ-+~C^;mroO@v8H6G)O4&4r9h zt1u;*P`wZ?ppN-tk1V(zre?mcw>5(4^%tehU8#=9i%;b-)r1qtio%S0h3kz48qsW& zYP7Bw!~6s#C`7Ek$8$xh$SCP)A~j9D4uTQG>jPZC`*Rn8*Azqq0cF=4);j=VUd{T8 zrFx~_Ncv0l%4uI1hK;aGFTJ$w(n~MR+;h)8Q-K1($)(aMYP!Sw#qbFZiMoYo6xEsL z#DR}tc|2r7jn2tYQ%3nFXtipbs6fLP_5R^a@@@30Y*sbRN~N;p^KCppeT4zQcnp1mou|N)A8vTovKB8by3LLpB8+ck$$Mr&?EN4JX{4<8uX`{)x zU5aaY!%SN^-^dwUxTeL&Ed z9cKFFY7v+d!MO-JJQj{96BI!b1_K9x5z^j5iM+CbYNLF@XD>bc!V52a^u!ZSto`IC zKLNHq2y3-Y#sB*s6xaW2U#YXtK0EjAZ+|;;_0?Ce|HoUdx<8YoCsk`TZuI~RO3sOk zpOUGGRYw^1#z&2Xbl#BCr3@CB0YB0(D8#A}MX@~7gzv~|beRw2?(+0i@?CJi2Z|*g zUOc48P0`p9Da)tQFv#t4=+xQggU(oVq*dil960RB;#_`X!ZGX*3iH6doo+gBfItv2SCS3?pP;8tM%(A~6VI z?8;=9FbSbNDTI+M*|*3rNOpsmitKB4l4qai{doW0pLhS{&=U4N;D8-}79HOpKqTR-P zJkno9LKHw{BU-*t1FO~-umd~yYW6!>=b+P(zC!r^8|gY5&^QL54yVW;J%$lLc0InB zC93uNk&;^5;oD`+AD3pN1pMa`)tXfT7W-C6e@!wE4|=FY?(U8Iyy?r<;xDV3>sqIh z)UxvH75|j^?Mh4utXXOhlM_~g(a#f-L7$Y};>nG>JfzBU3zw2iaka-TF;w!hnB8n_ zFQA5vYwBsVEGGzRz!8g(@|*#gh8sZTUKyE5kzYJ^bp>ULVowK$4eZb4!J{7>H?k#H z*e_U`y|tCIdU(g%zV8t;r^Rv)McQI@E~~UQ=LXli>Ml2AGhs_8|5CSTu?XRajrDRj z6g(?l^8CleezlygySsh&&~O+iE->`aOm&I9`-zur?JKq%CZj?RU=-WF8D4dkE2T@$ za2aJ4t@FOa!XUeGZ2UYvr^3(;*1|^mAe#_vmRE{BulB{jXPRBU#JLL;aNdBj@)o7_ zvz%%len1)ycder*^U=o;n`kx64qWV!(#zf-*QuxbbI+EbQxAsKo(Ha+V^J2{Nm}c< z?DeF%pdgct+LOI{)FXgOWC>Pe?c3)L^m#tFSY0q5@a3g5Iq$;|xysM^dy_8jjc6M} zG-R{vO^o%>qQT4#Y(%P5uPb&j6hV!nF)&;9!KB{#J+_e6iKxs|2dFvqFt&~RySN*T zV}1~}1PN$^Tbjo2Drap)O1`Bm<;t^g+5qz4pDEL?E*hE~@qSW3)DgRYn*)Xs_HJls z+HKE@2vZZ7M&&*DY_dPh;_P^v6qg@W3q=9AfWQuJGg$38QPIY2R>H)eJxz>CNdou2@q)#F)PHt~BQc~Iu)@t-8Bh4=U7Le1iY+XvGL(3N0zaOECp44*NCU<{a zue<$oyHiN;jy9uF3)i*mD}(UZtX zB$A_d_`0Jh494!jj|vmAjwZelDJa{LS+jAx`r6z9d)F<*6p7LB9xYg!j)4Yj{f_Rz zxt_$NIs(KA{zy)}Kus%bWr2wQFbK&uEA#dG9I!*5e(ZuHe|f9s_Y`Tnk9DMrj8AYw(Ybse5cqH$asC$!}h?&4LZ3oAf3Sbo|aNyS- zF^(DJY(~1My{e~xK;fGTg=@H*yzOK%VCt!We_)_FaQ>H5fnGzN<)3J8(Kex!%Q9=y z{<9&zULPiua0NL8j=}}o{qVHkH_ubRmJff335F*mQ{SUMSEsB)Ecxr2T8_ILdV5>G zxxdTm`9teBr$TbTW!n7rzwREj?0iY7cr9^3>PDZuZB1c&-xW8U>PA_end?zfof#tQ zhD!&+yn~|eV4e~OeFE)`VxK>I3C+H~o7aj6q&F){@?6=Mqgw^=>R8(o?+q(JyXQ{+3pFQ3wcg& zC^fLrwv1X$S~%>b$ggRA>kDS@ip$q2A%U>8^EX0QMvCrGwEnU?jlN*Krq*1tF3A~K z!dcs9J@G2r=n?Zz zGx0Y(@K-IsnaCJt;9>(I~7hKN;XWQ9KJ5dIt{_bKM&C!4`e1A0{ zY=~>U&)}!zdVadwxTc=DY#t>k;`;ven7?YcS^fRM+S}G{>9y?gp10hwWH5mMvtt}W znKKI0vsi|mTbCukKS6xKNqMDj2YF#4~m#4^{glhKh!tZcb=K0!%pUy>t6#BC?>Ze$R17~RNYRxhhIZBahh33Sa1uogfc-M7} z>l@9!2FBx0vKsO;`o$BILKRw%q^mPyzU&i4e5Y{KllnYIcRro93w!iQ`U2Ts zW@8_DM>-+n_3=8_wOrDsqLrv4asc%`b7R=!}6qO)XrZl(5G=%PLo|j5_LyWq~DYk@+-pED$=bjpkGC z1?*mHy4VDjK;4=q`V|^J0_F}b_E!2$=`1C0rE@BiX`Q5X56bwrOJZIlg$k>J>ZoFF z&3zLul&TV%!@1sKuf{-Jm+3y8Lh@x&zT zzZR&=e*MM6i(0JQh`Ws~wtvWP$kS#I>M`~s-WVJ|qBx=>o=c(zs(E6w&K~J5Jpj)% zi?dmZw9&v$Lrc|GJc%0qjEP-KI0NIdEA)65nXFVfRF=S)ux57pWi+#f|uezy}Yhg5nKDBnFCKFg{9GP+KMt1F*sGC-L8;?7d#hRj64 zQ7@wLvzp4e&zBZ{uCBWH-Bw7$xj0099n)44PI}QhCYBaoIq>*(L}aWx3R0AJs35a4 zBfO0&?wVBJgyWtaK19m!9P9$!JBJ1v#r>%CZvYyh7l^S zp`eg5Ue=9Z*!*_&tcE=VbWZ5fkhwnL9e8J6lIw6VE=7jj7 zuV`qzEEfac+eLqIC6P`r@U-QqnJ2oVv8{A}bb5;L3^-i_#kIf2NHG@SfF}$?mrRtO z=PC2+{aB{weA|Br0%OF(Zhxx6wt>RbhlN6^Wso0VIB)Xgc-kt9!c$|X#?Fb&@}Ft| z5l_n?{2Hz`iF_Kdh@PG_*@yevPuUwSs}@KM+#fFWaioZ=Jlgs`HpVvU_+le66b*uu zwX~Qx1EyqGE{xbeF21u7i^E!H{MtoG=Q*@nArz^T5Tz=bX)+;99P6;!`er(>V^`Ieb?EPJWQkK?DmWKz#UJ zY%*A9nycZeMI3upF%b1O-Zl7F1GoH{n!n3-jTtXvGy*hXEn@MC2180`52n-?~LEd$skww=`@%DD{zvz zbP0m$!(&&@334(stZpj87Yu$CwO~y#yTiPXw+h+2!`uPqGAG+~bN)PhvuhzO`~BXx z_{s1BbxtEAv4p{L3-y7EM}hXtN#3f`?Aque%1?P}_!$jJy=h1oje6D&b-pF>lTxe_ zX%a08p4Z|CobU7R$Eg-!N*an*6DQq%5R!go9jqOG7e`1wM?HgMdfoB3VedPe#?dQf zDA?Q|`BEl7Gejob2iYETT`i}3Fzk29A z?eZ|%Un*m5f~-H@4+>HywT4*58*(@2YXe5f0L@{+ch||iXIyJ-K_~Bh53AMH&3Z6n zR531ahV-c8Npwt>i;}Mj*mNQF*#nQm(ut?;!)&n$Y98a)jSe0V9kWyjELmVVMn+$Q zkZi+x?u1C<^E&oB>(p!?x1IPA(2khWKuu5)b4;qdO=T*Bdw#Y_Lst(2j0J(iWk)$y z#Q=-J(-wgzenR}zaR;n^Y7d?eoPFrW6X+=^G6BaFhrRU(v#HK_)e@R>ymh?r*5*5| zF0&Z3$|VqL>C6xN!#>b`F#)7|i)Wdmqd8j`sD$1$B?sM)l zhy9@WQ<}@Jl=o;cDk`>FFi(exAf@E|>gvnUgk;@?`W259tH9gT zroNVCh>B+|pJq4-4WGt#mUkWbEzf;LQ?zlc!o$T%^soo8!`v1&0eXaOz&_1T%8R#! zl|*B6;)h&e!7i5zlREw?t9n*lEJhx*ghSM{n%@~Bk8$>go1QG#G_9V$)|pR;bkh~> zOk1*|dZ84VU&pjN2(tFo802*R`{VXjsGLtB`)Sa{`J=tSV<>4Wmr)%O#92499=%-G zLpmJ{IV?x|ZVNiH(Dsjtjfkgl*%`DHAz2p3!Z@0-PsJ6`ui^xqgRV z)Djxx{iVoJ8Vl8~)uRb`mOoTSp`SrcfjR9{>OVVQ_FS zb8=%ZZDDC{FLGsbFLGgbFKsX}FgYSC9&GWp^dAV!dm%G4I;xGxw=9|ojUMluYHjFCVBW z#yB#~*ROaF-k$t9vvT=I+V8o!>-XZzK{_vv>?b=`h2oA*daRUOw-*xAP<+jh|706H zC^#GocaG>!mbIv-<)nA8p=Gqu2|T0(DELJ8T~pHhawYgcFl9G{+E}9*WI)Fo?E54KOW27%T?YV;T&oFV{_S>mGM6sxy#(J z$8E0^$z5%E>Tq;?ayX{Ubh0F3;&c^WzRA3&;AVwo!-{(M$5{%Ylmwm^i_6| zuk)5=&x0;6FYWZ7;Yomy!WQl+?Jvn@7jkMY{M0}5(5-N-a1%(MWDaLdaGnEMA*cS$ z!6lmUc&bTf`Av;`lBJ;~4|aS+_j)!7Ru^3K(q$d|EvN?e0~O!Q>Q2sA+zrhuc|!}d z*V5Hbusi)u=aspg&|xJl)WSKnoAv2Jt-$rq5?`L>CRI${)U|URUCDb?)O2*Jf*2Rk zUdq+vvt-IBkh7J@0k21dGq9z_0YIVe7W5{2LTq7Gv^E*NBa&G{56hQH$%I5x#)8D+ zhHqI$qMj6$u%)^Wa;`**&- zXa1)c81*n6U8FFgb-b+`)D*?hvjh0ua%QoNc=Z( zq5$}V{j!_3lwJRntESIx3e4ibs1ZGxK=tH6C@c9RhImIcROGXrG#g83WA=KY8g*0|zaE*Pntyo>?> zc%N!{Vu_x+E)zHp!63+nuAz{IX3&G--e7aESivZm3Zk4Bj0$Y; zWULwu(Td~W-j-lh&kF4t7$I1cr&YaOc@S9lFv)$+;;Q!@^Km2q@M*Y9tg{iEvl_4x zCfrKw*3W2f@*L5C$~S8oQu5eZ^9}M|_}W=+P4MIW{XY)h;DP8BB$QA~mElMN@S8^J zaoJ{wlE@YMSC}#rs9;)*r)*vEb4|sT>9>gZ-m&oL7TNgHcaavi zfO6`l!VON{yKUdYJ~t3#hivk+Bh}b;Dw*qU54s{G=x_ zx&&28hXJ=lJHghR@~?voreAM*KDo`|?u&*x<++F7XN1WyFl0$wnRR0hqFf<>;#qk@ zhu*|n8#sl)TmL+=#0dK_JtZpmO`?fwH(D78McQbo8#AfR#r<3F;23gx2pJg}0}Vh+&Y%%!+zER{7S~A0!o!%(0NSM-NN|UNcCTd&iPG`^n>bED zz0-d2TpKeV9xq?+5*cb_WTW4R@|uuuth1>|nO!lgs{jW{892LV4n1~EA8op_hf@e# z%MKjZUX$@t2vJdyOylK;Idu0i51UA9;Oa!|PsN&?kk+|bUpCl{YhEvRq$<(qKQdgb z)~R^SboujC`g!LY1rt}*`}$*8fYCVm8IYb7DakYYI~;4fygFr0@+Asx%Toi@e)`TC zlq}S*9x12y9gPJ=G2OA-*l+~Re<&Vw681oc9^X&<(cfV8XYw7E&aGf1ke76}ogI0{ zFgaFDrzB~NU!x@{@YNIPKWzFsTwyp z>hicp6E(q~MQ4!lnh(b=EX`!`nc5Uz_))D@@kJb7i+iD=$qb-sgbYR1oGf!l?NnL2 zd-x8FPE0^6(m!P<^R=iwr-Ht2oX@hsbd)%t=&e5FRVI`en${?VW);*ZaBh}-5K5mk zQ`K+Zx>DyrwX9r0D`$56OFTDkPfbUBr`5|DAalK=y0_5Gbd^IFB^Q~Y*$6kPf}~l9 zP&tX@J+BK~dlp=|LKiuwv3a?$49x1bDxAu8>OXHcZOp=%(o9f*!9hW!l zf3LMpB@ZNU&?`7s-YTTT>;H8q1MBQ7{=`&j;e3iG4CEHljHddy>qLev_g zZ1?YbteLEFL8bSR2)&6T5WI>2e`#ya#BCz&tuf86v}^*Kg-*EOlk z3uJWWYgrZDXQQdXYIwsk^_LsjROZvwI@eO%=fe3{SCV~C=2Irzb2^T6-fi)0RG>my zG+r)oyo}u0^!>8=4gMj~&G3b_MJW_3d+$gw_<;b&+BCq1KmpcO)R53>WEpAzw^#4^ zt985KrhL}4(L;qK1%{81v`1T1wT7!!?{o@*`I>3MU9&VXqIO+PRNA-ip3OoJp3XcJ zHFH(*OsTo0b~{moc3BcDz(;4e^4&rXLnTd9@zDk0+85QzIj+1tsr5U+cRyA?*`Tub zNAJ1gkPZYr9J!lC>md9Tpz-s=59v}urX*J$(M!AhqGAuf;~a;mFWs6~_)@RizQP?- zbvW}JwH0oo0*Fqa>k!kM!FEE!IY{k){K)W`i9+hwB9to8__^$gOS0!zm z-Zi8R$S zc(>mXaDDX)R4-0iYR2q>d-9yVhI(Xk>CaZ!)7U9l?69olGEK^ri|&5OeIojMu&N2u zWl(RM7z9yj%tnoq^vMPoj9|NJ~{{mlQ)dRR}EXa2oc_r&~Z zdK}UKpz}qX_kNZdG7ax)s70XKL%c4@$=Q_uVr`{6#_5m?d3G1gHlyAyyIk}{T1m!$<@|~HXkbOM)pC=$S z&Gy*_n}<#fm-N!QRm_(wK@VGZciF6nB%bvVM2^eg25H<-@^KN3$^xbY3ZmHi&1+t6p(Ln{-vg(W%6cD-Y><;9ee+F{r$2rb!L~?lPdDA^Zeq^ua-%F z#C*m_q$0!NZ+RQI_i}|-g@2ryK5wzbPYqPA+hC1+Uugzz;YMbT@e(?l(cV4%E4rSn z4`9tsabd#29s^O5=OvbLvOJ9HH-=Ke=hPyI!u>GQp;gm7pO|KZ;YbSX$L0Af7y%+K z-<%|0?dy9pamMQ>6lNIjrqx*Cm6$EQ_o%D#RI87W$wn+`)|{Y^D;)`27|YZC69=B> zlohJ8BUQxkOjPPGvyZ{qUpgj4`wPsISx8dnKC3Tz8=}B||0h&)bh_VZdhX>*SYYeG zJK{uVUMQzPAo0ypm8+^gZqN58H(o4WD%w)qK<3Z?Msci==x4m zGZ#!@uT}2zqelIc&d&`NEyaHjJH_0R7FR(i!A)a>BPFh%f&i%S>wA|KqpEbt{1-!n z+1hYAqAW`$WK^5q6a;V9v`5RuM75S*iJ*$0q@}GYVY53UrwP)AG4W-UAf9hD4EZ9F zJ)|amMZEMiECy?fRb5O6h6eJ~BigVQkRy}U+?K~N^#81cWYJ9(m_}pG=>)i4LUjf! z;Jn)Ae2(s7bg@%Ca^rVg6a$A-2CWz(xpwD`Y!F>JqIGyHzQ=Xpxt;yBxr|t%;xBZ!w%Q5H*A^RFL4>Fz?Ir3~ljf0iocP~0-DIte{IKHf2YN-IB79~^$ zN3Gf^IusFV;n5LGTX%ah%-!=vTaR_7XNwXn;jdMFtSG65g{GRHmPI-0FtfK#LHk1D z#y)c&8c?-)o12{u1B4W;L+jh{%+m4!MsAhg6_QIXMJmm4am&MvhCSSswF4(U6?%^c z6B3uXnEa*}4aZ)&_R9|%GA{Hw38RWMymnoZ9Lh(2(tCa2FSB)7u`3 zl^~;LM-cD9@IJB_Y6e0~|I{3mL4BZE@`wi+uQ&V3J2snA5$1fv&%WE|THDmYZ+ppQmgbn0woHyKHP$(4XGgAUYm!a4~`XtxYHU z0sC+Ujp!Cw$(9yRL|a)zJwMKG1e!h_1gL~!b;@AAA4%n`Az zuV!=}kD2chVK?!j3}f(-P;ElbM21(^&`qa- z%(09U#e4KVEk4+>FRdFyC7wKWbbiP8Hv0F3-9urHqS4^;$md2*0-d!6z16~Pa&9R*hZE*XL#;_o^@bFDTo%;AIVy}^<`NFhZn-QwvPHa-U z3P!K+cz9nwx?Vdz4@6Mg4Lu5g`tp&Z9mtGm_cDaiz0=8nAqvenFstg~N`d2kLlbFW z%9+{jJ}E*~BcYT6ONU@LN1?o3$&7wSiCzJkgl+>_syBSwpU*Z&%|&T>e#k`21Na1^ z()pXPAA0vR$yZ}3p6z?K-6$Szu}fQdF!N$9L9ogXX*KejrWS3E&|53C{{5g`FZb&_ z8Lu|*7w&c3q+%$tpJXwPegu%KGK7<#2~!vt8d6%veiqS5udV+v_eP5LlbD>^$E#BR zb_aIQ_CEI2K@ykbXP1umLH8ggn-X$OT{DAe{CjlWe7}N(1y}8^PwCHlO0BA-9rIU5 zeeDOuL=W$5BoA0xsy6v%*P7_C`&EvQS7rNB9iP|iE1%CP zGH6_-4=cqEs&baugg|SWJdRwR-2MFP!PBdkv+q7n2mM1`g$2N0(B|Ce-%yNWx!G5# zv%%>&nGHVyDoJmQppnAqaic3ElwO85%e#a_K{E;JxM(hdA`Y_eQ9g?=zQ$r7o7u_|4UUW6K#=jy^(S@?lI#vP&6n$nGR=x z8ni)&V}bB~jdad%O@B6Y7B`wSrAp~YE+(;=F)XaB{vhxJPn%R4CmrU!f_A|9<4=^q z$L-#2LDs)N-tR#iEx*g+-ph-iyRSZHis0VJ4BJ1X zNTFspDY;wFTz}cIDmn(nVF9+51W?DTDDK2Q_y(AgT%E)XTpgHaY(d0b)@4JH()ocNFLA+IoTZ7Yg*ZMdREx-C*ZHJ+Jr1=GCDzuC z*|>STifbN~qv_b652uMMetUi#XM&D?PZ=yTO8)qc%;Q-&Su7nKEfimdID>ED%9RW-%$NpZ_!yK$jAEtgJX#+# z@>|EH`3H1W-v8*aWtPZKIXLa>F_SP_z=@rNn z4_E`%XWGH25$Wt>D-le^w)iY-guOg?L(DAPAkLbQ(Mj{@ad+wvQC~1&t@UE!OUu6{ z!~@#i)|oy?l9Bu(Tzl-N7sePZB5lw$m)I^+tv}6o>cT4-Mx%NPPD5r5GGxZ`_J60@ z5!4;k@B#KZsJ75AZ|KZ4qFfGoCW70yCojU*dS-576b7znGSoDhsC9LKV+C9iuDR*3 zTXve*@9s!t$CcltSy1aeGXyASrqahGka-Kd06uHr{W19Yv;n6CV2Y%L+$;iQ5G!aj zv)Gg=9Yw?XTHsqj4>LI?;LvDjIb<~cGl6`_-NZ@jV=$=yfpW3 zcUtj!d9HcVS#H1eXv6$)_vTFlN9P@@^K(v&_2v29vTp{$=`)lNhPIrBG?o(J6|Ex+ zMX}m@>L_;2RY2jp1r>(3`!2|iTc|=oabWQ%`dHhhSHGyC?h#9V`q9PiU zh{Y{Ri~Pza_DU7D$>066klp(T`<2l*c2%Ua?ft7s#Yg6jwgLmKKMQ-Z_&Tb-#Ms|0 z>YDHc*Y@7kbn|BmEwlF?CykSG(u+CxuTqkMiP{WsxH~r!oMcTv1HNstQ3!0SSHJOw z)M^gaWBC#B1Di!~h7k{)zz^7n9kga;6GM@7WTKfj`b1%mmh>J3A3@5f$A#zj+bM#H?51PaAlbIwN-@cjOpG><;iR8;2k|by?c38N}tE5d-dMw z#geDvM2YWmCuT-5@mK8ag3~4Ozm3LFIIhlF)Y~v8DPAVO6kysirRhm7mZy{RM+Za) z>IO40?U%#5`6D#5IQ6PF)081_YdMBFsjPdqL}Hmb3*CHEg*QLq1?Up~Eg}AhZ9BBS zLMq3%z5R{_KYSRY4c}i0%?##OIVDd^{K{||(>G0uWxuVXA^$O&{#He1>ebgYO4~Um zm`*Um7Rd*6K(Hj$rji@{ZsGequoeA)>(=F;PuOP>JE zBeKhl3x;`fK=vTgThnoi0n#;kZ)18~!7l*36GXdGkC;(N+EPtYHNC+QDC=T_vUJY! z9-tAeYobZO5aXiLub5zv0e7Qua8T(850H+;5-4n*#hO@FGuvMKuq*wR!gP*c7ae7U zTdWn0&hX^H`AOwcgc6C0 zs%=}lOsLW0L{8Vrert_Ooug*&O;vBc?+m^@iDZU&$1Bfwp0Ut&>sI6*CUt_KSADbF zXX?dbe|o`VLGw%ags2xeIEBScckbSEQxA`6b|d6hpw{P zi9NaRad9E1kZIsOO)uH7I!eza`bquuF5zb_HDu$jr4Da-IB=}VN&9UT) zN3wZQ&prqqwa+Mc>Of1ncO^dUZ^Ow%@xifCv@Q|Two;k@vd*;0+5F#k6#0nlCpyz6 z@mwV*RDUI;7sl}7AB;iQ^k795arzzKFB6IDPKA$E@ze?p{6W0#y(;H(NhS5tJZ8JS zUQ7qLXj1@qcUqG@%8JV)n0qac7qAjps|(32oY2}?xDhjnyrDh90z92*W)v_!n(s^B zYVM1&PA{c&sw}XJ!cW=u4QMW-n-{!Iw%7c?xW&!rI*uN_nTRmD0H~|iv8mbr|Y~?&^^Fp5Z0eLi3iyi z4InMBpgdYKmT1#)Y&3AajA{uatA?}7HEql|_W#Nk8D+)jYL*?m2X~J%GH5{5u~0e; zK#mAfui@ITb=e||%`RJXzDW)4a9)kISPCt&&Q7Mz=9uG~#E%CVy`dOtW6yLk>(KST z9(n+eDP*UNMB(Ff(z3QHv!{GoH;bO;6EZ_U{xzIW5(g=1>w6 z&I7S0qe!>{N8^?yuvkn$Rs6nt@!_0Gu6q)mJn?FSvd8030%ov6nF=Oj)9XoA(%S-b zk6K#TTd7UL>>J?N@MrNMJ}sx(SwqCRO#(FPfotc3k>07-hw#X^tgMOQ6AWPwwz{)M z&B@Eivi^$YRvVr9v>YDY2kuji*lI)f-2>{g$jo?Zq*+z#U;Nu0U@_Yb%6bc_h}loV z@yA}*+l{7aq?@`$291RF^t)P47Y|+HaD|bfn{sqvk_iOHF=3gAE~Xj~__dDq0M&dY zorgMG1&n$-`di(XHOp;-Yg1bLW!kp5gocEX+K@V~SGO!H1l?6N+2;+HjPO&c;qaNd zY~fMF3p-UcCcSIm`1p|o#kmiU8OW>_SLG8`F6)|stDba?FP0mU3-Bvo{Sd=9?9(cS zuj67hH6o_wurtvqOpCO;P9-scI6DBORwaoe*p(Wd+=4|V#e`GPv=ax2h9d+GN-G}c z-HmKMG%Y2@F-o=s5lqt8Qgs5}zX`uWBjrddOQnX}xWUav(O`0GoO>!VlL_8uc(gUJ zod-@^tkNDLkw&0;ruvoSW& z_6>CYtPV*xw$wi{)M==dRDru{m%W~f5_)qiRQb;tsRg11+*FgKbJ0YCZ!Q>PB(+Dc}F;hLMAFRqjx!;7x}-}7vLI&G_SROIn>Dj3`oLHul;x36Xi&FF&-uF> zO`=0ZTU&Oc=5wdL#Zo^iShPQVUeGgfYVZ7~t>}vZ@#fB(yOv^ivYHz1pK z2pR;hkii(Q##5J|(JtNBCE=13XO+X3p3~$09R`DUoW98vMCzq$Z3tnqCO6{0+j=>& z+&xu0{M~RXCc=1rm(!tYjA|~4vUHq!B*57Gj+%wiFXb^@|0|EFWusCd?@ZR*ey-)ySs#6$jI}`-S3S+89&9MGXD8#Srv3SEl(ZS ziiMgoQ$eENzRC!>WqN`Hwj6*vM}z4lA7)QvHPIvrdeDA(a1vkv7;;(1>l#=D;zESS zjK_m8+D3L}@(P)*?;jX+tp`ZT(bptwEfMnG%ERYqGL_Pmzek&gVmhA9vEBNf-%dL} zia^>^B?Qn#G9jR)@j1kVA%~^?Wg(XQ+Lo|T7Csqt8WcOYqpLi*ba{DkQhjM5{2pCO zo~<3JB}nd*riNFwr@}3WO-4jE^liFNgvZG`NmP_e0smm&yb?po=xoUn?vykLZZJ*{ zZYa!f2c$}VMOZ4GoCPE|h7o4r0ZI1r($J!L86_j7NW7}X^qlfFO74}dPjOy`a26ZI>fQtLN6z9bUfv5>Un5l=A$E(iN)lgXD z9b-6w@rytISw>dx(nq+2WBFD-VioS|iqTWx%x6ON|ND;`SHw28lD=Uhrme#a+!VzD`)E3(wqUa55{=BLa+K_#_pht zgfK(8lFf=}YiG1Gi-e+?1eLL*>7c~xB#7!1hB3*Mb$~1lSfB(t`5~crq@W;GK7>-3 zXr4!i!3HA)Ex;4iyK(H+Uy^qe2bm@~?TqUIC|7R-3ji>gHk3qV(NA2B{wifYgVPi|N`j z?2_9`%%zs)&lIl83{G((eafnuP&$E+B_3XGyIp>!2f0q+Rc55FMaD44pbe=#ovnTg z$akw+{&Lh>jl8%1TuVEqL->@WGBj19i-R6vqz!xxBwhV>QaPYd3?%=7pm~XoA$-Z9lCm6z`P}l#^Z%$idJY)1peY^Ke@Z}m3q~6B9 zGPm%ThU@^LAt|D??5cxo^h5dDub8I+3}RClHqDqe>M=%^338~ZQpg9A8yn1z0YM9= z7JpXccwN^-RPIUjGOOv?$bA9_TmnupMhozVQeyF9Efln zqJfE~`)j8~pm2i1xRJVv`K*wv9X1codk?H1c6{HI*A+N;cQ&Kat9TBrt5}{Kpn2M)|&3&>4}Ui3=a&K|MxOW?`td zeBi(42n8?+Lj0kyW%t#>5Hrj7>+21Q3)cgWAJ246U$^dB@93SyRMDo(YW&23X6OpZ z&^*hzTCdlZE-#MbHE&*wF9T#=AL9&HGsv{No~%9|pG!xUrf|n+aK|T>eI!K)<&c*^ zrO;y%lBoi+gQ4$HI4c$5Ws4&=GL}AWty85b=u~M^MN$bZfu_%r>Lul!68gcf`1P)Z zzxBh=viw2Nhy704mL}OvS#>NeK!VVK`x-V5BZgqKDx!+&FCOe_d|q5`JZ=_O8w*oD}PftW(XqwomAc>oMG?FMX2j1(jZCNY>8clU=pAeU^PMt zw9Pd<_dF{T-m6x;Sq;RBMuy}=62>f&cYLbiZ+I~i@?g9?j>FQ7thw=&-S~8zlk6rh}lpyA`~?e zt7ZkEL8#eUt=O~n?2=eDqP4f$d(_@-t)kYo>CoDvXmx0-gWKP|_jAu*a6a#Qp7T8C zdEdi4Bps<;EYy!c4p<=eVU&<-v!PL6mE@cP^-AEF7%79ZA>b8|k%BI66xR#HMlA$@ z^hG`xC|F*@uwi4snut;zw+?Yuyc>?g$SG^XlPlmdNi{2)ZtT&XwZu$zr}{hjg7Kgv zgsugViOFX()WbMSOyWxVE&7IkycEt0QvuQD!Z5(1!FrVfL(goqkCjO~$<#>N!~dag zb^t=SU@#xF0^|(uM%MQLJmatBI>!OJcG2@1sttfqchAs0IRu^LjIxsikA<82h~fOU ztn$^Km`ASGh1)7C6^89R&i$Jc?+d(+ubj_PTx+QCiCuP8gh(J%t5I?$tKTj@mL0^;UA6@5GX8$O?&76MF%6Usvms23+)l*b=RlFE1tUfdZV zbM^PNFd>lsXS1NJ$v`5rQ7|2S4O8pulFjt`QU){tR> z`tT)2Zdy9a;T<%tNqLdh_1({2!Cg-yJtlF*qZwUD(y8t$dUw&;v2UI4 zEscv42fZ^gbPKB z?FRsWlC;4H6r?Eiw3`Yr{4v}{#fcu~Y%}HRMjQ^amu(?I?i z^$nk}^r-BH89*ESJZ+rIX*hm78fL6ehV%5KK0;Cg;quZqK9jNRFen)r=p^;v(kEqz z0#i_eXtIwQ8y?PjB}J(8k^SUtS2x4-y+kdas%=(nsft8{f;mK^XkPyf@wc0qA5Tx} zLw+6q={b!3W+o7%>}q%V|M;;TkPcn~0Ps6}k#7JH!z4oD2mLeLK`9%zHAvU~mi7`f ztoef*z@Eq=V}za6zAx%BF(FzwLe0oSgB<9`oJf5kCArjdkI%SJ=R($)&T@5M3g}dK z(HY6Rm^WLelp))Q9Go0$tI10=p2_uil4<0HJQP}U%V~BTHkL_vmPm4$w%b-Muv2;) za9aA9ymd<}A(2q~V*%&&YbNcjQ?Fm)MDNbWqUF=mkL;yIeZy?0jan-J%5`tD?-UzZ~*&5(|#4qSyr7G5sz)z z)@g^gvoUMSIQoNF1Qj=WUc4g66JR+P;tH|)AIIL-FIhLvZc0`?Xs)QJ8bewRcZ91J z{1H7kX&AVwQSfv7i{<*!!R*Pch2}q|*PfhhQxhVld|LC>3eQu%{LOT(z86^({)eoK z2S7Gk4%VwrT-QpR4mjw=-H>oQ1?LPDf{P)H3$$yxy+-%iuTHAxGR=s_Hj#0@L8nCN(^7LM#YQuzgbKZ;Hm0x%?%pW}fuL$n>4V@a2|WmY5lhEx&Y zs3DX>HZLprGc2)>p)Gkk%VQJ?BWsC{bRflD$2H}GY~LF2tGEs4G%*-kaX2c9+oaHk zwglS4O`V27dfIppnX;0k8dc6F86qu}eF>Dx8A79FuxgZP%5YJOsZ;tj zRQ_w_&2hA+kLf4cA5HUbMQ+Bg|MhI>Nn2K$A9(tgh25{ygY`W3I;Sj!8wb`JiKuiC zI`!@vt-U@X3ULZ~UL0pt;Um^-xd4 z1NJJ9S+SaZ_YqL>P$uK3SoyHJAFd|QWnL6!hv56;p{s zaEOtepu7&z&!q5$+K^B_$U+gw#!#|A^9X`G_EcMYYuOMcSA_k$|-+wkcgUGR=dP5!8sf z2}9r_M(9B+k}t*6#){!dR5q3#DmG|XD$?m0yQl@+RkXXdBDn*I@vhO#%5QRM8GrZe z#0AA3N?uYD7P@qD{FUY9--G{2f`-q`CS1GY#%`64h~YL$L_{)ft%I}L%*joMQAR?4 z&BR_>g_p5?L~ILOQZD(63acCreSkz(rKZsv(74pBNHdY+Zv0&Lf*f^w)r75Zx~T*i zE<@SoX3jHMXCXHSQ@>I(BQd$zK27{aVZ*G4hh%UBQ7_gcg4j^hS8HCSFvm=D86tK* zZ-{o-t)@nCv{O5oBaHRMs0C1RFK?c*hy37mSWujiMgHYij|ALIq2?+duNahBE>@X3 zA7>f`JFw7ZtQIBoud6w=G{!gEIVeu>-W9zz)-IPmHYs%)Vi>&4?NdL0pMpbj`ZS7us(W@hFlQAVMd}W zvbprw73gE?v*cG6j7k-ftQ0?Agipy3I>*CZAT5ypo#& znnL6kdh-PP>lThsQIebS_NjTXH9X7`cE(a&EAt5|GmlfkRk_i=@{%K>r?uxuin1cAnf;Z5g{;cSzMl;t@d(3 zBgNNagxgbeFsHxVn8Z!5MfGFm6C)?hS2o2w`B&h_zh1|0NLkQa-S3&0NOa!#MXcg2 zwHKq!no%qg!|Zvqqy+4=F|o^mN(_KnIk_5l;)sAG){PSArd*T)=a034rL#IbPt{_i zzsSv2l^mc;oVwnbZ0dA9w-6l*Bk|fph;YQzuEPlHk0ewt7Ues@1+^qYOxHBO^^C7= zE`lF~!8OTTGo#Uol<3G9bY$r$FmNu-16Ry_Xe(@YfAwaN!TY-(1G{yiBO>Ovw>`Os z@08GbCrxQGm)@_Fv{E@Fd{;BCC_9DQDQT5O@~X*Nq{{ty*Zk^VH~CHi&V9AP6(rAF z8?bEs_!V#=@~#Dw1OUK))18@MIVt0U;xWDQ>U?*28tk=tqo6+Qqx1lcvLT>S}!JkMOHOvfL zM7tO+<2rzMUl=gj>ZAZXccg7hvldd0xy0|MVhbmylp-2TZcgOaaN=zElCS=P1Su&G z?dPJ0%dhA~@&-_n3;RUfkIVgC)^bocB}a1PFj_T(Oon)LuOmQvuM9_1w}RN8ki=|5 z?W0L9l-5IFT3F1JN`T3uXHgX)|yIo&; zhF(w=8JHqamGVD|*Um2#OUtb{xWsQ~#Ud=ccY}M**FL`Fjy4AeDP8>d=en5$waITNFLX7iEj-Jc7Mj5z(<9 z&ns_dxnAiLUY1b#)FLW{p3$|M@vj0u@IsllNeWkDv;D^x|7q!>xnDJYE0Emel@FA$ zg|dC4IH?QrR(y(Yc5q}R*%lp~FDF*bN47Fd%oYBSk0!;U8(No&ex9<)11XpX!EZ`4!+Qvo|wUI!uQj6K`;22LI41A(tL4UQ`%7u zgeU|vGt!MYb+KEVYBzHvU^_|s|C?4hFB;7IQGnq}_khPv07vhz@^L$bjiPz z{I(<10s|FE`P`pv8$0c+&OGWNPyo%46Zl-YygnPet}y>WlZ(CkHsPyzP0sja;Fb}o zzIYoQ!q@sU*SjvK)#Y{j!46_2Y>tL?mT>4TWbEEszIOWcTjj|+%R76KE5P}mNUP$o zsF7yfE{bwQzJmJH}6bwr#SQ0v2jNX*p1J_-vQN+I|9f=Dnt zycYsWY?x@K0U6>M%%8t>3kAkr^XB@}#EkvdgOE!-4Ocfj`X0G#01+7+w37F83rq{GEpR+|_WIw_gUj zhL7t{tn3|Cj`!fFdz)s`=C>vr`S$m##81CAhs{j9u44w6bjz*dMM#R~_SHh{)@ZSS}_*z`qF3$;-^Uy-eQ4>G!9$NjcgM04eySN>PB_Zq}adKYc_*o>WHX_i5 zuzr=5zm7}315TMPsus*ox_y+L$a-DLmg_oRtb_;JY04lX`NVquus43Fmsj|^5t@$$ zj$wLKdyV%^Kxv=lJ7NrCu$iUQ|7jJ_DQ%b=yf-Q?Y3kEqYS~^8ZrdrHT^F3G@pq&< zK?eMVPW4A-$wCSGjsd4qS8s$*~6#*iT6Z6>@iSr zHhc>J7y|d8u4`+a$B!I|zF{jLT)`ZU4x++z@F*m;kG*&x)b&1H6;45eDzda^Qu*$xg`?ksPDg*nh$H(TNhE`SZpCk|7 zo$dg)PVP$Icce~@Fo1;+{+;YJ-dF}PXznM{00NNUVmh;J>~{}CrGYJEXq4Q6ApoRL zKT~;YHGs}M5^%$5q%)7kGDtSkkC72#@XA9df+dpEG2Wj3dB!zV@j4wJ90Bkqu}H8O ztHAHhIT@qjXG4F}X##G(AOt5F0*0F$#2afy!Rz@7gGG6ll<*fR#w&&R#-_#JlEy(9 z6VNbDzI85B3Ld$Gig>CFEUg4+0{Hgu-$pT_>$E}wETY)yxc4n2%_Ne8ej<7x3$`D~ zuKE1*_f&^F>VB##{%PL$8{db6gkp1{60z8E&Q0w==9s^5IsH)nmxepn-z$x&tpN0* z2z(SCC%{Ib$O<9Ba5cTooVP{Ev<97@n83bBdKjMzMvRZp;`VK9lT0mYCOVT%nHgjk z5XjC2pc3p37c<^!E*(Ia=ZCy{b+sDHYpm=Lr=Fp4C;@vHA{{-FK#e%V(NIb(;(TF4 z1IuWe7MJz&2Z{KFZB}>92&m6$-79Dlzxd|tu($Li%D_t`y_}9SUE!Mc-xPm;|NLB- z&HUg}{F8Pb<5|Hh^}%rA2iyO-z}a3FSaT#z%78=TA@Ho%SK@g)Ql;0RRxov-i$9{j~z22QzZp zncH~+z^qqS*MS;fEs(4yjeV=tiuDXC=d+qdb3XqgC=u1P&&xqBaqB{G)9X+gz6TLA z36-*_WakY1f)!IYGYg!-N;Ih|L)WC`X@Vu!7RURNoO8|K4;p<`xx?W=<({WVZqIG4{!EZYVE^Pf8k0B05C=J=5C+&YS3D# z>VuW=DA1YyfD_>?K&qJjl``L!OlTA9EMCEVX`u3i2c+c*Ry4xzh+fuQu+Pyq9%l{A zrp4sNuSnO-lqQdB8;fMiO84G77bz}%KmQ@Aj+f|bhbXBr9QQippCKJ`U)IlSS1fs~ zlD*vU1y_3C-PY1uCe=yeyZzY1q1YCySic*j#t?{k-o@7w87933?@C z!ia$~5>JXrZdG8QdEacieT4G9*VDJyR%^#?-Z~@i)}4t1#~gjw_q=RjcoU;BFELrG zB#}^byRLFSk=;;VzS`^No7^_F^`y#Imu2s+j(aOCtYZk3Rv#A-`e-}=PU|6%HYGUL zG9wuh)U4R2MNU{5)O5V1lL5x$kS0+!mhOLPM=kDpH=F#><3@APZ!|#J&&x!WQAT1E z?>vpeai#PqBYW<}IS4Tp;-_qjQ|0>;x%HwvN?Yum%X3tk^3hyIMXRpd=_xmmW&=Er zqia8BBqW_6Gu^PAp~-b#B2l~2RCeDcL=xmGDde{MBTCIg{v1*gYn>28P zA)Ld4t1L3&KPxQ}Yeskcn6Q+hDELm1{U}ihtyFg=85{#hPqRb8x`oXA@%#o+wVMuH zwV$o_LM@2-R~|%H%S0V@pQ~$lpZ$$LUOuj-{%Rqy5$%5CWcG}64{uQqVx2 z#0;wN#FWB{$@Yh(|Iq3PRvW{ss$k3UoLcLJ-9;M4*M`Q^>JD?#KKyqc~7R=$z(% zk>ng+?*GL3h(1X2bF`|%+>B4C-%}`k$c_Mb*l-BUCorWlUPGTlzC3{Zf35cr|bCq{NMf+RGBuP z{{;XB0_{~VhJw$=cLkjU#{}gKByFI--WCta{%JJah|Ejx6YoT97-KDuA|*vR`E%nj z{$iX_LDsLUKz-(l@cyxIaRIa2;Q`HN{VC5l)JwmPbj{q@Z*ke%Yvrpe_}r8%@-w1s znFv7`1P~@QwaEKY>g=|bbTxluAWc!UICDQWE)^GFOdsOO~YjbyuxozLl7yyqN0h>Ynn=JF(4i$7)Z| z6(n~rWeuJ9rhE|w1d|K5SAU)Pvy<~XwkS9XNbBL4Q$({f2pS2CGBw!u?@{nose?7O z7a5}qF6wsD>z5jTjgbD?@gae>U-Uk^RF2ubdg(g- z1rlFU<2xJ))qKFnhhbkqvmSZasE^k{kW(LoZPP_!mlroBN#Z%#UiWM#n(6 zpIiDjJK+x?k=6&8i>#UlLP?Jet6i64@Z9La3 zh3a^2KBKbYho1Ee-nF~^1$TsyZ7~&7>q63^0!t?qXe+Y5R6)Umgwb!YDJ?^B*xz}! z?s<(f&q;OLoVGiW-1hc1;g+aiY@w2g22@AlfMr+R!m{@2zZ4$#o9IX&T$=22?`<}y zz0ezZnWy(g{yVtC`^8W|_Ya4Ucc-Wfz?(NZJGFF_L3vFXU9FKG5|uu)%fJW zAo#~etiHh&0-jSgPbA}ByqpiCkE>y)=WOb`k=qA}>w5@G72|g*8DwVWDTaHyrqkF* zj_Ptx;<@_~TRhQ}T0&RRYe#pzr*9S?jhW{TNomzJcZ4r>geyAUaNN(kW=l*}ylv)O_xYT# zb)eSnyieor=C9$WVUy2&PPwHl;8#a~q*f39dV>d&0RVvH`j%{azkj7*wPBXiuqCEf zi;>W{^UpBOF->{W9c_S;g^HHI5oU-KPYhVLOLopmYl1eHp2tTls~} z)v0-m?$zg9uk1w%<42n35@yPX+Bd3zSqTX0xJP znb`qr(X4bj1Wn##JHEEHVYX)=O0wzes%tawzT$Try(XQoHR$Z0%CqKU^e=UT7yd%F zUPZ2Qd%r8WN{ZGWeiHvNdH%GT;p#dH0KrIHtm=^slsFXGqgww3HH#;8IlSkeiem+w zK#Hb&?s82TOt0FVBij(-npY08{Pc$!s+L>WruCU5>BT~_K4Z{H9J(wJCt?Io(cnkO zPH~tbfjDzBs!l?B8tO4Gcym8pYf8%y6FAde_vy)T@P`SFJt_Xm!~nbOEgxZ7^{D1Ll)%18wO*6ZUkz^zywt!9h!*NcU+R=iC3VY*%{ zYx;V&Lz`!B->@=R&ULK(gUhlXD|IoH@2SsOx6mnSFo)(m4MtyJfokc69T~hIs=3RK za%oxqgsIk&;{Ml^VUUA(yuVXb4B&h|m^&bM=8@;4n6S(|GR91ylnI_Fx3s95fB)+` z&Vf{AC)>E<>iY@mz-jE=C9Tp*y`WXZ4uwQ*uT0aWOL3@@jG=Onhs9k#wOV>@FLb8g z2y@1TZWPNAp*&Ri=cRd%Hk2MxCq_JqqB1me&U23CE%~paXI$9={4r&(VA>b7$jQ!| zWmYM}=DYdgvZ!Y^pU3{S>t7>)yeiTkE!uB8*fun%Y?JrdVt>)&vYBi6FMRGrffgmK zCTtcC@@hmHJ0N0#763KJW>u@!{y{&gqB^*h!Dv_erF`b~T!kD5s>}Pl7X%i>Hu8Z2qf{WzRPEe!bCRhM{G_ z@aG562;R$ecLzr-OIcUm#8jF%O210V7?v5gu3qkq7nwi1m)VeontH>nIU;f8`Xkqr zs!@_FiKsA`_%C!J!DuiV?ILbUrTKlvFT(zD)Q3$e`%9(Vl3lD$2+x$H7|c$GIycbMJ-J6%g)^DxI)Xn zn;)8crbvQxCy5rmlhU!ieO_mCA@2K{A3-r9Zl`Y}6Ehcq3yNO9T=%YwvyLm!40F^` zUGtc(s2u;cW%Q28`OO0piJX5any-9g%rNAyI{>K0M(d>oqVkZD_^~BlqoEw7+ zfTV8f{}J7RQPHAs#Ba*7(sZB#WvPS@->P&CVNtcP%JwX-=ZzVjAl{&|6bmU?jo|N@ za-gGRFhKJwsMW+7hF8up811(vc8t(Tft{wgM@eXXdoJ2^mvtiea6@{7%&1D8ZfA%iz53jY9`v)a3r8jyN)pn}66ayJ%?o@##6~Wf|Pt z*Z!}+wYWtL@VX4C`?!j?T{>;dc&t=@=soCd(02Du>=rO_zrgo{SUIanCfG&xxB0G~ z8IVt#qGCOWFNzOABh!E!SCk&!VRS_d1yST>XNQkFNXe*3Kj;@BLlpNjW1ud?f33tF zT2bGEk61(B!YpVEq=yrO<7#AuQdT%quUO<9sL*&{__~Bctf0d`S zLNZBA7?7aYP51Q)3$e$73Yj=p=Q{7B;(qh(SKnJe`jLqa9PG@o)i-BoMcau5+LtX7 zzd2nEv^t|aQ<|;qg^!@Eb=5re8j0yV)9%1%p0}v?eunr3)s5S_o?q=C#2I&Pu{(Yq zyey0dm`uGvN|%B@t*%kbIH4vc6s{E#9V6IE|I$X0Z4AUedyTJm>QB=e-}*nLeTK48 zer@_MeXl*z8;x{dA4CiuYyTB;V=C2R6FudHjHJ|0xekBSq_4kLi>Cz|!Ptbg9UI?34dv)~Xd%~OL@4q)T@0^}1 zZBgj#y88V5>OnK_ssGZ3k0dAVTl>N1KdqC6066ng!ZswV)f?fL+P?;9f8*`*Y8}Ke>RR?k;Tnx{@U?fd*R@E+g;SV&+)7_ z(qzBSKJ6(L1mEL+gA`_B(9BwQ`j;Rpc+xCnT^!W^0s{aNHvlt0%)i8L`N-*lIi(3l zfV6DWL_=BS!joLWTj`6&m3{UD&PT(gpie_yugee6%9i(5kxh9SMZl--i|4vB+Vx-m zce0mv1A|xBCoY83U*g{vS{BTXPtJz(g<0i4C`VaBQKi;*ppeEs&A$6&lTYjG zFg6|*VrE)DNQcr#G3@PJ1xGjF2q+Z(aAX5Bo@u@y-+nxm*e9Wi9tqJT2!)PM zC4Ftr;J(MIahNCCxK|FObaYaE8SlF!j(6UCS%tZv62@JX+jM44Q#gF}_+;m&R!Fw9 zqI-gsl)LxSU3h7j($=WndH1T_fPJPikvsLNXA7FG=Ur(+Zth$K*>S^si8n8q-Oljn zyDC6V|I{m4Spbw8nMoBYJnSCqt*(Lgab32ndX)Db`mvJk>uGazX{(S? zjb(V5UkG?y?n0t``?nTl8Rzk$w5L{7UxT;)~icJR)|(iOo;qAHy`(}GmoCu-5T`$XmzwK z7b3Ip8Zb9iF-m{4^CVf9O`eCpH|zQP!!K>P>@kn3q`afLIFS$5L*oIhUxGh|tB)^U zYXX4R$4OE{lX%{JH?nMF{r#;X7%x_m+{aF(=^_-e<{%E!R7!8(NHYh$g{2+_E1-bp zR2t2c)tg9(WJ0x~5e!j9afnNyQyKCY@DXi%oi*?^RiOe7U;&EwEcng&q6RUp&;dMlJs!r$YSo-@S*}iFB`zX!yG8&`F2an!{rmd~>H~74R$rOq&(7#&37(s}4 z25%bcn#)Rg{Xt`7Dcwi%qSS!daJBQHsQDA33v^b-weTjUVYU zEi2aR`YaoqhTQma3jbtn$YpTW>-hoDy~X;r%!nu+BG{Oth6kwyTL zQ1l|1KbVxA6{DaRL?l43@EW_!Tdr}6iow;8mZ2aqfIWa!C@*8gGEzyC^CVXi8=4%i zHqZ-zVqf#(rcjZ52nbGl9EC4jq@LW{vPv=3IhXBxqZ}bEF2xD-?LhL3ewt#0jV>kb zvemgsFq&o0A&jE!S8-sGb6ivL5vamMk?}3_`fE)Yw+?TmT(p1#uSz4Ypff2C;AJWZ z4g(Va0NC!?>xueSAz5J&D;-mR8776SgkYfTR8|?oWA(xj3Zv$lU!X&(jSjcMpYqJS zgb_+yDnJhGPI21xt8u(qs-@oj5?-a2$VW^89o7J)Xwc1*$fg9m-;zs`iAzARo zsovz?V{PBf-Q6#LA!Jr2rC`*s6uBT({^HHUvxxmqI*i1tnR^c;cy#Z}Un($dIg3b2 z_QSZM>XZpu0}UHEtA%O>eqTJk*O$bV&wW$;7T2iMy**Dd7692C=k2*Hit`F1?Ayib zsk&?6?5P1X*7#1KuKlVn{*PfyvIss5v|~<2u;Kb66Eb>uAW_q(QVIGqxEKOJ;|53Q z&NWykeWmF2`XbguCGF!y9iaba;VRskZrkW@V}k*s!wmsPO`0*eMSyN^>_-AcU z?4mhj{3xU^!?LASw0fjNvJb&R#*jA{hFEvsl|;k{U|}f?kRXdiUKaUJ59fp3t#OW5 zzrM6#f;To5o^1(BTsMj`GuCDM+P2}6r|1yOE8{=mf$RUP&uAxvsIk7 z=kxJl0D8!2W-n^8Fqg*=Q&hM2_Di}vAAgYW;wAL{dL`l0I9I5ky4-Q*vt3C!W?J7D zOa>3fKyY>rp@>ANh;)7|R1!b7YetGa+_^0=NKiHau{(ubG1os8nhU0@H6@^@?wMIf z5lNTFqN&fn@f7^fj2zGL)wv#*!or%_{(wFUr7jQ(J%dlXC>6k#3O*|$jZ6x#rKp*B z@J_mDL}F|~9BPp)i>+2vL^)t+84SXuar+4?hcQ4e08p!t%o{Nxr)lTGa9w7KBeRJS z4==12RWV>mla`_4;RU}WsIn;bgq1Q$7BE#B1Ra>>G$Hn&p#a5L1b!*ri);;*W&?xO z<2g~DOOyX^+H>&KSV@fmH9@@9N_ zOZ7irb};DF6Z`{5{9{}I7T@x%6!Wep2*rOfseDwuV{xAgk@ItLQ8?WrFsB)5lp+MiAo$P%+}*zSX=V$g9&DwM0l?_T>e@cgJuwckK0 zHa*8P3$HC{rT_Y>e;f}5>YX8G`)ToGbUy3o#;u%!t*NJ&pLGuX70%z5fAB341ex1_ zM^zGKOpXO;HnLW)fuw-m7f!4YBUxgK7eqBy)^RuHIPWJ7%^xb_XKxdFxW?w3A)|3i zEbz#;cPTDGAgv$E^jP-2K5@usx2^ixwK1kKyW(uTXMq{IwEluzh21;-kNmY>o>mu1 z4>f%|Q>s#r+QeG8VN|*hdSk*O|!6n3yaS+_l((70BqtqK1 z8xD-KtC*Uip5i^Da>M{Dwt+W#gWja{tOi z7FwE*Tn1)?GQ@rOo{_T$x5~Pm{elBS(h7}pyw0J%IfcpZugH^U}NAD5; z$A(-v=8XSlk71otugqis1O|NH6Q&QD@PLr{wRu~p0k-GW_0^cSGL7xuNN`AQ+~J;a zpVjAPh6j$p(U9T*rvBe{=s)d5$)%DG&V9nxw$LlGFv3Jhik! zM{8uCxKP$Me`?L7`P0*Ub5VUO)ikNck3L0rF-&f}$E`af!{sHMm>viQLUNpoU(oAL zVT*k?n3R|mpjwPibPLGdZY2fj`i$J-1w~bGendr%JHE7J09Yk|{;7w-P@6_ziaqd{ zY$FrVFLtp7;6@lD1d8pCJ98G3xZ-hu_T1t)k2YClFp$NDBM-|EB49>uQrsg^o@#ah zMlhny*eX|7OSaPt#Au_Dtx?m609sw*Ih|3f$p~IRk}a`yfrIohI1l6X@&P*c>fkWV zmHfH(L(y$_{KJzx!MyE*y{K~o`T-q*6&=B~CO!SyYu}y1Cr1KLQ2<N1r_`aC(kix-t_}vRyYHt?=k`m)n5*X6}YcK zfv4+aTsTvBN}eOfJ%6`v39R?O9@^C@3{>iTT1Ng7d@cbR;$qdZ8iv*;XlcyVVeW*R zSwih~8csY3wH4o!Sv~P$N&Pf$)yOelS-UeSufy-drq69_$+I$>% zJ>=pa3JKx1YEs_)5prCZBSo{O@BzVxRq1bc6frN`boOsOxN*Wa)e?ax1CW2IzwUT} z4ymc}7zP%8n&x8_4apIjwek{8PY)vkJR@CUr$T68FgT8pl^=1F7bZ&rGSw7yOcvkq za|&Qyrpj+SP=lwdft^huP#h4v3};ci1y^iUHW`sp8aA;gS=~Zt#6#M&=BDvAr_ywS z?Q3qCkS$|KoQ`1@U|wzlgj!OC(Fm~M)e)>kjZ>kF+EyYkqoDhzf?nNnX;rrGWYt-- zdh}d=@A3=tT$?Ai%QhSCVmhnOSNb<3iH3gjE7fLCGkr=^!?rgl<=pd~kZ$YAV=0a` z=kBm{B=S?nY-KgzAPgWClUBpES?!ogAoH?X<0sRA_Xq=!LJwKKKj)46M^=WkN*YP? zM5*(ef8bU=t5&vLUT$12^k_r&T{}bne$I9l0Jek$A{i{Oi|-x8ggX=@?x!#g%sOJK ziyF9UuU8)YqkemQvcci#K&tY^X!pfW+JV!zPd!ePA3lpJWPK)n!}XiL=QMAXKQ>A6 zK3Z1*?Z-M~(!A-@si(}8D9N!&W*gGv*_wVFWkQ~B70b!98`CZ0hppDjth$oC%Y+O?+CV0XI+v`~3R3K{#S>qj zJuQLqv+-t5a7`dllVO9s?xc#9AIMnAe~?N!SS-ERB20Wd!i#r&4o*%uofK8bXZtIx z-R|$?&UXO7`k#7yP8m#CQDnY<79q5ga+aEsjQ=tS4@SCTv>DjYSSwsy@M|gzF}pF3 zhF5dWyaNLXPI%6#KnMpUOf-3iI_A4FKY&UURfPBAfjssy<$qj7lrwT5A~h_m?DsAD zMsiWL2BJMuP-p6xHEZ+Q0RBRt+3YV$acsh_Rdz4p_w+V7pV z+1m%L2+w3bH`6I+A=W+dc$W+cp9=UR zIhgKqmGda{DoLG#hvO6@hjPtqghfRSnhe-@g<`XkfeZK$J0#(Cr4zRwSDF|fe~jKD z_>BduytcW3^-xzM-)8We^FwFVHgm4~?s&)c&c~6n7xLTdx{ue`ec#WN*BQ?AC28GU zlFoBz4=+7$BuUwQpedHC@L=Ebs9X4XRQ0dJ2EV$C%a4kk{(1R{`?9}FT~O}rqX|Y& z002iTF|)qQW}9OH24h7T7|AM5#RmQh+)MX6C_93-9OID*VbKDH3x9^(huh)2 zcQHTL3C@zaZFOjmTRhf+vi;!nUoM6vxL9#(G-5vUd;n+nZjs6SO|RXVwcq`vn6 zx7Q)riU6#KKn_%X&f3`py;Dt{#wqqx;|Yw&5Mb=VLlqX}p}D;H}jexsN(he?-{ z0gKkrk88=RK!KP=TvDCD{A`SG-I+bfypFbRJKW0bFajBhPvJMriQ|OX@m9;mev(j5sZNWypO}$~hGP{k4s%|=KS7J5J-$D~Ug0VLTenr_$exwYbaK6rk$vLgo;zzx zT!-X}s&@1a=<2)TX|RME!eDS}9oos}M1#`U;k#^D`h4I?*a707$OJ_~*Zs$jigtg~ z>EC8w98dO=mA4t&)TO9vlGcI`;NF5tz&6WS#ZHPL*0Z@YyB}@NTOi9$Bs*|Q@v=*j z^iX|Z&_ItaoFHO}Y8+B8c|9iyKn8~5F?`_7mgiUntwFLA%j0tL70#y6tJc6uX`+MohSj$KXRi&n=M?aL;n=1@d>##{1?K~57y@PeBIjj)Igt8IrAtZ3etWu?UPIQi)$A; zp&7)^4(0i`7yn(fr5J(K|GI5$g;AxhX)yV1WEy0}0+P&O_cFC;)dJcww4@#WTMdoA z{m^*l*hg}9v%u9}+>+EHF!ET_7^#k6%qm8O<^6za2MhEhsVQFYv7V;KP6*}h71XW| zOhoEb2rBBQi%0b*(ofwtbZg)L(QSUbA5x=mFFHDX>+kQN2|!{ln%G`n0agqOS{t_k zKGeQiCkpP1!M*Qs=wTFW&P{oNlG@JzQPz4 zM5-ngu%d3-P-QPs`LzoXvQ(65zRgHbQ@fsYk{(MEBLu9wpn?Y_n7Wh6xQ!|lgzAE% zg?YZbmrxowlxLX4E(=+ZPz%jy8p`J42C4DO672XphU!&zVk)K$7{wF(#pGmb-7%_P z!;Sr~@}R_f{*pw+) z0k^WtP9MYp;MT)HB6;&$o2t^JB!X2~7sQa@0w#lEa5z+lq!GZBtF?yeK**04CE`F< zr6l($|CT)Jvw2(7H@SCB?PM!c!R1*Ua&+rz_j(11vaR8NJiI@AJX)xxof+|9ykGvU ztZjOn_Gx4-YfIqjXJsR&tmMLcP1DJ`ZYPd_himh^SnB0(+#Bmz(nH26u6F(23QRkHOIrxMZYVeYH~Kwn5E1ur9pFNpC^iz~`VIb< zOv-Z_4m`)_n<^$uk{ag?=|vYxjLZ{P-c%PCdenqMT3htu`yF^_8wO97z4l}UUpBn3 zN(OIOLD}ke=1BYH5W=`l`nfP0$s2!;yDc$B2BKEH%>=@TiP!fW0{Nsp3SHc0E!=kQ zxM)>?tSNSIlRQ3JCyJ)ZL~|61EsKdQ*+~RhCX@iI?<^VoUC&vo;8uE>3+(T}{Cku$ z?>AGu%0B0NSAcjGR;2+3$8jtlEOnoSh5vGmO}d{{mrnG?-E5J>c>$f#CO7lbyKC6X zpT-9{q}oYW)U;iqSvt*#-chUd*qo)k2G{iB1AB#jo0kz*bg!=0K2e)TNl`yOIW@n& z`n}PngEnjR?**H4z9G#|x`j|u;soXn##5Q6D_=75F+(`lQ80a6k6gc;8)`=M-VJ$c z#@JlP(rZC$v{V_0l2r}$C!4+q?Xep4vMnX{Tkd+oMlL77fo<{7nE4i26kQ9RG8t6qjhFeJ}7qd!qxD(Rf- zKpL0bS+5HYRu@DEbn~kiSlt5-%D%QT-o1BPp&$lK-GUsndn$BCYfLk0Ep03#l7ny0sa!TUGc@=tWT)O0m%Pw{gx;8v!e zs~}Ht#)2-#@icuc>}WA|u>bE);Mf6}rio7nVU@u$$`s7aLoO45}C{pMfMf!~2d=12|oiuj6P=RD3hD*B#_)){=BQzSuK= zmDAMTLEyI%0u333A{Xue-7Y}z<$@bM+SK)`aoLAgPCd*QXBN)s3MiI?ZY^Jf7@${E z&vo?r`7`>%wR7voUWtv$)W9#@eXA@H(i+}YhTiMSG}Z`y(|9fK7Jcf6f2C$*|9gk6 zPYy(vUSI=tdVterG6|5B$Yf7j6oD{+%+B+fUFWkmp9{9qbA0J9&FopB#Ooc*%5s`p zFycAo+O=Y|(dfNQ@*cAQn z+HgeUJOS3T?~!~r2Eg4bK^JHe8$JHKBv&?yDpK!5+btuaaDLN@;q(n< zw?1Zy5!yu%u}dQk%p~5*VrusVd0Fc+Yq?Hn+6~Hbh*OuQ&>msJ!B)<>Wl$bi|!js^6LbH&mxLL?lH7G(78IwrJw!B z)KUxGrhhL>)uv9lAWfy_KhZ_ThAkH;_e6@9^CF7gKdiN#em+kBFWhUTPiaHDsxknU ze`#5BY@DaHScqUtYCg$Z>GX<;;2&@BwYO~U3&6x%AU2rnQm({06!-I z!JO*plAd>)7xRrTYc*yqwuiB*|54`#oGXd4Dd8E3V`SHKv3_|W@gaA^o;ZdSS)-be zw;kecZig&jVl9-{0;on=WaT(=AIpP8__ZRqe(FfiT5UAFLO|^7L+%v-sv{P)+!#wP zv9dwE39%fwZji2G_zWm-O%JVOB+1Lp(-iBS!H39HPX=ex zcBN53+M&pmT2eVI6DkhThv)zR@bHAHSQ45L;RzRj@I%oeLC$TKW~XwSn(f>U^wwmL zCNp%_3TBK(8wC`wXNx*@L}9*n!BE%-P;k7c z9u1uVrb#L4cpQaycXk|3*?pE!E>L!Ck^%@Z?ukca@v_d zlwJ*hOo%vdunzGbMz#bBltqfWLc{ZSWHg!f#xJQvx4eW zuuOZ^EA3WX4!1%qYK!OzQWp$$XDafH9?=Uda`F4)BHJLQ5-#q$(Z3e}o0z}F4skm# z^24%xm`OQuPgi?{3F`tzH;`$0%s@8h=R0h}CCb;X3J9qZ@Qg{L+9emnnZ$cyJY!Lh zgaoDKP5+j*DA?_+vat`9fa_sSwfB*_ZDH__oLRR_?E3~OwtD1G*tQ6&$3FDu%5AR= zkMXu|Y$LDh#;?8#h&tl`=k-)q`qiVzi8s$ZZgdft$x;Z;?ObVjbEdtJ7j*jXeeY9K zXV54BIDJDY|ISDW*j3n|=c3BINrpIAdq&4+U|>W*(`^<(aNDCHGOS(5D|zp8SNae{ zP8?@qf?^WRA(`BB5?Omw>GH5su&lfJRT%(WzPuU%ISdwWDiZNgAdn(~hs zTiZM}im~F(j{nbunq9%g&Hm=!(J$=FzCNKxv~@W|9hM4x_|Ch_uqei-KS$MG@#GQG zZId$iF5BvCJ6#aar|eZWzxhle3VBy5=bK=nRNDCbxQ=TBzekSb7hD88KTnN0>_Be- zX0UXYw@rosnI20PsHFIQiyG5a54cJFSEs`iamgXeR} zq`#3pV z@iV`5`{faj3wxF@x?B+C#;M28eHqmLgfC|BLL$Ky#CEDrvF8M)X#h6D8%YER@9&Ip z9xv?|zH^mmkd2Y`tC3P_cu}<3>~?mGIBvJhz_$3s>eZ*0E*36pRpj9Tas%8F>^4)G zLjQwbe@pv9?7J~#V{3{aVZ!UFQULn4CFWllv!<#3-)B9TC(a_s08&lKF1L=i~c+^D~i$nHf14 zU?~D0GZkhX z-h5#Vk?pC;fWw36tT$HJQ~KNeh8IR`P8?IqxMm;Ge|HGio?4;YRGJdtNWOzxbqLo| zm}PBSkhA+1#OL(cMt#Nn#aIz22P9$Tc@>n9!8OmHbYSF|NQoCO-(Dfv3r<~j8Q71> zd>>J>u|gvr}WSSrcXLo^a=UVbH8l|3y`vKLOppQf= zn*O=)g9%B7ZYAifG<73}6t-~B)4;WixhSV9RO%ix&J8z{(7#>lhUS`q=+R>f9VAi0 z1tVD=JeFlzLt&?=zAh{%P@EpX&BL>p8P}sH#zvj4cmI+Z4>W`huJcIn45bY*iz1U- zT-~$^&GhgRNLf6)IC9$ULb2jGcr`>BHX_Lh7wm6S|1gw_$Q}~JYKW*CHeI!-E|>Q0 zMJcuPG(+?z%7N<)&ZwRwRt`ls(4)t~YoV)P!h~cdb+knz>cR5o%?PY*pVs zr(rTcQdm~X&CA#SaN>c8;t1=}b9}#1QJAI!)lAFA)8G6{|MAXY+??E?wKh%!d9;z8 z$u^KFI^79ySp2&!<~tEq+LKR`XO_sw0KiNnwx1R z9wbhD3`;NO@p{N*=rY<88NOul*+c%^tGS_Y7l{NW- zHLK1sA>ACWhbm>GxpIbjU!4+{QGPBxC=x5$TQ*j;FZ=ChiFpNwp|EzL*)!|P;Y4U+ zy;S7m%;vbRIFWay0vYO`XpMPH701uql4~VqR9g~7FE7X#_&4%NU;9++e_H6X$2yU9 zVK0>_aY9(*Bs}`#jo{(hx30EF<7pS%yTk=w+=`6h1(N|lX@yd5cWJbU>fog7k4LR= z-z}FA8no~+tRI}0$UDb00dt?;t7QXrZADTx=BB*^@G_qIRhAdjo56kKGo`t3Zm*9J zpmfQnvRU=D%4J3QBjY{&>x$nKk4fKys%}2R;cq%@>u{dZ`L^9-{MS>eGju*C59!b7 zMK@GcJS7ch>KUe?XBA2J(>4+CL_}hh1)0$!J+UN3?_-A74-!o;K!p@m=58WtzR9lc zE()$hw}j;;fQRnGJo?b60oQ@j;MF0nhws93MX}1aGTj&y9M5s5NA$;6f1s)Pa5S#j zx-tyA-^CX(~2@1EU$w`E%N1~7zu9fD%(mCIif2*)%Jio+$NEak)?M;TbK+Vfipo&q&YDi z1|6$}@=ZZeg~%P7FW6TjcH!0Wl;%@DHt$czwz8Lx2$xT!stxu8&c(8MKk6W!N-R1% zBqJN*J#Aj|`jgj(QsZl$aTPzT+Pr*zHK<9*l`99X%|y1^U9xZKlZ*UT*!|(oaL$~+ zSl`^?G5vq|aogbde1@@k#Jf{3=r8F1$9KQQyem(9la6jb{F(uoCRE{(uydzQFoGB(j|40;g^(5n?ZpDzioF~O>kM5PCa#qtmaY0OKqZviB=k;TMyfPtEX2N%G@*o7|>C3-|Q&47J|bGQ=D77*d!eX;!I zEYX(I|&_tGgGM#!r`tr%0W|f|L94!!<$89je~2w2_UjjPY{2vjJEy33j{Z zu0QrkHxCAPqFEz8StXi`25(+^?PGs*_&f3>I+{-Z+>lO-cq2zlq91%YvR7(PNSn*U zg?00DKt*E=DuORuEW3*+$ygymyleRGWbYAV&xJP3^DD)kRcA337#7fof*H`ykMnAz z`?h<2-#Kkjp8KlxEQn2W7mEsf$wshT$mmHc&TdPXP9O$Vmi>VLrI0)TyW;ZdqXz(D zH1T1htpI#N*~F7PfaU$84^LV?gKQYdFS$!K)X*4~!f~TR{Po6&NJ=%2L9my|Q%P=? zdpVD{E$`oz|#N9C6Sa%1V86WkD&}iz|p5@z2r$k~Q%l!P~8!EX0V~;Vmlk{J&96@~ICM^aKFa#`- z{RKH8nK@~Mzn^wj52>TfV$&g!t^5|=fHr;uH<=LWoT|;{;zUMP2ZvRMR-o!SWRsXN z?{*uCF?v2o|1mq0for+lpIR&7{}A?Wb#;jZ>CCg~UiGLs=Kxm&D{8#DUEDE9^oz;p z-}&xrHapE zsolz6-&@b;WO-k0eih~aN-$}SBUqee?JM5k$m(UzSkaT_r5wvyr;3s~>0E15r#`>j zr-#~HI*+Ql(NE%mS15In!)QOsD!ml`|(SU>1xchja{#^p!pbgd61lHzW00gBt~8O zWcnoN?wjF_h$QzgI{vznM~Y;}a@enxo^H=n9JWn~Nb zt-gF}vn=ej8|Rbl(yxyca})8M{82p$;(SK)1)7$3JAV}h2HLHU$}233pZ*U==iyKF z_s8+iy{_xx;$AMU`MtRIy10Z?*UY$NCwqm9Br=n(y=7!m_TDQqd+!-ik&&jXqLN?z z{)6*4=RDr8^M0TA^Yt!q3hj855x?Bx`{gT7z{Y%KX0me}dq$1zi)FO+hZin39D}Z^ z8Q09$1AjEQY3s0Ge*fy^L2myA*Z1AU0GA`?h40-?@YxT~K4m)~UAJgfsugNB3DeI> z{6~jTcYi3QQI?n*;r>0az+_54hvf%EqICWw`}u8wMnh(j)#v)DSZ)dTmPoo&0MMFv zZGdwIaMYw`BT-to!y!0?Ovd&u(Tba(+I$%K|B%yzDs;k{oGGH!Y+WUg$07;|Qm1P5%}^;1yW_Q+SUy#%rrneD$KEYI8#ka&izO{w zQcMfAhD2gjMiGtC&2l=rD)osLC7#<1%2YZJB_fFxltCxu^9LsLzCWsee0LLYE&Ua2 zW8+a(yQo}^XAf^A1AlR7pN;gsd_HCUL0iTw6)vQKegpQM@Y!Nr^6*BaA6(s@srgIR ztk1KRl-8bvp>tD#tgCX66zWjz2<3PAwuHYdos(Wt(_kVs+2A0*aE5!8r6l{yK02W_ zWUBVX!zP>gx?cpys@xTBrJ&(>1`xqyEjF6n;co>;zZ;N`O_(4SUQzTi*t2xCz zfI8HEpCM)7x`*oR_qU=(D`V{E1K#Z<{<)QhQkQP86s5nTFZ$)^W=+}vC#h5@Ud?0I zzw=9Q;pg(P6<5~;-kJAT=jN85t#+T#HAuSu$Z6s#T`3~&23=f|rA}iOD7M*Gy5W?r z%e+irZe0a{lAbi%65(wnl&Q9gp;-AtHqa39IM_v3*=!T9EIf}~wOrpg;R(@sqbZxS zwy4k~!p6@lo?R1l_&|6;G~54OvY$j#+#;{rKD_hESd6jey+la-LH4hR)v;kQIdukn zo3LD$6jj)RuXC~q%xPh1rIiZcBbgp<C6St|q{lGWHAPc9m?sS{ej2o>d zp_4s?-mqkuR2FGF)#!i7uLu}oa?8Yx$noyk_}Z7-0)qy(EpF7*-y0V$uKJM9)9&&y z^eFf$!EOx#x9v|sA9@z^{r))V6o^sV~ zC=ABz0be*- z61IA#KgamKb>zeF>9|!(n*PyYC7+zPx46alx?atAf^2KfLf6;UKeDkr8fiRfJUczj zH{Q0|mN{YoVywA8D8JyQNta!@wylWq5DT08wFG2$#I>X-8f9Pz)o6;?fhP@s4sNBW zY%H#xFvXp`IqY{zORwRi96JAc1P~M7% zA1aW-mNT(;S#JpbR;tBUo@N=hvBjP&mfIZ>l8WxQ`|R&ue5q>^>IDD=Kc0M+4-}Yr zTQbQdGlw{2$9(G!*2r}}gHC`UrBIkRF&vDTmDH1`7rP$7QT3z<8 z%I02v=qnUt)+L%wv{AfVmveFP6Re>P005;@?Da$^Tb{VAP*A8EPx)c;le-H(Bt2Qt z<^dbO8wyUoTTOX>4lJANF7-)9hIp;QvUq{}mG6=cwO+uMWUAGRHDd))us8&~FP2c0 zA|&XMW0W>Eovz0&9`-MoN`Z?lOy@t5xC#rj15MiZpMa6=-9W_+EZ zo?X|20x-*r3{wu?ggUc-0rj@wv`+9-xcOLXqQB5FlOHj4?ca>4RQv6Zxp@kiFQ%LlMZpJ`@N)!XwaQZRg z7<{FnUGegGAFY$IikA4(kIX2%)YY8G@#RWmmByAs#^10Lg=C{v{i+oS@2MsR*_QL&Fbp!EfizMU-Ft-7Q@rO_QFC_#zJ`?)M8QD zcR24;vTIT0&(LY_&C;bSFF(jfe8);*sxQ4lIhptN^TF=%+`2S99G$EeDN7n2$!$_Q zn+Z+G?DPt|ayI$4EPb`!!t|jEeQlA5CbPIe`B5)(oQ7S~i4~&aehfNNwP`ak%xdAQ zTfzA=EC2OpU%z~md}mGBY4I;`j`J}}Wi1M8LR?!HpHRk%EOt7=+Xo(&>_2$IZwX?` zmorvEJOR{(K$tPUX;({iLLaRQEQhgB73&iArFyMcEH77J9mES7Zq`Z4M>oW%f%>@| zz|*nNB1~W3NTiGOKkpVi80)Mx??&QymovWB@%L&o7_aKqWO~ztii_lxC9W`|!jag% z&35M}FS3%tBH0HBiiL7FzMC;Hr_lMR*Y01q{&|U~Apc#i$GaCH49w(Ch)Rwqkf3V6 zBSKc))|KI38E0RQC_(SBsPX*1ue2aW;X|(B@B1U{kPk0nPB>%6!Za)tmG1y+fVmnoVD7zmRZqp8H3xTJUCRBl_I#&4MiWmViKj* zekcG(gh=>J&BXU?(Rs}jAJ>etgoYK&t)+*uek7Q$jX?x)d+mdjP%7-WJsHpfnPojR zU&|Gu$lQ5x164~|A?zz$ig8PsZR8`lWP7}S73he1!97z!a(3Y;si43bTf)=`s##qabBP{yKJ2nJ?&x$)f68{*K+#y2c$ ztQ`pciTx*7j7zXN;2+Lx~FziVcbT0cSK?bKORrp8gcK0+}!8{ zLjVA1(iAz9_%G?A1ebD}=}y#fejA0;IFJO64L14I|H0p2L6TLM)Tsy@M?VQb!5c6k z7#BF5jboT#U`t7oALTQ-UW%2cXdLO2H}@nUp2lE0LZtJN8*lN^B`c8#<91IR^%>bW zcGFjfj$C2h$8VVzO7wkk6|wcXUn;|yU2A^hy>2>Wd^UvL{ey;{?r3B`%@H5^7%mXTge-$qLwo~GUSl{ep)I@91kRsjxh*n z!kxDI(6A&~9Mx%X5@9y9=s``7m2Vr;Cjerj5X)*;RzaFAl6|k$4<0>Q*CF<8((RVr z)^YI{nt@$gv@NY>a=|~#983O0+IjruoAaHJYZm`Doy2`M7gRQ%jp|Y7Lr$*ye z8O>6^Db70hV~ywFx8ve*-fY#E#PpW*CQtwCHoG zPkerK@JCco*5=hHU1D{FGhB#KAi=0^@#={#M8508bHnBq9UrIT4b4Crpzot0caQt>`d;m`pGkFd$KD#8)01 zr*$CHSy2gk&tcU!vo7jX+}_nH1zakVS=zmazhhPOyT~-=>`KSzNr_HDb7RwrYcV#2 z>!n5d<&%f!r#~MYi8@!&4(kn#QD`aK7Zb{bHMd?Zp{Q@yKHKQ@qT(fy$rGcVWRu!h7{v+>{Qinxxy6aOU(hk^ntG!oRAa zm9Ljiw;$uOzu@8kTN5^GZ-4&_vHQdSvGvsGTc5Y2h3DDj!rwi{gHJE$g|YRW)y_=W zTJLgr1WD`V!egygeL>YWjBcD)NT)Uh007Q70>$G~2^$0KU@E4}TcoN8I{xVElt5NF z8LeW!0fqO|>QmFQ@cOg1gi=r}`npxpyCvUFIdv;v77qhO5Kt}$R*M)!o<=W}VPX&; zb)aq695{^5P<=f4^KGKomU5CJB4MQncjjXDsLGV z+l&1sjk+di96OmfxHW{SvEOH(mtMgNs~ErbkVwC zG{Y$P)~~s8@ziYgKPgJ7_Zu^@%fEmhp@$D8U&W}&?r8tm3#{_8In1H+a1s=BSF?B6 z21i1K?6-uypaM8T$tW`i6(|#Z4-sSQ->bWT^3;!RPE~$>W=}`|c=#{6G6{i?PJ)uQ z={1MYLV*UEs$eG#ujTX;-Dp)ayrdP+K&EX+g%yL`4ADTzvT(1WYdnS9079;aiMQLC z)Dj@hX2vL=KjbyI<<5p~QjSaj$RFwG9{5B?YB*CyWjTIT=(E$ry>mA-H2^DnpI>`? zt00t}g32`WLJ)r)Cqn;fCKTM1Ll;l zslXV&E+0B}6Q1s%*c0eD_HoZ14yhK3U@^&uu4U0?8E5|;~c#jce?HH@FD z&?2VbFfbppTIPU+nJ+^1U_K-zh8p^CKy7$;)>gE zS3R>hsbNGu{HJcP(+6`SXO}PC?NF>==r7)ie z6RmysVt*AUx|#i4<%fv6|MLY!)5_W-CGVBg052aaLF0vG*c2EvxRW8Jw42Y<`zLpJ+KbpAdap6$GbJmZrBQC&_p=wc(g9e@W~1 z;gvDeeU{ZU+I3ciLl2yhS+ zx62IY5c$bQ$k6C%<=YT-f~|1u@H3TNvjolew~XFP(cReTWXC9|Fs2LV-ogH?uc3)G z;Ja+Wz2#WIsT~NVjKm`Q_=xgXk!B)kS}niI19zK}E8plQ zWn!HEsl%mzb3HhT+x!Wae*5t0KL~-;h%kG8 zyMMSw0k17%$a_1sbn=E%2mspKvkEk>8*%i(J+{fr+;(<6v8#6W6@*zDF&u_4*gpVb zjG}XbfHNnJZD;Yo9(u#RKWP$-uSZv+C#Y%Yr6!W(3HUW}nSR}32TsTe6H4E1EVH0k zeGJBKK<3?G_?F_Qnl9P>`pC92?oiUpTx+2d-{?Br54AR5tA4)yN9}%ovKD88nki1H@?z$3CwJf&-W=;LQ0G>0^@2# zPO3!I8wv4q=mg$Qh#-@rWg1Eyh^owNJVIvVSzIxldE=-BUBIpN%SIB4(gy~28PXM< zCZ)$FbEDfQH*b4oHmDvf=+!a4{7>E~ZDIeoBy~$K#L(}Wo7CilSWl3N)|&@Ut#7&M z&8EJ=@^U&PRC{NuV87$+S<=bD&R9Vh_fb|{EO4i6OnQq(U=3@?kQ`+v2W zF>-rdb84ZQtG8FPeal-Qm@z?Ap=E?jtIhLXuQLhoJxP1;DAvhw$-|e@60_a_Xg1@+rF<7#xcxYL`YkA4^+!S?qTw4tBuR zjpa8zGKa0ZJ=k$RHvdKaJpU#hPT?$zkd~{Q3;L~JFE1Z(==jOFs^@KkoJ2lAb9c%q z45X&V+M|e6+X9Xlp~PAZ1cH!%1ZIfGnp48yxr)-7xnmfzi|tUaXD_c8WehXCv(%-e z7k&y8UPRk&Z)PcH5Il>}_3#obP6~0C@qVTxTPf>ar;0|=d>hfMMRJ>k<@(mqrQRd)_D^W$cHi`9&C2>< z;-2MoR0K=ncb~AGGG+#ZzV$f7A7+a!v9&2GQ3^x9k>uGv*hN~>poN62RHm!v@^NIi zK1DD}q5hH}<++=&y?eT13e9Qw4xe;>Tk4K&k>!)RcxRhmy${Sh z1zW7o$M$<%w=Syp+2i)7qqss6hq5&ZvJcH<7LBB^A~=+k6r5Q*iO^-2 zEMZ4jv4_DO(4O>=a9{;SgAC&%RT4V*PjSfEp{icrzF|s1an` zg<%rFR8)x3Lr@4yH5Die54C@pQOwnCOdjY{!R>nb#`~J$r-W!+=|LHibN;}niK^5| zkm~9;$dvn;Z17IDhsmyw>!W)!|J8V`1Pwj zMW_>uQdK=J@tWbGUmd?|;+q~uOdtTg8KEMLU_#s$u}bL?YH&7+MRa;5!2)Khdt+y8uvdE z@UqW7xd3q}srnA7SqG^Skn}w_dAtg4n;Q4|vQ$026d5HsmmG%v<_Ttx&0h^6+lBWU zgeZ&fT41Tu9NDFn%pZ>)z40^xO>!weVkj5?1ksZVb^(V}as1X;Fc{QE>v;5L>t0XG z*054w(zJN&8iFy5eZg49!jEn|Z$9O=5DIuzj6WOa4Y+O&0WlWbEt#d?k~}&-Uuenr z-tGFj!Rxo7myXD@va*0@ZayDhmLy&0ZX1gKGG12qmuSA0dvWpg(aiEi&yj*zHx8_m z2TB3~EU)fb4glx}9(GB{@qNO()$b`gnbN)0y}%YUN*PEpBo5?%g9X_Jnn0vy`{n`- zyVrfX&B#US_b-e4HaDaUQ@cM-^$xMrv^SztiofM3FXE%LrXb0eX0n?$w$T=F?6)!? zcGrUA)}w5<^|K~_`z+2?cT?^MEL;?Mf_Lh>kC9{R1?5GLnUl1CJ>M1DS8=J;7SrY_ zZl0N!g2m5mmfO!q@5oByy;1}+4o1T1c1)@*9Am&47I$=Gh&zf_&wxOX7BIY z1W?qFfUz`^BR*P+_fo{)#0(Y=9wkSQ;vKnBDq5&5wFCkd9p4Y5j24r3jF&G+4S5ZU z<;lb>@FVN=sl%a1FG?k&<|%FL)a|*C$@1GB%4Odz z&t`^k(<$5kb-b8(_LaEnACQ4ky+M{v}e*JVJkpi9m}*G82qz%|{uoZ*3%nzx=r@ zQ87#SL7og*VE>37ph4gb#$hpo3R%60*)Ku;#o0~`LhIl;)QSsuz2J~fPzG&AkeYy) z^5N}CZ`7n^%ODSPg=5=qw`sgv_4|<^S5ZIFS&{LmC*!We`ZZ3!MET7V*PHtazQc_* zH-FV^`gWUhRMm`{o~V6uu@6 z+3^&h)T23~sMKVO?%y^JO(uBWki5b^(5}&KxbW~6Vp~s&7lW}aEH6`LDY(t)fA{Hn z;ln_eFq;1aeuYG25-V`n`Kz62%|+VuQB(Q__qE@2Ui{|N=6bzr=K8&G48`0@zPI`tEFMMKFvn3a;!d75t46<%vSh2X(tKcK$OU= zko=8^dfLZuG@^k*pVM9~n{NmfE)tIh(U67b059hob5U@-*%SYAfQM2dq?e35$n9x< zX~ChpD@3IhU;-;yP~}Y*-}X&%&xZ5QPx_s-ywYn*zkY`%(?gzLTQ)*wjzm{UEO;-g4?`4YsFe0^rLh@zgHHir%6vO(CV zvABxD4<*~7y7?Xx)wMw>M3XZ83XK@!Um3a;!mpJNkli8kkyJuo8YZt_T=?w)7ytmj zJfb$xb(fSv`}g$?u$D|}Af%eYF^aYnQn6vfPz2iF%Lx}CW;Z@po}DM*+qq7$s5#oE`s0tNZVuW} z$G>ZQeSha5!(H>9{m&Y!#oVQ6-G)`UI^Wf)iUnW47k4ie4~<01McYzn0|4{4{`r9~ zO4_tw3|j=4(iYRE)(f=yX9@pD>%VNl9+Gvq=$tgb>v#XL4s2$Fbf=wzwlrq+wXcbc zUat$QN0n@4L`;^RT3H-RY(IFYH*;%^wP0v zgFwc4u50@$3qw~H3$HV|@pz{HT7RJi!rTuf*rsp&Oeql<_ zJ3{sMcD;$!J`s=Zv^px@GDxObPDcnqAi~cc?cRqfR&Yn2Xzvh12P6Yb-YlK+%jh#R-Ce0QT$vB4_ZOq?Ebws&!2gJXt%?x%#Ue#TQksLF4w<9^*3t!P^6YR|FZx^H8fXA#;@jf!{V>a%ah1G3otx9nwmTx0oXf6-hkJ0 zm?u@s+TL3-Y3(k-K&A;WUCFeMtan5M1FAjTg`h^yD$JAJPS2QMP4Ul>jN2y-qyKgC z9|QlsS=`!2q|%>)?1-D;uSbWeiTK`;uz1T!6=`A+Jz56D$HazZp{K^sNABpz8d8Kp zL!TYHLnGoqY=|Zq5vah%dUX2L5anlUs5a%$mYA@}Wo2h%J=kP4reZs~5OI0*c+7#e z4J9|dB_h?&tle!*IscmWkB#G^MJ#-r%XNB?0iB_7jcyD)nuOzP)n~2n`96#9x+Sj) zp?`81?##641f$tDH+NUK@0))|C7nOmyXsHkhb8p$oh#y(v&3j@%)WFQ&pUOYt?BVC@nKF6$&NQsY(4>edQVH!`q_#mvT@Q}utLvy zE-K0+W?K4*@1}W2uNdBk%>_-+_TU=3UmNZ`t!jGa=Kh&eGvSG3x<+_6eWJNYy#h&B z6o{}hs#2cF$JV_4t6{^SM}N}lb~Au1aQvMtwis08Z#i^ZtwYOL7|aR&UluADN{Mdn zbzrK9Q7dHtXDVsa)1~_h-5-e8o6B-68E1^>%aSc*a$Pex9bv4cBdSFRzPq9|C|7-QX>MSdGTTq#3R4rbAD0VjBrx|=> zyGKTEGi2alY3X13`&3$W0&SeGGW=v3{nT>*kfarJkfz#S$mh8y&GndegF|~P_Hzn- z0qY%_{pa4Fe#`ouQ3ecN8VWV6Ja|e<_&30H762^H zV(@2Kvr=6m!maP9v&+rMKDf*%T$`rUxBqb4?zjzBoESms2`_F@3=+MI1wmn;NXjq` z=GYLVIip(Wu)A%lH}?KC1-%Olch{LgLYGg73{TqQQ`95^Oi(TEc!ezhKSHHdT1W?j zrikT-HzXr$30EbW=q02}?5m263t|8s@Z97opCVfdR$mBVi#?*Cb|WVZeGJI)i!|aX zd1CX;m2`bTotCEe{{0$dl@@T{ETa^&EHj!*UY6lrgnpkJmOb9nm3Q$ea~+^ry}KPle&!V zk>qg}f&u^eTgbFurwg?evWL@(4J(9W29aWqw}(^+E5E)%BK zWj~lmHwRx0msfBv!EKu27B{8o@zUXm+(wgr{6slmQVc$6#jgt3IY3;*ahd#5cxet! zIMnVHcaI8TP=`2%*?2F|(2b{B;n$qu#J4AmH3fxl>dNIzcFSlX{M)fb+$eG~Zi$)( z$)b@ZQ2*O(f{Gqu#pWuemmaUFSjZFBQgo&n0+?$N+r{?W#D;^vpSy}d)r`YaLC;wbH z1{dC!5Y_lix@Re}_Z?j)-TmE%UTC;wIneE&I$RFjwo#e*Tf!pDxdb%%-6A5ojwJtb zgo8#RyHitpr!ttm-6iPax9a&&o`1)2jz1S!1c3I2)SG=dcUMdAZI%jwVzsH`l#?^J zvL1&b<9Gwo?AQtbSBqzD0=GSlD~6uB59cKBat6qvwYRysS)^2C*uanK<zpH|H8j1t_mpk`L@19?kU)m4IUAMLge#3k%>*fAt-3*=g#YOJ^gUTnFt|fti zL0`>wf6crxGqkSLW4g8xmKL`EBjWAAuR2v9CL`TC1SbE94b<9Is<$w4IhrA)(dW7kdCD%4FXr&x{KW!KTQ z!P4v<^YHzqIB_riWW4&4sriHQrs#?&-nd&d<}FwLxS9Lqh+X_X3;wU9f(0P2Y1kG; zbUYmUyS2wReqFj2Jzb@0C!XL9!5giND#@UZiKm^uu zT+tfF&y3DsFc`fJ(ajhHkz~~98NK)35QoFiA-g^rc`xQc*9aK(6m7{|=$xQ-~)LilBl2qbFX6 zMPY!uH|Tfga{!NFf#w+qnXx&OI3yIGlzj(T9HqjF(jj%GvZYBQwO&A=ND)IN-#`h; zrJOMpA*tze4x>m^oUFZ4?kphrpdhVF)^;E_k2os64{4`Cq!|97Abb?5799m+2g}(r z@ur0n7jka9W=g}M3eKF{0cPn@WUOio@8;kPq=dFfl;DtzJa0w?BqD3Bv!+CLJW>A zjUc>CGLG|1z3<3!*4m#M)LXZmqrABsz!teCl1--a1?|;SE+mSgASs!Hy3kC7ukPKA zQYrxv%2@bhj2@Yqo5`7$M5icMimIGj1ik!x%9)!KK&mn}Wc`b9y85A7NJ!I|wZSum zC_>}Tf4tY9OJ|e!-(>7&j8_S3we=+=6cL-WL+s^A_U0(-@rfuN8h2?r0xYjMZlTZ^ z8BKsBL#EC5tHtKz#+gJu17Q~S22=ara00Dl>>w60`Djeip2Xy$mN;TlT~m{l)?1$* z>Dfwxp-87?NMt7`%e9`cC(b%f8{u*6fpTL{trcBq9zCnvgv+L!q)i?L$wK~sBicE|G zb`=$6-<7^)Js16j7D>_1)U~?`ySe>pmt45|$A2<6s5Nd~KE<9b?98qQLZ{fe-0u*_XY?_JgWqM~c2l29*QN=dUcX;Dac)F6OpM2*8H?UeSBbh+`| zHZ~ZW-7jSW&G)LNJ4!F`L%z~)HOI!EJ`G<`^774alhe`KL%9qI4s%lS+Z;uJRgj=c zb|<6g-DpHKIglF;#XSTUFsgGhN;{^O0Eewqn3uK>l`G=Z#et~wVa_n|g%PI*CA#gg z2}Z>km(~j1hw#L6UvpQ>PaTFU{APOPLn#yXzXM09dJ2e!TD+jM!GY3vzlrA^?5%Q1 z?_@0YKLwhGtc!WsHS8G$1Rx12=hqsdYHy6G`2PJRZK4@whU!N>p(#qlu>{d0#E}&c zKzY-=wg#NqR*`(+xjpOV3^WMz~s!J1cbMX6tAh}!osok&DOT%Lu?Q%BX%dt#F5XZ5OZu(FWr{pgw$(Z4`{)QuErXKDZOco(eX)^i zvY(EsPN`@7R4&X_xkemO$**-zcgb%bX5F9sDPZQbjW`OjdS~kSlEGJ64&PrqN+I^3 znZgkO2;QSfUp+L;hVVY4RtND@I`B8NJuf1ynYW55kfk2rGCtp8=OMxSruL{d`QL94 z;}E>3dY6Om0oi!c{FT0libYvbo$#`F$ADY!(y2GSgXg?Iw57zAB*iI7bycyyxrK)- zkFaxF5*nZRQ1BbaUm=PK`|5`Ss6st2^Lz{+KoSy z%Dx%ZfSe&fRPt-}lwaY6N)@lnNSpMeJU>#X>M$)RLRsYq%TyJ?Lgq?p!2nk>vpB)H z2;3mUuvBHvWq>o=v04g`S29y!SU|{kpk*(W}^w z4{a8{B;Hb7OGT(w{;qF_B?04}uv~caYw@H#RmMK21qVZM0s!MvN7<(Zm~(sURV-;n zjW908dNrGgh0egegYT&o@ke5T856!rXsyocnqUpV%C59;bY!H5v@JyOe3;!;a-y=Q zi+Y*Ogr^^MUEX=P8JLQF*M12s2X95)ry*#4l`SMMNRY#<{ujghajo~lC=0(;^jU)Gbf(leFaaC0hza zO)%1N_+Hh}o)Q?tBajeKAPl3j9}~{oy*;q=Ji-(0k1<(pi55IGGh(7+SR5_sNE9Xp zMy1H)w*-Z-Jtd_r?UKH0ZrX_*#EOp|(Z8F~H=T1Nn=X7WS^Im0?Q(48Y((NK^En9%QHs0Aw#>?1r{~g^%(9 zwL3VTV{3pMluO>M23r@+(*Sd9`cfyB8Squ|lwxC4#25_WDUo?fZ|H~PN`kDaXM@j% zN&fH`Eo${}n2TFe)>IgI8;|)RXj8vy{P}X+H}gN+KCs({ns!Swn0 z(nd~2I!ZWc&Cp+Qe(%K7E4Hx&CMDdlGkp8Eay8_!0J+s0A^0j;imv{;`9s$(XO=Ot zxa?d|KPpMTXGTerw10pgsRuH+fX#H+aumj=p3-E%gdwQ-STKUqnI5D{5`)5Nsttb1 zt>9CYc^2%f!EFh%Ly2}-y5X&D8V8R683Tx=#pd0i#hEOcD)V4F#{0=!-yZ8adM{1PoG7CF z4Z9Aa+`gMh?WJ$^B=`;-p18HXFez$ulkFCxPuSMG^*~rcpBc&RK-r2|8kwj80HXWj zLoJc|5(--cq&QXF#OD_R>8C<=?%R;)#{^F(A2d%}-m2slrJ+uVjD03)t2>u?Yq}Hn zX+$?KB8^;I*-W@q+sv)z-GM9kwCv@}VEwpx<2UcO^VfC{8+3`SyTe^(7mnH~Ojbd8I>+R&BXGNmCqYOrkN4n#_#T zgZOU>7((kYY54}%tat0&_%S64?oNcSI;G9Z{~>~))sl-`WD z)P|M+Fp+XNED5{L>|S*xmEryumXKgK*L*zn@fExze3qGCF0Q1}P>^(~dBYt6#vQP3+eGQqFXgOgOX|hL*Xzowy)gNiz+U|e!s0|fekvL8XPF`G}w4~G4 ze`_dgG`!q9r&BK}{n%?Dr|QMu0xi!GJpU)AGPvDI^z^4(RqX7+TE-LMP|AV{5pAT$ zU>(ozNrRq{|5$m_)C(g5|wWu`{6(0kSJ96p!i-Sx(+V^7$YTqAz6#)xs&Lq zlgQ{b4QL{Y50kdZ!tnx;*73t8g+PE~5wDR-2RDD&AStC_|8oLka=;%!h9N6{40ysD z@<4T51ibAMI^tT;1hbdgxnlk1N_8q~@tUyDqs1?o%Z&8UG{gh>iZl(oV%bggvy)9j zXYVVMR@#57_tI$X_Li0GKl84iM@VVb#nMgHE<8zZbO~@^Dc>zenG`*0{3Mjc*78Mr zWRP&H_U;se;{BUNvkQ_}0024yq+SMp??t?`z2owK%AvQF4I z>(l}pXo(HRml41Yzx8w}s}xmxrrQSCJ50Ls>O7NQbtyE?67kBUzD?K=Wnet1|FY0} zJN*^2ukOX482n0wzYauG@m!aQrQ54u*r0vF4O*)PCD5 zM5u9EU***&=EeS2bE~_$Rn?^*^x52X-;Rd;QJW#E0dC0y0N@|tVA zWnji?T9XLp+8`lMp5bf#7pmy$O#bgYS0*NjM^7^#oL8F+IG-xVnn}7wO-(`8B#n=J zobDGH%pMu6Vn*uS6V1795ciO(>4kq{Du&ym5L0)1W`{hhW*YJl3x&3=30|z=2*s-_ zwY%`Z!DAKf$w&9Q=pr7F<0gohcjT2Nml_@is{H$!fz-Vd@_4}NCkvOmQ(ZtEWc13P zRnyf`Q2Gor!?VC#FoUo}f%VraXZHePBe^hm?vjH&6l5UJ zndkKU@$*mN&pZy_EA@yfb}|5yAb_gaZ`u}6;Eu?bq5hDB(q$NM7p9^-2&nKYPD&HV zxqNe}nwgbM?Q|VF8e8blQ<(2$#(msTwdgTPh{80=Og-&L%v<((X1puTD)!{d+WWCG zjF;dJGMIyUMF$7Je`wNrK1%=v084!CtOlF@tz0}Q91f-cCwP+)ncd4knYS+oJs$l1O2SxArstyU z&qFXJUnE^%Wd5)1eW5=WNoGGnrgB~|C0CNCq0QLY)79Ob{+&E9rc`3}Pl39dA+=>n z&pWbdS1TWfn5j~pCP?y_!1Qn}+ zE)g*iNu;8%*ItE0S1cipju;leiAcW#Z+6JH2#?itL82q6#;XVgorNidl;wq%#Dmk= zR>D2L{^z-yn(Lu(_VJ3*9l`iJw9?b*?CE^4u6!+Z|D)G!=xkKnkO-H`s-jw=mP9V- zeUzls@_l+-L3Z1$t{~!5t;U7QYdhWbt4Wupv3rl|S2eYD%rZM_{`3B3sY@O5oTJX| zz10sv&d|QVMk_nTHOiQ93=j7|iw_Boge`LMkt+^-=sx*+dJkac3URv5!BGS^*IkOA z0x3$2ydq=(f*86rv2NVt3GFN#orjt2BKdRqqFHANRKq(0M+P}%cEUu%1+AS^Nz_$x z;aL-Be68E36xMKBJZqstoB5B0+k$+|SRChSvkl1efba1GK@LpS79?2Y6oTZMVCH?l zAFY)5_rci=gy)kI!#T4e?KrIm!_z2k1aJ8YRO8-~6OeKe!~vdPxgpj}tSITun?GNA zPsJkvIHw7Qh><}Yz(83CW|jZ79JlQ_j~Z&011KjFwQkwo366tO-~4ZVQ}jb~0su&j z@L${@iQU3aPysfg;I{GYHAy+iLQn}Yj!iLvhHRRvz&lqIizTK}(RrqOU~*>3r*X?D z0udY+1Gj3WCGyNAr-Uine|9D-N>#OD=QU4o%4$^M$Q{COOtSkOJM&9KhIVYWzhw>< z{2;q1h(V6liThoZGMe`)Y}GdBdDPP15?L&mOe?G|u~jx^p|g1U<)TRX5?&F!&ymuk zr0i~=Vjf6X-u~=%k?h~s{-AYf_2RO3ft5t3&jFI=*B6*%aP$8wr|!Yd&_OrbgD+;y zG5+5Fwi0y#?%PidZ6(E#fJ;fdQrWwWz8j)TL7pnVC0xm`fE^is!<|1ttF}nq36!bDMJm7gcm*kliIwIQ+sZydEYb`5FI>d5#DHi2sac2@Tw-RZNTV!<|mqJVK=jk@Pko5|i z^uh}jPb(|9EFbE(Ka9`dU(vMGR7|+AsOxQWoi`t7@VWT3`MuuM!`-c%H)cb9;;GcL z%X=bJOE;6XApq@0RVo$)BU3|^zW4^iL~D``0JsFjra0R#q8Bm#raNlUBvEKDuEY{% z+%7x*4||1t?_JJ&dZJT1c>Bt5RzD_6!lpEaJ?WFU=lZyLqPgWvc_q|Rv+=@S7j(Gh zzG>d{83p4?3jEvBTXO7AL&B_a2p)ww#S7WMB?_1E3{kWOQyQF^d5SM34uN@^yHOO5bMCVgqE!=B_)FYE$&Wigg# zJJYuFp~u>1$ux-3V)=2Qso5uq#uJ~~?2ol(hE9z#mi6_IR(cnU@=EV5t-t*8COGWh zfQ5-560lhbbHIT!rp!c+kpL_$&FBQ_HCc;vtIlR&LeDIFJHNFQz5b-V|1oUjGQ?pu zV9f35*`4DrRuu~*ueD!TDM!(s002<^m^JrXOx;OEjV3^v>uTeWz(=szXFmRj(5!rC z-oZINKbMLZeaKMD3;T86|ATRn<5}d_`Op$4ALh4@i@YL#u$ISeX{IDvw9!fae0|(Ez^C zW7_&5qa9Hmq2qi!xSPJOWRDs}q$X}_veog{l-MkAaWTsB?7yOJ z`Tkt!UeG5C7hSWZ#(7&_sj!sF7&SSfQ33?AB(hr%V*H$JFiVFUGZK!0Q8cIuco%@H zSlkt%8BB4LqIBqa^ahxT`UCNjCjg{BVjP~;1kd6Cx(~Zl*tmY^uvr8V36%u;^K1tF zW>I#hAph6y)ZcOptJ`EZU#sK%N!@f4ny+s3mzn%|>Bn|Pyp*zR1@9`3FI3Ri=%|nx z-0JoJ8->RBB)Ri@8r3#x?&6&;*P(hMt1j~*grQ^o{G?mfd*er6 z=lYuVe~LD*Q|9Uu$Hq2-Ukl&y@&$5L^4-pCaFYZIb`QuEiAPC+Twxp>gH**RiJ+O9+a+CwJo7`zZoRWIE&f>^m$p`C$X{&G`_9d!i7L@d?XdZk1hqpY`)oY|;sxYqM zAZjKONPQT{bBq?(@(7_9U0#+TWhw zI3DA%TP7pp`FXH5H2?s4e}-i$GrN8T9 zZx_fO$1~O_Q>63;`J3=~W_7e8gDSD7kBfx(Mh$orHUM7m`;4lY&DhB#X2Z?HF08TZI^$bN-M*o1rIsoLa zvKqJ-U*VpM@SSO!kVt`knoBQKkm$BIqJ^0;n-LIl2B5 zQ&9l1V7wUQf<7x0GJWN;8%i@^rgqZgHCS0&BTzvd|J9_e=&@`h;*jQ^>DQy0=ACMd zr|(|Iy5uQs@OZoLPV8XSlk0YMfPw))_YoDq za$TM0$+=SR;6@sOXYKreBlnJYORjTULw$MTPQKSebbh~Vt?8EHfyn zP(MHikubmW6OTt9;8SMc3ybD#bDCVu#Kfg&ViA4!kEHd6H4yR8k1MW4I8p>B^dHTi zm0om)lh%>>D}DX^5d|NnlKCTqtgIHlEdDCI%5F=%MXM|&AnWf*sZ&oe0m-4JGHf(m z(2TLukKNVvBYmh7?5rYnE+jD$diGk*$gui9>&x$6E%JwLrr&g^QDA&f6x`>8r%Je$5Hq|l^LO#WHCY102p znd@S;0gBVC6f5Z+DB`&Jydu0bn05 z(#XE@9+Z5hj_i{B>JzhbHeAKk3Ma!u%J}FRQGWVTc8PPfXu>^QOwD2Eeb{XoLRR^I z6~_kHYilj&si6m3Ke;Bj@b5qeg0$)pk0SzWkCH2kyZF@^D`nJj143=z5Am(QBdBk% zqx#IM^GRW^2~2y8dL9b?hlj`OKl$ieuQ}U1YpOQCK3o5BJ7`wtKt{Z>#cS|=X4J3? zz|=Zv#KeN?^Uvk`Tn2YBUk9s`K034vZqu^+yz-DOMnh0m$ ztbl+dm?X0Yhjylw2l~S8c)qgi7*fL%T_fM^om9i~3|OyO%HqLr-7rdV|L05TZf{Z` zGg)cg<>=h3i|L!CgMzJc&Yo z$zItGGUV9(ok()Lhj5^6oULfObn9(_( z$HFE@!n+d-s=3Ke;M4gWneyE;$_uZ*YE91>uG%=GLmNUfk~O4tu))6Yvx z>@0zhle?#CC=0f>0hibh^6ok+gWOQcb2g2m#y$S@1ZO|`>kv&!G!H>TP}}DfyQ?^9 zd%QsWTx&-O;=aklwlyR+hpJ1bxkh)Mv3byJc6W7BQSEDh{%z5`loRy)tcST}uA3`L zhw)c?9M&lFmTB3{xl&@=8f?We>!EBSHx76`zUCN=E*8Ex@;yZE`?l}Oe6tGuV;NZc z{zYq{QFYKXMXv%zFw_R|VDJ^Ws2Bt+49;@qWFoRjp3@aI^se-QrSP?J^Qr`6@le1#`0s?=8*6a$yI_AAAsxubBGD7px;Xh#zzBbZQM;|G4S>KI`-C;qlf4Ggd2eYm10U9x9Fh z+C-yEa#97rn)1Z=HPdz=QijL(Q#*P&mj^6`1vZHr%(sY$8>f;4c<*R&6AN$YG406r zO=3^Qh>T38*$JId6Fy?T_M#Bhjzqcilb?1@ny$4*_A|Cvd}DNXuHE&wGBn{~T4~pd zE&ib)!&bfwDst{f+L#gA46qaj-eL5&X31TZS+N8wURQg}3IAwwe(po&#K>O)v>St* z03c`y(~}C^C7?%H@7r<$^aL7Nl-e+iFAJg-=Wr7+h>x>xm^7%lH>O+vG0xIb+VS4} z+}D=<99T*FxAfb~?aR{JrvS*ullU;94x|WCg)!;sQ!opY^W2Uc+=)eu>=bihxJujUnTXgS z3VP7TCV%9m^wRor%na1@{^Izx@{s)^L%#?-Ve6M52V4P3~kFwI_?0}44SLjV^nffF?q#~ zin(fskt*x3niX12nrG*?D3wcPRDQ;mrhk59H60sb#Ao?hFREgxI*YKc%osbq!0&{1 z2%67xeB||T0;pZe9jtZpT;^^?Ynkvx2*PcwK?>nX7xruzRF=3QfJeo^;K6D-Km<-r zikrB0UQPZ#E4&&7%XWw$8WTYm5U{7p9Cg|R1xzx3hB1=UjVg1`UlKLoFn1J^;$bG*AE_>YnCJ-QAo< zaGfh60Aaz$yn!u(`pXF1RgBG^#+z)|_|dUfUWM{yM(O>#!S|8IK1@4N(d$*a!QTJG zlncD4cYiL(UHq(HU0v^Q+JK&e$lV6y+sWq2YOT8DYrZD}nS+S3V@b#7>1yes0)ldf zh$te_4UeMouYB*B6IoKe)+;j5&kL3~Kpg2HTUDQSFamkF4miqapSCew>4Lf~z_5$cGi^>3ddX@O~e24#}lG*IJNS=TgZ&I~6iGeJ)> zyTJK~kTN8X7rC7sO{2zn3IP$5j~r{)(DGuL5uD?X)GI^4XZgy7(k{gX09^U9L~y2 zC7K0rMFKQ5ja*0mr37*wIX}&u161Bos7JJbuKB4!;)iO`Gzz|n*oZFXZ0MBo9nssy zYt~{>QDr@$`m}RPT=6B&%_8Y9Y7n>8{J6g-nVC`rE#%kvGxJ z;GrGD{~=UXvZYhd=d6Z3fX*+524H>}>#kAt49w8AVHc~X_#}h{w7+~{#4J2X_~#@- zgZDmQ-hAq`_Wt5#O5mdzsxKlWqm5imTy1hnoYNmiDAZ`{0ioCr+?i1_x+a-YZXI}V12PgOi6 zh@uSV!V!{=a&zs=NB8f7zfp!OCB_@t;L?yjUTK`;M6E|(kfM3mY+%%<)7?$T%WTTH$;v!Yif2T)7HatcPMXp7_ z&Ahf9^7Z?9KdjrwTh?qjsIkIb0LYSRo1^_|UEj;&HhEblSd6^a_y@yhnbjjx5W^Sm zr;dz#eTe^4E8l&PH?X9>@v41FymKIxHnfHNiNW)^-^UFan)mAO7k?gGkjVfovWU%W zPBaE-j!F{YXxWxePI$=<0D-HLgLOJRf=CFMkQBm@+rLF}l9L2P;0aefD57!`o9|RU z&w4r}ChhsTu%{S52QXp{8n=fK7FU5xT9BG}y03&y`_0Vm$8GezV zomg#l{}W?!3TdsCu6MdW9TVmJ+Q$8}BFn#=RtH_cyTn`p$a&h5*jz=&Gv=G-*7)G) zU!>JViQKQ1wC02E-*g9_G%HBRi%b{0pi3YonlR5OWzBI;Bwlz7rFffArLY19fy138 z?unnmv7|Prk~Mz1M2O&gECs20bQ0!N0C3KLJM%03$B6ciW$K&$WH2UK4PALUEGj~y z48le5$MA8hK2IYirEyea$r~i=&EAeGixXBdA(W4Ycw#*l$oXj@Rh&eCfP|+BN>3Xh zEGOveBK{0+>ylePV|$Cyb-G2wc5UmJ?UsTiZ%Z_4^XIKC!=FYC{ohT6Omp+H@7H}I zsom#mUbiuRWd}0Y8C(C>n*Cf;Xm*0gZ*2O5d_Z#wEM9I?;AYv&ZJ& z^QtEoUXiE%OVwB)8MaI9&w$B;wh+e54``={>Py^4nF)2_hRbGxGw(yWqHpdEbO0PG z0RFnR!to;&N2x%grE*lyJ?!ZnMp}*WTTc15pQaBz+=TQcu2FV-`S(H|S;5SAHUGz` zMeeEIf3r}>x-}>CgU5&TC5%l(k_!1Wa=h`cpOstYa`undT3yH8K8or1J%=MMr2}%I zRTzJ8JjCx4f4_jOs)_E8o0|)I05JPCuDXj$)GU)Buhoi#Tm{33Er_6mF2Jf5W(c1(4_ValzP3nsvt2j{ zPZJw4LWV((|Cglm{--+L-m0Z_-L@>cBqjfMp!oLXb{k~O(_qdhX4{R zbCk;>@pU03H-uxxppNgezx7WkJV8|^F|k%uM=svWiWM)iRAFwwjxy=sfIN!L-Q*aw zk2)k)fl4KdFO0s6wx^8?3^lTileS_;$r4e*_`Wb*K*Q&}zzc1eRGXM{>$`V$i?Fxd z;-lS-%%0T7_VOQGO|th@{l9$FIWvrffufeu1vBZxNGcI$%{R~H$h8$IMd&vdzsi}i z6^I1zryVQ5b!8oJUBh zF^4;k7B6J$fbA65o}T5}=Ra<{T>str1IO*gkA_3#_g&m~SoQ)PoT(Z3G3|IuQ1_COHY-5-YQvsd#S^~P{1zgY+6M+ZlW*^I zPRCS9ffiYi3`Ih0qg2==34DDI1mv29NRV7`6AyeBU$L-Ak-jBCG7{&Nv5c+0mAF`w zr{fWVl@Tc|4EeAY-2^>90I*j6(u>vw3&7>A$;@-|4DI(>M=95#y<^hE3$0Pazm|1OzzUPl+DEd zrFB+X%7yMZU%XR%_M%!uYw%6Z-V`G~B2X5h%1D!=6y$F1j0w=T-@QCL{AfmKyJ0&p z)k)v|4(x^yhjS$K+G|-G8>4=^Y|u?McN#8A#RwYR*F6x2r&^`htfMwm5f^YaePXnr zup7E8&e4H0L>&~+-T63gc!9T;drqLsY|0O-q3SGcvqF}=mnSel+zz2`gs~&g$!2jg zc6kuoyCkn(#b^-NigAGwPAh^aAlbE94jE*P?5|r*EY?os{NCDxW!rEtWoRI{r*o3I z-pw0HKR8Uv7|57Y`YCs9!`ZN?&6ksswhk7}dh#Xx(W6gXz86zx9-aS;8g75`;_&eG z$6&wpgCkcs{@;vmVC+jBQR!_EqE^AE7Fa?Iy<#Y(<@u`nijl>==}|&aurwhkhMX$x zS5VOLPx!D$ZZ@g>%dh@2Gw90fD-z6dLXGw8nC-EvEYt1CI_)M(38>}0dInm0D8!L) zJXv)!4#AO-xuZH*aV_}aC5w&bmY%@X0+Xg}I-&IE4gU#qufpe=Bh~Zx?RSaC!;Mva z1{df{9($;La2}8Q5$ZQPTE=KUG9h%qOG4E9KZ5e{=jUbs*lC+3C`Ts{r!S3p(Br@i zO&Zx$m#Iw)_p%GqjKoI@@MIn%@Je9Bh%AVPI^K+i#}8@NFlgoiLCO5Q?W0NUiGbOL z>ULVCviedp<1xyVBv^*33cHFM5ymwepJSgSh!X3x`FFagp={W}XL5#ep%@~BW&j!} zWg|VLE%1dLG!8AREb*4oY=)JH^fCEk|7zkvQM6S8^(ge3^&eX4v6;bxN()^+ooP0s zuO$!naC*%5_;!-To^5=-`tXYt?jp92WLE3FR@|COqh+=I5a<}O3(iIW-3zOvEc9aaNzJrE9b`h-^jI9`<& z$e0uL!cOw^IMZLoC~Re-6_7ZUZ511)AzCUnfpRB=9!fNe5RQ8048*vHJ442U(=`-| z!K!MeN#%jU{2IJeks=@zp#DPo^vRd@Pbt_H`5SuNkws|Jm3Z(J(NCWfW8KG3<@JY- zW-7fQGfiuNLtl=;fqm(1A~q$oA2WZze|CQ~S(WAS^Af!SMMDnr62Uh7mLT~uWdAp8rT+Z?wK zu@Q`#nz$^V8;KKo<G4b#n^SP1@*?x9(O>>U=g; z3K^5d>j*^p6d2r$I1K6g0H&wCpvikK@)y%1-9L(h+G^T6Ql?aK~Ruz@p5i6hVj8t?Gs%D?WCEJ;~Ieg{buHJWiUnG4|m4-pAb z7>J?>t^+7Wm+btk%8)qfl!S)Ey*w`?NYC(yfIwWY6sdyj5d}x={G+ATsR4dt3%N zCR#OPzga}2AV7wEq>myvZcdF|=Ukulse!WzAss>1*~a^+RGWUm|4Lgfbo00B$X?ZD z%(Ckc^IxwvWBi7U9yz3Eig$Z-d8f6P)o*)^#rNK;hMYY0NUf6L55xnW`8-FCt4(jng4 ze)A+I7=EfhJt@taNSb5v6AT`g*O^98OW%D zkrWJoGkEeU_BEllz9mR+p@ICZd`UkvQ$d|jJyUv91$lm4A>d_j;+V-I9!V0y=2uQ^w3bTQ;;YsJ{e7z;A^4Bmn6lpxiP8>GKX*Yrq(o( zo4YMj&B~K*>aLk{_YO0^p%2Ly7-bpIAIc8{51LI&uE))!99LFml^+^M_0U8RTro_p z*Z=y(yWTxI#Q{`TM|uA!VWM}V?M?5;_qR(mBu#8Iz%q0)sBy{2vGP3Wz<$D!7kgLu zhF~;O+Jp)kmt;eVZZG&+sch4O2JzaI-twLTfsw?C`6@Z%Zoixxj&;uP&if%Q7)HE{ z6J{_R@C7FbTlbSOXdF8#yp@E;X?%ssqLBzM8#4u0(+GlatMGuZNT5@9C^E)@3SF!A z4i};kT3Vmk&sP;PTYaO7Y@-CLQnJ-|xy*j;!)M3V#}cA33;mriACkhJXCaa=4Zrza^P3jSGega$ zm5E7Xc70yAjyT2SQYKdgt#$k>d)Lkik%g9rOAc=n-v)Vr^de*zzg2{%$ z_b>F;*8Zx|7iL!bu*ZioO^-ZyU0#W8lS?X5!%aHsecDeWhdG?4v z`Nc*Iap64-sz;nXyg(2D*D6WnS_xwYd{=Xfp~50Je7>z#kW>yJPsK zNJiv2k3#}j1#RMl&7`(%cC^<97xUp@=qYJKRmyGYt@4`?Y~@o{ zftD1~3P`7#3uzWQTx9qd0X6~E+k?fc=?bEbl9%Mo>BQ7kkXonTx0aB%^tku)M$bOsc z^WPL;$?f%H$JTfU`Jtc&qWfz2Uvrm3xih^k(%^c$gYif`Jd8$Fxu=jZ{4E?G2EL)n z*q6#kD5UOQb%xq8LhUdRXEk(Efhq;86RJA*YgS%R!Zw0KvDDTUL&#C-%iIxcJ?cSE z_ejRVWr&n=eqk|KNeM7T^7Z_#H4-Rgv?frv0#OnDcAy*u1koO!;F)%5lG$#LL|35W^? zU~se%cRAnd!pBg0sH<>zc-DoHj^T$cqV)_VarJu1K(pzE=FpYfnNc6_(JBnOy8MNS zG)3BGoBNXtMWP42bEE$wd$ZVepY)tyH50i&&F9V~T^0ns=g6Jrvr_YNSYuD~~-9 zu;?6P!fcfo1<}Rw1$Ngx`KbSL)K}NOo?2{y>pVGBP7zupCV!vdeI%Dr9KYQjV zr{T4%)!DOnA(x-?Bj@=^1@#&LQ00IxJZ4UyS+ku`;PlY13rz&H{gaab$zRGn+5F#G zoCK*>bJ()Oyaj3%^3sO#%7M;n@`10}gs*emC=mUQ7|@~#V~!Z(Z1gf$wO=!$_-wD0 zce&-J)m)vO6-?`@c>8ki`BUj*_LRiX^M9qS0NNOp*D{OW6-LlepZ5#RIhGQIOZ1K}(NL>vk=KzS?IFympxJPBSQpc4P$NLqGM5 zj`AkGOV=rfaii!j;!-wfQ8IjBK`t2})$}ikedvY3;8syOcEbScq*I=cW`zLzT1c7z zgFqJI<+D)OcxQPOq)|D@21Xr{N{!+8Ws_$ZhN0?^8ppFZbOQvHKzvtpmqw8kqBjuB zi^M_hn)%(qz!o$J&hZ5+$!N>FS`kTN;Lnc&tc!lwuH%e3?39yRsa#seM`F^hBWduiTIP8n8|h9CYn@Me-wmc*G^o)7XIpvB>-7dVb>BW3KQF(3f81)^%(SKSDCgbz`5sW(35a##!tiI*UZEifu)n|g4Yn>kLUzg9 z^N$f}zwT!{;IbabVep@O`LoWyRf$voyE_rOse4u1FkTM7J(#uOs}qbO(@5%d4EHQa zIMIy?%}IfJe(VH0KA?j%g-*HJu@5K*@-zIpC8KVQ(lp%f4%{Al!pNR`@?4`hiZj}1 zasA54*Y|(=_SvtSdQ~RozQ3|klw3G?nIv>ldVYRBWXs|wTLw_S*-q8To?>$tFpqO9 z5oOPwPUHF_t)S7h6-vrV(ClG?6sN>(`@`D>6*@`?W4M({hoK8h;k=tO~MuyPRT4B zZ?^`L=YLe~#h82dezk@?%uhF=AM~6yp0+QyjN=`h$rwvp`6lGxt>evi0odYaMr82sopVi_*pR$B? zkY(JpB-dC@5N+rECc%T3mxqH6z2B;P8b12FMveFh6Gs?Tm8?>th-7a+_oAJX}5&4^3fcD@`Z{YlEnVB84hykiwl z422|KLR=CH{TjKsmDKSiexI*CE$7C1hT$C12Cv0{47s~^N$Jm?l1GVN7p5AVJp99S zFiG8*Yw7fAxO`WT*SZt^#ePx~3;+PCX@0c(=v5{ulvN+4)61hgFImR8oGV|Ju#?sf4Neym)w`)}5HFhL~t^6s>F%l`uWT?=NIGz-m?@ljot%7I>a}7rmQ? z?vHwcR`#b(a^hejY^t%*^Q+k2DhTH;m}^k?>mP)2i07z?LbJEhHK^9vq>Spzh8!^5 zb&J+BPjrl1V!K7&{J6lNMgMVO>Cnx^HZ46zW9K+SRP8n?P(^!tbwgs5&DLw@&hHyX zy+{s)Hn->+1rfzw4yyJ@J)R*%V`kZH`IX5 z)%d#ZTti-0zqYSaw+D-41rmzKhuDR(b@haHeYYT<7bgm?OV+yoZZfO3y$_OWKNBBY z8F^0?E0=dyX!sq&*K7OkZ*SjUd2_yU54^2{bMVS6Jg&D!-h1=EDByrZ4HUEmr_kdp zf-Cl=EtTyov_P;zEkk>V;ZQ6d%7mj@OPxe3q|7HWclA*w4$!oQc9NqC)KoClrA!>} zG%i(mRhF=+uxH!FL8rt>?UE9SGmnop1_QLzGe%?U+iss+^6QVO+4gfHc_v_Z4FNL{ zqQ!9D_z4K#P%eP`EthqfDOcP7Q%GJZ83htK7e}zE@r=zP$y~zZ8-HvQq_Cxf=i?G! zl;qr{-=f8w3A^5j`>$qPXcYl~c1enfva9|TjY3jU0hCTiwvBkiwB$$s%KPI~5d_$C zRTf@-EROrfBO_bmHvWHlggtVjOLoLCUWW8)@29F8Ecj;QOG!PKkRCv6SGR;=f{pdU zNc;>tDbq?;N&GPkMVhYMWx|i8)LqV!F%eO2j#IlbEd5;csaTVI@bNcuD=x22O>h)~ zhijWwrO@-{-#?vvaSQ;`o*t&z-H!F};w76KoF5|}Ooj+yb?|7c70V}tm0w7>v|Z0r zU~p`5MX;pkU8;>*<8R6Qt{CNXN_Tl?UY9s4lO{)e)Lndw*3u=iMvfMJFY+^sw9$+H zS))2mjtGq}=b4ZEzZ;AU^oV@gxeUbZ9Sb^)}Go@Pwfqveq zDL>k-zBtnErS2nzGT!*4;iq85rEC$dk&$@55z?&ecOq&1K-u_VvB~b}`L!=r>X7+X zNA>`o^nU*l7Kr%jVakfsc5TCST@m(vUFIh2TV-aBi~z5<@UwQE;ZUl1QW|&VMXe~o zhA-}QOoxgm!zX7Y{#&K+rx80VQB7_LiU7ePlth;E2D28;t3t@(5+7fwi;!+1gut zw%@y|E1|_!LE%tPT^1gbWq}^~TLXe2OPL-e(gBWth&FeZTWc>g zy?-F8Vo+iXwsaniXBJ5uGUvj7IVWh9Uu10!$m|@6KIq6Y|5%x0oj{(Qcyf1xb1Hw| zQ1#%MTK`CNE|LiqD5~-G-!Q!b+0?r{^tOt-_O+<1%pLwkaz-1Um)^N_A)U3vc5gweYKF6Dk-B zQbPnX&}L28r)1&!Hz8 z!EiRAN4Jn0oS^4BVe}&Rw#@DY?&?A@+q;IzF{I zk-qYIN1HyW#Ghp6Vk#%MgT7Kw^u^w1vDvzVqTIU9@2j7`*}XU2oo}}fuf~hl3*Y>A z4stj9(L~NKS`=9=QW9_y1(T&}s;NdF}lETXW@XY_n{H zU*mB0Th=MjYQf0+guEiH8w4w%EHuTo)f1X%Qv4xViHLpBr(Y<%B?E)2&P;ALWjKm|lFn!`bd*sZ=G)3six8Pf;b-x(a1#Cgp~ zvNtxX>*wThyQKfCIHAyuerX-IObt>~#gM8Sb?{AiuB4uTzUoD>ve6E~AJzeT#ur~` zxG?h=R7Vc2HI>^Iu0j;%%JrFMzh~F2#m)c2xSzTGD*tLm0f0NcZVubFeuRne&!v9MOE^0(p%yJ{@Da>87x`rXwES?TG; z%&AyW*-$k+(})lT(iGN(gb}G%W}n6eUk#Ybz61#H@$qBLyIiBSwABfHPdRUw9k(1b zl_h9jABZO6NqQ=(ii|vUwDSocaG@#T3f&CXPM8_JFbJF#>wNb6_M9P8{tH#3xyCeU z38%2@r#JWVDh4Ev5i;~?_i<*Fm%hV6c0zb0dG~&2BaN^x zOZ>iye)^=u+e@agxk2SmYY&T$_`zg+lAMSMhcVp^<5mQX?XXiu(O6L*q~&ZEgW<;L zRHzuyX=;)!;0~8R_rLhG5Yx-0l~kNkDY;qTNGvSe1PKJbMG$z7&X$j+*p=wNem^L^ z)p2zZOasdl!AoBGJp%=RXI<#3R<44_Sp=~NN-af!1wc}m)vBx`QlhfLlKPegK;%-g zd8gjOKbD;hfGA%XdgZ?gY>07Os@?=H=EmJV%>lr#>OS3-{Q@jYm&LRCso6QV)Xa!w zy6cImwO@KNn>l|eQL~)C!sWKh#>=*cIx3aeqnZ_RKizY}OiPej(e2;<)xXzI-;esY zS)PBcbi4RN25I;V!^jO(|6|RQHT3(E%BcW=%JTHZHSX+}AzEonnKpIfjZqxYgJH3F z#P*2j+?st^K79L{jkN=>nZ6CPg2V`g#STal9%F$Ffiln>s6DlW5k3kE&X-R`qI5Uw zvv1$;N2)HU?1b~Phc^@J$)TOKlcXr56hT)QuEjE4pGSdGxZpn!5c51?YTGJ%3|#P7k2 zyqJS)KFKF|>TPOX0C7g&hz-3e=lDEoJp%5^HKj~;#u%o5>XcHG>cO~Ik^_kc2Q`t9H0$x}qjSut2wXmm(JM8>n z13jx|8@uhuo?Wi3m{$Lv-*3*}{>1R*BYR%|x%uW)Eqm+3cf{M7inqjSs}EOxf4JWs zaPm!Fn>$90A9ZFGAtQfUs&V`KAKba#O|xg&TWX;_*5^OQ&r50{THSa6g@z#_!`6Ip z_J(=wn<9 zyKXDPTiM5@(^6B5Dmcod7fF{2VH9rrxz~uVHW$5&W4Zc51Ng^JqphS`-Pj#>AL$6s z_z*)fx4uYB9j10CFX-o+STom|Jzq$xUO&K4g=+NQ26y1Qui1({FuCg`Y33;ji=LKY0D$@`3&-Iz4uwP0DjX4N(a*}PNxn&Ik$1l;Z5-Oq zm%4IA^a&(jXlS-tTwEeI`zxu$Scp$jT}$Z_+be`%xtH(q;hF&)c@(3 z?oI8H_TZY?_OZolGwluLgDXu9j!jD=;|H%D_S)SZmN;E=y4?OM_v&>S*{TIc$Cu~y zCp@*%7D*;`cj@Eil2*b208+w&@~4jzMu}8^bBUOO8)CfVD2wd>=QXm0IgA7s(-#!5eK~(dn+iml%OJ zh$I%MtWr8=*+z0D3Y9IvHym;z3I&a>5|r$OPgh(IR6Pc+O?^A~e)C;JrR@FB?_QkC zn9q-#-EMQUeDvYBQ%i}jqpy6`#A^BKm-SG#J|hkqL^+}0K#cQe=YFoy001ELPGX%) z>M%z9q9ecvfy+5YWGWQiElihs$-=YTL22k&l;&{UP}y?T+IN>Ey~c1x#qgBblYraG*DdC48e2aq1}$<|?lw``9uj4m8da}qyj>cai^KBYe|`1Eu~7iF;QeLx zQn})_{JMPEEM;G{SKM6BE+4ze=iR)w^A~0zq%Mva2=xl2H4CTfm!+%DjZB&QbXz9}ui=EtKnLTLF?9E;TM2oR>b zRp74ksb@5o3(Gg{YGf<~*`jnca^oNJ5T~x({tu4Wu$3}X_D+h~Iu@vR{l#0)8f16KC#KWY&?jUcUH}HyPC=_+rZ`}ZP<1H1Lv*oO=jGNUtzB+|y7sOY zmDblRY(V4x^avXu@X>1a{$IwtDn5IeEYyz*AzObcx)W%g*DjDS0HK#3`P~g0=k9BX|4t#M0#*?WSyti)TFvDo&yOOm}7aH1A~%RgQZ; z7vE*-6+tk=G2#%xLlMiVd6QBfLMZr@ zx(Pv2lWp)Tnw(F2=A5|ik=;DMS9(qw(fr{5^t|Y$S7m{Sz{4bgh@2OUuE(=aFX~x1 zYMFT#ie8{w`21?P0zQJF&tFa&03fB3PY~N&_Wd3mRA%jYo%3g_y+-;JEN#*HL{IOA z4Tlq*!U?2G(A< z+7hRR9U}J^;MH9bt#wTfp@eW@wk14Iy7ID?X5WmW*p+bQ3;x2t5_c+EByL(h@(Hc%^83Z#pXN9Q z0Kn>L#Ha$r1}_X+FLd_a8&so-BOFt`?!mm0bswY3aY+_=&<5l@wDm&?xS~zo4gQy; zvv6xV+Qay7W57US^azn|VWUJq94TGW5+kJ>1V!0Kjg)SX77)0!fS_~^X#}N9LR3Nl zsjK&%zu@jA!X)#X0x;d(fq5UedZ&z~2s9dyz zfqR#8)+4JQictS7J#I3fK71%a_28$z)V#_Wmd43z=GCjFqnids66S?-es9ioZFS)~ zsf`TWFG62jpKOacO#&FOu1T`r?R4XnXE}Xfl&@v|1FIJjvx7%Dkv*N-t+pfiF@sto zBf9}V(n`4U8}@e80>b6gTK(b|;N&8%u-==vGPl;>_-Aj(71P_geWZut+is8SQfFyD zh)pb*gBquLW(JwYmz(tc`OmRg-}0Bu=O3>_uQUPheLXVmf^Seo1Ud9(t+3syV(&~` z&G5(D531vqIR%f~=)Hwr*6q+K9_w|sMdpAn&2o9lo0U}1g%r`Mz88-Z+(yMV0>H9) zO0GE-YSO_*H$E2jdOsbB+xv7*M@){$>;1@lrn-|FWi*p4I=}VoN|0|t(xzSB=d~hC zlimz>2yI&Uq-bMTRI}&DdR=`zLn1K#50_sMCl7SN!FXt;iVDblU#p>tsE;@zE8hyL zkTHgLTbdhCtf=q^WR(%X)M_ADp)Z#aw+ip@KgF@*9C*zP_gvWYi(JW5T-KZQpWA5Y z^7wSCinvy!Q^OEyu261?5qZK~dD<&aAK11yJ!5)LIiUI%ChEA4GuVSX%kb@xDw!i+ z(fhquewi>GGB>jJ*_12R zCywQ=n>uktZjOT}ag0viJsC!6>KkZc5kyykNtc(Qw~){!73H`tUNE}nH%AjX@*vdK zAbh}HGp(rUH0Sr?{0d&iPJj2lkL1u}#tJC^PF!rSu};01x-nY0*3442a2BG*-P-ud zg9({;?;eEHAXHDlB8$05zQn6ow{Fk$PSy4R<7)}Iv$!Xfej;zV@(35vCXtv(!=4PO z<4Tgir$*wmIG)xB)IEDH7oufjuH=u(OMSCz_r``yNRe4le}*z4I* zmnAkhd)Q)WqNcrxxiAR=ZJ?NhuFt%Xy1sn#e~RM=)@S5r&IMVAOWib!UAD>%6ont? z)Q-mdt`Z!r;%(vlntPS>xljDwE_2UH<-Q=@PZ0!pgRk(FaMw;_g0)3bvb=S&9Veoeg`l@d#&kJt zWo~GJ?7~yMSiDINq3o&i_^m>Mqd-E0CP{*iY1WV{d@YobuEjHV&_UJK!HSREvVJ{GwU3GnVw}Eg^ezEz(nB*_Bv&NEz1Jfvl57W(uFC2ZvMD~}3ZPpv6 zLf*V&P(96dSuX#|C+7kHfbLr1SuX(q-E4eh(!~+D-V|k5CFQ@-OZFOl;Ne4$W2h*q zE1W48POl?>k|8~TH5MFsO(M7!I>j(+T-jw?b`amV(#`dsvO_JN4h5*f#nNZbt>4v+ z_|(H~Y0Jk$!FjXNkG`99EJ@B@HitxKii|et1sn5ir&p@ze|Hj6ZD{>)6}xG2BOjymHHlxX z&a#sLK!co?1mAeKjz*+mzTOCxviO`UIU?5)-n{X}N~M&=tIbd~3i8n^>Y3?l-3rme z#pNgVj8=>;(w?Ront{n9BJ!GC1|B;`p7#AkrYfRN{;-kb zxBMGr#8#C0hGS!8i}Rb1>k#u$hBB+6x74>>I|zG2KP%K)rj5ua9Q5S1dHWo#mOL#B zx8GlRH3I-|i;ey!k+vDCM-Sp4c~l5kOJO5d2)Zy@Q4`UW6q;+Ib`I zxuD&^bCiK)ci8PVRkWsPB8TYw2IakzMkZ~h~_JCR(Lki`1n3L;5~ygHU9ht{8& zsHb)p4VjV*U(Z5o%L>NBVwe~ot}{OBE%{|HJY~XRMFx*9>nPB1000p0A_0=Qv4|?5 zf`$Vf$wXF|s21f=p6TdLyzT?H!0fvw3wl(VJz*PQP7V{E^F9+I&LNEwEW%q| zgEySLtZ}PW?KHZ#uu+i>GV2%|+-XcD+UEJdta2~^KZ+s(D$indue@odo?mn~OJkNC zd(xRm4{5$(#glT^GI_j1*$l~Agjz#TC^0M-$5uRL4HRwDAt!}s^dR;AAan% zJf!VhQJSuJx5|Wh)pRq|RLHg2QRHQpe*m}1&jF7{{JUa1-=N)RT5TdljkKwPA{C)L z)y_3>Q?j#aPkw&sS<{vKPryU3^W?^WiU2o2$iI5)dnTnX4=R-J=X!ifi_QuO@sZ{| z_o8|AT!>^S@n3iUf^71W1{_ce6MtCEpq5?{PgLfXFmB~U?$UJ-z3!&mpltWtl)+v} zM3T2cFeOIM=ocPo5GGmZujd@IfTuC8i!geV=Ir(R?LTP?02_K56K?JjhE2lc54}iU z(CoV@)*yU(Sl^V#w{y)6D!|mU82xMB+HmrFm)zx#epR55K=XPU)Dq(_kx_gE@3 z-w>ZbwQzdJ_Vz^<*x2ebo+8ITV>lS{(06k4dS!!$C zpT}cF6muoZzeEW|^Y5*7JW}-y=grd1n8-j14!nk2nvRa;$=QYX%E{8ZUEbIHOfRVn;gr1CZ=MG$ zY`nQp*`UC}Ow(7^?SVldb_WaU%z-S}->GZj4KG^HABi7aavRgHA1zB)QU6FaGLS=l zk=lG;Qe)WIn%Dd&^t*$~d&0o|(LAk--xq}NwMM#i<(E2Oxlyi#;k?mK|Cz$DMhc_t zJ~HqoP>krCqPd0igE2(sW+M_M$gluT>7hWTF^BQ4YZ^GV(HLeMN8cHh%YTf93zezB zB+DF$O7+nwOIZEOA|9dFX%V98{F zfB049)Sghf_UZb}W}N{}Pb)IG24RkTS_$R@{w}ibw(m$DuQ@5cj1@&Fj?+j!{nJoo zQtKQ~3kk|py^+E^C@M5@+UYNpWje3Bp_IFVAmf59%oj6n{3oeQDU+yqzS|HjVD|ib zV(Oj=myeoupmnS5!`I@*CG9ug@k^bbJS^{i!CD)?ewOmTs8{4hwDg#pm*&b@#Srd^ zM)OSY9SPmq5M@d}{&+&x>H5c_pS9UCy^yIl0!-|Pr)n{zr06N~*yJct6K0+12LOPq zur%l|iH@}qtj?LQ;Ht=U+KJ>$O7C%r-!{h=YUGy(zq)M@J20QbQTS3>BfPF7fLsx+iH~ zL!VNmOLy-w&&)m^%Q^hdJ=dkMbp62dBm&dTe9tAZyVobz4jd?x%u2>r*2&De@WyFs zDiSP4`M5l`ITEiF{RVUc_#6M;%x_NjtM}K> zJin`5sN1X+htbo7-*r#CPc0Hrf%A5r=M)Pyqhh9F!@bpF>%K$Mt5)Rfe*k|H_b2(D zLh{!w#m}ta^e)SIu%)e`A||Yik2Io(!w?%c(*Ke;Yr)X|060+T#P+~Rw6&=@L0EeG zk7#;s4*gnZGv@N}hmPwaM?Q??mPxCW0vgd$nnE0G$*&rO#AhG+A@s$?#Kpjo0%T_{ zHQxnyEw}Q!XWfk{P~A1*{UwfucZJgU=&j1WM6tbQvEit2{aEG8@4sb}m+AKULE@tw z-Dnx-*Fnqwk^60t+w)$^jrRQddaHf7%mBeEVHeAaUfs;!+xob?TSIIz0RVu|m8}}{ zVqOoY;UNwS0(fbONLD6Ciw`HQZjTyvPDXk_8k>3MXBqxUn+d!zqxW$yj%}si`E30O z-wV1vVJY1X>h1%s$MJ;H)9YX{JZTBCrNr7u0iKzvjGRB>4*QBtie5?Bj^RrF<#j{U8P2lK!x2G!G(Ba#GJpnnh{rE z;!?UsFQ4?_ONQ7n!Q|LhQ-qgk0tz6yv!$F}_LNM`A(5XnjZdGr0ClP&tfZ|B(zYOf zkkUYjPhkS3kYTtXI6!~a_7r7f(pI7f0q~L!gxJa>v0PFplGHmxP{@wJM~XFAi*4ac z6;)L7IP(Jt2$wESOe`WoYgIyIudy+KsYTzGT2=+0Rri_b8hfgT)2m5q?u(_juZjIG z=6k8Rue;nMx~-d-#vg6bQ0VjKl_OGaL^fq0Gs8=lB|7=0{Q9KyFCAv;(OqIVSp=K| z@tP^^oTtrWvz#OmVBQJu1I>_@3-~}`U7gX-(>iNKZH&6r8og1PUxVmJJ;brJf_;iU za85H$C0Wj%5Em&}Q)$3CGPzBu3rOojXaX*a$q#;zY>RhpNz)icXJGVD;r=Af;}tnO&Sd z6QkE2n`x`i-!%e-y#o)MuBK8}f0npu9&j>nTLmw?)uk%=_-)q4uZNCbD4ve_k(NEu zV(^Js3U%CLlFGdNy?&D(n17{&v88Og0UDz1E@CDuTe(KptXS zA>*wPW8VTz6yQ=%wbTixEu5&m{rfSW-f1zlORV(8KWWqBHVQR$-744%#>k?3o@l(F zJ>&f=ZOR_rve!BbrKi*qd@syA4fe z9fux|JM=cc$j?ylBd3**d{plApS)>8HO<4VoMf%hy9&>)a%NQ^c#KNMi>VUIl$gcj z^f5>Hdtt5jwi!!GUp`zPhX(-^Kb4;5vS-76p_wdXaCY)H!7ks30Z6o{=E39g)KcPA zSkZ&1v+X!`@P^!o9eUZ~7Ei7x(=k>YsRasqenMoydmp%|yrfj;~V-6loebg^AdY$}2Rz?F(5qPS19EdSv?R`+N79 zOq68<{Xo&!^{0o^H5Ws~h%Y{t1A~}R?u8)`TR+DN2Ldt8K+4I{Md&Vc?<$1!WAr;$ z{f%zG$%%kj4k#!t8${cecZr-t{FAn<4o zkk(q^cRSoW&rM-#TuPRrmMcARL1k5sgGgKJ!t(vleM(4;XrbLHRiPs-*b?e9Q#r?SjIZ?g*WrSTv zXk%L%HR>OkIt7CsrQo@Vy6ZO~;OG#27z56|`d>hoGIGP?{^-9z%%)Jq`d>1M-uX<# zb7icjO0b-A6nUy*am;q8Cq-KSh#2|cdGZJN{r})5f~?Z(2`qM-`6=2mDRu^{(GxPY z#7gv%yqpKx8ij0wNFJ6_{==q`{CDXaC2!dxK-m%+5g7(%wO$$;(s|yE(cS3&z^vrt zKl#mJaCyZZ&}JQ!Ja<-9_s8|61_}UPb+RQ*!oG4zu@*vH=dd}%PJY~(nA|iz2n93z zBN{*nnm8IFG0Kh@MQD4cVxKHhE8QhC(IZ^Ymmo11Qxxah!vfRT@$Q-)PN#=shJHN@VdX1k#y+aXbSfQgq*EJzGSt;gUp)TIF}X`z1Q!owp6=NlPm8s z=uHbQ456$69e)Vv-5gWnR}hIe-_1Rt#e=v#2I_XBFuhpgopvUD?3^46Cjz5{aDRw^ z0Dpr~*v>(ch>A{37lzrTTv>HyktP6JplL>8R(cAj_yK}sDB`e624}nK!(rBCKSOzg1p0=CQevx55vo-)`3lS0U?UUC9{Iis?FqZNvMjd+BBQ9?~@7!q6fd-$5RFOLpMzSRK4fIy=Bjc0PFmo zFh32^@)(FSZQI-1pV$raLHZoX_iachY0)+wbb3F(K?;)H?5;buanAqoy<}{jz39*V zBMCWo46qWWhs5dY&NhT5{(CABcsoU>shp=y2kz!2CI&PraeIn#=HOC;E!dkHmS@@PaTZ}{Z#GIq5y^4@__&tSRNbV5lwC6PMl~9~RT;HORJfP;BcN$r` zCf7z^?`~)sJYY4p(2$OuEB82jXoijbs*uECO>3UPrZX5*L=wk;>Uk6>Bldj})o0+FF)7R;iE-X|#Qjff-5 zDG=zSm2vnALu4Bcr9xa?5@NzT3a-uoLxL^Nt@ScTs&-WD^|Y>eeYk6;WHr(k|HLYf zpKC>}AE9b7Xfg<77|XR%(1k@n1;PE%R5&=JDpM}4kaon+rzu7(Jxs0byo-sIq_z~d z6AuxA9e4T|T%Vp67!3~l@-L&`hj^XKdi`PiQK8kEqnIZTN+ZVV5Xvb=_CZr%R2iBc z-PunsWY_6brpZoXN7P%q#U{%M;UrT!qJ-!Z(E^$UP?|7C<|K1WY*ArsG#uKM$O+B_ z3IWC9d(_NSZqdV*6P++RvqKpk0XF)lw)D$CTl>HT9+V7rBo=R6{R%bprAV}yGV8$A znj9^0g0I|GJK2ef3f~N6NtS6md%oktRX>m07;vG|k3Vo7wzq`aQjO#^8D zHBM6pp~;4QIC<>#gTPdPqJ20$$cU_z-_@)1JP@tTCEEG<4=jLLr5;<;Qm%CXL)2O$_~uR`Fe-SG zXD`<~4gsadFU2<9|6+Q5O;-f~Zhm~O;@iMViiAC>9vLOvkTVWLMGQ|YCP9Dpmy?Kl&KQEDhsxMfU>Y#Ky)Tg|jA+{J0Aixzm9DZ>XDCvg zgNDT*Ng^|x<%_hGGOvllte%N}nO7Hz%sFOP=BlzXKRA)CoAtyep)24k*NN2G_okt} znQE(!(6hxSw_0obu3PqQUtis?I#>=(d;9Ww?{N4%%ZFD|*UQ&GuJ>-wzU|mteDUG> zRn7Ge%PLdptwAhn3#hr7Ct0Py$m_>jG>Vc;N~CUl4k$cZ4ln5nBL&B)3&DB8k!rz2 zMEJocP$&%;qgcwqO9FOR2RQ^ZzV5->#xe^j^%y>E6(a79tR(9^;V%>4@THT&Z16c{ zmG#%>nlO?$1yAm89R%F%qh*}MaB^2!riNGLiZDhWEBfo*z1iEuWyPheKw1qoQPQYb z&?=-C93J2wHa&HJ<`t{GRTgi+vYiC_2H!0T*QyX1$z7#{GO&wbeFfK61sjC#-y@)R>R%>?v`?LvA`KQpKD+=*wrK1XE813bB~OMTtqU#E8@bBWg*8 z+j{=I_1(DXZXe5H&0XUOIpM`i6Vi^0Cw~$Ar9i@kww7aZR{zZ}fnv56`Or6_4Zcm1 zUVa}pPdA?3oC++hYG@U6(vf!Z%Uf*A{2;7YJyY@c%G`6-Ao550(~%FC7oqZZF1`na zhMrtDjE$LpQZoq#{i{m}`in6thZ*{oE0K`X!JMg#>D9F&8b79XiQAYi{&Glel+TTL z=6uOBygI|scr`)s&mCBB8`koKPk*JoRxwQU-5H?GB0|=5ME8`v=GR%=Hc&RMNsFpy zPe6;h`0o^K{leQAhG?Z$EU^z*8|vis?LS z018(4sp72tByajOt-x^G0Kn?Qv9+adz`8)?>&H&$7F=EFbLIwtn`9{#g28?P}m@ zqxwuXhJ zA{l3UggVJ23&Q+m3Y$A}U)^!|)@8vkUqNtwrVKi`yi*aa1nG}J-#zoeVFtliNER_a z7O5hkgdXdV@J7|^tQK3(`Tube;j{=7Exbc;;V?vF)DtLZWm!nINpKhPoFFUl>)R!s z8i{0u#iO#p>tYiE$O$#eM5y6)RI*iozM_}oAFA~>vR!D-8;fbe{;u2QQeAg8H~s5| zCu#3%{6FpXIx@cBujwl+e}8v;W0nKRr#PDI>t``Z~z5`e@InY0C9F{Kjdm z>7w3~^Ftezo*-B}(2|4#08@;Uy321t5^H*_Qa>vslY+4m8qxR3p_~mtjDwjF>qV;n zE?~Y2S<_z+nltAP7H!*WPSJ5e2Qy^!?7vvpdyqP?X$Q(vYecwK%v$s1E9k(+dVBeU zTexDIPRE)DTK~C&1a3nGMR1E_7eBzCr927NrLiRw)2;PWrYQQ0elwp2ZfqUj7D@H7 z8f&LKo*-ytGQbxYvo7P*!;iSTx;*E9djr&0qu$Rb3Lk$Y3Diyvr6{*0U~W^?0VuAW zuo1y%HJXF$n{A23PiokMq_1uIb#8+am&PN<9FlMj{WE*xzl6fbR>j#+Py7(ZUHYs$v@Tn-z^f1 zHWNMhv3>}95Gq?X+RjXy9W-eU8)8o7*8kmpn=3tD_tD!C4NIOhGiyt;xR&|zt;$y( zCI6`h;$(L@4tHoab}M5W8{S!qiiA)5y9ajC(p!YNUH?0ZE`=WbwEO7nSIG0EIo&Bu z*DV@hk8-!~DzeWKv9%2$qapM$X$vuFD^e3IN#hK_F+CU@Du{v^r=8cqu0q8{Uc`gw z0SoApgm`Il%_l=JiY01;G_!oTEdj-NgaAy%Ouycwh)jSMwrQYQ)tIQ#m6D%8YO#j| zs173(zGdPko~$%_xx4l!d;IO2H=w$8ui9Fe897Vch{^pTljd5} zNe%t>&mDwtz3TGX&t57WPzjzD|CKf!8Pn~W+Muwve2+&*9nNsj@pPiu`Hyr_BTS4E ze6Y59UDeaz*Uoj(sR2y`e*%9kp&Ru_04*WK@weC4^ILls%A)|${gtUC!WV4qw{7_` z(!}|q@%}FPL7Ja^w&NqU?WqoTAj+6H`RJY;DhP8nvw-0ElAaQ_FCB3h253o%bA(}e zSL&Hl3R#BE!V2J(2xg$071BTz=nxF)C;#LVM@7c~?I##RdWi_V7rn%o2@<;pw0!Ct zop7L3#8!Av`EI1-GqmC`enj#U2=GW2MyjICy0=&Xh@=A!u^O(<`crD>+sR#u#r>if zlP6gMGE$K!?$1Yko?{;;pZIgd@u(z$rL z^-p!%v#dw`zfjd}@`^4AS2ZnLTNTgjvzJ}1_O(x5`hBo#1#b|oqHq1H9*wlaV<->c z-FNc)6(D5Wanbz{fDa0a=->g<3828-lV7zWZ*sVL(Z6Rl3H1KB?XVB($_=sCDJBU@ z9STQ{A6-*6v>=V`b&w4>2~E?8T}UHkAPIc*_nW3nN*3Z#0Q)lj+tz3li)E*y zUvzOn=bTL zsJ|Ak%q#A+o`dT*az38Qgl$ntGsqCLK;^^Y9x^DhuX@7r%hQw1+qns93lU{9kNj^B zXJ+lQfwHkbEkXSe45zPW0DG~9nQ5?XE6Z{t(K zIl{DdKPe-tj?bobtS0pOf^vrP-~5!z4YSdq+CZqgw}P?K1QU>>E;x{HH7K>~Luj_8 z9f{|@OYp}#fmf0PtPP~8JroPiEO^4BY`wS4y)8s&B_BxB-VmlDN}@AmtNJu9pZ{U( zpF0Qx8#4E_{_?S?FFT*<{vqa_N64Dm31uB&fzkH5(`^0bao(7krMGjpoQkkm^4Q(v zi{I?7X*XP;o5SO}2<8=zPGVGGlFPqtymha00RZs0Ab{yi%j1S0BIFxoH0`nF&~7*r z-_1<8Bn*RehW3`C`-AZS9}xr;2Ei%w@p6Z&W|-YAhl7(Pc_}z05V;t^M0TOtv`je! zt&5r>^W-)-ks8hhcG02+3z6&f!fr6pP(yX2$q@ZUf{A!s`(%BmIH-_lh=dIMXg}Dr z`A3f#5uj?CwrZI~Lh|eWk7Mhtd+#*YtmkhMLQdF*#(aF+zId73al4r*AMot_+w{fT z<2Ovo{xEr4p~svr&mV6&rDXQOuVlRM(=u^1Nw$Rawi59#FHS=^69EAHA40F~#aG2a z8D}3TMnzM*jYP7J#(+$7RD#Qi>QbKOmW`h#U7B+DydYJ0XB;6vHIhFUq6`ko+kCIf z&$z63DIgE~fYy#;apaP{e)7~p{tl1_jGIZ+}k zp?H8L2{$jo^qISL8zoUxQnql8i}%tqbGCP`eFWyt+!M#6X>o9h04@T;Y_Ix5Ife zC^%rtH%Gi~la!$s{B`SP0fKrowh?`o&DpC|){bI7u(p*-o%+JR$u5K?nzf zyIK$bqTg%e*-Ty{FLb5`%9CuUpROb(9~*-TijO0$og7 zsj6V~nj&I*yeC|qghb&f=eFRQ^nab~JlmtJ4@~WOG713z^5s!g^E85fBxCW6$A)4WbjkbeiMc}$&A1c1ML?nTh5y2WZ6 zD>fW4w(CeglUU@Ka+u=e(w@a33;fyg!6gK3I4tTxQX~~LGX$^1kIbUzR4Jw1pBRAtZb(JTP)esA?G#UnZ2+vnqb5=4MwF9?tm& z5X^4C5B-;_vkHr~^xrDF((PLY;Q1yLl29+2+t?uK8wQ%V|X z2~k1BK-j-~AMNLOoqX4Nzk5CJwcbEf(pTDmV-f_EFi6NVkFZJ4I5xyV6y73>yjPCT zGB9BCv><#=g1^#K617WJvY6ex8j^tDK0$z(QbD#PDJHc1nvQiSQGzVUVd4vHA`^4X z^diVo;2o|#z7N0O=0!)3^UTZy-k9F1i1<>E2yOrK^iR*bx9f|*!X5yCvLY?Xe(q_g z$U>!|aVr2XB0+)_F9;J>9(g~eSk}=^D$F!OK~uJ&WyPeJPA!g5M5h=TX&1@F8_rJo z#n_wN`@gI1LUx0MG*8|LdfXh1{WU(M5;KDT7EFd#aoB5ZH2j!M8$9-L{Pm#WpnBjR zyMp_9zE5_k7l0Vl@vd%2xx-iVUwiqfw8#knYJN;x@oglyj1#1v?G=wD0x%n-(=#Lw zG$;(L{{{b>cZodjFu$?o-0+kHHCzLu1pcj+b3OhLX=#d$!$lb(=6u1qQI zrx6D-A`V3g1fdB8B1Sfx)La3c5%MGmK6>m4u{2m~=)JTx&4Y2e8mgTz4pXA@zEEO8 z3L%JL!3XYQ)?hkbB-dSb3MGre&mgqCaJ0osjuqvG(l3oR>B@zgVHw$pc+^xXux$awJfEmtBVkzXXU0Xpb1038DNlfy9pc6mOO zWchTcf6@{=sf>#~T}+ym;~K$E8ZVRs@8FikBWel+I2jPjV30yV(U9_o;KT#^$4A+X z2sn%!!x2u8HeYezLZXOzUk_sQ#S8Kq%Zm(fo=2G}Gj7s1O167?Ts&RF)O@@+M zunBer8OQS42^Trb*PMh}(T_Wp42a5--moQle6{=5=Dzf_)!yE6fu$r{y*Y5nq6HwN z2}N@NK<*+^NhLR1lo(bh2XI*Vj3wS;WTFJOEHBG6f(rbmdjiuPxvza z)&kQ4dqQ&PuIjsAsvP_Ve7W2Zs0n^;)Lj2w!GYF#Njnp{PPh+sG!gsGhvoE-XY|Q$ zcI9X#{2Pr7!P)u&b%M2dc?>B#(v{S*87Cboh=R6rA>{)U-RCOeuB8WpVs;C%O4&m@ zl`x}kEHk%PpS{@^l8WVkN5kaSabRVVg$_;KN0Utqni3Ek69DuUgtBnQvT|qbI7S5t zM)rcDtV|;1!A}`GttWXaaWl{OZkk>TTbcrpl3jGR7UJ00>|Au5!NkkX8D!+ntH z4ne`^c}g{Efl}1TABZ#srKEmo;dA?R;T+mGT^U^-4vMOg@~C$Z zi{@IQe@+C6s9G(LK1Vi=iD|I?onLU06Ls-{b|8U*gl2a-`W)VpZ-(3@~RT7LUbR5=93^MF4$J`oK#2PCNvi z!~(NVP&>FzWpR0r%Vfgpb1EEd0>#%lHDdo6?cHf|J*iv)i_ageX(?$uY0n!M{a;oEEX%bKpm8-Dnbb)kkAqjUc~FHl7FwBdfoA;ozvePbB}KZh|AwBJ(k5-<#W)c|Ai@0 z(C(a&re21c$N0yJBwv*P3jh841|vauhAgGpUHO21eZ5kD2o}q0dXpaA=P9m!xR>yQ z?ZNDY!k*$+XfZS{A%R8h>pQ*Yp|Kq^Zb;*Bj%AWYExc1{)c7D_To<*Kge|*Nh=X>Z z(LUjNmp2Qi1B*cYuZD)_<|3UvpKousLuxb?|77+84}XZvYRSBv6Iqg#UZfV|$`;D! zB!q<%hZ4XUIY<*q1;aRa;r0YTI1SYb=+spK+{komsU4wUY{mfqLozE9^jk(C$*e=_Rd=?KB>k_Ji#fS}mrA`U^=2Jeq(Z}e#t(%$e9;e; z`>?J28%aP-`UXX;?e)}U;Qr*0nAyz5bZQ#oYLoqyw=c8HBkXP8?m^+hQH11L_q`w z(o=5Ua=@_t*vRxLz>rD%$fOd$Yi#0i7L5mlVv`lLMY7Vzka~CVa31P{WT;`q(99ea z;-JE9tb)SuJA~RN14Uj6&7c8lV`MxO_^lum9?X942a$@Yw}@yATvw6exulUfxIE#{ z>jpb3>Edbi3z21sm}Oi{+}sbtv8cN_1ex350@HIs8mrc++HJh<#*~+1-%p0*nEHE% zLyLCKoD(}?uU97s739TD-%9ZL9Bk0C7H|h&{p+}IZ!Z2lo^1*4QU#r+&;CzQ=7AzXiw$i?zQ9XF-<7U`ZTL}-mJzQh>_3-v~>-JP}Mi797DxOP# z0M)nm#zrVdyDud8ib8F~PW$`85t^2v&m>5SS%PtFM8=+w3`@BNfYFkOf~*%tg9nDn zdi3Qp0k|P2PE?zvlNv12fs?=k4MZZS0T!lBl&}pRB-8~|-}f=RmN=VEF;Z0R&1hdG zU+?IL<@$v|DpENwf{fSB9vyfbrc6Z~x^P`p{GTM(1fg*|jrPw=cY~MoSP1NQWEinr z`d~S{r-;CtP@&DNIOA^;P|JL1P!2JB;O*^zQLKN_F2HSeQ{!Mp2n9`TS`u9x7->X&CU*p|#eN*il@PuYy zE9!Cg`R)I!xJJ?~*XY6LeQT50F518IMii+)Pzdl>L6%B56yK5x345ga^$IgEIt-vK zw}-iqDR>1j^?(?Ri;jto4E2GUsk+>p9)IICdOn*g7%OVfs;_Eke=1aOXtWy5RqX0s zL+Sb2n!mz#;eawpd)=UHu6A(UwpNc@4@nj$kP5ChOi#R$8-7`l*)20@{mktm%IeDV zoz|&>=`-c5q#q4txg;sN^V=4GnV<-pH}I6M!ZQn58UI5F;E!K84M9AUbj99k^~=S2JL z{ZaevY*=S7-L~GA=RM=+yX7m-OFKx5qoqrmdwcFg;7gnpSTpE8AfWvv#jVxA(Jrki z`l6JKSJwh^^z{S_>cC%tg7t-bH8c zlHP_qeocFZb}=PfHLX?5Ef$YVKfOpVHZXaggdL}M{mGcDh$7DE%b$sKW2H4@Y{^ zTGIG!-xR)cTipV_!0&e5lh5w{H$MMV881yh)%}pp`B!qaqT$^Kie4)=A-jj|r_z&+ zRkZ*7V^>{`=Gcy%IO3T&n_eyMA2~6KnhqRfRlEHj-OM5fKn4s+p)$rRIz$8z5GZsh z5((*5pl-aP+gvcY+nCOmN75pnV2P%y$* zFL26j^KMDUkM$85;qlVCeP4d}oSDu)CQ~)RofP7~e`kQD00^=p$cIfHuE3h-oy@T!^L(GE+JIx$t5~Xq05gQEWZKKiYnSuU4>&64SOR`SNNZFX#Hk zgs*}>$?DN{b^~wT@J6>|m!d%2(AV+BSkttX>rbZpCoeXOlZ_VFsBc@#ya(txMC0!E zc)uL+ZY}Mh|FX%jB)M=VT0a7>yP&^JsiI7;GNS&u9hDz@-t$|ExflQmeVGzr0|1TW zyX;_1{SN34BB)g#^}9ob?;)!KQF>;63_tY9d`sN<5d_5*t!boTrg=38#eC3 zVQ|sb($8YtHf4{vic5XxiIdV`O2O&ok4P23qe46sQNwigL}14*hGV#fln z>tpGc!+&5bA=y(x|I6!s}qIaZ{o0Oj+6b!L`dY@n8*1THRD7WVMZQb_e+<^J_ zmr0HUk?J2eze%|GGx-nA$|vFg7YE(CH@t%6G_+wh7Orm9S0)mTE~3En<dE&ir^_4)JV!@7GE zY)_m4vTrihw5T*EFi)rm$v@%Pm<1S1xLsZ2J(C_f&1ojIE5IC82Sz8Yw~?P+L=$x>l8nTD}KMYG%{ zJ7>jT)VlZ-g+C_S%zWc%(qHrAxx(Z3SGVv$%QhW{pqQYc0>5}Gn_B%tRiET~XP{;F zvP2;23n7{EP|*ON-?5|Vi7T?*|Jw(2?*dv)vuTl%ogc+V#P1trOb zH2fL6q@5TupsuYk0SgQ+eeC!*{e}V%TFJFnaADm@jhIK41JU}jHtwgz@5V!`PFuoh zzdpbPy=zm_awZX^(A%(4-0scCm`MujXRNK!s?#qj#@#pmeSe{L-aWWQ<9nrd$-LcB zhi9p}l;))WdS_%$W3f+6YwC~Zh=ZKtyRY9GP-{gMjyJD|ypTKg`%*72u9>g4KlhxE_V-u=onwLM>_P3LkqWZip&Z*3?zS0Ez{SPuB1 zCmBdWt5(z`;zN7zF~L|$l>2aF>Ya{^3~!!lZBv><$S$kHjeyDH$*O>_Ptg-XrK1W8 zJZ2q*9fe$^!kRinV;0SmpqNkS9Q@_x8gCuy_?_9AUR2Z2Sl_o9@;+sCd&~GJiY+1g zWX*KV5T1mD<~<`5RZ1OEBP$ZFLa3=^{rD%QU=S$T4j8CVbgjh;-{c~HEx>{w_C*x0 z7#cJNiX*leiIjs+37&)aXdLun|6SjtcN`0LD(BaKJB0olt2>-$n_JK5rV2i z?paU~mX(y}wnaVEi_j#)(@bp5J*NA-+uUvIglW&!F}{7?*e(2YBw)Q)n)M<=<4MZG zxj@2W0|WrVvWKV8T1f^+(lV+2O}`0)2%Pj5tK2ocW@C6-9K#QEv|hPZv$;p@7k|3M z#vb*y<3P2g!IoP5WLo|d#PtO62Spkxj`yv9ak3_l2Jj5v#Pv0UNeIqGeo)Bs)oUwa z|4__lFVdCdU(%fWr=nQsKM}hj(s;;yOzFlcL_D&v6}YSWrAIr?-0uiNB$60q*S%~b zSd<5IJF-Uv3&)5qOkPWAV_=$>F=7E~7`hkw{evKf42PYQsFx2F2-Hoq!b(`jKD|&m z$k9LEosZ5)fv4J;?SZqIaPhP(RosyS`7Pt)5oeL~2M7AF#DIDcfL?u}3Ua2-NS%NRWC zbdPidKP5t0*MWr*Tfmjx-|;=g+@_qzGHSs)Gl z#hupzCV&1}c+fc?d8PmTr2je>+_vu2JZL#1#r$c$@NLyUW?wlk8-$3J#kpAV3lTw{ ztOIV5BxLM>mMDsLKB%K;R>LX+23BHetuH7dF3NAs&(c3aR*@X=q&l3Ccu-c=ShdN$N#9B`3?3*eB&L$FGvvdi-JLpf&BJqpmIt zuX^%E;Up0pAaLwrtwxdaTQuQ$$lg~rIi}QodSNLu;_^0aaL8K(E4_TU+Z3Y@+vw@M zl(N#iagn;%Yfx=nP&q2F54MQkqP){rGoiD%EX}2jO4YaO7e%H#@M#b)<1COCRc_O zE$hFw%_iaQULMnouRa*ady!`EYH@$ao?5TP6_HfU-}jBpfMqmUIJNZDFQp3;=>17H z5U2Vzax=9g@ccgcw7Fa2;!Bk#`)7ZgMFAHAJ^58bf!b)+k@Ec$+`8xK^8;ZPlkpq6!U!{prAnt6iebX zE{T#|7?17Is5hoRb8qktSAVQJPf}|u>5t?wLk4Z5$NxO-@IRYBzuRP}G_!v5fId#~ z;AV7k{@w6_g!`4up}OSq$av21&n)RDVn_cr5c~daBDZ7uFl(#i@DknfzQ+{QIm!e8 z>{66KuEL=DGXqTGwXiL?Jn=w7S={BEI?w6aT97Uy>YYjA_4>EBm=AB`@YyOuG%_WT zB=QOT_=094D7elLc(wQ&e$vHh+3IJk-6V_nBQlad*X5eOxFgWBbJ8SWONSSJ8v9Z# z@DDcjTQ{DGkfI_0sB1Lxviir%9TB1OKjx3FT%cd96#lZmlh~%A9&?Xb1g+8!B;kE6 zWZ{?>_h?u!qTDGoQ&%bL$T{&l6-xH@;LZ@qym*t4!JR-SSsj)|X2xBW>6PlejAFVF zd4cppKGiQjtwHIYyq-M!X#kHM3CU74aeFLIx(v5=8VqMT_CPXWF~bAEm@O-_2bMhq ztZ8dWZwsb&nta9u&HPAWdwL`rpB-sCDEBe?O}MG)n#{j60jaVc->Qi-ykVlOC-6x7 zTt%gtcIhM>;rQS&m5}*#bhq&Z3Fw_ZdlGsnHG1fGT0PXX)0&H?aQawC%;3wk$y>~? z0m-@n2E$TmdY6e3sswh=#-SNN%C3;yL&=N4dj1;-smY!KJ1G2W)jePbopQlG()G%a zj=7VeT}P_%9@AAIvHvRf*TinD*Hd!-(3ev~hcq^6yRY&8xZHaZR_a)lxu06vQR`JX zd}=v5zN&a9^6QMx@(#OhFaQucj;gnI^!o|(=!yst8AdA+faCa%H0b71#Z~1`Uf3Ay z36{?m#_>DoMs-LnSGZ>ksVuS>z?Gy@<|!5w5~s+gOB05^vjCDnZNK*E)Bm({dRby9 z(yw1oRaUyw(h)YHY1hF^2DZSZITIcc+$(1X-AtA|5Yn}dw~(q8B*U^)c)aazhPe6i zHDj!QWE9KJxZdE_%-g1T?LP#(;M}LcGR*Vfv`xv1eJj zr{f=X{uXTPcGi12hHkrC7s;h#H)ud*ANqImnheVp>q>p}VL;C9?JAU~_-~bg+Y|hH zgh8~KQkdbsjeG>1HP$O3(LeFk(?yuuC!1vkPHhKb`vLion{B8)k* zi7Fu?bDVzTyQ+1W3S)c=e1allq{=?U6I$Xk@jB{h&n+@IiM7VNnBo#UZJ~``;wxBc zaO9c3XR~H?25ok_dICpm;TMZHpKfwhYgKZw8Y!&dDz>(_oguc0@bnUiXNk8-pPTJl z^n)PeSrw_aQfTpyH<7#jm@s!lc#if~OGM;&&Qhm+3SE>BHWhbNJdUblTO8hudeo@| z30H&i79{oVTrf>XGqGb7$m0ypndQ0iZ`xNqq7pAx+3@KjyEmv2&37AFYtzD&1wDG! z*CL$bC>*vUKZwG|kKQLf$>MQ8Rv2AS0sshCClH7Sx55_RuT)|ZP0K&$74RKO+p-pV z?=gyEF@VHTs>n2&j&JKb6J_`>imWC4jRblygw1@#ndokB%*0*3zn|3%Uz=+98XB*f zuO*zM9qa%PCf7l!AvmAbJRTvAiRzSnCYhc+NUt2d%U>oMmflo}&sET<{a@*bd$O{T)d4%nr@apllM!pY_up{7M|TLce%5kc&si%F{k(y#(yb?s z^9ofRIFKpC%*8Xu$|rWs_w|cdLQ}W4{;xW|M82ya1E}Qr6(ccL_o2O>@$}b*kFdwiQM>pmTT3e&@$!w?;upZ& zyE8vA(`K-6gr|B}YzQc$_rMlCd=h)!crGjbZDJOv@Y0GSg^ra#bFj#sB>-h>*LacP zpo_6}k~e-QYVcu%|GwkeUNr6wNQmr%%8T6v-SCd`1`k||8pA^^!WQRye6nfh%_Yvh z8P=9fXDv>74qO<@4Px7(WJ)72ZZ?(R{0|9fcZDf+Y5uNY&%V#OOm*^T+{o6bm~*P~ zmB`B+80x#u?&dSAN-}0u3R^^o`hQ22K>)lPjlYpF7vgv#YdL^>)M4UU&E{E1Q-1n9 zl+=XMl(49u-r(Kq6zPX*$yfK+R@+a8*ymlpB0N;6m74GoOvBkh&qd4oMb}QQ1p4O_ zGH#_C2_QMFLexm|c<~`Y&*)j9WZHk;b|zeKZNH{vO}gixi*LxDpP`h?eP}TG#y{So z@j%sNy;^5B1poA7Ht|`{$J^UMqU@I_xE807Lr^gU#uTI!5;XhPqqv{N=~&+68RO1i zcKfL|ycrb5=m6rB(8>)f3v*NmR?mH*V1N0|hu=6+{j4zf0)&5$`eSk7&a{D)h|~sd z?^~AQ_7-2}m(>(*72yS%f7jGpFT{@0-9_tLYYiJnOZ{SJtk+NO%8EFD)G|@>aC%8i zS)`PV8&ZatwAPo+Rlf4& z%e1IHUoi-TLkpP2v12>w6k0WqpyI4{K4w~oiQ}NM?uZM3$3+i#P+L2cCJ_$hsXs9p z&9>L$j?p_$<5iJk_{(H6tGPK0FbVx z+0Lu5Ng}TC#Qe8|<+eiywvPA=mQ zw_UAfVs2i$fA3uh|NYqV->tNmOgE=zQhF`XEO5+XL^nWnqf<21e|2~vnFz5v8@WWSbuNnG4 z5Nj|uEQW1`gx3`&IBSK?n#8`S7`Eq`Hjq{rd&i#eDSsiGS?tBWrhlEXqp9cE=qoF< zWs8y{RR^kvY~-G_YEjy6j;H&fI!B2QvpUda_0t_Q@h27t3o5j#WcGP~9&Dj`$jWu!jA z=v2~iu`Pj-3N?NhQBoTrn%4&2&*nY4H*XG)oK!9B2tuZ;BqsA6p*#Ay^Z@>{N0^<#^ZbMC8YRcd4>O#_7xSW2zxuaVvT2JK`A-ld3 zxRFm3B@v|)qBmhH&ap&;>^N@VdS6V9P^t^#!^2JXO}|x0Q;Ps=XIQCmrQVZPkUa0S za%EBpIfeT>$q!Q797z~Ruih<0?NZY_h##+oAOV=ogi>y45GO25H_YGw33a{l4UlY3EfVC~)v zGF7~Jp@tG7ax%7Y{AA{wJuZ)TL|3JkX->_*lWb%-4HWL0-&5Tz9S*#qe}eA+M>y-` zp4poV_s384e=Yf5^juz5pI|Dg{daw$ZW=D#KkX_Mx?fnqp(|yJSn~4jLNV;KKXvJ7d2H zXMfCwl3^BwijqbW3N5zm*M5J*ZrQupef{xv0+Z3SRPD2ITVvn(_Giw^y{o|Q`@R8x z{>kdvy0FMnmWA}ItDKsf_vY^YGIf@^y8G2s%x^mDZQaRj&&i^tIGBtB0DvHXoQ$jp zb*>MjG-862MFxbU=@gZpkN(ifX1)pK!fH{zPP~}%n$Ae5 zcwqj<){jnh{;&oRYF$mfm{8T4 zL}>MeYVNEa<90E-9rI?TEsLcm-~ef!3MyV!2q#ixA^wlGypgOI_IqgHEe9VDH21c0 zZW5vwq@ZAlLIPlUj#eMFe{DLmBjTHkgk3^B82Q2kW$9sC0EH(3mX<*u{j<-CJ>cJt zwe5JyrfRxHVk>-fbRr}*8zzDo7eQVYoUVFmA4=~%!mEE(;{m$M`BkD#ax3s%ppef4#K_W%!=4CZCA00_k4-2P#6AdI16T5Ir=KA747TvYf9@ zQCdYgno8X&vEj6?e$;ADn##G$^q_K5+3o7Hv#F-cwSLUtC2HRDp|rQ`#>A?of??ak zi`GH)+4F%vBXgL-tGxz;4ENk-l~?w9tny{-%M^wmi0bDfa11D2I!7qYu9W`gq|RL8 zg3r~&inC|2v{oOViBL&|ve-ZdiQ{5)bqSEBIF5!>v=FRd4*`JgP$o+{^3h^QTO_GdsNUbP9?0L}-e~g`B zEc|I29-g_SK7FYz^7EXiVMCXGrSmVe*+FbS?N`j;!e4M2yxex7%{tsEjxKEOA#5m@ z25fA{eNQT+m&C}iLidOu!7DMUYn)0$q=x^r`Wn62!JgIcl4FTAyNtJ2PXu>nw0|Ax zY_6G>J=h->$&Kre6|W<27Cx&r>_k81k=_43?Wa-lw1TDh`Ba2ZJ^&14rQF|4}jqtmzl#{v6x;XeRUEUnXWloGr~f9;W=wkgmtYHB?Sta3m-TA&Nk$R7lZD2oOk- zVCv7A6xK-)l@ZD_1Sv`I*vTOC*qBPB++|cisv%56B|{i<@L`3&VGV`BvTk{UxC_hKLI;WtJ&6e)SkGBYqLN zXK8FOZNec7NL(l+Qbb5{^>W{1o4_H++cHKsDz?A`;I>}R@ zS^z)_I^_+f_6r%c$W_z4R9;N^d1T^5n$+!O6sK=ec!JfY(}OWYYw#(?R9l=S8roHzUt*MNU504O z=809Odh5}kvvE$Q0FDNVJP0s}M`2=+DC)q@W-MNYrbO=(=vC7^6S^T02uPlR0ngY} z&T+)4O`~(s`!9Wm6Fe@4Fbi?g;BySftB&=GF0&{A0O{C7^P*YG2;Jr`pB2@e$6sI_ zhQL@BD~JxQTG|utClt8y_@vnCCmSo^{?RhWix=N(2CPw0kkl>}5zt(_i5ECs|!dAJN zbg|pkaST0;0aSl#0E1x@5dZ)N3P1z_O0uLdPtm~t`>+HFfCS!HT5}0Az^F?52xW$j z5Ve_Wj3jT$2%_!%h7GB;vE(TQ*w&nN=>@osx}hN;1_0(P5^ROU1h7FRB5=UvGB$WD zx(z84$=RY13Ia|5&?W#Lxds6P0XmaHLXt%hQP@ntaFu4r5b`{f2Jv&Wl1P@E=VC|W z*{xmJ=!~~xt21|5?#)#nq?u0b9!*!l9shaH6_Th(A{JTOL*~XoHmDX8He>(18PNa) z#^@A5h54F5gb-jL!B!M#R54_#*wc}f=SK%kVzrn$Ske!b83{&YfLz2$6M{`cA{)VY zi6!s`CINEWqIuap^V=r}n-QWpAgF|%A26tXI4fd;vIJ3}n2)DPEU<#LW9B85k-AnJ zyGD^7R1;H}6iL7|iYFvW-2(YkyU=5bt=3&+$CfO+X{=|Q$Df`XJ+uF<|HopfqEx1Q z#o?30EhhEq22WH#04gws3l-iR8ps}6E+Ndd=uBJ)_N;AUApK1NOf+dm0T_c=0#SNc$Ru)L`y-1-wGszu!6B@8cP8aUx!)(!SBIOrr z8`I+kP)I(1ri~SD2x_Px03mULND5k(rWzg~06;}%YybPO1PXuz)MeRQ2^{c^D~l;% zBe+p*hii-^Z-Q5??X`v)AxxQ~u0`bII5y%{VaQ^huB^z@6as;!*e!xKWd>5wl6CO> zhGR`y79S7IFbY`!QY|M8ilEQ>hYa()~Z1y_4djJmd;CCor<;mLAVZu;NlG5nUhm|Y1E!&r z6>z(vGPfV`fb%Un!276@-KE8X(@oj};5vz7Ec0*@St(iJGFoW>%kY@VOuyXb-RE$g z1^4XzOAd=pbu#1Uk{vHl<3>*x=^3V9D$`iGW>GL;J0eM%!=hn2!c>y(TSZIFyW&=I zJIVG(#O}>=)h*2qjfR(oB;3mH?nl;1ejX0A#3O zqL>$(u&%H1qWa?o3>YfPyo~wvc2i9MW1e}rx{D4i1|2Z+1l=}QJQ#*4$T9sP01Xy#OmQ9sDORm2hUTS|%33k_r1wp)8IA z$5ECEi0*JxRB*I+Br!5)OOhEuG(RwWN++s;f<<32DVUSi*y0z7j*}Dnj}<&{1q_%J zL)4HfC}H>mqjOhCRiA|#6_plZJHK0FVzHLZwAsJ+hw!$Y?@g4Pa+^w~Z}TTJ&n&@r zAYp<;U1V>l!)ncVM9P!{C_zGC5d$9?S>(W@K#Pfmm>5}bgMwB8h!#%1{7Y9Ja9b}Nbo{Z-xhk%f&Xfs*M zpsEdlNg(ObMlJ*_Sc9F&o+AwggUmGo&MTl>Cyj=Io-e_GK|zRjsFA93Rq!be5=f&j ziU;%NJEL&XIF5ua2@6v&vPW0GP*ufFgf5h>Ose)ss>m#NXJ&0rvStw^N1O0+5{8C^ za?Y4WF`_40S*>+VMK|olfQSdrNrak|D&lChD74M$0AdgT040w`)*&RoDTReVFUat? zCPT=W$eP8Q=Y|D>w&VZ%uml|f1*K)!TP#K} zh3i{wVdywg9hqm0Byqv)tS$9~jp#7EEWk<3k3Axh)O?;^lyN1Y3CmbcJ|ZBGs1hWI zFQq2BwE8rt?6h$f#M?AJGB)zF54^YqgvE-Is>*j)Ik~1&iH$kOl#wA@8ok6VtJ_>i z<}7S6Bc?v6Y#z4^uw1z7GLU7nUG=xdvr|b)e+7vQDD&$-v6tp5P!hEwAOHX=Qbm=G z4r@U9HPR$~du5^Wa4g&K*OcK{Hv2s;`qG~EvsFt|F8Bwp0R3uh^V)IxO~ zax%_Zr5tAD$s)Slo9eWZZq0JrLklXZuY6a>Qng;N_Yo8N#rG9aE%Jjz<+akiWzRG9 zPP@z!*TBLMW^;Q8WOIo&ZrO2vq6-I&omdTM}p&!alK7Qekyx6qZiA z)-CFldNha?O%N^_45ML|NKq1$LdGVWE8?ov!FvUiT?=W)NR*75QEW>#56;HIS@Js= z;Rz(9h^ivhfWl*;M!6839f}KZ;mh_4Y-D-G1L4?tnvx`^n}O=SZM1VZ-&PcphsVo5 zfPhXb)i?dc&or@=NJ*(zp>=?ZSi+-CU;!nL(#U^O?XIBf!qR0>0_+CMmN%qH6N%-RcTs`_T*$%^x{-Pj!g^34n-Uha76XyN35;3W@BL)_ zzT|oQ!tUG7<(9~CZ)HC-4G$75#SVDIBf6R@w~J%|2oTI1V&xV=O2%SU0&BwvB29L- z&R$AZvlweI6U5-tq`EQ^L^HvWfN=q~44q|CQgp~#;AdNmY^TU9lvOW>a#WKW>)rCuqtF zeT0Z)wb-7yK%`PpS)6G0&+WudiSm-PBL1>wmzwoe!c4_TmevJedY%5T?R8c`2sD$V zAbi>hjHvA{FAD`zr5sa9o@ra+i* zZrYm`AXtN@^^P#+RQ#i4j$dM#W?!Pu;Vh3oBFL+rUU{F#!65?X?kRzgl{MN%$p?PZ z(vr_001yg}kX%4v4uF6#YW#!cEFrO|lRsdtv@-8X%*w*z$$fJ%D|#xIPC#}LUnj1Q zjotIhzLccplm6PT8vDy7J9kRIOFW<(Zo@tZE7MD;mZ$X4}lzB|Q@eS1_k^rIdA)(1_|?xmwG* zJf&9VkwMD5lyTK;%Jx`d`5zWDo>4BOdGTjtCu>`O6$+UCE*9gIqW}NMT27u7^;DkDeurbpeLvvR|^kz`p} zo^v^0>B(5oirk7ng(ExpQ}#g;M`j%nR{HGIn>ak320LJaJSUSVFd%48g11VhoAgqF zshw(epD4XgDUM2FcJ0-qly3~+nJmNmAhXC$1e8oRT2@i<8noQ?sQU-QNWrB{1zo#g z65%wM83xIyx9Sv^!Zm5q27f~yQ^e(~JM{Wb(Z00%1AHzrI<17IY-Bg8}iSa}ErE+Gbr?qcS9-G(OPL5|#x zNfer~8i1d98yk6L6R+$HwBfTVgMes|RX{t)@fyjlsx|B~j4;d*fs-p*#Li-pSqxDqXyV{9aE!Tc<%^@NS#SPOTFIx@QzrBUiz)ELzwSONu;K-eiD zSqZ^JP@y(TB4TM{FS>y$ZLp|0BrcK3Zl^R3H{%>xibVQNt&Y`SQD(_lX`g!-W*<*v z`R|5ibJHNl+A-Yob2$$9>gOxuf=53yWG79eO8VL&P?H8Y41MB-z_5Mh+zxt=F}$9j zAV2^UFF>XyVJB8WnI-BJHij81Pzn$1vOPTu%4+LDJh=d(uEQhuSj7hsCbHC z&zC02Q0ZsW*OGGD(xDTJkVld)QeCeqBLO58Wc7-eL=@EiAk~mY*FRc zmjS|}WCB1aD52mX8M<23kV;hNNQFv-kb^r6d4j`^v>jAz4Tg<9sUawsg$pSdbl6J~ zMU)YHX#xi5RxuG!aPCP>Zw@Ujsj&jg*z*txx@1HYG1CE;6(X8L%}Bmnyt4b1{M_60 zt+yAnwfC3XToD~1ig^rhmn>*V|KR7NK(w4d1PBQ$7>g|(F(_Gjj=n8$x$6J>umlSL z1Z7>=;|Uw!s4S|5ZG)at-Fsuzg@6JBF6^?ffCQ$n2=f3!7=OJ&k-)fx^hx9h$V)Sk z8$-#7Xr@5Qq4AVUF4CzGp)u*$(6bZUN@0wQBk>GQX0R9m#WJK&P^WfI{KLywCTuV1 zel;&ZTKG1lsv!})pN55z(>z?8Ozc*!q-G|=#o`5niwDk)iasLADnXt9XaWF0C!(N6 zVIrtg4W6M}2n3E82q}qxt;TMkOPVhJL-X?v^d9y@)6cP)2x1ow!Z05&Ck`OlTJ;A> zKT3;rAX_`T(ZfHFuxkCv_QV6_= zLcoiqxWMVu&)X?ZuAKACa}CR3IeGTGszBx5^OBk6wi?AT+OFKu-+M0jjn#KB_pJ7Q zpHVLU_Wakj`Fam~x$a`+$~FJmj;5~_()BU?J92WyS*e)k4-`%+>&X;9W^T z8#R+@xKhzIB?M(CI$fajbhwU~z*ub>ovwL9zbWyUC?$>@Au5X$VdM>^V<8-I2p}G? zW7xrrVF!~YTn%$3`Kn6dD(@JO*AJNoTEw=b3k>O5-8rc4mQXV^*HnEc=E6X3IPEkm1Si!1Tc^k2_%F#ZRHeUzp@jQY z1=$QtJZ_gK9fwi-YpA@UuY7`rg6v)haUe+KbFHUBTk#^ zJ63Y_B_*1AlKo>(FYGDSrH0yUx;H1SF0n1A+}+C`e+o&+$2$4QX`zYd_BRaI-6j-v zcSE~)=km;Dl$WI%vxYG#Tt>~QO)FS^HmP-iv(orIKA14x}#Xj<6jSpp9+a1Qi}AMO>aYQk#ktJJ#O*>jJy(|IXPyCw_z3*4ohigaUW_Z_WToB6AV| zKml&yWizt;hdO0+CR3oo)8*V}Nr3#p(l{K_kIOVsDg`1X1rtON+^I~q&|*}x4SYBM z`>+HYfMiu(T5|>);;Af3!D)uXQkjQkY&^<>Yci|lh7RCWCNKm5gYDLpZy-_F!kQ~o zEGeT}8682p)U>M}M{On%@X6lIEw>@afwq#@fw5 zzcwKDKEHgpbf)=l=mH3q9 z>86T37pFxgIE*;!1|{qbWh4efrRfFaKCdObVBbVvn8CRyDXPF)E7j@)u-1R`3~ z*_R?GZoB1F%+^ybPDXoG#k%sM#4buY${8`6d)5s;8%2syw)#DbwF8zO8;(qESiAJ?NRUCsOnEvVKg zp{IsDD}5^@J2!Tg4T!C8X>QuW!TMo1D<%l)55@ewbN+{^600gEe4syxFCP!6-gn(< z?k$~bsX1j-gKd1ZHW=?@3Sp~FHTGSOG(&Fism3BI&?@OqR(IzZ+@pJ%!bDv zB!p>$A?e*H=hI+jg5ptcN@^oWU}!`HL_tO1c!{z)ss_yi9a-s?i$gZYQMPa##Gyd} zcK`dZ1QCD)bX(c;FETKlE85s;gTzoxmu>7Iamp|)Y%!FL`0)xb;GlJMX$wj0i9OA7 ziqo~KYfGY#`Bk|3hRmn7z!fx+=@A~UA|rg~i06hwo>PDS>9g*me)qQINk@=wfP$|x z&N8gkS_PFUZThdQ&+_XxTjM_B-(&WwPnD=bCn_wOPNnx&8ETPUkTC!NlOj|lh=5>F zyVhL@X$sfU%TKk|JSkxy68^V2Eaai*ltb{;Dn)VAaGi$%dNNiT{X4I{GrJat)RRww zAqGe$?x|3t%c@Jn!=$Ih0-^wJWSsNhah4V^(&dy}uz3}bm^j2j(Dn!n74(qu3T%lX zA%ii*p%^n5!HUHZThdoCibPJ)h`g@H+{-8C5c?hbpigKra~Tb^zR(@y6Vo|NNk9iQ zf%9Vo7BLVKcqBuGWDak?4BNBL^oloD^i0v@oo>)99*Pq3QHoQE!DxD7b18VnGZ&i{ zmI=*~7S@-ck)@!7#~+DR`{OsVn=77w&XHv^>sie`pB9l@&ot?CX>u+}*_$En*kpxH z0E-kN+J*s2mQf4mgCK000Xjhd05VZ0Y1T3@(}mItga#c;)qyITnz6TLg%^9{Q3O#3 z1OcRJk){F)a)m>5d{PMw%0*0t2w)@#nL_GOrD9gr${isjWoD#FNIU7K@hg{scoK>+ ztATb!8#Y3@k)w8KUtwIMPfbnHS;F2Gcm^e^L}{tb_5|B?iS%U1#uJ&AU`!;jVX!M{ z6?tWMbxM>1Y+ztF08rWu!!Mv$Y+y?Ew4Hvs@wjQ7!H^XEyg32{lENwH$|%i?y)0`U zn_>3<`>+HXfFvhd+H(dRP?9V<>0yJo6MbuA%q0SEQB8j@@(63+o?b!=r?nd~o$rGPZv2+cUP` z3Wh$=~3Du-ZrXy`n&G-D>=tT&XU@+^jzW|Qp%l(bSuZu z9W(3%d1`i4E2tyFU1TLpx z+I0$9^5&se93m*fWVaxnwyv1!z~qKHm1%ttt+Na`Om%ZOR5mPz)X^ml9?#LLBf#O( z4F$E@%<9Z#>0A-jn`i7KZ-N^v?6riA`4c;l|Lf{d@@;9n zIjGs_FH}>ry&{XE4R4M_&I*p^9VCVfD6BI&<@V6a%}A6SV`Kx8b=Ds^WTe4K8G+Hv zoXEn(t9Bq&3Q6Q`Xxbe@ob7Z7p5>IL)Gl;ac zQvU#K$&`;Fv@qY<|G7Cb7?K?bC@{eWB5t?r)d7v*- z%~e)chAk3MgAqxl{GoE$6}0GRVbGn#Y!n(MnNiOpaxI3}o#{J2wK8nM+{m&^eU^`& zx!7+zl}tQf`_}SjOY}|MW87N>iG!zPUQq#$2~85v_+HQ0t6UJS@Q-QaDpq_U10-^P#KwL%p`Au6|C&E_93Zpe0qH?$MOZu z6tG;{1hwg zVq&Cth{XXMR3BxBhY?vqVqu5Sx906N;9+l!Ow}Cp7&E!Ynv!Ob|{|TxvoN z_u2k_6+OaDDzF0CM^K0*n@Bt2AeY{KWG*}@7W*@E;%~aECNv{1GMW-=9XGK&!cyP9 ziP%;clrJeN>@&?BhpL=mK7%tdF>ayH3J&mJ?zj%Ztvl&aauR+s+k9*0A8T{Tb8gRjk#{!C`ez++&ZF6lJ66JQon1$0e71 z)M_Kur7Sd`t3uMF#kaN0!+a~$KP$|Q{dwA2etP*hYE|5z+#UjvtzMlppvA6 zJYi8F-da^EPt(X)OJB5=?EOGg^x|m1@(9dDW3zbFW=0MHux31tg^6Kl zKIAhqwW}Q>10%weO4Y4?Hxb8-BDQ+zmhl^$#Xs`ai896O(-iv-k{WK}4LZPx-ogSW zd}{HZ1c2^`*JFoQNLJ_Gd7e#l=rSfW``~3y!qo?1Rt)1?my;MClZBKwHrCv!}{;FuJNz?+i%x=Mw>HVvp2ZM%;qJF z`-IEWd1mSUzbLHl_HXr=Q`&`aTdL3tK)?VlKv2_`7yxjoE3q!jCGl^(wUJB<6>&){&wahx70+DilT} z&M9iB5vk7W$QG>s`>+Hy00dE0*!ugn)zq03&7~hwlO;%_zd8lEeamtIwHX038%4 z!UcS%LUAX%?zNcg%PFIFA*dv}1-NF^E(_qdOO#X{`c-70Z100Pk18ozxNNiz+=1$e z$1PTeC>J~l7kRAOg4irSFOR1~Pkv``rIlQ*9Kve~K&}Ty*~3JFA~0YsmTStHPwi*i z8kv`Q=Lr2IrJFc;`DtsUaW+Dy;cUgI>a0EEF`)BKCi(kpknS-EncMs4 zEINfo8N6y~peUYgUR2vgY?<`+HkZkxwwy`Z^@U1RhewN)frq4r^;oOe<_+R@<* zzEm|9HUm>mgWapeDQSm}xcI)NXBk2fg;i}eZFD)pVsIi2RIp%KjkFj%QI*>eN3AOb z`r?29ioOdT5qyI-JJg$Db@A`WvtW40DbfcOeNlupTi+9q!`>jdQ4{)2FS>nly7mgKkjeUuEp1ae~`3Dw(IH_yWI- z5!%|MbpKCmjI@2l^Ucc*`Lgv-GvU-vXi2?us1e1n2 z7WCH9r5A+IIw7K|ijpq+!mM_>)&r&=Ul@SErUQ40Hj3E&&KCeHF zoUFE_OO01#e96nuHnp++_Fg@Kx5EI1G1zkH1UwzdmotSB5*V`wD)~dE#}_-tN=Kg; z`LEJHbYr)3EGhpjqiU z6`H739G&iwKh6{WjTqI3o2pn{8fbpp_@N!5wN{0$!ng0&>Z~=sP7oNy+xhCY){mEo zB3P#6&PID&!sLXd!{HviSpSJEjC1oaW<}4~&ja~M%gnXu1xp5BE~JJ#mI?`t2@Rs+ z2c(9iUhMwt$be?dEpcaNJjkhWVdijAGbRdz!9r$8TMaE!HBQzh(_5mEJYWlqt47&` zI0I5HL!_h(5R=Z74H48ukCg~V&H;!?j$*bHW|cYxnq~GihbG0OK>$yd=aQ%4lI3ER zl}%`PkGL%T;7Llgn#55o$`vJ?l0o4bx0j|deAH3g)ZDuM<9329Yi!0i|2S-Jn##r% z+oC-HkH)(Y8_jLzg2kqaEi@p7n+8MbY1`e5Cr%lZUcr4 z4A>~@7_dw6kH5~6nlmQ_U9(a3c>9kR;A%65SFrqR&)>-5tWidMc{6FBwRAXj?1ADX z=z~bJWw0DGSAbjSr2?JT8rcLS|NF26EC2+`S=Vz6GvJHsy82;*eo+BmVeBMvf_}4X zb%dI+KB+BPSMyFh{FNQ)=k@P?OFQ$W7~QJ%n6BF>3y(Lu-1I**WEjo4=4ZcDo2IDP z7)&8ZRRH=PrVd~q(Ms-qivS@&005JeDHolE8C4z;2|Ov_q~1i;i5+Ry<4_}*cv#97 zb&Cg}6h1h3tQ`cTh2lzMLV1}ueJ386&aH;W?rfP7--XMj8MOL4HhUY~wl*emneBDN zWwL`XWr|R9h0~qDdHJYpCY{xzsViD>%=sk+D0FVaBWD?!TNw+3jRgHH$cz@IwjF<8 ztqE1+)4H5U06-~73hO{;;GiSw16f*%AyR`P%T8=8x!Qr8_l`qegwo;`JW{(HREg8x zuI0@M3|583ZlSQD>3N9Vs2{txl{u?lF#bx9zcV%w!2yN}ba$}SQjelWOQ?*>mhgdw zpTGTHm(^LNA{@O$PY(;@KZ_lU0}oRJvWF=TJj#8x$pb$zBme=sw-FKf0x&8vA^-|v z0*AA+OI13@MhM&R@vNCl+(q$rEOOL!4QE|992cCsU-I^x6zVH1Lr$R{C(XV@=8&Dvam{I?`a z$;k3=MT^;MOKnm#+D{C>PT+6makc;ZummiD1np>7dn_|>plq7`VTOKDp@U)UF%3$a zF=|PM8xTgOiYgT)OlA+t1goD@%jGZ9>zO*t5H9zP2>i(VdHwBWoWkMX5W!YDZ;T z$+o!t{(B|ME{`Y)A~?BWxKATKkd?X;xD5+;QGhH67iyP=W@^Y0@DY=t7ttotKan-x z8Df1>zzcTqKES~3X^RUSH(LeH1T+N;hi8tRyFcm5B~`oeq)G$huVCOeqcme~oJm~y zYe^Fh+>F%9apA1Ac8}PbdBm4<`GXesx~m=hXrn5dYciXUmATzNXS!zZs7Y#@f@c{P z-!CPRh~afC!-On#U;V%R*Z=@BX#zN9Lc*8`bcyUv8aji5WK2OSlF`I;)489pm;E85 zE2cQ>xN0uX(0wZ!@|dRc-nWyf6BPV3_NEe)LCR98ifc!FM#7Q#b8!>J1CW#mnTNs= z;s8z(EFp8%K%%^)c3pe>JEZCQ-Dw>scb~wNwfS1TULR7>9l#5g-n^I#X zP#PS}5YykUfie@BBRr}Ax7gGK1R8(@KWNx{DI4&K%ey^ch-wmH zfnDq{&4MJZY;}eWxl3RFH_8EZYg8CD_gdd6+!j9$wyjX(b?NF^0>qaeBy5ZbAiTpB z{zD?$1yGIq7p0qF434gPQVR5>#ME+y8$C$s#W{#0_9~Y#YqE78;5A3o16Nv*0EKtl zbZS_dVF6yqfS>P~cw)#h_O9glZ3S!v1@j`qe)-!}VoX~~oPg=+`|L%JQP|249H%Zj zmAX+%LkdB>@_MB<{cg&GdfEq?!)dI+!qhtM?DFfOtpl5Y=p}*XC6NlpSwoQOm61c8 zVkWEJx9NE0KH}oLF}Zk^iEZa32LYr`uW-{-tFtOZ2mk_yfNp?9EfOv{lw-?u&_JUt z)qun!MkgQ+BnnRvyvfSHX_fEhJII~=t|m;szxH$Hu@cGP@?@FF4@KbW&D6PU?)eXv zS8l(mPYDuGdY5G7opE2hPmGf$W9CoF^_{l6HocMydA4?=?k`{VrOQ`mrkD8}u~wUV z&dtA|+XdJ`>jS#qIYXCJ$SO!$AOH)Kae%OtXORfd0}v2SS#i`=wnZZ1Hy2C-3H2kQ zUQ=Qx6N=AR5(kCHC7@`@5%!XumKGLlgymXU9dQfjoim*&F1gD%5GEciZTXPdoG7`a ztotx`Eeie9=^dfOT3lLasF}|=H`vKR6-Pj1;&LtVW4agSNQP)g(+Pa18(E!mmYOI! zvzLWfKmY&{xE^>o$!3DOgqq2I-!yaYoUFHm`*rd&4QzqyCb0z z)4IOUvE{I+b~wB)#xr`lD%zaMY*>OW-wUYWQ2{Cc`>+HmfCN%Z*ZV9(FpW$r8et>E zQ5lzE%p`5XsxvFKhoQM`t{>2k^F1epu5YHl$V>f~D}gFB%5#cXm1q+W4uTLGgyYtw zlW`%29TzCH#g8H@xd-=pT3}=V0OY(t0FQx6rYH$yY>7t{Inip$*sEAfsY4tWLOlP{ zJd*iL)H@u2Cupf`uX^tc>{b^<{>qwOQP@%;$k8nKE-2R`h=gtd+Ik6{g}V?+K3@G8 zM})_&r`=RJH2#z>F*P5Uv`@#q488K{H##JIAFM#zA_J^rMYj8fxW1&kNSgv?=X0;Q14v28+%*ic;sW^=w}Sv<3gN-kix z^~)B8k#$(XqqokQMECX%rVJZ~H>_i1nB}mO5Zkz$MI?ezum}JETGx)LSC#-{frTb8 zgH$*&=7^L;H8x|csf(mZaghNUdae@+`zwo(8fapvR-95A!dWb06v~zaxvYC5-kb}S zDuG8uUa58k97b7NT{f{{7{iI+Xk=VayIz@3IVLmi6t5;~F_V9d;=MTUu>cb|lod1@ z4H0%Mi7{g+@)k#*3@%Sr?+HCFk0^VN*~Fsg9}rcj#X1 z0brjoh&oSV7`LAfY2{eBduM~D87EsB4UuA7GUJ4soB#W;1S|jqPh!_|4?)nQ4C?)1 zD7FwWL0`-mae^tZE2)MJ`Ig%Bnx@Ah#0d1gQJTy*FQwN#uOD?UzLK?mb^mI2m|dOR zOxioZtcr=&6ef}N{h!=RQUCw|10~!N(sqy#yoVoeiamvek)qQN#!%y z+k{({#wRaB5CamYtu+kVhnTP+sH7@*c>tss1DXZaLQF*>gv4Uv$BZhR&z58jAt)+B zc{OO`U&_ZcyAn}w@kJau$gQd6XpI-Cz9`_PCDuW|!q~e|@#tKvxpivhH$_@6-1DH$ zn}>k<6~;Q%BF2egmo}AgE7Z*|W?D@#ZqVvH2nwu#c$eZ}x(%FQPtv;}0T$%%R6h8@ zE`;Q=Qvu3>hJuf5)a62mFI$`cRwtfY=X8JFN(%?1Az&7H6Wx!=ZslHC$#6=2Hw3bDT7;aHUfX^f3esqw|4|Ko$ zjf){vL12IbmR<+|w#h&)0C1E!A<-S37b+WSOi5EpCLB1q;1S~IQN?6UwcQ*kCS`stGnLZX0>VSoVt5kZP$!Ms#;L?M{FU%&>GZIn}R@L zGRQhY+bDB_WMcFi-^y{czLT=$b@G4>4c*17Lu<1cc<3IuPpaRTEX2IaA#flRNK8aV zaE9d%l@jKllz^hkdlQCn_=&g@sKoS^TW%-PQ)Nwr)P&FNOM^xp|J!YoL$+?j#xuG+ z+BuHC!Rn)iXCh%1nXqCi?@eix%9wCF3!7BOnF1T(kqlXjZIssQ=h)$kHSPFrlqwA| zfoe?JGC+ETG$IDimQfZGPpA68gn$45dbuUBK@fDqL1-$_RZEduYdN9n zIu8|UEaABKsZ#RGCgQI~b;b=>qhjf-z8tK?8*uzD@NJ9f$F$E8aH+H;o$novT0Ucr z1Z@H6;F!!i`!zYNsHlfr&_n`@2R{&grbZM!Swv=O>meIauK)Y61Py=$PG8si2^?~W zi#rWrBYaVnmtE{6al*edsa3NNnjrZiywlf97==o*CBuXw6lDHZtZ5Cc zl{tCp#&aHv1LiMw2jMoMx8b{jXaA4!?RS39#m@7{nkI$Zr0c1@80Z&>bTjVF8 zIi##tsr_y*yj^wy09@YLc!r|5`(jEbKGRG|sFx@2gSEYs?(K5yI!E=B3UhH_VMVV$ zLBx*(%mD#V?ydwNLZZU+)yk;EvR#c%#4nJJ&l%0pg*a9Zs?U02yG|Rs?Vg7U-D7qOFxfSpB7kbYJKl%5mwjwKRC>fd@}W zWXRz-W$I2jEM>%1mG2XSEW$LnJ}s9VXC;48&K{)bH?38=;jC8INd4`NGnc{WR0&R= zlv4Cg%}y4?4(CG`3eM;6#R42bVcO zvs{-mmm?l78Z8_GSQ8N~2Pc^rNT`)MU#5s)B|3J&)9(wT4>Z^=TB6MnV?&LNnIn`k z?FfL&%+{f}gLZgc$5HyBh{AG*q3f3|NuVoJ?vuRhyS8gU(O2~W)C`g*Krl9+}BjzNo-@>YGnp5(VDC4533s`!s zGKa$qjV=%&I3^K)N+yYxmxMl20U;4`(T%K$DZ(KNPlAfq(+Tqb`>+HJ00co-S91wN zaEVLG{b3`1Q6)`X%p`HbMzE|kl#bb9)>#k~1(UFhA2+rcUq2|p=`#-xXzsOSzAv8o zCELVkOBpi+Rn(98szZ#k>8QbQ?0u>;S!2it%|-g={Wh$1Lh~;^&ocw(nphv*-LEWM zP0tU`+cZ-3$8ilvBQ$8}9N0zgI>7r>Ot$~EcMw}ppaDfmH!Vm>kV<(7FzwAC6o42h zAg0co47TJ=G3w1Az$PXkVI(g)D3FA(k)1wRN|aknh=xullIt&(7b8skSn_mbbV<|L z{D-=o=({4BkHZU^RYW9(^4~Mxh7aH9EZ=CEBsgYFL6}pJ&2W#KqoT+@%3_j`>wz)9 zJnRKUCi$ai(r5uMHt{sa$RO9s(punnNrd1FWu>Hwex-Gk>1*$U4^s8;{i&nI%Y;jl zDIL|I%uZg;`U`_^hUIO>7SXuXP&tb(nriGbr0k_((w#q4I{9tXE2l-x>Ql(iu3<0z zEfh~Es8DehZ02<06_hzd^$Yc<=lva|!wEvfg02t>A9KKF2cWT+x&Ka(8z3k^0J(1B zf+J91&GK&mAUDf;ld*HI^lw(XcOp&IhqmuzF=~1_H;t$n%lKj#j7u7Xt?82IQWb;Z zb%bUK=Dly~pbS6?77!^CHicwJL+lVXiFD?zF=_}yGAxWgAwtYru#&$Qs&A5NGp?5A zCB~#%?*ZDWkO)Jjdq!`$&v`QG8$|?jF7zV*1~I2!wbd49hjwHs001f+1Yk>BD}=x$RTomtGJ(Sji??6rms`O*9~`iD_j+O&DJvkS-AY{q-4UBfW|{tq2) z(jA%}-Mv!MNh9Z!XoD}d4hQNw77rU$F<}Kw;(D1yH28Y8=bIl~)y@4#!hrp5B+&?c z=UgZk7ERGHl6 z1+?LSu1hbUhT1Wdtt$*v@dZCo?vUnGILeY$n6+};RypNHu9M2?ld;lE@d8nT4JF%- zYQHXJM$B9-okfZ<9StKN6;d}^rB!8uAZ2kJe4@#3Df9f=3Aw21xR|C{o4KvxCJX)N zmYUG(;t#soWlm-@EiDe{iU0zkp&}VTnk|8jF5;ZIDn&*UW!+On&j3Gc@>?l;-+3O0 z$bznqA#P15stH$B<{;pbz)f|hr`sMGr+n8zP z>rMcij`cD8{Lt!1M#@9r|;cDw?L4bxgJ@_Hu?;drZY!>Y1lK-o(TDlFty@snH4B)cS09AATme)`>+HXfFvzt z*Lw*Y;E?Mp3SotAQYnpD%$X4b0Iw-YteN=_>+RGT=4n9zyU!Qt9mJ3{We|@F2P10m z6$oG=jY_#6&&|P}CLWKl2Qyy{O%oREatVquWzr0m1Qjs= z%(2iR(R1s1mn^ai0(oMD~6bcDIZ7@a>@h`HHclfZ6L}nVZ zAh#I%yJSJVEz6_tx)D`(+w9H!m-(H$&bP`l%x1D1k-NKW?v6@7D}HWDE#LUd?C*v1 zacasX^EYtR^wGI9+p@Q)8Jl)@V@Uu4X=BkHp_mA+R53N!F@$c4Hlc3ZZU6hQ1P*{C zf?`&4CPXlv>>Ao(=x$QAU02Mc(Ml^ZE9r!e&_iGNav-y2?ZA|hNGt|*91s%{e_igG z+ArZbD89b2u0rDK}PjKJh$EYCUr?#s!c7#9>g$3E7hoQxIZX zCy_|h(39(QEx*&CBUYsOOACwXRvWnBOQM$q>Oye+viE!Z$}^~lznCS42v`>+HJ zfdsl`Rr4t`;Ev21?O`Lf6IGv8%q0^7L9lCSh9S9iOCL6F{;y#Q?EvFt7*LuAX$3tp zR<<22DNDv%{`$sFJO!cU`RvsfuHwc79>0@&;2eqO7!L_|2T*Ugy%!q`MZ=1D}I7~F{=g{37 zW_8n333@AVN~~;APv~2exsb)L3H{JqTKRRG$5wD%<2`op3rSXsb48P&Fz560MtpI4Hq-l32Z< z>w}t|EfIp2VL3}O-ZlX2DKJp@_HrbhxJe}-8YwZMAVG9!P{KFdIuf34=j}APtNuA> zlVldGZO4@kMQZz{s@E(k`01*65s#r%R7Hv^Z?^8lARx+ot}kxoA|9>29m3x;n39F`}VZ+8C%5 zUY1ab4T^B=^+{^(c?|7%OM7LB9NTb3(wj8At9aDdspXDT^{9`GV-Zkb#nNOYL|k#l zfdSN~WE+if@n$(tsAr|0tFk4Kjq}mo>}yXB3!Jwah$bYZ8qu#!##Q>JTw#IKpa3e# zcveOc9olYM91Bhm0{koreWw~0qw}#kc_-40>Xb_ov+Yj8r;98Vc`7Xp7jH2$LFgPx|geU1H{I?002# z8`bkmyVllUC-w6K9ru}x%KjK;k4TzX^&C+NX*@L#ud*nL1hlh5LmB`8w6bpkT1|j( zT_8wY#*mdZnu|AOjUjDZRycZB0m!9shteUIV$QrB)9%XUtrNe$_kqyR(SUUY15xEx zBOt>yp#~Fa$osQnLT{--93kL4?>eJ9gT;g}@Kij#TB=5f-Y`^o6DORN7KwC%nne0C zMRnYZ+{{4D%0m?Ej!t=jQ0Tf96SyvF?4{TGKSVEk5qR z`=i60Y7U2{rPR&`%tH68!BZlpi5T9;(%ue7c~?Q?#yZvd8ufKOaK89tWZcnkgyW?Fbw3gsB=Kn_v*_3 z`_Kdq00jA1)pcRu0H#bjx~#kaUR8r-`K$l~%P{RXGk^h(uGa2e1RI&kr$bM2OdT^! z-2P}0S!3Dz zJAr$N&Y|xLT85P|=J9O#zY&Qwwam_~k`U%PiC-FaN1D7iZ{NAZi4z~^{O?-L zbGzbfZ*}!zg$_0%YWdE)UbT8W_rI^*@lR}SYGYA1@2pdQ;_xNb{&%b9eSA{en_2tb z;Z3}K(=oSioLZ4H^NoKc_hT}rPATfPsHiR^zz_ri0DxPmfcgg@4i1(DxxtIC6oziCLM=Bxls`QTIP~!3A-{GYtFN3D3xA`~t~>Va$S>K3pE+~} z{J>JEX7r{x9gN1I`TyVBr-tprG=EYj1yMt<<*=2=N_t&K-W%GpBuY)KcQF!}3ZRQV@DsTdXKox! z9rZvwIC!|~P{iPsNkaX)Q?2XU5$93Ci?|X8P0wqQH<_0~II!p&b}PzxUg8_br!7k_ zRfgj8kkxmJp54dR8ojF5BU9f!ex4hjia2gO<`_~^Fx;e(726F=)U!ozJG-Z*o7HPr za>NNM${+6`%s0(gluH`T6I^ny#v#7^rk=$uH7-{vsOswYqm}{|000334JsG_93*;S zLBRj}&;$qr27P7JCvD&Wg~iJ~>?8nL*_lfXq<+h7u_*=2CHtY2F;pO+W@3@f-9=2< zpmkSjBbWuE;wZ{O>a@1x(@R^-#)%P&R=X1oWVBas#uSueBrW+Q{n}W|J(6Rpy4Ff; z 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� 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